@cloudhal/core-contracts 0.3.4 → 0.3.5

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.
@@ -1,1050 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://cloudhal.dev/schemas/v1/site.schema.json",
4
- "title": "Site",
5
- "description": "Root node of a Site Graph: one deployable website with its locales, domains, theme and page index. Pages and content entries are separate nodes referenced by id so they can be versioned and locked independently.",
6
- "type": "object",
7
- "additionalProperties": false,
8
- "required": [
9
- "schemaVersion",
10
- "id",
11
- "projectId",
12
- "name",
13
- "slug",
14
- "defaultLocale",
15
- "locales",
16
- "domains",
17
- "pageIds",
18
- "theme",
19
- "rev",
20
- "createdAt",
21
- "updatedAt"
22
- ],
23
- "properties": {
24
- "schemaVersion": {
25
- "$ref": "#/$defs/SchemaVersion"
26
- },
27
- "id": {
28
- "$ref": "#/$defs/Id"
29
- },
30
- "projectId": {
31
- "$ref": "#/$defs/Id"
32
- },
33
- "name": {
34
- "type": "string",
35
- "minLength": 1,
36
- "maxLength": 200
37
- },
38
- "slug": {
39
- "$ref": "#/$defs/Slug"
40
- },
41
- "defaultLocale": {
42
- "$ref": "#/$defs/Locale"
43
- },
44
- "locales": {
45
- "type": "array",
46
- "items": {
47
- "$ref": "#/$defs/Locale"
48
- },
49
- "minItems": 1,
50
- "uniqueItems": true
51
- },
52
- "domains": {
53
- "type": "array",
54
- "description": "Hostnames serving this site. Exactly one should be primary: the address canonical links, feeds and previews use. Sites run on their own domains or their Cloudflare account's workers.dev address, never on a Cloudhal domain (ADR-0037).",
55
- "items": {
56
- "$ref": "#/$defs/Domain"
57
- }
58
- },
59
- "pageIds": {
60
- "type": "array",
61
- "items": {
62
- "$ref": "#/$defs/Id"
63
- },
64
- "uniqueItems": true
65
- },
66
- "homePageId": {
67
- "$ref": "#/$defs/Id"
68
- },
69
- "localization": {
70
- "$ref": "#/$defs/Localization"
71
- },
72
- "theme": {
73
- "$ref": "#/$defs/ThemeRef"
74
- },
75
- "design": {
76
- "$ref": "#/$defs/Design"
77
- },
78
- "brand": {
79
- "$ref": "#/$defs/Brand"
80
- },
81
- "chrome": {
82
- "$ref": "#/$defs/Chrome"
83
- },
84
- "timeZone": {
85
- "$ref": "#/$defs/TimeZone",
86
- "description": "The site's time zone (RFC-0008): Studio's calendar, schedules entered as wall-clock times and recurring automations use it. Absent means UTC."
87
- },
88
- "publishedSnapshotId": {
89
- "$ref": "#/$defs/Id",
90
- "description": "Snapshot currently serving production. Rollback = pointing this at an older snapshot."
91
- },
92
- "rev": {
93
- "$ref": "#/$defs/Revision"
94
- },
95
- "createdAt": {
96
- "$ref": "#/$defs/Timestamp"
97
- },
98
- "updatedAt": {
99
- "$ref": "#/$defs/Timestamp"
100
- },
101
- "metadata": {
102
- "$ref": "#/$defs/Metadata"
103
- }
104
- },
105
- "$defs": {
106
- "Actor": {
107
- "type": "object",
108
- "additionalProperties": false,
109
- "required": [
110
- "kind",
111
- "id"
112
- ],
113
- "properties": {
114
- "kind": {
115
- "$ref": "#/$defs/ActorKind"
116
- },
117
- "id": {
118
- "$ref": "#/$defs/Id"
119
- },
120
- "name": {
121
- "type": "string",
122
- "maxLength": 200
123
- }
124
- }
125
- },
126
- "ActorKind": {
127
- "type": "string",
128
- "description": "Who performed an action. Humans and agents share one actor model so the policy engine treats them uniformly.",
129
- "enum": [
130
- "human",
131
- "agent",
132
- "system"
133
- ]
134
- },
135
- "Announcement": {
136
- "type": "object",
137
- "additionalProperties": false,
138
- "required": [
139
- "id",
140
- "text"
141
- ],
142
- "properties": {
143
- "id": {
144
- "type": "string",
145
- "pattern": "^[a-z0-9][a-z0-9-]{0,40}$",
146
- "description": "Change it when the text changes, so readers who dismissed the old one see the new one."
147
- },
148
- "text": {
149
- "type": "string",
150
- "minLength": 1,
151
- "maxLength": 200
152
- },
153
- "label": {
154
- "type": "string",
155
- "minLength": 1,
156
- "maxLength": 40
157
- },
158
- "href": {
159
- "type": "string",
160
- "minLength": 1,
161
- "maxLength": 2048
162
- },
163
- "tone": {
164
- "type": "string",
165
- "enum": [
166
- "info",
167
- "brand",
168
- "warning"
169
- ]
170
- },
171
- "dismissible": {
172
- "type": "boolean"
173
- }
174
- }
175
- },
176
- "BodyBlock": {
177
- "type": "object",
178
- "description": "One top-level block of a markdown body in the store's index (RFC-0014 §3). Written by the store only: a client's values are replaced on every write. `by`, `via` and `at` say who last changed the block's content, through which channel and when; they are absent for content written before the index existed.",
179
- "additionalProperties": false,
180
- "required": [
181
- "id",
182
- "hash"
183
- ],
184
- "properties": {
185
- "id": {
186
- "type": "string",
187
- "pattern": "^blk_[0-9A-Za-z]{8,24}$",
188
- "description": "Stable across writes that keep the block's content or its place among unchanged blocks."
189
- },
190
- "hash": {
191
- "type": "string",
192
- "pattern": "^[0-9a-f]{64}$",
193
- "description": "SHA-256 (hex) of the block's markdown without trailing whitespace."
194
- },
195
- "by": {
196
- "$ref": "#/$defs/Actor"
197
- },
198
- "via": {
199
- "type": "string",
200
- "enum": [
201
- "studio",
202
- "mcp",
203
- "api",
204
- "import",
205
- "ai-command",
206
- "proposal"
207
- ],
208
- "description": "The channel of that change."
209
- },
210
- "at": {
211
- "$ref": "#/$defs/Timestamp"
212
- }
213
- }
214
- },
215
- "BodyBlocks": {
216
- "type": "array",
217
- "description": "A markdown body's block index, in body order (RFC-0014 §3). Absent means not indexed (yet, or an HTML body), never empty.",
218
- "maxItems": 5000,
219
- "items": {
220
- "$ref": "#/$defs/BodyBlock"
221
- }
222
- },
223
- "BodyProfile": {
224
- "type": "integer",
225
- "enum": [
226
- 1
227
- ],
228
- "description": "The markdown dialect a body follows (RFC-0014 §1): 1 = Cloudhal Markdown v1 (CommonMark + GFM + `asset:` + directives; raw HTML escaped). Set by the store on markdown bodies."
229
- },
230
- "Brand": {
231
- "type": "object",
232
- "description": "The site's logo and social links (RFC-0025 §1), shared by the header, the footer and SEO.",
233
- "additionalProperties": false,
234
- "properties": {
235
- "logo": {
236
- "$ref": "#/$defs/ImageRef"
237
- },
238
- "logoDark": {
239
- "$ref": "#/$defs/ImageRef"
240
- },
241
- "logoHeight": {
242
- "type": "string",
243
- "enum": [
244
- "s",
245
- "m",
246
- "l"
247
- ]
248
- },
249
- "social": {
250
- "type": "array",
251
- "maxItems": 8,
252
- "items": {
253
- "$ref": "#/$defs/SocialLink"
254
- }
255
- }
256
- }
257
- },
258
- "Chrome": {
259
- "type": "object",
260
- "description": "The site's header, footer and bars as data (RFC-0025): enums, menu keys and short texts; the theme renders them with landmarks, focus and contrast guaranteed.",
261
- "additionalProperties": false,
262
- "properties": {
263
- "header": {
264
- "$ref": "#/$defs/ChromeHeader"
265
- },
266
- "footer": {
267
- "$ref": "#/$defs/ChromeFooter"
268
- },
269
- "announcement": {
270
- "$ref": "#/$defs/Announcement"
271
- },
272
- "consent": {
273
- "$ref": "#/$defs/Consent"
274
- }
275
- }
276
- },
277
- "ChromeFooter": {
278
- "type": "object",
279
- "additionalProperties": false,
280
- "properties": {
281
- "layout": {
282
- "type": "string",
283
- "enum": [
284
- "simple",
285
- "columns",
286
- "cta-band",
287
- "minimal"
288
- ]
289
- },
290
- "surface": {
291
- "type": "string",
292
- "enum": [
293
- "plain",
294
- "muted",
295
- "inverse"
296
- ]
297
- },
298
- "tagline": {
299
- "type": "string",
300
- "minLength": 1,
301
- "maxLength": 200
302
- },
303
- "columns": {
304
- "type": "array",
305
- "maxItems": 5,
306
- "items": {
307
- "$ref": "#/$defs/FooterColumn"
308
- }
309
- },
310
- "ctaHeading": {
311
- "type": "string",
312
- "minLength": 1,
313
- "maxLength": 120
314
- },
315
- "ctaLabel": {
316
- "type": "string",
317
- "minLength": 1,
318
- "maxLength": 40
319
- },
320
- "ctaHref": {
321
- "type": "string",
322
- "minLength": 1,
323
- "maxLength": 2048
324
- },
325
- "social": {
326
- "type": "boolean"
327
- },
328
- "copyright": {
329
- "type": "string",
330
- "minLength": 1,
331
- "maxLength": 200,
332
- "description": "The legal line; {year} and {site} are the only placeholders."
333
- },
334
- "legal": {
335
- "$ref": "#/$defs/Slug",
336
- "description": "A menu key (RFC-0003)."
337
- },
338
- "extras": {
339
- "type": "array",
340
- "maxItems": 3,
341
- "uniqueItems": true,
342
- "items": {
343
- "type": "string",
344
- "enum": [
345
- "locale",
346
- "theme-toggle",
347
- "motion-toggle"
348
- ]
349
- }
350
- },
351
- "credit": {
352
- "type": "boolean"
353
- },
354
- "region": {
355
- "$ref": "#/$defs/Section",
356
- "description": "RFC-0025 §2: one optional surface (kind `surface`) above the footer's columns, built and checked like any surface; the store refuses other section kinds."
357
- }
358
- }
359
- },
360
- "ChromeHeader": {
361
- "type": "object",
362
- "additionalProperties": false,
363
- "properties": {
364
- "layout": {
365
- "type": "string",
366
- "enum": [
367
- "logo-left",
368
- "logo-left-nav-center",
369
- "centered",
370
- "split",
371
- "minimal"
372
- ]
373
- },
374
- "behavior": {
375
- "type": "string",
376
- "enum": [
377
- "static",
378
- "sticky",
379
- "hide-on-scroll",
380
- "fixed"
381
- ]
382
- },
383
- "shrink": {
384
- "type": "boolean"
385
- },
386
- "overHero": {
387
- "type": "string",
388
- "enum": [
389
- "solid",
390
- "transparent"
391
- ]
392
- },
393
- "width": {
394
- "type": "string",
395
- "enum": [
396
- "content",
397
- "wide",
398
- "full"
399
- ]
400
- },
401
- "surface": {
402
- "type": "string",
403
- "enum": [
404
- "plain",
405
- "muted",
406
- "raised",
407
- "inverse",
408
- "brand"
409
- ]
410
- },
411
- "mobileStyle": {
412
- "type": "string",
413
- "enum": [
414
- "dropdown",
415
- "drawer-start",
416
- "drawer-end",
417
- "fullscreen"
418
- ]
419
- },
420
- "collapseAt": {
421
- "type": "string",
422
- "enum": [
423
- "sm",
424
- "md",
425
- "lg",
426
- "always"
427
- ]
428
- },
429
- "nav": {
430
- "$ref": "#/$defs/Slug",
431
- "description": "A menu key (RFC-0003)."
432
- },
433
- "utility": {
434
- "$ref": "#/$defs/Slug",
435
- "description": "A menu key (RFC-0003)."
436
- },
437
- "actions": {
438
- "type": "array",
439
- "maxItems": 3,
440
- "items": {
441
- "$ref": "#/$defs/HeaderAction"
442
- }
443
- }
444
- }
445
- },
446
- "Consent": {
447
- "type": "object",
448
- "additionalProperties": false,
449
- "required": [
450
- "mode"
451
- ],
452
- "properties": {
453
- "mode": {
454
- "type": "string",
455
- "enum": [
456
- "none",
457
- "notice",
458
- "choices"
459
- ]
460
- },
461
- "policy": {
462
- "$ref": "#/$defs/Path"
463
- }
464
- }
465
- },
466
- "Design": {
467
- "type": "object",
468
- "description": "The site's design rules for people and agents (RFC-0021): Markdown that agents read with the theme's DESIGN.md before they build. Guidance only: it changes neither rendering nor permissions.",
469
- "additionalProperties": false,
470
- "required": [
471
- "markdown"
472
- ],
473
- "properties": {
474
- "markdown": {
475
- "type": "string",
476
- "minLength": 1,
477
- "maxLength": 24000
478
- }
479
- }
480
- },
481
- "Domain": {
482
- "type": "object",
483
- "additionalProperties": false,
484
- "required": [
485
- "hostname",
486
- "primary"
487
- ],
488
- "properties": {
489
- "hostname": {
490
- "type": "string",
491
- "pattern": "^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}$",
492
- "maxLength": 253
493
- },
494
- "primary": {
495
- "type": "boolean"
496
- }
497
- }
498
- },
499
- "FooterColumn": {
500
- "type": "object",
501
- "additionalProperties": false,
502
- "required": [
503
- "heading",
504
- "menu"
505
- ],
506
- "properties": {
507
- "heading": {
508
- "type": "string",
509
- "minLength": 1,
510
- "maxLength": 60
511
- },
512
- "menu": {
513
- "$ref": "#/$defs/Slug",
514
- "description": "A menu key (RFC-0003)."
515
- }
516
- }
517
- },
518
- "HeaderAction": {
519
- "type": "object",
520
- "additionalProperties": false,
521
- "required": [
522
- "kind"
523
- ],
524
- "properties": {
525
- "kind": {
526
- "type": "string",
527
- "enum": [
528
- "button",
529
- "search",
530
- "locale",
531
- "theme-toggle",
532
- "motion-toggle"
533
- ]
534
- },
535
- "label": {
536
- "type": "string",
537
- "minLength": 1,
538
- "maxLength": 40
539
- },
540
- "href": {
541
- "type": "string",
542
- "minLength": 1,
543
- "maxLength": 2048
544
- },
545
- "variant": {
546
- "type": "string",
547
- "enum": [
548
- "primary",
549
- "secondary"
550
- ]
551
- }
552
- }
553
- },
554
- "Id": {
555
- "type": "string",
556
- "description": "Prefixed, URL-safe identifier, e.g. site_01HZX8K3Q9. The prefix names the entity kind; agents and the MCP server pass these as opaque handles.",
557
- "pattern": "^[a-z]+_[A-Za-z0-9]{6,32}$",
558
- "minLength": 8,
559
- "maxLength": 48
560
- },
561
- "ImageRef": {
562
- "type": "object",
563
- "description": "Reference to an image. With `assetId` the image is an Asset node (RFC-0004): the store writes its media URL into `src`, and its size into `width` and `height`, as a fallback for readers that do not resolve assets. Without it, `src` is a relative path or an absolute URL, as before.",
564
- "additionalProperties": false,
565
- "required": [
566
- "src",
567
- "alt"
568
- ],
569
- "properties": {
570
- "assetId": {
571
- "$ref": "#/$defs/Id",
572
- "description": "The Asset node shown (RFC-0004). Renderers that know assets resolve it and ignore `src`."
573
- },
574
- "src": {
575
- "type": "string",
576
- "minLength": 1,
577
- "maxLength": 2048
578
- },
579
- "alt": {
580
- "type": "string",
581
- "maxLength": 500
582
- },
583
- "width": {
584
- "type": "integer",
585
- "minimum": 1
586
- },
587
- "height": {
588
- "type": "integer",
589
- "minimum": 1
590
- }
591
- }
592
- },
593
- "Link": {
594
- "type": "object",
595
- "additionalProperties": false,
596
- "required": [
597
- "label",
598
- "href"
599
- ],
600
- "properties": {
601
- "label": {
602
- "type": "string",
603
- "minLength": 1,
604
- "maxLength": 200
605
- },
606
- "href": {
607
- "type": "string",
608
- "minLength": 1,
609
- "maxLength": 2048
610
- },
611
- "external": {
612
- "type": "boolean"
613
- }
614
- }
615
- },
616
- "Locale": {
617
- "type": "string",
618
- "description": "BCP 47 language tag, e.g. en, tr, en-US.",
619
- "pattern": "^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$"
620
- },
621
- "Localization": {
622
- "type": "object",
623
- "description": "How the site serves its locales (RFC-0033 §2). Absent fields mean: prefix-except-default routing, no fallback, no required review, the machine-translation notice until reviewed.",
624
- "additionalProperties": false,
625
- "properties": {
626
- "routing": {
627
- "type": "string",
628
- "description": "prefix-except-default: the default locale at the root, the others under /<locale>/. prefix-all: every locale prefixed, / is a language chooser (x-default).",
629
- "enum": [
630
- "prefix-except-default",
631
- "prefix-all"
632
- ]
633
- },
634
- "domains": {
635
- "type": "object",
636
- "description": "Optional hostname per locale; that locale is then served at the host's root.",
637
- "propertyNames": {
638
- "$ref": "#/$defs/Locale"
639
- },
640
- "additionalProperties": {
641
- "type": "string",
642
- "pattern": "^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z]{2,63}$",
643
- "maxLength": 253
644
- }
645
- },
646
- "fallback": {
647
- "type": "string",
648
- "description": "none: a missing translation is not found. default-with-notice: the default locale's page is served with a notice and noindex.",
649
- "enum": [
650
- "none",
651
- "default-with-notice"
652
- ]
653
- },
654
- "review": {
655
- "type": "object",
656
- "description": "Collections whose machine translations need a person's review before they publish ('pages' stands for pages).",
657
- "additionalProperties": false,
658
- "properties": {
659
- "required": {
660
- "type": "array",
661
- "items": {
662
- "type": "string",
663
- "minLength": 1,
664
- "maxLength": 100
665
- },
666
- "uniqueItems": true
667
- }
668
- }
669
- },
670
- "label": {
671
- "type": "string",
672
- "description": "When readers see the machine-translation notice: unreviewed (until a person reviews) or always.",
673
- "enum": [
674
- "unreviewed",
675
- "always"
676
- ]
677
- }
678
- }
679
- },
680
- "Metadata": {
681
- "type": "object",
682
- "description": "Free-form string-to-string map for extensions. Keys should be namespaced (e.g. cloudhal.source).",
683
- "additionalProperties": {
684
- "type": "string"
685
- }
686
- },
687
- "Path": {
688
- "type": "string",
689
- "description": "Absolute URL path of a route the site owns: starts with '/', lower-case slug segments, no trailing slash except root.",
690
- "pattern": "^/(?:[a-z0-9]+(?:-[a-z0-9]+)*(?:/[a-z0-9]+(?:-[a-z0-9]+)*)*)?$",
691
- "maxLength": 1024
692
- },
693
- "Revision": {
694
- "type": "integer",
695
- "description": "Monotonic per-node revision used for optimistic locking (compare-and-swap on write).",
696
- "minimum": 0
697
- },
698
- "SchemaVersion": {
699
- "type": "integer",
700
- "description": "Version of this contract. Readers reject unknown versions; migrations move documents forward one version at a time.",
701
- "enum": [
702
- 1
703
- ]
704
- },
705
- "Section": {
706
- "title": "Section",
707
- "description": "A block inside a page, discriminated by `kind`. Variants are written inline (not via $ref) and `kind` is a single-value string enum so that TypeScript gets a literal union and Rust gets a serde internally-tagged enum.",
708
- "oneOf": [
709
- {
710
- "type": "object",
711
- "title": "HeroSection",
712
- "additionalProperties": false,
713
- "required": [
714
- "id",
715
- "kind",
716
- "heading"
717
- ],
718
- "properties": {
719
- "id": {
720
- "$ref": "#/$defs/Id"
721
- },
722
- "kind": {
723
- "type": "string",
724
- "enum": [
725
- "hero"
726
- ]
727
- },
728
- "heading": {
729
- "type": "string",
730
- "minLength": 1,
731
- "maxLength": 300
732
- },
733
- "subheading": {
734
- "type": "string",
735
- "maxLength": 1000
736
- },
737
- "image": {
738
- "$ref": "#/$defs/ImageRef"
739
- },
740
- "cta": {
741
- "$ref": "#/$defs/Link"
742
- }
743
- }
744
- },
745
- {
746
- "type": "object",
747
- "title": "RichTextSection",
748
- "additionalProperties": false,
749
- "required": [
750
- "id",
751
- "kind",
752
- "format",
753
- "body"
754
- ],
755
- "properties": {
756
- "id": {
757
- "$ref": "#/$defs/Id"
758
- },
759
- "kind": {
760
- "type": "string",
761
- "enum": [
762
- "richText"
763
- ]
764
- },
765
- "format": {
766
- "type": "string",
767
- "enum": [
768
- "markdown",
769
- "html"
770
- ]
771
- },
772
- "body": {
773
- "type": "string",
774
- "maxLength": 200000
775
- },
776
- "profile": {
777
- "$ref": "#/$defs/BodyProfile"
778
- },
779
- "blocks": {
780
- "$ref": "#/$defs/BodyBlocks"
781
- }
782
- }
783
- },
784
- {
785
- "type": "object",
786
- "title": "ImageSection",
787
- "additionalProperties": false,
788
- "required": [
789
- "id",
790
- "kind",
791
- "image"
792
- ],
793
- "properties": {
794
- "id": {
795
- "$ref": "#/$defs/Id"
796
- },
797
- "kind": {
798
- "type": "string",
799
- "enum": [
800
- "image"
801
- ]
802
- },
803
- "image": {
804
- "$ref": "#/$defs/ImageRef"
805
- },
806
- "caption": {
807
- "type": "string",
808
- "maxLength": 1000
809
- }
810
- }
811
- },
812
- {
813
- "type": "object",
814
- "title": "ContentListSection",
815
- "description": "Renders the newest entries of a content collection (e.g. blog posts).",
816
- "additionalProperties": false,
817
- "required": [
818
- "id",
819
- "kind",
820
- "collection",
821
- "limit",
822
- "sort"
823
- ],
824
- "properties": {
825
- "id": {
826
- "$ref": "#/$defs/Id"
827
- },
828
- "kind": {
829
- "type": "string",
830
- "enum": [
831
- "contentList"
832
- ]
833
- },
834
- "collection": {
835
- "$ref": "#/$defs/Slug"
836
- },
837
- "limit": {
838
- "type": "integer",
839
- "minimum": 1,
840
- "maximum": 100
841
- },
842
- "sort": {
843
- "type": "string",
844
- "enum": [
845
- "newest",
846
- "oldest",
847
- "title"
848
- ]
849
- },
850
- "filter": {
851
- "type": "string",
852
- "description": "Filter expression over term assignments (RFC-0002), e.g. 'category:news+tag:ai' or 'category:news>*'.",
853
- "minLength": 1,
854
- "maxLength": 512
855
- }
856
- }
857
- },
858
- {
859
- "type": "object",
860
- "title": "ComponentSection",
861
- "description": "A typed block from the block registry (RFC-0015): `type` names a registered block type (one global namespace of English names), `props` follow that type's props schema, which the store validates.",
862
- "additionalProperties": false,
863
- "required": [
864
- "id",
865
- "kind",
866
- "type",
867
- "props"
868
- ],
869
- "properties": {
870
- "id": {
871
- "$ref": "#/$defs/Id"
872
- },
873
- "kind": {
874
- "type": "string",
875
- "enum": [
876
- "component"
877
- ]
878
- },
879
- "type": {
880
- "type": "string",
881
- "pattern": "^[a-z][a-z0-9-]{1,40}$"
882
- },
883
- "props": {
884
- "type": "object",
885
- "description": "Validated against the type's props schema by the store, not by this contract.",
886
- "additionalProperties": true
887
- }
888
- }
889
- },
890
- {
891
- "type": "object",
892
- "title": "SurfaceSection",
893
- "description": "A generative UI surface (RFC-0020): a flat list of catalog components with a `root`, plus a data model their props may bind to. Written and streamed by agents as data, never code; the store checks the tree, the catalog and the limits.",
894
- "additionalProperties": false,
895
- "required": [
896
- "id",
897
- "kind",
898
- "catalog",
899
- "components"
900
- ],
901
- "properties": {
902
- "id": {
903
- "$ref": "#/$defs/Id"
904
- },
905
- "kind": {
906
- "type": "string",
907
- "enum": [
908
- "surface"
909
- ]
910
- },
911
- "catalog": {
912
- "type": "string",
913
- "description": "The catalog the surface was written for: `<theme>@<major>` (RFC-0018 manifest).",
914
- "pattern": "^[a-z][a-z0-9-]{0,40}@[0-9]{1,4}$"
915
- },
916
- "components": {
917
- "type": "array",
918
- "minItems": 1,
919
- "maxItems": 200,
920
- "items": {
921
- "$ref": "#/$defs/SurfaceComponent"
922
- }
923
- },
924
- "data": {
925
- "type": "object",
926
- "description": "The surface's data model: JSON its components bind to with `{path}` (at most 64 KB serialized; the store enforces the size).",
927
- "additionalProperties": true
928
- }
929
- }
930
- }
931
- ]
932
- },
933
- "Slug": {
934
- "type": "string",
935
- "description": "Lower-case URL segment.",
936
- "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
937
- "minLength": 1,
938
- "maxLength": 128
939
- },
940
- "SocialLink": {
941
- "type": "object",
942
- "additionalProperties": false,
943
- "required": [
944
- "network",
945
- "href"
946
- ],
947
- "properties": {
948
- "network": {
949
- "type": "string",
950
- "enum": [
951
- "x",
952
- "bluesky",
953
- "mastodon",
954
- "github",
955
- "linkedin",
956
- "instagram",
957
- "facebook",
958
- "youtube",
959
- "tiktok",
960
- "threads",
961
- "rss",
962
- "email"
963
- ]
964
- },
965
- "href": {
966
- "type": "string",
967
- "minLength": 1,
968
- "maxLength": 2048
969
- }
970
- }
971
- },
972
- "SurfaceComponent": {
973
- "type": "object",
974
- "description": "One element of a generative UI surface (RFC-0020 §1), in a flat list: `component` names a catalog entry (a PascalCase built-in primitive such as `Stack`, or a registry block type such as `callout`), `children` refer to other ids of the same surface, and `props` follow the entry's schema, which the store checks. Field names follow A2UI v0.9.",
975
- "additionalProperties": false,
976
- "required": [
977
- "id",
978
- "component"
979
- ],
980
- "properties": {
981
- "id": {
982
- "$ref": "#/$defs/SurfaceComponentId"
983
- },
984
- "component": {
985
- "type": "string",
986
- "pattern": "^(?:[A-Z][A-Za-z0-9]{1,40}|[a-z][a-z0-9-]{1,40})$"
987
- },
988
- "children": {
989
- "type": "array",
990
- "maxItems": 200,
991
- "items": {
992
- "$ref": "#/$defs/SurfaceComponentId"
993
- }
994
- },
995
- "props": {
996
- "type": "object",
997
- "description": "Literal values, `{path}` bindings into the surface's data, or `{call}` named functions; validated by the store against the catalog, not by this contract.",
998
- "additionalProperties": true
999
- },
1000
- "visible": {
1001
- "type": "object",
1002
- "description": "A visibility condition over the surface's data (`eq`, `ne`, `gt`, `lt`, `and`, `or`, `not`); validated by the store.",
1003
- "additionalProperties": true
1004
- },
1005
- "motion": {
1006
- "type": "object",
1007
- "description": "Motion presets for this component (RFC-0024 §2): `reveal`, `hover`, `speed`, `delay`, `stagger`, `replay` and later `scroll`, `loop`; enums and clamped numbers only, validated by the store against the catalog. The renderer turns them into CSS; agents never write CSS.",
1008
- "additionalProperties": true
1009
- }
1010
- }
1011
- },
1012
- "SurfaceComponentId": {
1013
- "type": "string",
1014
- "description": "A component's id, unique within its surface; `root` is the tree's root (RFC-0020 §1).",
1015
- "pattern": "^[a-z][a-z0-9-]{0,40}$"
1016
- },
1017
- "ThemeRef": {
1018
- "type": "object",
1019
- "description": "Theme (a.k.a. Experience) applied by the renderer. Config is theme-defined and validated by the theme's own schema, not here.",
1020
- "additionalProperties": false,
1021
- "required": [
1022
- "name"
1023
- ],
1024
- "properties": {
1025
- "name": {
1026
- "$ref": "#/$defs/Slug"
1027
- },
1028
- "version": {
1029
- "type": "string",
1030
- "maxLength": 64
1031
- },
1032
- "config": {
1033
- "type": "object",
1034
- "additionalProperties": true
1035
- }
1036
- }
1037
- },
1038
- "Timestamp": {
1039
- "type": "string",
1040
- "description": "RFC 3339 / ISO 8601 instant in UTC.",
1041
- "format": "date-time"
1042
- },
1043
- "TimeZone": {
1044
- "type": "string",
1045
- "description": "IANA time zone name from the tz database (RFC-0008), e.g. Europe/Istanbul, America/Argentina/Buenos_Aires, Etc/GMT+3 or UTC. Wall-clock times a person enters are kept with their zone, so the instant is recomputed when governments change the rules. The pattern bounds the shape only; writers also check the name against the runtime's Intl zone list.",
1046
- "pattern": "^(?:UTC|[A-Z][A-Za-z_-]+(?:/[A-Za-z0-9_+-]+){1,2})$",
1047
- "maxLength": 64
1048
- }
1049
- }
1050
- }