Composition API pattern implementation for vanilla JavaScript libraries with context injection, async support, and namespace management.
npx @tessl/cli install tessl/npm-unctx@2.4.0Composition API pattern implementation for vanilla JavaScript libraries with context injection, async support, and namespace management
npm install unctx or yarn add unctx// ESM imports - Main context API
import {
createContext,
createNamespace,
getContext,
useContext,
withAsyncContext,
executeAsync,
defaultNamespace
} from "unctx";
// ESM imports - Build-time transformation (separate entry points)
import { unctxPlugin } from "unctx/plugin";
import { createTransformer } from "unctx/transform";
// CommonJS imports
const { createContext, createNamespace, getContext, useContext } = require("unctx");import { createContext } from "unctx";
// Create a typed context
const userContext = createContext<User>();
// Use context synchronously
userContext.call({ id: 1, name: "Alice" }, () => {
const user = userContext.use(); // { id: 1, name: "Alice" }
console.log(`Hello ${user.name}`);
});
// Use with namespace for version safety
import { useContext } from "unctx";
const useMyLibContext = useContext<MyData>("my-lib");
interface User {
id: number;
name: string;
}unctx provides three main architectural components:
Create and manage context instances with typed injection patterns.
/**
* Creates a new context instance
*/
function createContext<T = any>(opts: ContextOptions): UseContext<T>;
interface UseContext<T> {
use(): T;
tryUse(): T | null;
set(instance?: T, replace?: boolean): void;
unset(): void;
call<R>(instance: T, callback: () => R): R;
callAsync<R>(instance: T, callback: () => R | Promise<R>): Promise<R>;
}
interface ContextOptions {
asyncContext?: boolean;
AsyncLocalStorage?: typeof AsyncLocalStorage;
}Global context registry system to avoid conflicts between library versions.
/**
* Create a namespace for managing multiple contexts
*/
function createNamespace<T = any>(defaultOpts: ContextOptions): ContextNamespace;
/**
* Get context from default global namespace
*/
function getContext<T>(key: string, opts?: ContextOptions): UseContext<T>;
/**
* Get use function for named context
*/
function useContext<T>(key: string, opts?: ContextOptions): () => T;
interface ContextNamespace {
get<T>(key: string, opts?: ContextOptions): UseContext<T>;
}Maintain context across async boundaries using AsyncLocalStorage or build-time transformation.
/**
* Wrapper for async functions requiring context preservation
*/
function withAsyncContext<T>(fn: () => Promise<T>, transformed?: boolean): () => Promise<T>;
/**
* Execute async function with context restoration helpers
*/
function executeAsync<T>(fn: () => Promise<T>): [Promise<T>, () => void];Universal bundler plugins for automatic async context transformation.
/**
* Universal bundler plugin for async context transformation
*/
const unctxPlugin: {
rollup(): Plugin;
vite(): Plugin;
webpack(): Plugin;
};
/**
* Create AST transformer for async context preservation
*/
function createTransformer(options?: TransformerOptions): {
transform(code: string): { code: string; magicString: MagicString } | undefined;
shouldTransform(code: string): boolean;
};
interface TransformerOptions {
asyncFunctions?: string[];
helperModule?: string;
helperName?: string;
objectDefinitions?: Record<string, string[]>;
}interface UseContext<T> {
/**
* Get the current context. Throws if no context is set.
*/
use(): T;
/**
* Get the current context. Returns null when no context is set.
*/
tryUse(): T | null;
/**
* Set the context as Singleton Pattern.
*/
set(instance?: T, replace?: boolean): void;
/**
* Clear current context.
*/
unset(): void;
/**
* Execute a synchronous function with the provided context.
*/
call<R>(instance: T, callback: () => R): R;
/**
* Execute an asynchronous function with the provided context.
* Requires installing the transform plugin to work properly.
*/
callAsync<R>(instance: T, callback: () => R | Promise<R>): Promise<R>;
}
interface ContextOptions {
/**
* Enable async context support using AsyncLocalStorage
*/
asyncContext?: boolean;
/**
* AsyncLocalStorage implementation for async context
*/
AsyncLocalStorage?: typeof AsyncLocalStorage;
}
interface ContextNamespace {
/**
* Get or create a context by key
*/
get<T>(key: string, opts?: ContextOptions): UseContext<T>;
}
/**
* Default global namespace instance
* Used by getContext and useContext functions
*/
const defaultNamespace: ContextNamespace;