@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,738 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://cloudhal.dev/schemas/v1/page.schema.json",
4
- "title": "Page",
5
- "description": "A routable page of a site: a path, editorial status and an ordered list of sections. Sections are embedded (not separate nodes) so a page is the unit of locking, snapshotting and diffing.",
6
- "type": "object",
7
- "additionalProperties": false,
8
- "required": [
9
- "schemaVersion",
10
- "id",
11
- "siteId",
12
- "path",
13
- "title",
14
- "locale",
15
- "status",
16
- "sections",
17
- "rev",
18
- "createdAt",
19
- "updatedAt"
20
- ],
21
- "properties": {
22
- "schemaVersion": {
23
- "$ref": "#/$defs/SchemaVersion"
24
- },
25
- "id": {
26
- "$ref": "#/$defs/Id"
27
- },
28
- "siteId": {
29
- "$ref": "#/$defs/Id"
30
- },
31
- "path": {
32
- "type": "string",
33
- "description": "Absolute URL path, starting with '/', no trailing slash except root.",
34
- "pattern": "^/(?:[a-z0-9]+(?:-[a-z0-9]+)*(?:/[a-z0-9]+(?:-[a-z0-9]+)*)*)?$",
35
- "maxLength": 1024
36
- },
37
- "title": {
38
- "type": "string",
39
- "minLength": 1,
40
- "maxLength": 300
41
- },
42
- "locale": {
43
- "$ref": "#/$defs/Locale"
44
- },
45
- "status": {
46
- "$ref": "#/$defs/PublishStatus"
47
- },
48
- "sections": {
49
- "type": "array",
50
- "items": {
51
- "$ref": "#/$defs/Section"
52
- }
53
- },
54
- "seo": {
55
- "$ref": "#/$defs/Seo"
56
- },
57
- "availability": {
58
- "$ref": "#/$defs/Availability"
59
- },
60
- "chrome": {
61
- "type": "object",
62
- "description": "This page's own header and footer (RFC-0025 §1): a landing page without the menu, a checkout without the footer.",
63
- "additionalProperties": false,
64
- "properties": {
65
- "header": {
66
- "type": "string",
67
- "enum": [
68
- "default",
69
- "transparent",
70
- "hidden"
71
- ]
72
- },
73
- "footer": {
74
- "type": "string",
75
- "enum": [
76
- "default",
77
- "minimal",
78
- "hidden"
79
- ]
80
- }
81
- }
82
- },
83
- "motion": {
84
- "$ref": "#/$defs/MotionLevel",
85
- "description": "Overrides the site's motion level for this page, up or down (RFC-0024 §1); absent follows the site."
86
- },
87
- "rev": {
88
- "$ref": "#/$defs/Revision"
89
- },
90
- "createdAt": {
91
- "$ref": "#/$defs/Timestamp"
92
- },
93
- "updatedAt": {
94
- "$ref": "#/$defs/Timestamp"
95
- },
96
- "translation": {
97
- "$ref": "#/$defs/Translation"
98
- },
99
- "metadata": {
100
- "$ref": "#/$defs/Metadata"
101
- }
102
- },
103
- "$defs": {
104
- "Actor": {
105
- "type": "object",
106
- "additionalProperties": false,
107
- "required": [
108
- "kind",
109
- "id"
110
- ],
111
- "properties": {
112
- "kind": {
113
- "$ref": "#/$defs/ActorKind"
114
- },
115
- "id": {
116
- "$ref": "#/$defs/Id"
117
- },
118
- "name": {
119
- "type": "string",
120
- "maxLength": 200
121
- }
122
- }
123
- },
124
- "ActorKind": {
125
- "type": "string",
126
- "description": "Who performed an action. Humans and agents share one actor model so the policy engine treats them uniformly.",
127
- "enum": [
128
- "human",
129
- "agent",
130
- "system"
131
- ]
132
- },
133
- "Availability": {
134
- "type": "object",
135
- "description": "Time gates of a page or content entry (RFC-0008): the published site shows the node only from `from` (inclusive: an embargo) until `until` (exclusive: an expiry), checked at render time, so the gates hold even when no scheduler runs. Before `from` and from `until` on, the node is absent from every public route, list, feed, sitemap and search output; previews still show it. At least one gate; writers check that `from` is before `until`.",
136
- "additionalProperties": false,
137
- "minProperties": 1,
138
- "properties": {
139
- "from": {
140
- "$ref": "#/$defs/Timestamp"
141
- },
142
- "until": {
143
- "$ref": "#/$defs/Timestamp"
144
- }
145
- }
146
- },
147
- "BodyBlock": {
148
- "type": "object",
149
- "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.",
150
- "additionalProperties": false,
151
- "required": [
152
- "id",
153
- "hash"
154
- ],
155
- "properties": {
156
- "id": {
157
- "type": "string",
158
- "pattern": "^blk_[0-9A-Za-z]{8,24}$",
159
- "description": "Stable across writes that keep the block's content or its place among unchanged blocks."
160
- },
161
- "hash": {
162
- "type": "string",
163
- "pattern": "^[0-9a-f]{64}$",
164
- "description": "SHA-256 (hex) of the block's markdown without trailing whitespace."
165
- },
166
- "by": {
167
- "$ref": "#/$defs/Actor"
168
- },
169
- "via": {
170
- "type": "string",
171
- "enum": [
172
- "studio",
173
- "mcp",
174
- "api",
175
- "import",
176
- "ai-command",
177
- "proposal"
178
- ],
179
- "description": "The channel of that change."
180
- },
181
- "at": {
182
- "$ref": "#/$defs/Timestamp"
183
- }
184
- }
185
- },
186
- "BodyBlocks": {
187
- "type": "array",
188
- "description": "A markdown body's block index, in body order (RFC-0014 §3). Absent means not indexed (yet, or an HTML body), never empty.",
189
- "maxItems": 5000,
190
- "items": {
191
- "$ref": "#/$defs/BodyBlock"
192
- }
193
- },
194
- "BodyProfile": {
195
- "type": "integer",
196
- "enum": [
197
- 1
198
- ],
199
- "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."
200
- },
201
- "Id": {
202
- "type": "string",
203
- "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.",
204
- "pattern": "^[a-z]+_[A-Za-z0-9]{6,32}$",
205
- "minLength": 8,
206
- "maxLength": 48
207
- },
208
- "ImageRef": {
209
- "type": "object",
210
- "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.",
211
- "additionalProperties": false,
212
- "required": [
213
- "src",
214
- "alt"
215
- ],
216
- "properties": {
217
- "assetId": {
218
- "$ref": "#/$defs/Id",
219
- "description": "The Asset node shown (RFC-0004). Renderers that know assets resolve it and ignore `src`."
220
- },
221
- "src": {
222
- "type": "string",
223
- "minLength": 1,
224
- "maxLength": 2048
225
- },
226
- "alt": {
227
- "type": "string",
228
- "maxLength": 500
229
- },
230
- "width": {
231
- "type": "integer",
232
- "minimum": 1
233
- },
234
- "height": {
235
- "type": "integer",
236
- "minimum": 1
237
- }
238
- }
239
- },
240
- "Link": {
241
- "type": "object",
242
- "additionalProperties": false,
243
- "required": [
244
- "label",
245
- "href"
246
- ],
247
- "properties": {
248
- "label": {
249
- "type": "string",
250
- "minLength": 1,
251
- "maxLength": 200
252
- },
253
- "href": {
254
- "type": "string",
255
- "minLength": 1,
256
- "maxLength": 2048
257
- },
258
- "external": {
259
- "type": "boolean"
260
- }
261
- }
262
- },
263
- "Locale": {
264
- "type": "string",
265
- "description": "BCP 47 language tag, e.g. en, tr, en-US.",
266
- "pattern": "^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$"
267
- },
268
- "Metadata": {
269
- "type": "object",
270
- "description": "Free-form string-to-string map for extensions. Keys should be namespaced (e.g. cloudhal.source).",
271
- "additionalProperties": {
272
- "type": "string"
273
- }
274
- },
275
- "MotionLevel": {
276
- "type": "string",
277
- "description": "How much a page may move (RFC-0024 §1); the reader's reduced-motion preference and pause control can only lower it.",
278
- "enum": [
279
- "none",
280
- "subtle",
281
- "standard",
282
- "expressive"
283
- ]
284
- },
285
- "PublishStatus": {
286
- "type": "string",
287
- "description": "Editorial lifecycle of a page or content entry.",
288
- "enum": [
289
- "draft",
290
- "review",
291
- "published",
292
- "archived"
293
- ]
294
- },
295
- "Revision": {
296
- "type": "integer",
297
- "description": "Monotonic per-node revision used for optimistic locking (compare-and-swap on write).",
298
- "minimum": 0
299
- },
300
- "SchemaVersion": {
301
- "type": "integer",
302
- "description": "Version of this contract. Readers reject unknown versions; migrations move documents forward one version at a time.",
303
- "enum": [
304
- 1
305
- ]
306
- },
307
- "Section": {
308
- "title": "Section",
309
- "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.",
310
- "oneOf": [
311
- {
312
- "type": "object",
313
- "title": "HeroSection",
314
- "additionalProperties": false,
315
- "required": [
316
- "id",
317
- "kind",
318
- "heading"
319
- ],
320
- "properties": {
321
- "id": {
322
- "$ref": "#/$defs/Id"
323
- },
324
- "kind": {
325
- "type": "string",
326
- "enum": [
327
- "hero"
328
- ]
329
- },
330
- "heading": {
331
- "type": "string",
332
- "minLength": 1,
333
- "maxLength": 300
334
- },
335
- "subheading": {
336
- "type": "string",
337
- "maxLength": 1000
338
- },
339
- "image": {
340
- "$ref": "#/$defs/ImageRef"
341
- },
342
- "cta": {
343
- "$ref": "#/$defs/Link"
344
- }
345
- }
346
- },
347
- {
348
- "type": "object",
349
- "title": "RichTextSection",
350
- "additionalProperties": false,
351
- "required": [
352
- "id",
353
- "kind",
354
- "format",
355
- "body"
356
- ],
357
- "properties": {
358
- "id": {
359
- "$ref": "#/$defs/Id"
360
- },
361
- "kind": {
362
- "type": "string",
363
- "enum": [
364
- "richText"
365
- ]
366
- },
367
- "format": {
368
- "type": "string",
369
- "enum": [
370
- "markdown",
371
- "html"
372
- ]
373
- },
374
- "body": {
375
- "type": "string",
376
- "maxLength": 200000
377
- },
378
- "profile": {
379
- "$ref": "#/$defs/BodyProfile"
380
- },
381
- "blocks": {
382
- "$ref": "#/$defs/BodyBlocks"
383
- }
384
- }
385
- },
386
- {
387
- "type": "object",
388
- "title": "ImageSection",
389
- "additionalProperties": false,
390
- "required": [
391
- "id",
392
- "kind",
393
- "image"
394
- ],
395
- "properties": {
396
- "id": {
397
- "$ref": "#/$defs/Id"
398
- },
399
- "kind": {
400
- "type": "string",
401
- "enum": [
402
- "image"
403
- ]
404
- },
405
- "image": {
406
- "$ref": "#/$defs/ImageRef"
407
- },
408
- "caption": {
409
- "type": "string",
410
- "maxLength": 1000
411
- }
412
- }
413
- },
414
- {
415
- "type": "object",
416
- "title": "ContentListSection",
417
- "description": "Renders the newest entries of a content collection (e.g. blog posts).",
418
- "additionalProperties": false,
419
- "required": [
420
- "id",
421
- "kind",
422
- "collection",
423
- "limit",
424
- "sort"
425
- ],
426
- "properties": {
427
- "id": {
428
- "$ref": "#/$defs/Id"
429
- },
430
- "kind": {
431
- "type": "string",
432
- "enum": [
433
- "contentList"
434
- ]
435
- },
436
- "collection": {
437
- "$ref": "#/$defs/Slug"
438
- },
439
- "limit": {
440
- "type": "integer",
441
- "minimum": 1,
442
- "maximum": 100
443
- },
444
- "sort": {
445
- "type": "string",
446
- "enum": [
447
- "newest",
448
- "oldest",
449
- "title"
450
- ]
451
- },
452
- "filter": {
453
- "type": "string",
454
- "description": "Filter expression over term assignments (RFC-0002), e.g. 'category:news+tag:ai' or 'category:news>*'.",
455
- "minLength": 1,
456
- "maxLength": 512
457
- }
458
- }
459
- },
460
- {
461
- "type": "object",
462
- "title": "ComponentSection",
463
- "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.",
464
- "additionalProperties": false,
465
- "required": [
466
- "id",
467
- "kind",
468
- "type",
469
- "props"
470
- ],
471
- "properties": {
472
- "id": {
473
- "$ref": "#/$defs/Id"
474
- },
475
- "kind": {
476
- "type": "string",
477
- "enum": [
478
- "component"
479
- ]
480
- },
481
- "type": {
482
- "type": "string",
483
- "pattern": "^[a-z][a-z0-9-]{1,40}$"
484
- },
485
- "props": {
486
- "type": "object",
487
- "description": "Validated against the type's props schema by the store, not by this contract.",
488
- "additionalProperties": true
489
- }
490
- }
491
- },
492
- {
493
- "type": "object",
494
- "title": "SurfaceSection",
495
- "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.",
496
- "additionalProperties": false,
497
- "required": [
498
- "id",
499
- "kind",
500
- "catalog",
501
- "components"
502
- ],
503
- "properties": {
504
- "id": {
505
- "$ref": "#/$defs/Id"
506
- },
507
- "kind": {
508
- "type": "string",
509
- "enum": [
510
- "surface"
511
- ]
512
- },
513
- "catalog": {
514
- "type": "string",
515
- "description": "The catalog the surface was written for: `<theme>@<major>` (RFC-0018 manifest).",
516
- "pattern": "^[a-z][a-z0-9-]{0,40}@[0-9]{1,4}$"
517
- },
518
- "components": {
519
- "type": "array",
520
- "minItems": 1,
521
- "maxItems": 200,
522
- "items": {
523
- "$ref": "#/$defs/SurfaceComponent"
524
- }
525
- },
526
- "data": {
527
- "type": "object",
528
- "description": "The surface's data model: JSON its components bind to with `{path}` (at most 64 KB serialized; the store enforces the size).",
529
- "additionalProperties": true
530
- }
531
- }
532
- }
533
- ]
534
- },
535
- "Seo": {
536
- "type": "object",
537
- "description": "Search and social metadata of a routable node (page, term archive).",
538
- "additionalProperties": false,
539
- "properties": {
540
- "title": {
541
- "type": "string",
542
- "maxLength": 300
543
- },
544
- "description": {
545
- "type": "string",
546
- "maxLength": 500
547
- },
548
- "noindex": {
549
- "type": "boolean"
550
- },
551
- "canonical": {
552
- "type": "string",
553
- "maxLength": 2048
554
- },
555
- "ogImage": {
556
- "$ref": "#/$defs/ImageRef"
557
- }
558
- }
559
- },
560
- "Slug": {
561
- "type": "string",
562
- "description": "Lower-case URL segment.",
563
- "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
564
- "minLength": 1,
565
- "maxLength": 128
566
- },
567
- "SurfaceComponent": {
568
- "type": "object",
569
- "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.",
570
- "additionalProperties": false,
571
- "required": [
572
- "id",
573
- "component"
574
- ],
575
- "properties": {
576
- "id": {
577
- "$ref": "#/$defs/SurfaceComponentId"
578
- },
579
- "component": {
580
- "type": "string",
581
- "pattern": "^(?:[A-Z][A-Za-z0-9]{1,40}|[a-z][a-z0-9-]{1,40})$"
582
- },
583
- "children": {
584
- "type": "array",
585
- "maxItems": 200,
586
- "items": {
587
- "$ref": "#/$defs/SurfaceComponentId"
588
- }
589
- },
590
- "props": {
591
- "type": "object",
592
- "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.",
593
- "additionalProperties": true
594
- },
595
- "visible": {
596
- "type": "object",
597
- "description": "A visibility condition over the surface's data (`eq`, `ne`, `gt`, `lt`, `and`, `or`, `not`); validated by the store.",
598
- "additionalProperties": true
599
- },
600
- "motion": {
601
- "type": "object",
602
- "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.",
603
- "additionalProperties": true
604
- }
605
- }
606
- },
607
- "SurfaceComponentId": {
608
- "type": "string",
609
- "description": "A component's id, unique within its surface; `root` is the tree's root (RFC-0020 §1).",
610
- "pattern": "^[a-z][a-z0-9-]{0,40}$"
611
- },
612
- "Timestamp": {
613
- "type": "string",
614
- "description": "RFC 3339 / ISO 8601 instant in UTC.",
615
- "format": "date-time"
616
- },
617
- "Translation": {
618
- "type": "object",
619
- "description": "Links a page or entry to the other language versions of the same work (RFC-0033 §2). Staleness is computed: the source's current hash differs from source.hash.",
620
- "additionalProperties": false,
621
- "required": [
622
- "group",
623
- "method"
624
- ],
625
- "properties": {
626
- "group": {
627
- "$ref": "#/$defs/Id",
628
- "description": "The group's id: the original node's id, shared by every translation. May cross sites in one project."
629
- },
630
- "method": {
631
- "$ref": "#/$defs/TranslationMethod"
632
- },
633
- "layout": {
634
- "type": "string",
635
- "description": "linked: the original's structural changes propagate to this translation as drafts (RFC-0033 §4a); independent: nothing propagates. Absent means linked.",
636
- "enum": [
637
- "linked",
638
- "independent"
639
- ]
640
- },
641
- "source": {
642
- "type": "object",
643
- "description": "The node and revision this translation was made from. Absent on the original.",
644
- "additionalProperties": false,
645
- "required": [
646
- "id",
647
- "locale",
648
- "rev",
649
- "hash"
650
- ],
651
- "properties": {
652
- "id": {
653
- "$ref": "#/$defs/Id"
654
- },
655
- "siteId": {
656
- "$ref": "#/$defs/Id",
657
- "description": "The source's site when it is another site of the same project (a language edition). Absent means this site."
658
- },
659
- "locale": {
660
- "$ref": "#/$defs/Locale"
661
- },
662
- "rev": {
663
- "$ref": "#/$defs/Revision"
664
- },
665
- "hash": {
666
- "type": "string",
667
- "description": "Lower-case hex SHA-256 of the source node's canonical JSON at that revision.",
668
- "pattern": "^[0-9a-f]{64}$"
669
- }
670
- }
671
- },
672
- "provenance": {
673
- "type": "object",
674
- "description": "The machine-translation record: engine, glossary revision, checks run, quality score. Required when method is machine or machine-reviewed.",
675
- "additionalProperties": false,
676
- "required": [
677
- "engine",
678
- "at"
679
- ],
680
- "properties": {
681
- "engine": {
682
- "type": "string",
683
- "minLength": 1,
684
- "maxLength": 200
685
- },
686
- "glossaryRev": {
687
- "$ref": "#/$defs/Revision"
688
- },
689
- "score": {
690
- "type": "number",
691
- "minimum": 0,
692
- "maximum": 100
693
- },
694
- "checks": {
695
- "type": "array",
696
- "items": {
697
- "type": "string",
698
- "minLength": 1,
699
- "maxLength": 100
700
- },
701
- "maxItems": 50
702
- },
703
- "at": {
704
- "$ref": "#/$defs/Timestamp"
705
- }
706
- }
707
- },
708
- "review": {
709
- "type": "object",
710
- "description": "The person who reviewed this translation and when. Only humans set it.",
711
- "additionalProperties": false,
712
- "required": [
713
- "by",
714
- "at"
715
- ],
716
- "properties": {
717
- "by": {
718
- "$ref": "#/$defs/Actor"
719
- },
720
- "at": {
721
- "$ref": "#/$defs/Timestamp"
722
- }
723
- }
724
- }
725
- }
726
- },
727
- "TranslationMethod": {
728
- "type": "string",
729
- "description": "How a page's or entry's text came to be (RFC-0033). 'original' marks the source of a translation group; 'machine-reviewed' is machine output a person has reviewed.",
730
- "enum": [
731
- "original",
732
- "human",
733
- "machine",
734
- "machine-reviewed"
735
- ]
736
- }
737
- }
738
- }