2.9 KiB
bridge
(no submodules)
Purpose
This module ties marshal-request, marshal-response, and streaming
together into the two halves of a working Fetch-Request-to-Response
bridge over a single MessagePort. createMainBridge hands back a
dispatch(Request) → Promise<Response> function that worker-isolated
plugins consume; createWorkerBridge runs inside the worker and routes
incoming envelopes to a user-supplied handler.
Features
- Single bridge dispatch RPC method (
http.dispatch); the main-side listener correlates responses byidso multiple in-flight requests multiplex over one port. - Optional request- and response-body streaming when
inlineBodyLimitis set to0, threading through thestreamingmodule. - Worker-side error rethrows are forwarded via
errorToEnvelope, so the main side observes the originalSuaveplanError.codechain. close()on either side drops pending calls with a deterministicROUTER_BRIDGE.STREAM_INTERRUPTEDerror rather than hanging.- Strict envelope validation on both ends — a malformed payload fails
with
ROUTER_BRIDGE.MARSHAL_FAILEDorRESPONSE_INVALID.
Usage: Basic
import {
createMainBridge,
createWorkerBridge,
} from "@suaveplan/api-router-worker-bridge/bridge";
const { dispatch } = createMainBridge(mainPort);
createWorkerBridge(workerPort, async (req) =>
new Response(`hello ${new URL(req.url).pathname}`)
);
const res = await dispatch(new Request("https://api.local/world"));
await res.text(); // "hello /world"
Usage: Advanced
Wire a streaming-only bridge for large uploads/downloads:
import {
createMainBridge,
createWorkerBridge,
} from "@suaveplan/api-router-worker-bridge/bridge";
const { dispatch } = createMainBridge(mainPort, {
inlineBodyLimit: 0,
streamWindow: 32,
});
createWorkerBridge(
workerPort,
async (req) => new Response(req.body, { headers: req.headers }),
{ inlineBodyLimit: 0, streamWindow: 32 }
);
API Reference
createMainBridge(port, options?) → { dispatch(Request): Promise<Response>, close(): void }.createWorkerBridge(port, handler, options?) → { close(): void }.BRIDGE_DISPATCH_METHOD = "http.dispatch".BridgeOptions { inlineBodyLimit?, maxBodyBytes?, headerDenyList?, streamWindow? }.WorkerHandler = (Request) => Promise<Response> | Response.
Implementation Notes
The bridge intentionally re-uses api-worker-rpc's request/response and
stream frame shapes (and PROTOCOL_VERSION) so its traffic shares the
same wire dialect — a downstream channel can multiplex both ordinary RPC
and HTTP traffic without parsing ambiguity. When the request body is
streamed, the same numeric id is used for both the RPC correlation and
the stream id; that is safe because the streaming-frame kind is
disjoint from the response frame and never collides.