Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
# `bridge`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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 by `id` so multiple in-flight requests
multiplex over one port.
- Optional request- and response-body streaming when `inlineBodyLimit`
is set to `0`, threading through the `streaming` module.
- Worker-side error rethrows are forwarded via `errorToEnvelope`, so the
main side observes the original `SuaveplanError.code` chain.
- `close()` on either side drops pending calls with a deterministic
`ROUTER_BRIDGE.STREAM_INTERRUPTED` error rather than hanging.
- Strict envelope validation on both ends — a malformed payload fails
with `ROUTER_BRIDGE.MARSHAL_FAILED` or `RESPONSE_INVALID`.
## Usage: Basic
```ts
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:
```ts
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.