Pluggable wire serialization for TypeScript
Zero to a working round-trip
Section titled “Zero to a working round-trip”One adapter install yields a working serde — the JSON adapter brings the interface package with it:
bun add @insler/serde-jsonimport { jsonSerde } from '@insler/serde-json';
const wire = jsonSerde.encode({ createdAt: new Date(), tags: new Set(['a', 'b']) });const value = jsonSerde.decode(wire);// { createdAt: Date, tags: Set(['a', 'b']) } — rich types survive (SuperJSON)The getting-started guide walks from this install to swapping in every binary format behind the same seam.
One interface, every format
Section titled “One interface, every format”The zero-dependency core @insler/serde owns a single
contract — Serde<Wire>, two methods, Wire as the only knob. Every format
binding is its own adapter package implementing it:
JSON (SuperJSON-backed — Date, Map, Set,
BigInt, and RegExp survive), MessagePack,
CBOR, and Avro. The
binary adapters are all Serde<Uint8Array>, so they are interchangeable
wherever a binary wire is expected.
Built to sit under a transport
Section titled “Built to sit under a transport”Anything that moves values over a wire takes a Serde — the
rpc subsystem’s transports accept one as their
serde option. Develop on JSON, deploy on MessagePack or CBOR, without
touching a call site. The core is the bottom of the stack: zero dependencies,
nothing internal sits below it.
A contract you can rely on
Section titled “A contract you can rely on”Every implementation honors the same conventions: encode(undefined)
produces an empty wire, decoding an empty wire returns undefined, and what
you decode is what you encoded. The reference documents
the interface and each adapter’s exact surface.