Schema members
Every entity carries four plain ZodObjects as statics, plus the class itself.
Snippets on this page assume these imports:
tsimport { z } from "zod"; import { Entity } from "@btravstack/entity";
ts
Organization.input; // ZodObject — everything make() accepts
Organization.output; // ZodObject — stored state and response body
Organization.createInput; // ZodObject — input minus generated
Organization.updateInput; // ZodObject — output minus immutable and computed, partial
Organization.entityName; // the tag, as a literal type
Organization; // …is itself a zod schema, parsing to an instanceoutput is input plus the computed fields. All four ZodObjects generate JSON Schema in both "input" and "output" directions.
The class carries zod's internal slots (_zod, ~standard) but not its methods, so it composes anywhere zod takes a schema while .parse() — which throws — does not exist on it:
ts
z.object({ owner: Organization }); // ✓
z.array(Organization); // ✓
z.optional(Organization); // ✓ the function form
Organization.optional(); // ✗ does not exist
Organization.parse(raw); // ✗ does not exist — use make()
z.toJSONSchema(Organization, { io: "output" }); // ✗ throws — the class carries a transformThat last line is the design rule made concrete: contracts compose the four plain ZodObjects; domain code composes the class itself. See Why entity? for the constraint it comes from, and Expose an HTTP contract for the recipe.