Files
suaveplan/packages/api-stack/api/api-router-worker-bridge/README.md
2026-05-27 23:29:53 +01:00

4.8 KiB

@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, and streaming together into the two halves of a working Fetch…
    • bridge — This module ties marshal-request, marshal-response, and streaming together into the two halves of a working Fetch…
  • 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…
  • marshal-request — This module converts a Fetch Request into a plain SerializedRequest object that is safe to ship across a `MessagePo…
    • marshal-request — This module converts a Fetch Request into a plain SerializedRequest object that is safe to ship across a `MessagePo…
  • marshal-response — This module is the response-side counterpart to marshal-request. It converts a Fetch Response produced by a worker-…
    • marshal-response — This module is the response-side counterpart to marshal-request. It converts a Fetch Response produced by a worker-…
  • 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…
  • 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 ↔ SerializedRequest round-trip.
  • marshal-response — Response ↔ SerializedResponse round-trip.
  • streaming — ReadableStream<Uint8Array> transport via stream-chunk / stream-end / stream-ack frames.
  • bridge — main + worker bridge factories.
  • error-codes — frozen ROUTER_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"