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,78 @@
# 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 — `SerializedResponseSchema` enforces
`status ∈ [100,599]`, ordered `[name, value]` header pairs, and
`bodyBase64: string` plus the optional `errorCode`/`errorMessage`
pair the wire format uses for sandbox-tier exceptions.
- Failure surfacing — non-conformant shapes raise
`SAND_VM_BRIDGE.UNMARSHAL_FAILED` with the Zod issue list attached
as `context.issues`.
- Base64-url body decode — `Buffer.from(str, "base64url")` rehydrates
the bytes; the result feeds straight into `Response`'s
`BodyInit`-compatible `Uint8Array` slot.
- Headers rehydration — `Array<[name, value]>` is appended onto a fresh
`Headers` instance 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
```ts
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:
```ts
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; throws
`SandboxVmBridgeError(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.