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/.