Quick start
This page takes one Zod schema from a first encode to a codec you can store payloads with. Every snippet below builds on these imports.
import { z } from "zod";import { compile, decode, encode, fingerprinted, safeDecode } from "@chichurita/shorn";
const Person = z.object({ name: z.string(), age: z.int().nonnegative(), sex: z.enum(["M", "F", "X"]),});
const person = { name: "Grace", age: 45, sex: "F" } as const;
const bytes = encode(Person, person);const back = decode(Person, bytes); // typed and validatedThe payload is eight bytes. Field names and type tags never leave the schema. Where the bytes go labels each of those eight bytes, and Byte layout covers every wire type.
Pass Zod and ArkType schemas as they are. Valibot needs one extra argument, the converted structure. See Valibot.
Reuse a codec object
Section titled “Reuse a codec object”compile returns the same cached plan as a codec object:
const PersonWire = compile(Person);
PersonWire.encode(person);PersonWire.decode(bytes);Use compile when you want a codec you can pass around or keep in a registry. It is not faster than calling encode and decode directly: both forms share one cached plan per schema object.
Store or queue data
Section titled “Store or queue data”A bare payload does not say which schema wrote it. Decode it with the wrong schema and you may get a plausible but wrong value. For anything that will be stored, queued, or read by a later deployment, add a four-byte fingerprint:
const StoredPerson = fingerprinted(compile(Person), { bytes: 4 });
const stored = StoredPerson.encode(person);StoredPerson.decode(stored); // rejects a different wire shapeA fingerprint identifies the wire shape only. It does not change when you add a validation rule such as .max(). Read Wire fingerprints before storing data.
Handle expected failures
Section titled “Handle expected failures”Where bad input is normal traffic rather than a surprise, use the safe variant and get a result object instead of an exception:
const result = safeDecode(Person, bytes);if (!result.success) return new Response("Bad request", { status: 400 });result.data; // typed