Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,145 @@
# OpenSpec Change: enterprise-serialize
- **Change ID**: enterprise-serialize
- **Package**: `@suaveplan/serialize`
- **Category**: universal
- **Target path**: `packages/universal/serialize`
- **Status**: IN PROGRESS
- **Date**: 2026-04-18
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/serialize.md`
## Summary
Greenfield implementation of `@suaveplan/serialize` for the genesis branch. The existing main-branch serialize package provides the baseline public-API surface to preserve; this change delivers round-trip-preserving structured serialization — tagged JSON (preserving `Date`, `Map`, `Set`, `BigInt`, `Uint8Array`, typed arrays, `URL`, `RegExp`, user-defined tags) plus MessagePack binary profile and streaming variants. Eval-safe by default; opt-in legacy adapters isolated under `@suaveplan/serialize/unsafe`.
## Current-state audit (genesis)
The package does not exist on genesis yet — this is a fresh build.
## Available workspace deps on genesis
| Package | Available |
|---------|-----------|
| `@suaveplan/error` | ✅ |
| `@suaveplan/types` | ✅ |
| `@suaveplan/streams` | ❌ not yet built — implement chunked stream via Web Streams API internally |
| `@suaveplan/opentelemetry` | ❌ not yet built — use `@opentelemetry/api` directly |
| `@suaveplan/feature-flags` | ❌ not yet built — skip |
| `@suaveplan/schema-registry` | ❌ not yet built — export Zod schemas directly |
External deps:
- `zod` → `catalog:forms`
- `@opentelemetry/api` → `catalog:observability`
- `@msgpack/msgpack` → add to `catalog:serialization` (new catalog group) at `^3.0.0`
- `tslib` → `catalog:build`
Unsafe-subpath-only (isolated, not in main bundle):
- `serialize-javascript` → add to `catalog:serialization` at `^6.0.0` — only imported by `src/adapters/eval-safe/` which lives under the `/unsafe` subpath export
Dev deps (via catalog):
- `vitest`, `@vitest/coverage-istanbul` → `catalog:testing`
- `fast-check` → `catalog:testing`
- `mitata` → `catalog:testing`
## Preserved public API surface (from main branch)
### Main export (`@suaveplan/serialize`)
#### Codec
- `serialize(value, opts?)` → `string` — tagged JSON serialization
- `deserialize(json, opts?)` → `unknown` — tagged JSON deserialization
- `encodeBinary(value, opts?)` → `Uint8Array` — MessagePack encoding
- `decodeBinary(bytes, opts?)` → `unknown` — MessagePack decoding
- `encodeStream(value, opts?)` → `ReadableStream<Uint8Array>` — streaming MessagePack
- `decodeStream(stream, opts?)` → `ReadableStream<unknown>` — streaming decode
- `deepClone(value)` → `unknown` — structured clone via serialize/deserialize round-trip
- `SerializeOptions`, `DeserializeOptions`, `Codec` (types)
#### Type registry
- `registerType(def)` — register a custom type tag
- `unregisterType(tag)` — remove a custom type tag
- `listTypes()` → `TypeDefinition[]` — all registered types
- `getType(tag)` → `TypeDefinition | undefined`
- `getTypeByCtor(ctor)` → `TypeDefinition | undefined`
- `TypeDefinition` — `{ tag: string; ctor: Function; encode: (v) => unknown; decode: (v) => unknown }`
#### Errors
- `SerializationError` extends `SuaveplanError`
- `CircularReferenceError` extends `SerializationError`
- `MaxDepthExceededError` extends `SerializationError`
- `MaxSizeExceededError` extends `SerializationError`
- `UnsupportedTypeError` extends `SerializationError`
- `SerializationErrorCode`, `SerializationErrorContext`, `SerializationErrorOptions` (types)
#### Error codes (re-exported)
- `registerSerializeErrorCodes()`, `SERIALIZE_ERROR_METADATA`, `SerializeErrorCode`
#### Legacy
- `legacySerialize(value)` → `string` — old format compat (no new tags; for migration only)
- `legacyDeserialize(json)` → `unknown` — old format compat
### Unsafe subpath (`@suaveplan/serialize/unsafe`)
- `serializeEvalSafe(value, opts?)` → `string` — uses `serialize-javascript` under the hood; emits a security warning in dev
- `deserializeEvalSafe(json, opts?)` → `unknown`
- `EvalSafeOptions` (type)
## New additions for genesis
### Catalog entry
- Add `serialization` catalog group to root `package.json`:
```json
"serialization": {
"@msgpack/msgpack": "^3.0.0",
"serialize-javascript": "^6.0.0"
}
```
### Structured errors
- `SerializationError` extends `SuaveplanError` with codes under `SERIALIZE.*` namespace
- Codes: `SERIALIZE.CODEC.CIRCULAR_REFERENCE`, `SERIALIZE.CODEC.MAX_DEPTH`, `SERIALIZE.CODEC.MAX_SIZE`, `SERIALIZE.CODEC.UNKNOWN_TAG`, `SERIALIZE.REGISTRY.DUPLICATE_TAG`, `SERIALIZE.LEGACY.REFUSED`
### Zod schemas
- `SerializeOptionsSchema`, `DeserializeOptionsSchema`, `TypeDefinitionSchema` — all public config types validated at boundary
### AbortSignal support
- `encodeStream` and `decodeStream` honour `AbortSignal` passed via options
### OTel instrumentation
- Histogram: `serialize.payload_bytes` (encode + decode, by format label json/msgpack)
- Counter: `serialize.error.total` (by error code label)
### Property-based tests (fast-check)
- Round-trip for every built-in type: `deserialize(serialize(x)) deep-equals x`
- Binary round-trip: `decodeBinary(encodeBinary(x)) deep-equals x`
- JSON–binary structural equivalence: both formats produce semantically equal output
- Cycle detection: any circular graph always throws `CircularReferenceError`
- Custom tag round-trip: registered tag encodes and decodes without data loss
### Benchmarks (mitata)
- `serialize` / `deserialize` 10 KB nested object
- `encodeBinary` / `decodeBinary` 10 KB nested object
- `deepClone` 10 KB object vs `structuredClone` baseline
## Impact
- Adds one new package: `packages/universal/serialize`
- Adds `serialization` catalog group to root `package.json`
- Adds one new spec capability: `serialization`
- No existing package consumers on genesis yet