@appport/schema
Schema adapters and JSON Schema generation for AppPort capabilities.
AppPort publishes JSON Schema on the wire so the manifest is consumable from TypeScript, Rust, Go, Python or Swift. In TypeScript you may author schemas three ways, and all three publish the same thing.
import { s, fromJSONSchema, fromStandardSchema, toSchema } from "@appport/schema";
// 1. the built-in builder: validation and JSON Schema from one definition
const input = s.object({ documentId: s.string(), title: s.optional(s.string()) });
// 2. any Standard Schema library (Zod, Valibot, ArkType)
const zodInput = fromStandardSchema(zodSchema, { jsonSchema: z.toJSONSchema(zodSchema) });
// 3. a raw JSON Schema document, validated at runtime
const published = fromJSONSchema({ type: "object", required: ["documentId"] });
fromJSONSchema is what lets a generated client validate against a published
manifest without access to the original definitions — the same capability a
third-party implementation has.
The builder covers strings, numbers, integers, booleans, null, literals, enums, arrays, objects, records, unions, optionals, nullables, timestamps and binary references, with full type inference:
type Input = Infer<typeof input>; // { documentId: string; title?: string }
Semantic annotations
JSON Schema says what shape a value has, not what it means: 90 is a valid number
whether it counts minutes or hours. annotate publishes x-appport-* keywords that
say what a field is, without changing how it validates:
import { annotate, s, semantic } from "@appport/schema";
const estimatedHours = annotate(
s.number({ minimum: 0 }),
semantic({ concept: "https://vocab.example.org/work-order#effort", unit: "h" })
);
const priority = annotate(s.enum(["low", "urgent"]), semantic({
enumConcepts: { low: "https://vocab.example.org/urgency#low", urgent: "https://vocab.example.org/urgency#high" }
}));
Only x- keys are accepted, x-appport-* values are checked immediately (concept is an
absolute IRI, unit has no whitespace, enumConcepts names declared enum values,
encoding is iso8601, epoch-seconds or epoch-milliseconds), and optionality is
preserved. See spec/appport-1.0.md §15.3.