npm.io
1.1.0 • Published 3d ago

@spaceteams/warp-als

Licence
MIT
Version
1.1.0
Deps
0
Size
6 kB
Vulns
0
Weekly
0

@spaceteams/warp-als

AsyncLocalStorage middleware for warp — expose context to legacy code.

Bridges warp's explicit context into Node.js AsyncLocalStorage, making request-scoped values accessible from code that can't receive parameters directly.


Motivation

Warp passes context explicitly through function parameters — but not every piece of code can receive it that way. Express middleware, ORM hooks, logging libraries, and other framework internals often rely on implicit ambient context. @spaceteams/warp-als bridges this gap by exposing selected parts of the warp context via AsyncLocalStorage, making them accessible anywhere in the async call chain.


Installation

pnpm add @spaceteams/warp-als

Peer dependency: @spaceteams/warp


Usage

Creating the ALS bridge

Call createWarpAls with your context and exposed-context types:

import { createWarpAls, type AlsOptions } from "@spaceteams/warp-als";

type AppContext = { requestId: string; userId: string; db: Database };
type ExposedContext = { requestId: string; userId: string };

const { middleware, getCtx } = createWarpAls<AppContext, ExposedContext>();
Registering the middleware
import { buildRuntime, callable } from "@spaceteams/warp";

const { resolve, component } = buildRuntime()
  .use(middleware())
  .provide({ db: createDb() })
  .require<{ requestId: string; userId: string }>();
Declaring the extract function per component

Pass als in the callable/usecase meta with an extract function that selects the context slice to expose:

type RunOptions = Partial<AlsOptions<AppContext, ExposedContext>>;

const createOrder = callable<AppContext, [string], Order, RunOptions>(
  {
    name: "create-order",
    als: { extract: (ctx) => ({ requestId: ctx.requestId, userId: ctx.userId }) },
  },
  (ctx) => async (productId) => {
    const order = await ctx.db.insertOrder(productId);
    legacyAuditLog("order-created"); // can access context via getCtx()
    return order;
  },
);

Components without als in their meta pass through unchanged — the middleware is a no-op.

Accessing context from anywhere

Call getCtx() from any code running within the async scope:

function legacyAuditLog(action: string) {
  const ctx = getCtx();
  if (ctx) {
    logger.info({ requestId: ctx.requestId, userId: ctx.userId, action });
  }
}

getCtx() returns undefined outside of a warp component scope.


API

createWarpAls<Ctx, ExposedCtx>()

Creates a scoped ALS instance. Returns:

Member Type Description
middleware() Middleware<Ctx, AlsOptions<Ctx, ExposedCtx>> Warp middleware — register with .use(middleware())
getCtx() () => ExposedCtx | undefined Retrieves the stored context for the current async scope
AlsOptions<Ctx, ExposedCtx>
type AlsOptions<Ctx, ExposedCtx> = {
  als: {
    extract: (ctx: Ctx) => ExposedCtx;
  };
};

RunOptions shape. The extract function selects which parts of Ctx to expose via AsyncLocalStorage.


License

MIT

Keywords