@suaveplan/api-router-worker-bridge — HTTP Request/Response marshalling across the worker boundary. Pairs a main-side and worker-side bridge over @suaveplan/api-worker-rpc, transporting fetch-compatible Request and Response objects (including ReadableStream bodies via streaming frames) without exposing the raw Request to worker code.
Stage-3 HTTP bridge that marshals Fetch Request and Response objects
across the worker boundary. Pairs a main-side dispatch with a worker-
side handler over a single MessagePort, transporting bodies either
inline (small payloads) or via the @suaveplan/api-worker-rpc streaming
frames (large payloads, with back-pressure).
The raw Request instance is never placed on the wire. Only the
method, URL, allow-listed headers, and body descriptor cross the port;
worker code reconstructs a fresh Request from those fields and can
neither read the original socket nor inspect headers on the deny-list
(Authorization, Cookie, Set-Cookie, X-CSRF-Token,
Proxy-Authorization by default).
Documentation tree
- bridge — This module ties
marshal-request,marshal-response, andstreamingtogether into the two halves of a working Fetch…- bridge — This module ties
marshal-request,marshal-response, andstreamingtogether into the two halves of a working Fetch…
- bridge — This module ties
- error-codes — This module owns the stable error-code registry for
@suaveplan/api-router-worker-bridge. Every failure path that aris…- error-codes — This module owns the stable error-code registry for
@suaveplan/api-router-worker-bridge. Every failure path that aris…
- error-codes — This module owns the stable error-code registry for
- marshal-request — This module converts a Fetch
Requestinto a plainSerializedRequestobject that is safe to ship across a `MessagePo…- marshal-request — This module converts a Fetch
Requestinto a plainSerializedRequestobject that is safe to ship across a `MessagePo…
- marshal-request — This module converts a Fetch
- marshal-response — This module is the response-side counterpart to
marshal-request. It converts a FetchResponseproduced by a worker-…- marshal-response — This module is the response-side counterpart to
marshal-request. It converts a FetchResponseproduced by a worker-…
- marshal-response — This module is the response-side counterpart to
- streaming — This module marshals binary
ReadableStream<Uint8Array>bodies between the main and worker processes by piggy-backing…- streaming — This module marshals binary
ReadableStream<Uint8Array>bodies between the main and worker processes by piggy-backing…
- streaming — This module marshals binary
- testing — This module hands consumers the in-process scaffolding needed to exercise the worker bridge under a real `MessageChanne…
- testing — This module hands consumers the in-process scaffolding needed to exercise the worker bridge under a real `MessageChanne…
Modules
marshal-request—Request↔SerializedRequestround-trip.marshal-response—Response↔SerializedResponseround-trip.streaming—ReadableStream<Uint8Array>transport viastream-chunk/stream-end/stream-ackframes.bridge— main + worker bridge factories.error-codes— frozenROUTER_BRIDGE.*registry.testing— in-process bridge + conformance harness.
No-raw-Request invariant
marshalRequest returns a plain, structured-clone-safe object. Inspection
of the wire envelope yields exactly: method, url, headers,
body { kind, ... }. There is no Request reference and no way for
worker code to call request.clone() on the original — the deny-list
strips credentials before serialisation and the Headers instance handed
to worker code is freshly constructed from the allow-listed tuples only.
Install
bun add @suaveplan/api-router-worker-bridge
Quickstart
import {
createMainBridge,
createWorkerBridge,
} from "@suaveplan/api-router-worker-bridge/bridge";
const channel = new MessageChannel();
createWorkerBridge(channel.port2 as never, async (req) =>
new Response(`hi ${new URL(req.url).pathname}`)
);
const { dispatch } = createMainBridge(channel.port1 as never);
const res = await dispatch(new Request("https://api.local/world"));
console.log(await res.text()); // "hi /world"