# 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": "", "v": }` 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/`.