Other runtimes
Any other runtime needs a few lines that call the handler.
Any other runtime needs a few lines that call the handler. The handler is fetch(request, platform) => Promise<Response>
and the framework imports no node:* module. createFetch(handler) from @shadow-js/dusk/server builds the
{ fetch(request, env, ctx) } module that Workers, Vercel and Netlify expect; the platforms above are its uses.
import type { DuskHandler } from "@shadow-js/dusk/server";
export function createWorker(handler: DuskHandler): {
fetch(request: Request, platform?: unknown): Promise<Response>;
} {
return { fetch: (request, platform) => handler.fetch(request, platform) };
}
The second argument is the platform object. The handler reads two things from it: a string clientAddress (the peer
address, for event.clientAddress), and, when envSource: false is set, its string properties as the environment
that defineEnv validates on the first request (for bindings that exist only per request). Static assets and the client
bundle must be served by the platform; the handler does not serve files.
getRequestEvent() needs AsyncLocalStorage to follow the request across await. Dusk finds it through
process.getBuiltinModule("node:async_hooks"), so it works where that exists (Node 22 here; the source names Bun, Deno
and Workers with nodejs_compat as hosts that expose it, untested). Where it does not, hasAsyncContext is false,
getRequestEvent() throws DuskError SERVER_ALS_UNAVAILABLE, and tryGetRequestEvent() returns undefined; pass
the event that middleware, API routes and server functions receive (and context.event in loaders) instead. The
option asyncContext: false turns the context off on purpose.
import { json, tryGetRequestEvent, type RequestEvent } from "@shadow-js/dusk/server";
export const GET = (event: RequestEvent) =>
json({ sameEvent: tryGetRequestEvent() === event });