context-handle
v1.0.0
Published
A tiny, type-safe wrapper around Node's AsyncLocalStorage for dynamic scoping and dependency injection.
Maintainers
Readme
Context Handle
A tiny, type-safe wrapper around Node's AsyncLocalStorage for dynamic scoping / dependency injection (using the service provider pattern), similar to React Context, but works in any environment where AsyncLocalStorage is supported.
Install
pnpm add context-handle
# or
npm install context-handle
# or
yarn add context-handleRequires Node.js 18 or later.
Example
A common use case is propagating a database transaction so that any helper called within a unit of work participates in the same transaction, without passing a tx argument everywhere.
import { createContextHandle } from "context-handle";
const transactionContext = createContextHandle<Transaction>("Transaction");
const findUser = (id: string) => {
const tx = transactionContext.get();
return tx.query("SELECT * FROM users WHERE id = $1", [id]);
};
const transferFunds = (from: string, to: string, amount: number) => {
const tx = transactionContext.get();
// ...do work using `tx`, calling other helpers like `findUser` freely
};
await db.transaction(async (tx) => {
await transactionContext.start(tx, async () => {
await transferFunds("alice", "bob", 100);
});
});findUser and transferFunds don't take a transaction parameter — they pull it from the context handle. Any code reachable from the start callback (sync or async) sees the same transaction.
API
createContextHandle<Context>(name)
Creates a new context handle.
Context— the type of the value you want to scope. Can be any value exceptundefined.name: string— used in error messages to identify the handle.- Returns a
ContextHandle<Context>.
Each call to createContextHandle produces an independent handle. Two handles created with the same name do not share state.
ContextHandle<Context>
start(context, fn)
Runs fn with context available via get(). Returns whatever fn returns (including a Promise).
context: Context— the value to scope.fn: (context: Context) => T— the callback in which the context is active. Receives the samecontextvalue as a convenience.- Returns: the return value of
fn.
The context is active for the synchronous body of fn, all async continuations awaited from within it, and any callbacks scheduled (e.g. setTimeout, queueMicrotask) before fn returns. Nested start calls shadow the outer value for the duration of the inner callback; once it returns, the outer value is restored.
get()
Returns the current context value.
- Returns:
Context. - Throws: if called outside any active
startfor this handle.
isSet()
Checks whether a context is currently active for this handle without throwing.
- Returns:
boolean—trueinside astartcallback,falseotherwise.
Useful when behavior should differ based on whether a context is available, rather than failing.
