inkan

Schemas

t: the schemas that validate, type and document.

.().(1).(60).().().(/x/).("date-time").()
.().(0)   .().()   .()
.(["a", "b"])   .("a")   .(.(), .())
.(Tea).(1)   .(.())   .()   .()   .()
.({ … }).() .() .() .() .() .()

.()  .()  .(v)  .("…")  .(v)  .("Tea")  .()

Infer<typeof Tea> is the TypeScript type. Tea.parse(x) throws a ValidationError, Tea.safeParse(x) does not, and Tea.toJSONSchema() gives JSON Schema 2020-12.

t.date() accepts ISO date-time strings (including a timezone) or valid Date instances and returns a Date. Responses serialize dates back to ISO strings; the wire schema is { type: "string", format: "date-time" }.

const  = .().( =>  % 2 === 0, "must be even");
const  = .().( => .); // Infer: number
const  = .("kind", {
  : .({ : .("cat"), : .() }).("Cat"),
  : .({ : .("dog"), : .() }).("Dog"),
});

type  = { : string; : [] };
const : <> = .({
  : .(), : .(.(() => )),
}).("Node"); // import type { Schema } from "@vxnsin/inkan"

Refinements and transforms are synchronous, run in chain order after successful validation, and remain outside JSON Schema. Transforms document their original input shape; use them on request schemas when the parsed handler value differs from the wire value. Optional, nullable and default modifiers added after an effect bypass that effect for their missing/null/default values. Modifiers before an effect supply its input.

Each discriminated branch declares its matching literal tag. OpenAPI uses oneOf and a discriminator, with mappings for named branches. Name recursive shapes so OpenAPI can reference components; toJSONSchema() includes named schemas in $defs, making its references self-contained.