3.1 KiB
marshal-response
Purpose
This module turns the value returned by a sandboxed handler into a host
Response. The sandbox-side handler returns a SerializedResponse
(plain object with status, ordered header pairs, and base64-url
bodyBase64); this module validates that shape with a Zod schema and
constructs the corresponding WHATWG Response for the host's request
pipeline to forward to the caller.
The validation step is what stops a misbehaving sandboxed handler
(returning null, returning a primitive, returning a partial object
missing status) from crashing the host pipeline downstream — and
re-rehydrates the structurally pure JSON shape (Array<[k, v]> headers,
bodyBase64 string) back into the host's class-flavoured Response
type.
Features
- Zod-validated unmarshal —
SerializedResponseSchemaenforcesstatus ∈ [100,599], ordered[name, value]header pairs, andbodyBase64: stringplus the optionalerrorCode/errorMessagepair the wire format uses for sandbox-tier exceptions. - Failure surfacing — non-conformant shapes raise
SAND_VM_BRIDGE.UNMARSHAL_FAILEDwith the Zod issue list attached ascontext.issues. - Base64-url body decode —
Buffer.from(str, "base64url")rehydrates the bytes; the result feeds straight intoResponse'sBodyInit-compatibleUint8Arrayslot. - Headers rehydration —
Array<[name, value]>is appended onto a freshHeadersinstance so duplicate-name semantics from the sandbox are preserved as the response leaves the bridge. - Bodyless-status enforcement — 204/304 responses drop the body even if the sandbox produced one, matching the WHATWG fetch rule the host pipeline expects.
Usage: Basic
import { unmarshalResponse } from "@suaveplan/api-sandbox-vm-host-bridge/marshal/marshal-response";
const response = unmarshalResponse(await sandboxHandler(serialized));
Usage: Advanced
Use the exported schema to pre-validate cached or replayed responses before they re-enter the pipeline:
import { SerializedResponseSchema } from "@suaveplan/api-sandbox-vm-host-bridge/marshal/marshal-response";
const cached = await responseCache.get(key);
const result = SerializedResponseSchema.safeParse(cached);
if (result.success) {
return cached;
}
return rebuildFromSandbox();
API Reference
unmarshalResponse(value: unknown): Response— synchronous; throwsSandboxVmBridgeError(UNMARSHAL_FAILED)on shape failure.SerializedResponseSchema: z.ZodType<SerializedResponse>— the Zod validator used internally; mirrors the contract published by@suaveplan/api-types/sandbox-bridge.
Implementation Notes
Headers cross as a Headers instance built via append() so duplicates
(multi-Set-Cookie, etc.) preserve their iteration order. The body
decode skips the Buffer.from call for empty strings so the common
"no body" path costs nothing. Status 204/304 force a null body in the
constructed Response because WHATWG forbids a body on those codes —
the bridge enforces this so a sandbox that mistakenly attaches one
cannot break the host pipeline.