TemplateManifest
Zod schema for the object a template's `template.ts` builds via `defineTemplate`: a discriminated union on `output`, the artifact class.
Zod schema for the object a template’s template.ts builds via
defineTemplate: a discriminated union on output, the artifact class.
Validates a BUILT object, not parsed JSON, and owns a template’s static
composition only: identity (key, a name of at most two words, output), its formats
acceptance set (websites hold exactly the geometry-less website singleton;
image and document templates one or more of their own class’s formats), its
ordered pages (each page’s label, optionality, ordered section instances,
and — websites only — path), its canvases (the editing-surface grouping,
always explicit on the wire), and optional intake preview chrome.
Cross-section reconcile rules are not part of this schema — they compile
into the template logic bundle instead.
Pages are the composition unit in every class: a single-page template is a
one-page template, declared exactly as a five-page one is. There is no flat
sections shape.
Import from @homepages/template-kit.
Signature
Section titled “Signature”const TemplateManifest: z.ZodDiscriminatedUnion<[z.ZodObject<{ key: z.ZodString; name: z.ZodString; output: z.ZodLiteral<"website">; formats: z.ZodTuple<[z.ZodObject<{ id: z.ZodString; label: z.ZodString; category: z.ZodEnum<{ website: "website"; "social-post": "social-post"; story: "story"; brochure: "brochure"; flyer: "flyer"; postcard: "postcard"; presentation: "presentation"; }>; }, z.core.$strict>], null>; pages: z.ZodArray<z.ZodObject<{ id: z.ZodString; label: z.ZodString; path: z.ZodString; optional: z.ZodDefault<z.ZodBoolean>; sections: z.ZodArray<z.ZodObject<{ section: z.ZodString; instance_id: z.ZodString; required: z.ZodDefault<z.ZodBoolean>; }, z.core.$strict>>; }, z.core.$strict>>; canvases: z.ZodArray<z.ZodObject<{ id: z.ZodString; label: z.ZodString; pages: z.ZodArray<z.ZodString>; }, z.core.$strict>>; preview: z.ZodOptional<z.ZodObject<{ blurb: z.ZodString; intents: z.ZodArray<z.ZodEnum<{ for_sale: "for_sale"; for_rent: "for_rent"; }>>; types: z.ZodArray<z.ZodEnum<{ single_family: "single_family"; condo_townhome: "condo_townhome"; multi_family: "multi_family"; investment: "investment"; }>>; demoUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>; }, z.core.$strict>>; }, z.core.$strict>, z.ZodObject<{ key: z.ZodString; name: z.ZodString; output: z.ZodLiteral<"image">; formats: z.ZodArray<z.ZodObject<{ width: z.ZodNumber; height: z.ZodNumber; id: z.ZodString; label: z.ZodString; category: z.ZodEnum<{ website: "website"; "social-post": "social-post"; story: "story"; brochure: "brochure"; flyer: "flyer"; postcard: "postcard"; presentation: "presentation"; }>; preset: z.ZodOptional<z.ZodString>; }, z.core.$strict>>; pages: z.ZodArray<z.ZodObject<{ id: z.ZodString; label: z.ZodString; optional: z.ZodDefault<z.ZodBoolean>; sections: z.ZodArray<z.ZodObject<{ section: z.ZodString; instance_id: z.ZodString; required: z.ZodDefault<z.ZodBoolean>; }, z.core.$strict>>; }, z.core.$strict>>; canvases: z.ZodArray<z.ZodObject<{ id: z.ZodString; label: z.ZodString; pages: z.ZodArray<z.ZodString>; }, z.core.$strict>>; preview: z.ZodOptional<z.ZodObject<{ blurb: z.ZodString; intents: z.ZodArray<z.ZodEnum<{ for_sale: "for_sale"; for_rent: "for_rent"; }>>; types: z.ZodArray<z.ZodEnum<{ single_family: "single_family"; condo_townhome: "condo_townhome"; multi_family: "multi_family"; investment: "investment"; }>>; demoUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>; }, z.core.$strict>>; }, z.core.$strict>, z.ZodObject<{ key: z.ZodString; name: z.ZodString; output: z.ZodLiteral<"document">; formats: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{ width: z.ZodNumber; height: z.ZodNumber; id: z.ZodString; label: z.ZodString; category: z.ZodEnum<{ website: "website"; "social-post": "social-post"; story: "story"; brochure: "brochure"; flyer: "flyer"; postcard: "postcard"; presentation: "presentation"; }>; preset: z.ZodOptional<z.ZodString>; }, z.core.$strict>, z.ZodObject<{ width: z.ZodString; height: z.ZodString; dpi: z.ZodNumber; bleed: z.ZodOptional<z.ZodString>; id: z.ZodString; label: z.ZodString; category: z.ZodEnum<{ website: "website"; "social-post": "social-post"; story: "story"; brochure: "brochure"; flyer: "flyer"; postcard: "postcard"; presentation: "presentation"; }>; preset: z.ZodOptional<z.ZodString>; }, z.core.$strict>]>>; pages: z.ZodArray<z.ZodObject<{ id: z.ZodString; label: z.ZodString; optional: z.ZodDefault<z.ZodBoolean>; sections: z.ZodArray<z.ZodObject<{ section: z.ZodString; instance_id: z.ZodString; required: z.ZodDefault<z.ZodBoolean>; }, z.core.$strict>>; }, z.core.$strict>>; canvases: z.ZodArray<z.ZodObject<{ id: z.ZodString; label: z.ZodString; pages: z.ZodArray<z.ZodString>; }, z.core.$strict>>; preview: z.ZodOptional<z.ZodObject<{ blurb: z.ZodString; intents: z.ZodArray<z.ZodEnum<{ for_sale: "for_sale"; for_rent: "for_rent"; }>>; types: z.ZodArray<z.ZodEnum<{ single_family: "single_family"; condo_townhome: "condo_townhome"; multi_family: "multi_family"; investment: "investment"; }>>; demoUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>; }, z.core.$strict>>; }, z.core.$strict>], "output">Constraints
Section titled “Constraints”- on parse when a composition rule is violated, each with an error
naming the rule — a
nameof more than two words, duplicate page id, duplicate format id, oneinstance_idlisted twice on the same page (listing an instance on SEVERAL pages is legal and means one shared instance rendered on each), a rendered template with no format or with every page optional, apreset-tagged format whose geometry does not match the library entry for that tag, a website format set that is not exactly[presets.website], a canvas rule — no canvases, a duplicate canvas id, an empty canvas, a canvas naming an unknown page, a page on no canvas or on two (canvases must partition the pages) — or a website page rule — duplicate path, no root page or more than one, an optional root page, a non-root path that is not a single lowercase-kebab segment. Format geometry bounds (positive dimensions, the 72–600 dpi window, bleed ≥ 0, no mixed physical/pixel dimensions) are enforced by the format schemas themselves.