Files
2026-05-27 23:29:53 +01:00

3.6 KiB

serialization

Purpose

Round-trip-preserving structured serialization for the Suaveplan monorepo — tagged JSON (Date, Map, Set, BigInt, Uint8Array, URL, RegExp, custom tags), MessagePack binary profile, streaming encode/decode via Web Streams, and a pluggable type registry. Eval-safe by default with the serialize-javascript adapter isolated to the opt-in /unsafe subpath; all errors flow through SerializationError codes registered under the SERIALIZE.* namespace.

Requirements

SZ-01 — Eval-safe by default

The main export (@suaveplan/serialize) MUST NEVER execute arbitrary code during parse. All reconstruction happens via the type registry's decode functions. The serialize-javascript adapter is isolated to the @suaveplan/serialize/unsafe subpath and MUST NOT appear in the main bundle (enforced by tree-shake test).

SZ-02 — Round-trip fidelity for built-in types

serialize → deserialize MUST produce a deep-equal value for all built-in types: Date, Map, Set, BigInt, Uint8Array, Int8Array, Int16Array, Int32Array, Uint16Array, Uint32Array, Float32Array, Float64Array, URL, RegExp. Plain objects, arrays, null, undefined, string, number, boolean MUST also round-trip. NaN and Infinity MUST be tagged (JSON null fallback is not acceptable).

SZ-03 — Tagged JSON format

The serialized JSON format MUST use a { "__t": "<tag>", "v": <encoded> } envelope for non-primitive types. Tags are short stable strings registered in the type registry. The format MUST be human-readable and diff-friendly.

SZ-04 — Cycle detection

Any value containing a circular reference MUST throw CircularReferenceError (code SERIALIZE.CODEC.CIRCULAR_REFERENCE) before any output is produced. Detection uses a WeakSet and is depth-bounded to maxDepth (default: 100).

SZ-05 — Type registry

registerType(def) MUST be idempotent for the same tag+ctor pair and MUST throw SerializationError (code SERIALIZE.REGISTRY.DUPLICATE_TAG) if the same tag is registered for a different constructor.

SZ-06 — MessagePack profile

encodeBinary → decodeBinary MUST produce bit-identical output for identical inputs (field ordering canonicalised via sorted keys). Custom tags MUST be encoded as MessagePack extension types.

SZ-07 — Streaming

encodeStream MUST chunk output into frames compatible with decodeStream. The Web Streams ReadableStream API is used (no Node.js stream dependency). Both MUST honour AbortSignal.

SZ-08 — Unsafe subpath isolation

The @suaveplan/serialize/unsafe subpath MUST be a separate entry point. Any code importing only @suaveplan/serialize (main) MUST NOT have serialize-javascript in its bundle. This is verified by an automated tree-shake test.

SZ-09 — Structured errors

All thrown errors MUST extend SerializationError which extends SuaveplanError. Subclasses: CircularReferenceError, MaxDepthExceededError, MaxSizeExceededError, UnsupportedTypeError. Codes under SERIALIZE.* namespace.

SZ-10 — Zod schemas for options

SerializeOptions and DeserializeOptions MUST have corresponding Zod schemas. Inputs are validated at the public boundary (invalid options throw SerializationError with context).

SZ-11 — OTel instrumentation

serialize.payload_bytes histogram (by format label) and serialize.error.total counter (by code label) MUST be emitted via @opentelemetry/api. No-ops without exporter.

SZ-12 — sideEffects: false + coverage 100%

"sideEffects": false. Tree-shake test. Vitest thresholds at 100/100/100/100. No .skip / .only in src/.