@marktiderman/genesis-sites 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,764 @@
1
+ import { ReactNode } from 'react';
2
+ import { z } from 'zod';
3
+
4
+ /**
5
+ * The documents a site is made of, as zod 4 schemas: a `SiteDoc` (theme,
6
+ * header, navigation, footer, SEO defaults, redirects), one `PageDoc` per
7
+ * page (its sections and SEO), and the `ReleaseSnapshot` a publish freezes.
8
+ *
9
+ * A page's `content` is an array of `{ id, type, v, variant, props }`
10
+ * section nodes, which is the shape Puck's `content` uses, so the editor
11
+ * reads and writes these documents unchanged. A section's `props` are
12
+ * checked by that section's own schema (see `defineSection`), not here.
13
+ */
14
+
15
+ /** A link target: a site path, a fragment, or an http(s), mailto or tel URL. */
16
+ declare const Href: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
17
+ /** A labelled link: a button, a menu entry, a footer link. */
18
+ declare const Link: z.ZodObject<{
19
+ label: z.ZodString;
20
+ href: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
21
+ newTab: z.ZodOptional<z.ZodBoolean>;
22
+ }, z.core.$strip>;
23
+ type Link = z.infer<typeof Link>;
24
+ /**
25
+ * An image. `alt` describes it for someone who can't see it; an image that
26
+ * adds nothing (a texture) is `decorative: true` and gets an empty alt. The
27
+ * accessibility check refuses to publish an image with neither.
28
+ */
29
+ declare const Image: z.ZodObject<{
30
+ src: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
31
+ alt: z.ZodDefault<z.ZodString>;
32
+ decorative: z.ZodOptional<z.ZodBoolean>;
33
+ width: z.ZodOptional<z.ZodNumber>;
34
+ height: z.ZodOptional<z.ZodNumber>;
35
+ focal: z.ZodOptional<z.ZodObject<{
36
+ x: z.ZodNumber;
37
+ y: z.ZodNumber;
38
+ }, z.core.$strip>>;
39
+ }, z.core.$strip>;
40
+ type Image = z.infer<typeof Image>;
41
+ /**
42
+ * Rich text: the JSON genesis-ui's `RichTextEditor` (TipTap) produces. Only
43
+ * its outline is checked here; genesis-ui's `RichText` sanitizes it again
44
+ * when it renders, so a stored document can never carry raw HTML.
45
+ */
46
+ declare const RichText: z.ZodObject<{
47
+ type: z.ZodLiteral<"doc">;
48
+ content: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
49
+ }, z.core.$strip>;
50
+ type RichText = z.infer<typeof RichText>;
51
+ /** The band a section sits on. */
52
+ declare const Surface: z.ZodEnum<{
53
+ base: "base";
54
+ muted: "muted";
55
+ accent: "accent";
56
+ inverse: "inverse";
57
+ }>;
58
+ type Surface = z.infer<typeof Surface>;
59
+ /** A short line of copy (a heading, a label). */
60
+ declare const Line: (max?: number) => z.ZodString;
61
+ /** A paragraph of plain copy. */
62
+ declare const Copy: (max?: number) => z.ZodString;
63
+ /** A section's id: stable, letters, digits, `-` and `_` (Shopify's rule). */
64
+ declare const SectionId: z.ZodString;
65
+ declare const SectionNode: z.ZodObject<{
66
+ id: z.ZodString;
67
+ type: z.ZodString;
68
+ v: z.ZodNumber;
69
+ variant: z.ZodOptional<z.ZodString>;
70
+ hidden: z.ZodOptional<z.ZodBoolean>;
71
+ hideOn: z.ZodOptional<z.ZodArray<z.ZodEnum<{
72
+ mobile: "mobile";
73
+ desktop: "desktop";
74
+ }>>>;
75
+ placeholder: z.ZodOptional<z.ZodBoolean>;
76
+ props: z.ZodRecord<z.ZodString, z.ZodUnknown>;
77
+ }, z.core.$strip>;
78
+ type SectionNode = z.infer<typeof SectionNode>;
79
+ declare const Seo: z.ZodObject<{
80
+ title: z.ZodOptional<z.ZodString>;
81
+ description: z.ZodOptional<z.ZodString>;
82
+ ogImage: z.ZodOptional<z.ZodObject<{
83
+ src: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
84
+ alt: z.ZodDefault<z.ZodString>;
85
+ decorative: z.ZodOptional<z.ZodBoolean>;
86
+ width: z.ZodOptional<z.ZodNumber>;
87
+ height: z.ZodOptional<z.ZodNumber>;
88
+ focal: z.ZodOptional<z.ZodObject<{
89
+ x: z.ZodNumber;
90
+ y: z.ZodNumber;
91
+ }, z.core.$strip>>;
92
+ }, z.core.$strip>>;
93
+ canonical: z.ZodOptional<z.ZodURL>;
94
+ noindex: z.ZodOptional<z.ZodBoolean>;
95
+ }, z.core.$strip>;
96
+ type Seo = z.infer<typeof Seo>;
97
+ declare const PageDoc: z.ZodObject<{
98
+ schemaVersion: z.ZodLiteral<1>;
99
+ root: z.ZodObject<{
100
+ props: z.ZodObject<{
101
+ title: z.ZodString;
102
+ hideSiteChrome: z.ZodOptional<z.ZodBoolean>;
103
+ }, z.core.$loose>;
104
+ }, z.core.$strip>;
105
+ content: z.ZodArray<z.ZodObject<{
106
+ id: z.ZodString;
107
+ type: z.ZodString;
108
+ v: z.ZodNumber;
109
+ variant: z.ZodOptional<z.ZodString>;
110
+ hidden: z.ZodOptional<z.ZodBoolean>;
111
+ hideOn: z.ZodOptional<z.ZodArray<z.ZodEnum<{
112
+ mobile: "mobile";
113
+ desktop: "desktop";
114
+ }>>>;
115
+ placeholder: z.ZodOptional<z.ZodBoolean>;
116
+ props: z.ZodRecord<z.ZodString, z.ZodUnknown>;
117
+ }, z.core.$strip>>;
118
+ seo: z.ZodOptional<z.ZodObject<{
119
+ title: z.ZodOptional<z.ZodString>;
120
+ description: z.ZodOptional<z.ZodString>;
121
+ ogImage: z.ZodOptional<z.ZodObject<{
122
+ src: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
123
+ alt: z.ZodDefault<z.ZodString>;
124
+ decorative: z.ZodOptional<z.ZodBoolean>;
125
+ width: z.ZodOptional<z.ZodNumber>;
126
+ height: z.ZodOptional<z.ZodNumber>;
127
+ focal: z.ZodOptional<z.ZodObject<{
128
+ x: z.ZodNumber;
129
+ y: z.ZodNumber;
130
+ }, z.core.$strip>>;
131
+ }, z.core.$strip>>;
132
+ canonical: z.ZodOptional<z.ZodURL>;
133
+ noindex: z.ZodOptional<z.ZodBoolean>;
134
+ }, z.core.$strip>>;
135
+ }, z.core.$strip>;
136
+ type PageDoc = z.infer<typeof PageDoc>;
137
+ declare const PageKind: z.ZodEnum<{
138
+ page: "page";
139
+ landing: "landing";
140
+ }>;
141
+ type PageKind = z.infer<typeof PageKind>;
142
+ declare const PagePath: z.ZodString;
143
+ declare const MenuItem: z.ZodObject<{
144
+ label: z.ZodString;
145
+ href: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
146
+ }, z.core.$strip>;
147
+ type MenuItem = z.infer<typeof MenuItem>;
148
+ declare const Redirect: z.ZodObject<{
149
+ from: z.ZodString;
150
+ to: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
151
+ status: z.ZodUnion<readonly [z.ZodLiteral<301>, z.ZodLiteral<302>]>;
152
+ }, z.core.$strip>;
153
+ type Redirect = z.infer<typeof Redirect>;
154
+ /** Fonts a site may choose; see `FONT_CHOICES` in theme.ts for their stacks. */
155
+ declare const FontChoice: z.ZodEnum<{
156
+ system: "system";
157
+ inter: "inter";
158
+ "dm-sans": "dm-sans";
159
+ "work-sans": "work-sans";
160
+ montserrat: "montserrat";
161
+ poppins: "poppins";
162
+ "space-grotesk": "space-grotesk";
163
+ "source-serif": "source-serif";
164
+ merriweather: "merriweather";
165
+ "playfair-display": "playfair-display";
166
+ lora: "lora";
167
+ }>;
168
+ type FontChoice = z.infer<typeof FontChoice>;
169
+ /**
170
+ * A site's theme choices on top of the brand: token choices only, never raw
171
+ * CSS, so a site stays inside the design system.
172
+ */
173
+ declare const TokenOverrides: z.ZodObject<{
174
+ radius: z.ZodOptional<z.ZodEnum<{
175
+ none: "none";
176
+ sm: "sm";
177
+ md: "md";
178
+ lg: "lg";
179
+ full: "full";
180
+ }>>;
181
+ headingFont: z.ZodOptional<z.ZodEnum<{
182
+ system: "system";
183
+ inter: "inter";
184
+ "dm-sans": "dm-sans";
185
+ "work-sans": "work-sans";
186
+ montserrat: "montserrat";
187
+ poppins: "poppins";
188
+ "space-grotesk": "space-grotesk";
189
+ "source-serif": "source-serif";
190
+ merriweather: "merriweather";
191
+ "playfair-display": "playfair-display";
192
+ lora: "lora";
193
+ }>>;
194
+ bodyFont: z.ZodOptional<z.ZodEnum<{
195
+ system: "system";
196
+ inter: "inter";
197
+ "dm-sans": "dm-sans";
198
+ "work-sans": "work-sans";
199
+ montserrat: "montserrat";
200
+ poppins: "poppins";
201
+ "space-grotesk": "space-grotesk";
202
+ "source-serif": "source-serif";
203
+ merriweather: "merriweather";
204
+ "playfair-display": "playfair-display";
205
+ lora: "lora";
206
+ }>>;
207
+ }, z.core.$strip>;
208
+ type TokenOverrides = z.infer<typeof TokenOverrides>;
209
+ declare const SeoDefaults: z.ZodObject<{
210
+ titleTemplate: z.ZodOptional<z.ZodString>;
211
+ description: z.ZodOptional<z.ZodString>;
212
+ ogImage: z.ZodOptional<z.ZodObject<{
213
+ src: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
214
+ alt: z.ZodDefault<z.ZodString>;
215
+ decorative: z.ZodOptional<z.ZodBoolean>;
216
+ width: z.ZodOptional<z.ZodNumber>;
217
+ height: z.ZodOptional<z.ZodNumber>;
218
+ focal: z.ZodOptional<z.ZodObject<{
219
+ x: z.ZodNumber;
220
+ y: z.ZodNumber;
221
+ }, z.core.$strip>>;
222
+ }, z.core.$strip>>;
223
+ organization: z.ZodOptional<z.ZodObject<{
224
+ name: z.ZodString;
225
+ logo: z.ZodOptional<z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>>;
226
+ sameAs: z.ZodOptional<z.ZodArray<z.ZodURL>>;
227
+ }, z.core.$strip>>;
228
+ noindex: z.ZodOptional<z.ZodBoolean>;
229
+ }, z.core.$strip>;
230
+ type SeoDefaults = z.infer<typeof SeoDefaults>;
231
+ declare const SiteDoc: z.ZodObject<{
232
+ schemaVersion: z.ZodLiteral<1>;
233
+ name: z.ZodString;
234
+ lang: z.ZodDefault<z.ZodString>;
235
+ theme: z.ZodDefault<z.ZodObject<{
236
+ colorScheme: z.ZodDefault<z.ZodEnum<{
237
+ light: "light";
238
+ dark: "dark";
239
+ auto: "auto";
240
+ }>>;
241
+ overrides: z.ZodOptional<z.ZodObject<{
242
+ radius: z.ZodOptional<z.ZodEnum<{
243
+ none: "none";
244
+ sm: "sm";
245
+ md: "md";
246
+ lg: "lg";
247
+ full: "full";
248
+ }>>;
249
+ headingFont: z.ZodOptional<z.ZodEnum<{
250
+ system: "system";
251
+ inter: "inter";
252
+ "dm-sans": "dm-sans";
253
+ "work-sans": "work-sans";
254
+ montserrat: "montserrat";
255
+ poppins: "poppins";
256
+ "space-grotesk": "space-grotesk";
257
+ "source-serif": "source-serif";
258
+ merriweather: "merriweather";
259
+ "playfair-display": "playfair-display";
260
+ lora: "lora";
261
+ }>>;
262
+ bodyFont: z.ZodOptional<z.ZodEnum<{
263
+ system: "system";
264
+ inter: "inter";
265
+ "dm-sans": "dm-sans";
266
+ "work-sans": "work-sans";
267
+ montserrat: "montserrat";
268
+ poppins: "poppins";
269
+ "space-grotesk": "space-grotesk";
270
+ "source-serif": "source-serif";
271
+ merriweather: "merriweather";
272
+ "playfair-display": "playfair-display";
273
+ lora: "lora";
274
+ }>>;
275
+ }, z.core.$strip>>;
276
+ }, z.core.$strip>>;
277
+ header: z.ZodDefault<z.ZodArray<z.ZodObject<{
278
+ id: z.ZodString;
279
+ type: z.ZodString;
280
+ v: z.ZodNumber;
281
+ variant: z.ZodOptional<z.ZodString>;
282
+ hidden: z.ZodOptional<z.ZodBoolean>;
283
+ hideOn: z.ZodOptional<z.ZodArray<z.ZodEnum<{
284
+ mobile: "mobile";
285
+ desktop: "desktop";
286
+ }>>>;
287
+ placeholder: z.ZodOptional<z.ZodBoolean>;
288
+ props: z.ZodRecord<z.ZodString, z.ZodUnknown>;
289
+ }, z.core.$strip>>>;
290
+ nav: z.ZodDefault<z.ZodArray<z.ZodObject<{
291
+ label: z.ZodString;
292
+ href: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
293
+ }, z.core.$strip>>>;
294
+ footer: z.ZodDefault<z.ZodArray<z.ZodObject<{
295
+ id: z.ZodString;
296
+ type: z.ZodString;
297
+ v: z.ZodNumber;
298
+ variant: z.ZodOptional<z.ZodString>;
299
+ hidden: z.ZodOptional<z.ZodBoolean>;
300
+ hideOn: z.ZodOptional<z.ZodArray<z.ZodEnum<{
301
+ mobile: "mobile";
302
+ desktop: "desktop";
303
+ }>>>;
304
+ placeholder: z.ZodOptional<z.ZodBoolean>;
305
+ props: z.ZodRecord<z.ZodString, z.ZodUnknown>;
306
+ }, z.core.$strip>>>;
307
+ seo: z.ZodDefault<z.ZodObject<{
308
+ titleTemplate: z.ZodOptional<z.ZodString>;
309
+ description: z.ZodOptional<z.ZodString>;
310
+ ogImage: z.ZodOptional<z.ZodObject<{
311
+ src: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
312
+ alt: z.ZodDefault<z.ZodString>;
313
+ decorative: z.ZodOptional<z.ZodBoolean>;
314
+ width: z.ZodOptional<z.ZodNumber>;
315
+ height: z.ZodOptional<z.ZodNumber>;
316
+ focal: z.ZodOptional<z.ZodObject<{
317
+ x: z.ZodNumber;
318
+ y: z.ZodNumber;
319
+ }, z.core.$strip>>;
320
+ }, z.core.$strip>>;
321
+ organization: z.ZodOptional<z.ZodObject<{
322
+ name: z.ZodString;
323
+ logo: z.ZodOptional<z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>>;
324
+ sameAs: z.ZodOptional<z.ZodArray<z.ZodURL>>;
325
+ }, z.core.$strip>>;
326
+ noindex: z.ZodOptional<z.ZodBoolean>;
327
+ }, z.core.$strip>>;
328
+ redirects: z.ZodDefault<z.ZodArray<z.ZodObject<{
329
+ from: z.ZodString;
330
+ to: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
331
+ status: z.ZodUnion<readonly [z.ZodLiteral<301>, z.ZodLiteral<302>]>;
332
+ }, z.core.$strip>>>;
333
+ }, z.core.$strip>;
334
+ type SiteDoc = z.infer<typeof SiteDoc>;
335
+ /** A `SiteDoc` as written, before defaults. */
336
+ type SiteDocInput = z.input<typeof SiteDoc>;
337
+ declare const ReleasePage: z.ZodObject<{
338
+ id: z.ZodString;
339
+ path: z.ZodString;
340
+ kind: z.ZodEnum<{
341
+ page: "page";
342
+ landing: "landing";
343
+ }>;
344
+ doc: z.ZodObject<{
345
+ schemaVersion: z.ZodLiteral<1>;
346
+ root: z.ZodObject<{
347
+ props: z.ZodObject<{
348
+ title: z.ZodString;
349
+ hideSiteChrome: z.ZodOptional<z.ZodBoolean>;
350
+ }, z.core.$loose>;
351
+ }, z.core.$strip>;
352
+ content: z.ZodArray<z.ZodObject<{
353
+ id: z.ZodString;
354
+ type: z.ZodString;
355
+ v: z.ZodNumber;
356
+ variant: z.ZodOptional<z.ZodString>;
357
+ hidden: z.ZodOptional<z.ZodBoolean>;
358
+ hideOn: z.ZodOptional<z.ZodArray<z.ZodEnum<{
359
+ mobile: "mobile";
360
+ desktop: "desktop";
361
+ }>>>;
362
+ placeholder: z.ZodOptional<z.ZodBoolean>;
363
+ props: z.ZodRecord<z.ZodString, z.ZodUnknown>;
364
+ }, z.core.$strip>>;
365
+ seo: z.ZodOptional<z.ZodObject<{
366
+ title: z.ZodOptional<z.ZodString>;
367
+ description: z.ZodOptional<z.ZodString>;
368
+ ogImage: z.ZodOptional<z.ZodObject<{
369
+ src: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
370
+ alt: z.ZodDefault<z.ZodString>;
371
+ decorative: z.ZodOptional<z.ZodBoolean>;
372
+ width: z.ZodOptional<z.ZodNumber>;
373
+ height: z.ZodOptional<z.ZodNumber>;
374
+ focal: z.ZodOptional<z.ZodObject<{
375
+ x: z.ZodNumber;
376
+ y: z.ZodNumber;
377
+ }, z.core.$strip>>;
378
+ }, z.core.$strip>>;
379
+ canonical: z.ZodOptional<z.ZodURL>;
380
+ noindex: z.ZodOptional<z.ZodBoolean>;
381
+ }, z.core.$strip>>;
382
+ }, z.core.$strip>;
383
+ }, z.core.$strip>;
384
+ type ReleasePage = z.infer<typeof ReleasePage>;
385
+ /** Everything a published site serves: the site document and every page, frozen at publish. */
386
+ declare const ReleaseSnapshot: z.ZodObject<{
387
+ schemaVersion: z.ZodLiteral<1>;
388
+ site: z.ZodObject<{
389
+ schemaVersion: z.ZodLiteral<1>;
390
+ name: z.ZodString;
391
+ lang: z.ZodDefault<z.ZodString>;
392
+ theme: z.ZodDefault<z.ZodObject<{
393
+ colorScheme: z.ZodDefault<z.ZodEnum<{
394
+ light: "light";
395
+ dark: "dark";
396
+ auto: "auto";
397
+ }>>;
398
+ overrides: z.ZodOptional<z.ZodObject<{
399
+ radius: z.ZodOptional<z.ZodEnum<{
400
+ none: "none";
401
+ sm: "sm";
402
+ md: "md";
403
+ lg: "lg";
404
+ full: "full";
405
+ }>>;
406
+ headingFont: z.ZodOptional<z.ZodEnum<{
407
+ system: "system";
408
+ inter: "inter";
409
+ "dm-sans": "dm-sans";
410
+ "work-sans": "work-sans";
411
+ montserrat: "montserrat";
412
+ poppins: "poppins";
413
+ "space-grotesk": "space-grotesk";
414
+ "source-serif": "source-serif";
415
+ merriweather: "merriweather";
416
+ "playfair-display": "playfair-display";
417
+ lora: "lora";
418
+ }>>;
419
+ bodyFont: z.ZodOptional<z.ZodEnum<{
420
+ system: "system";
421
+ inter: "inter";
422
+ "dm-sans": "dm-sans";
423
+ "work-sans": "work-sans";
424
+ montserrat: "montserrat";
425
+ poppins: "poppins";
426
+ "space-grotesk": "space-grotesk";
427
+ "source-serif": "source-serif";
428
+ merriweather: "merriweather";
429
+ "playfair-display": "playfair-display";
430
+ lora: "lora";
431
+ }>>;
432
+ }, z.core.$strip>>;
433
+ }, z.core.$strip>>;
434
+ header: z.ZodDefault<z.ZodArray<z.ZodObject<{
435
+ id: z.ZodString;
436
+ type: z.ZodString;
437
+ v: z.ZodNumber;
438
+ variant: z.ZodOptional<z.ZodString>;
439
+ hidden: z.ZodOptional<z.ZodBoolean>;
440
+ hideOn: z.ZodOptional<z.ZodArray<z.ZodEnum<{
441
+ mobile: "mobile";
442
+ desktop: "desktop";
443
+ }>>>;
444
+ placeholder: z.ZodOptional<z.ZodBoolean>;
445
+ props: z.ZodRecord<z.ZodString, z.ZodUnknown>;
446
+ }, z.core.$strip>>>;
447
+ nav: z.ZodDefault<z.ZodArray<z.ZodObject<{
448
+ label: z.ZodString;
449
+ href: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
450
+ }, z.core.$strip>>>;
451
+ footer: z.ZodDefault<z.ZodArray<z.ZodObject<{
452
+ id: z.ZodString;
453
+ type: z.ZodString;
454
+ v: z.ZodNumber;
455
+ variant: z.ZodOptional<z.ZodString>;
456
+ hidden: z.ZodOptional<z.ZodBoolean>;
457
+ hideOn: z.ZodOptional<z.ZodArray<z.ZodEnum<{
458
+ mobile: "mobile";
459
+ desktop: "desktop";
460
+ }>>>;
461
+ placeholder: z.ZodOptional<z.ZodBoolean>;
462
+ props: z.ZodRecord<z.ZodString, z.ZodUnknown>;
463
+ }, z.core.$strip>>>;
464
+ seo: z.ZodDefault<z.ZodObject<{
465
+ titleTemplate: z.ZodOptional<z.ZodString>;
466
+ description: z.ZodOptional<z.ZodString>;
467
+ ogImage: z.ZodOptional<z.ZodObject<{
468
+ src: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
469
+ alt: z.ZodDefault<z.ZodString>;
470
+ decorative: z.ZodOptional<z.ZodBoolean>;
471
+ width: z.ZodOptional<z.ZodNumber>;
472
+ height: z.ZodOptional<z.ZodNumber>;
473
+ focal: z.ZodOptional<z.ZodObject<{
474
+ x: z.ZodNumber;
475
+ y: z.ZodNumber;
476
+ }, z.core.$strip>>;
477
+ }, z.core.$strip>>;
478
+ organization: z.ZodOptional<z.ZodObject<{
479
+ name: z.ZodString;
480
+ logo: z.ZodOptional<z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>>;
481
+ sameAs: z.ZodOptional<z.ZodArray<z.ZodURL>>;
482
+ }, z.core.$strip>>;
483
+ noindex: z.ZodOptional<z.ZodBoolean>;
484
+ }, z.core.$strip>>;
485
+ redirects: z.ZodDefault<z.ZodArray<z.ZodObject<{
486
+ from: z.ZodString;
487
+ to: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
488
+ status: z.ZodUnion<readonly [z.ZodLiteral<301>, z.ZodLiteral<302>]>;
489
+ }, z.core.$strip>>>;
490
+ }, z.core.$strip>;
491
+ pages: z.ZodArray<z.ZodObject<{
492
+ id: z.ZodString;
493
+ path: z.ZodString;
494
+ kind: z.ZodEnum<{
495
+ page: "page";
496
+ landing: "landing";
497
+ }>;
498
+ doc: z.ZodObject<{
499
+ schemaVersion: z.ZodLiteral<1>;
500
+ root: z.ZodObject<{
501
+ props: z.ZodObject<{
502
+ title: z.ZodString;
503
+ hideSiteChrome: z.ZodOptional<z.ZodBoolean>;
504
+ }, z.core.$loose>;
505
+ }, z.core.$strip>;
506
+ content: z.ZodArray<z.ZodObject<{
507
+ id: z.ZodString;
508
+ type: z.ZodString;
509
+ v: z.ZodNumber;
510
+ variant: z.ZodOptional<z.ZodString>;
511
+ hidden: z.ZodOptional<z.ZodBoolean>;
512
+ hideOn: z.ZodOptional<z.ZodArray<z.ZodEnum<{
513
+ mobile: "mobile";
514
+ desktop: "desktop";
515
+ }>>>;
516
+ placeholder: z.ZodOptional<z.ZodBoolean>;
517
+ props: z.ZodRecord<z.ZodString, z.ZodUnknown>;
518
+ }, z.core.$strip>>;
519
+ seo: z.ZodOptional<z.ZodObject<{
520
+ title: z.ZodOptional<z.ZodString>;
521
+ description: z.ZodOptional<z.ZodString>;
522
+ ogImage: z.ZodOptional<z.ZodObject<{
523
+ src: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
524
+ alt: z.ZodDefault<z.ZodString>;
525
+ decorative: z.ZodOptional<z.ZodBoolean>;
526
+ width: z.ZodOptional<z.ZodNumber>;
527
+ height: z.ZodOptional<z.ZodNumber>;
528
+ focal: z.ZodOptional<z.ZodObject<{
529
+ x: z.ZodNumber;
530
+ y: z.ZodNumber;
531
+ }, z.core.$strip>>;
532
+ }, z.core.$strip>>;
533
+ canonical: z.ZodOptional<z.ZodURL>;
534
+ noindex: z.ZodOptional<z.ZodBoolean>;
535
+ }, z.core.$strip>>;
536
+ }, z.core.$strip>;
537
+ }, z.core.$strip>>;
538
+ }, z.core.$strip>;
539
+ type ReleaseSnapshot = z.infer<typeof ReleaseSnapshot>;
540
+ /**
541
+ * Read a stored snapshot page by page: a page that no longer parses (a
542
+ * schema this release tightened, a document written past the checks) is
543
+ * left out and reported, so one bad page doesn't take the whole site down.
544
+ * Null only when the site document itself doesn't parse.
545
+ */
546
+ declare function parseSnapshot(value: unknown, report?: (message: string) => void): ReleaseSnapshot | null;
547
+ interface ReleaseMeta {
548
+ id: string;
549
+ siteId: string;
550
+ number: number;
551
+ note: string | null;
552
+ createdAt: string;
553
+ publishedAt: string | null;
554
+ /** The brand the release was checked against (`brandHash`), when known. */
555
+ brandHash: string | null;
556
+ }
557
+ interface Release extends ReleaseMeta {
558
+ snapshot: ReleaseSnapshot;
559
+ }
560
+ interface PageMeta {
561
+ id: string;
562
+ siteId: string;
563
+ path: string;
564
+ kind: PageKind;
565
+ title: string;
566
+ sort: number;
567
+ rev: number;
568
+ }
569
+ /** The size limit of one stored document, as the database enforces it (512 KiB of JSON). */
570
+ declare const MAX_DOC_BYTES: number;
571
+
572
+ /**
573
+ * The form embed's contract with the host. A `form-embed` section names a
574
+ * form by its slug; the host says what that slug is, through a resolver
575
+ * passed to the renderer. This package assumes no forms table.
576
+ *
577
+ * - `definition`: a genesis-forms definition. The page renders it on the
578
+ * server with forms-web's `<Form>`, and the form island makes it
579
+ * interactive; answers are POSTed as JSON to `submitUrl` (the host's
580
+ * endpoint, for example one that runs genesis-forms destinations).
581
+ * - `embed`: an https URL the page shows in an iframe (a hosted form).
582
+ */
583
+ type ResolvedForm = {
584
+ kind: "definition";
585
+ /** A canonical genesis-forms definition (`defineForm(...).definition`, or a stored one). */
586
+ definition: unknown;
587
+ /** Where the form POSTs `{ form, answers }` (form: the slug): a site path or an https URL. */
588
+ submitUrl: string;
589
+ layout?: "classic" | "focus";
590
+ submitLabel?: string;
591
+ } | {
592
+ kind: "embed";
593
+ /** An https URL. */
594
+ url: string;
595
+ /** The iframe's accessible name. */
596
+ title: string;
597
+ /** The iframe's height in CSS pixels (default 640). */
598
+ height?: number;
599
+ };
600
+ interface FormsResolverContext {
601
+ siteId: string;
602
+ pagePath: string;
603
+ mode: "live" | "preview";
604
+ }
605
+ /** slug → the form to show, or null when the host has no such form (the section then renders nothing and logs). */
606
+ type FormsResolver = (slug: string, ctx: FormsResolverContext) => ResolvedForm | null | Promise<ResolvedForm | null>;
607
+
608
+ /**
609
+ * Sections: `defineSection` describes one kind of section (its props schema,
610
+ * variants, presets, migrations and server-safe React renderer), and the
611
+ * registry holds every kind a site can use.
612
+ *
613
+ * Modelled on genesis-forms' `registerContentType`: one registry per process,
614
+ * kept on a `Symbol.for` global so two copies of this package (a host's and a
615
+ * dependency's) share it; manifests are frozen; a host adds its own kinds and
616
+ * replaces a built-in only with `{ replace: true }`.
617
+ *
618
+ * Everything the editor needs comes from the definition: `label`,
619
+ * `category`, `variants`, `presets` and `sectionJsonSchema(type)`
620
+ * (`z.toJSONSchema` of the props schema) for its fields and for AI output.
621
+ */
622
+
623
+ declare const SECTION_CATEGORIES: readonly ["header", "intro", "content", "social-proof", "conversion", "footer"];
624
+ type SectionCategory = (typeof SECTION_CATEGORIES)[number];
625
+ /** Where on a page a section may go: the site header, the page body, or the site footer. */
626
+ type SectionPlacement = "header" | "body" | "footer";
627
+ interface SectionVariant {
628
+ id: string;
629
+ label: string;
630
+ }
631
+ interface SectionPreset<P = Record<string, unknown>> {
632
+ /** Shown in the editor's Add picker. */
633
+ name: string;
634
+ variant: string;
635
+ props: P;
636
+ }
637
+ /** What a section's renderer is told about the page it is on. */
638
+ interface RenderContext {
639
+ /**
640
+ * The level of the section's title: 1 for the page's main heading (the
641
+ * first section that `providesH1`), 2 for every other section. Items in a
642
+ * section are one level below it.
643
+ */
644
+ headingLevel: 1 | 2;
645
+ site: {
646
+ name: string;
647
+ lang: string;
648
+ nav: readonly MenuItem[];
649
+ logo?: {
650
+ src: string;
651
+ alt: string;
652
+ } | undefined;
653
+ };
654
+ /** The page's own path, such as `/about`. */
655
+ pagePath: string;
656
+ /** A stored link as the page should print it: site paths get the host's base path. */
657
+ href(href: string): string;
658
+ /** Forms on the page, resolved by slug before rendering (null: the host doesn't know the slug). */
659
+ forms: ReadonlyMap<string, ResolvedForm | null>;
660
+ mode: "live" | "preview";
661
+ /** A prefix that makes ids unique on the page: the section node's id. */
662
+ idPrefix: string;
663
+ }
664
+ interface SectionRenderProps<P> {
665
+ props: P;
666
+ variant: string;
667
+ node: SectionNode;
668
+ ctx: RenderContext;
669
+ }
670
+ interface SectionDefinition<P = Record<string, unknown>> {
671
+ /** The registry key stored in each node: lowercase, such as `hero`. */
672
+ type: string;
673
+ /** The current props version. Nodes at a lower `v` are migrated on read. */
674
+ version: number;
675
+ label: string;
676
+ description?: string;
677
+ category: SectionCategory;
678
+ /** The props schema (zod 4). Its input type is what an editor writes. */
679
+ schema: z.ZodType<P>;
680
+ variants: readonly SectionVariant[];
681
+ defaultVariant: string;
682
+ presets: readonly SectionPreset<z.input<z.ZodType<P>>>[];
683
+ /** At most this many on a page. */
684
+ limit?: number;
685
+ /** The page kinds it may appear on (default: every kind). */
686
+ enabledOn?: readonly PageKind[];
687
+ /** Where it may go (default: the page body). */
688
+ placement?: SectionPlacement;
689
+ /** Its title is the page's `h1` when it comes first (a hero). */
690
+ providesH1?: boolean;
691
+ /**
692
+ * `migrations[n]` turns version `n - 1` props into version `n` props. Pure
693
+ * functions: `migrateNode` runs them in order on read, in the editor and in
694
+ * the renderer, and a publish writes the result into the release.
695
+ */
696
+ migrations?: Readonly<Record<number, (props: Record<string, unknown>) => Record<string, unknown>>>;
697
+ /** Server-safe React: no state, no effects, no browser APIs. */
698
+ render: (input: SectionRenderProps<P>) => ReactNode;
699
+ }
700
+ /** A definition as the registry holds it: props erased to a record. */
701
+ type AnySectionDefinition = SectionDefinition<any>;
702
+ declare class SectionDefinitionError extends Error {
703
+ readonly problems: string[];
704
+ constructor(problems: string[]);
705
+ }
706
+ /**
707
+ * Declare a section kind. Checks the definition (and every preset against its
708
+ * schema) and returns it frozen. It isn't registered until `registerSection`.
709
+ *
710
+ * @stability Beta
711
+ */
712
+ declare function defineSection<P>(def: SectionDefinition<P>): Readonly<SectionDefinition<P>>;
713
+ /** The built-in section kinds, which a host replaces only with `{ replace: true }`. */
714
+ declare const BUILT_IN_SECTION_TYPES: readonly ["nav", "hero", "features", "cta", "testimonials", "faq", "pricing", "logos", "stats", "gallery", "rich-text", "form-embed", "footer"];
715
+ type BuiltInSectionType = (typeof BUILT_IN_SECTION_TYPES)[number];
716
+ interface RegisterSectionOptions {
717
+ /** Replace a built-in kind, for every site in this process. */
718
+ replace?: boolean;
719
+ }
720
+ /**
721
+ * Register a section kind (from `defineSection`, or a plain definition, which
722
+ * is checked the same way). Re-registering a host kind replaces it, so hot
723
+ * reload works; a built-in kind's name throws unless `{ replace: true }`.
724
+ *
725
+ * @stability Beta
726
+ */
727
+ declare function registerSection(def: AnySectionDefinition, options?: RegisterSectionOptions): void;
728
+ /** For `@marktiderman/genesis-sites/sections`: register a built-in unless one (or a replacement) is there. @internal */
729
+ declare function registerBuiltInSection(def: AnySectionDefinition): void;
730
+ declare function getSection(type: string): AnySectionDefinition | undefined;
731
+ declare function listSections(): AnySectionDefinition[];
732
+ /** Remove a host section kind (tests, hot reload). Built-ins can't be removed, only replaced. */
733
+ declare function unregisterSection(type: string): boolean;
734
+ /**
735
+ * The JSON Schema of a section's props (`z.toJSONSchema`, input side), for the
736
+ * editor's fields and for validating AI output. Refinements (safe URLs) don't
737
+ * appear in JSON Schema; the zod schema still checks them on save.
738
+ *
739
+ * @stability Beta
740
+ */
741
+ declare function sectionJsonSchema(typeOrDef: string | AnySectionDefinition): Record<string, unknown>;
742
+ /** What the editor's Add picker and fields need about one section kind. */
743
+ interface SectionManifest {
744
+ type: string;
745
+ version: number;
746
+ label: string;
747
+ description?: string;
748
+ category: SectionCategory;
749
+ placement: SectionPlacement;
750
+ variants: readonly SectionVariant[];
751
+ defaultVariant: string;
752
+ presets: readonly SectionPreset[];
753
+ limit?: number;
754
+ enabledOn?: readonly PageKind[];
755
+ jsonSchema: Record<string, unknown>;
756
+ }
757
+ /** Every registered section as editor data (no renderers): the editor's catalog. @stability Beta */
758
+ declare function sectionManifests(): SectionManifest[];
759
+ /** A new section id: short, alphanumeric, unique enough within a page. */
760
+ declare function newSectionId(prefix?: string): string;
761
+ /** A section node from a preset: the editor's Add, and templates. */
762
+ declare function nodeFromPreset(type: string, presetName?: string, id?: string): SectionNode;
763
+
764
+ export { unregisterSection as $, type AnySectionDefinition as A, BUILT_IN_SECTION_TYPES as B, Copy as C, type SectionRenderProps as D, type SectionVariant as E, FontChoice as F, Seo as G, Href as H, Image as I, SeoDefaults as J, Surface as K, Link as L, MAX_DOC_BYTES as M, defineSection as N, getSection as O, PageDoc as P, listSections as Q, ReleasePage as R, SectionNode as S, TokenOverrides as T, newSectionId as U, nodeFromPreset as V, parseSnapshot as W, registerBuiltInSection as X, registerSection as Y, sectionJsonSchema as Z, sectionManifests as _, SiteDoc as a, Redirect as b, type SiteDocInput as c, PageKind as d, type BuiltInSectionType as e, type FormsResolver as f, type FormsResolverContext as g, Line as h, MenuItem as i, type PageMeta as j, PagePath as k, type RegisterSectionOptions as l, type Release as m, type ReleaseMeta as n, ReleaseSnapshot as o, type RenderContext as p, type ResolvedForm as q, RichText as r, SECTION_CATEGORIES as s, type SectionCategory as t, type SectionDefinition as u, SectionDefinitionError as v, SectionId as w, type SectionManifest as x, type SectionPlacement as y, type SectionPreset as z };