# `marshal-response` _(no submodules)_ ## Purpose This module is the response-side counterpart to `marshal-request`. It converts a Fetch `Response` produced by a worker-side handler into a plain `SerializedResponse` envelope safe to ship across a `MessagePort`, and rehydrates that envelope back into a real `Response` on the main process so the host pipeline can apply Steps 9-11 (response validation, ETag, Server-Timing aggregation). ## Features - Validates status code is in the 100-599 range (`ROUTER_BRIDGE.RESPONSE_INVALID`). - Preserves status text and full header list (response headers are not on any deny-list — the bridge only filters request-side credentials). - Inlines bodies up to `DEFAULT_RESPONSE_INLINE_LIMIT` (64 KiB) and streams everything else through the streaming module. - Hard cap at `DEFAULT_RESPONSE_MAX_BYTES` (16 MiB) for inline bodies; oversize payloads either stream or fail with `ROUTER_BRIDGE.BODY_TOO_LARGE`. - Tagged-union body shape mirrors the request side for symmetry. ## Usage: Basic ```ts import { marshalResponse, rehydrateResponse } from "@suaveplan/api-router-worker-bridge/marshal-response"; const wire = await marshalResponse( new Response(JSON.stringify({ ok: true }), { status: 200, headers: { "content-type": "application/json" }, }) ); const reborn = rehydrateResponse(wire); await reborn.json(); // { ok: true } ``` ## Usage: Advanced Stream a large attachment response via a stream id: ```ts import { marshalResponse, rehydrateResponse, } from "@suaveplan/api-router-worker-bridge/marshal-response"; const streamId = 99; const wire = await marshalResponse(largeDownload, { streamId, inlineBodyLimit: 0, }); // caller pipes `largeDownload.body` over the streaming channel; main side: const reborn = rehydrateResponse(wire, mainStreamFor(streamId)); ``` ## API Reference - `marshalResponse(response, options?) → Promise`. - `rehydrateResponse(serialized, streamBody?) → Response`. - `serializedResponseSchema` — Zod validator. - `DEFAULT_RESPONSE_INLINE_LIMIT`, `DEFAULT_RESPONSE_MAX_BYTES`. ## Implementation Notes `statusText` is preserved because some clients (and HTTP/1.1 caches) still depend on the reason phrase. The body tagged union is identical in shape to `SerializedRequestBody`, but the two types are intentionally distinct so future divergence (e.g. server-sent-event hints) does not silently propagate. Status validation runs first so a `100/600` test case fails cleanly even when the body would also fail.