Files
skills/docs/api-stack/api/api-events-worker-proxy/src/payload-codec/payload-codec.md
2026-05-29 08:20:56 +01:00

3.5 KiB

payload-codec

(no submodules)

Purpose

Encodes and decodes the wire envelope used to ship a single event from the main-process EventBus across a MessagePort to a worker-tier subscriber. Includes a depth-bounded structured-clone safety probe so payloads that cannot survive the transfer are rejected at the source rather than producing opaque DataCloneError exceptions at runtime.

The codec is intentionally conservative: anything beyond plain JSON-shaped data plus a small list of well-known cloneable host types (Date, RegExp, Map, Set, ArrayBuffer, typed arrays) is rejected with EVENTS_PROXY.UNSERIALISABLE_PAYLOAD. This matches the structured-clone algorithm but is checked synchronously and surfaces the offending path.

Features

  • EventEnvelopeSchema Zod schema for the wire frame ({ topic, payload, traceId? }).
  • encodeEnvelope(topic, payload, traceId?) runs the probe, then constructs the envelope. Throws an EventsProxyError carrying the offending path on rejection.
  • decodeEnvelope(raw) Zod-validates an inbound frame.
  • probeStructuredClone(value) returns the offending path or null. Detects functions, symbols, WeakMap/WeakSet, class instances, cycles, and over-deep graphs (limit MAX_PROBE_DEPTH = 64).
  • DEFAULT_BACKPRESSURE_HIGH_WATER = 1024 — the default per-subscription queue cap.

Usage: Basic

import {
    encodeEnvelope,
    decodeEnvelope,
} from "@suaveplan/api-events-worker-proxy/payload-codec";

const wire = encodeEnvelope("billing.invoice.created", { invoiceId: "i_1" });
const decoded = decodeEnvelope(wire);
console.log(decoded.topic, decoded.payload);

Usage: Advanced

import {
    probeStructuredClone,
    encodeEnvelope,
} from "@suaveplan/api-events-worker-proxy/payload-codec";
import {
    EventsProxyError,
    EVENTS_PROXY_CODES,
} from "@suaveplan/api-events-worker-proxy/error-codes";

const payload = {
    invoiceId: "i_1",
    whenIssued: new Date(),
    handler: () => undefined,
};
const offender = probeStructuredClone(payload);
if (offender !== null) {
    throw new EventsProxyError(
        EVENTS_PROXY_CODES.UNSERIALISABLE_PAYLOAD,
        `payload rejected at ${offender}`
    );
}
const wire = encodeEnvelope("invoice.flagged", payload);

API Reference

  • EventEnvelopeSchema — z.object({ topic: z.string().min(1), traceId: z.string().optional(), payload: z.unknown() }).
  • WireEventEnvelope — z.infer<typeof EventEnvelopeSchema>.
  • encodeEnvelope(topic: string, payload: unknown, traceId?: string): WireEventEnvelope.
  • decodeEnvelope(raw: unknown): WireEventEnvelope.
  • probeStructuredClone(value: unknown): string | null — returns the offending JSON-path-like string or null.
  • MAX_PROBE_DEPTH: number — 64.
  • DEFAULT_BACKPRESSURE_HIGH_WATER: number — 1024.

Implementation Notes

The probe walks the object graph synchronously with a WeakSet cycle detector, accumulating the offending JSON path. It deliberately rejects class instances (Object.getPrototypeOf(value) !== Object.prototype) because the receiving side reconstructs them as plain objects, breaking instanceof. Date, RegExp, Map, Set, ArrayBuffer, and ArrayBuffer.isView-typed values are recognised explicitly because they ARE structured-clone safe even though they have non-Object prototypes. The depth bound of 64 is generous for legitimate payloads but cuts off pathological inputs. Cycles are detected by WeakSet; the probe reports the path that re-entered the visited set rather than recursing infinitely.