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
EventEnvelopeSchemaZod schema for the wire frame ({ topic, payload, traceId? }).encodeEnvelope(topic, payload, traceId?)runs the probe, then constructs the envelope. Throws anEventsProxyErrorcarrying the offending path on rejection.decodeEnvelope(raw)Zod-validates an inbound frame.probeStructuredClone(value)returns the offending path ornull. Detects functions, symbols,WeakMap/WeakSet, class instances, cycles, and over-deep graphs (limitMAX_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 ornull.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.