@tanqory/dev-mcp 0.0.0-stage → 0.1.0-alpha.1

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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +94 -2
  3. package/bin/tanqory-dev-mcp.mjs +16 -0
  4. package/bundled/examples/blank/config/settings.json +3 -0
  5. package/bundled/examples/blank/locales/en.json +22 -0
  6. package/bundled/examples/blank/locales/th.json +22 -0
  7. package/bundled/examples/blank/regions/footer.json +35 -0
  8. package/bundled/examples/blank/regions/header.json +13 -0
  9. package/bundled/examples/blank/src/bundle.ts +15 -0
  10. package/bundled/examples/blank/src/components/parts.tsx +32 -0
  11. package/bundled/examples/blank/src/entry.client.tsx +6 -0
  12. package/bundled/examples/blank/src/entry.server.tsx +13 -0
  13. package/bundled/examples/blank/src/sections/chrome.tsx +132 -0
  14. package/bundled/examples/blank/src/sections/commerce.tsx +242 -0
  15. package/bundled/examples/blank/src/sections/content.tsx +111 -0
  16. package/bundled/examples/blank/src/sections/editorial.tsx +107 -0
  17. package/bundled/examples/blank/src/settings.ts +15 -0
  18. package/bundled/examples/blank/src/styles/theme.css +195 -0
  19. package/bundled/examples/blank/src/templates.ts +14 -0
  20. package/bundled/examples/blank/src/theme.tsx +76 -0
  21. package/bundled/examples/blank/template.json +24 -0
  22. package/bundled/examples/blank/templates/404.json +14 -0
  23. package/bundled/examples/blank/templates/account.json +14 -0
  24. package/bundled/examples/blank/templates/article.json +14 -0
  25. package/bundled/examples/blank/templates/blog.json +14 -0
  26. package/bundled/examples/blank/templates/cart.json +14 -0
  27. package/bundled/examples/blank/templates/collection.json +14 -0
  28. package/bundled/examples/blank/templates/index.json +36 -0
  29. package/bundled/examples/blank/templates/page.contact.json +18 -0
  30. package/bundled/examples/blank/templates/page.json +14 -0
  31. package/bundled/examples/blank/templates/product.json +18 -0
  32. package/bundled/examples/blank/templates/search.json +14 -0
  33. package/bundled/examples/blank/tests/theme.test.ts +49 -0
  34. package/bundled/theme-abi/contracts/render-context.v2.d.ts +849 -0
  35. package/bundled/theme-abi/contracts/theme-abi-v2.md +1833 -0
  36. package/bundled/theme-abi/generated/capabilities.json +80 -0
  37. package/bundled/theme-abi/generated/field-types.json +869 -0
  38. package/bundled/theme-abi/generated/limits.json +173 -0
  39. package/bundled/theme-abi/schemas/conformance-report.v2.schema.json +482 -0
  40. package/bundled/theme-abi/schemas/theme-artifact.v1.schema.json +230 -0
  41. package/bundled/theme-abi/schemas/theme-manifest.v2.schema.json +254 -0
  42. package/bundled/theme-conformance/docs/storefront-tier.md +221 -0
  43. package/bundled/theme-conformance/schema/conformance-report.v2.schema.json +482 -0
  44. package/bundled/theme-conformance/schema/storefront-report.v1.schema.json +110 -0
  45. package/bundled/theme-conformance/schema/x-tanqory-ai.v0.schema.json +70 -0
  46. package/bundled/theme-kit/docs/headless-api.md +220 -0
  47. package/bundled/theme-kit/generated/kit-strings.json +180 -0
  48. package/bundled/theme-kit/types/headless/index.d.ts +36 -0
  49. package/bundled/theme-kit/types/headless/theme.d.ts +99 -0
  50. package/bundled/theme-kit/types/sdk/schema.d.ts +197 -0
  51. package/bundled/versions.json +8 -0
  52. package/package.json +53 -3
  53. package/src/bm25.mjs +69 -0
  54. package/src/browser.mjs +123 -0
  55. package/src/cli.mjs +127 -0
  56. package/src/devserver.mjs +82 -0
  57. package/src/docs.mjs +329 -0
  58. package/src/index.mjs +33 -0
  59. package/src/kit.mjs +150 -0
  60. package/src/manifest.mjs +82 -0
  61. package/src/prompts.mjs +97 -0
  62. package/src/scaffold.mjs +471 -0
  63. package/src/schemas.mjs +127 -0
  64. package/src/server.mjs +595 -0
  65. package/src/theme.mjs +91 -0
@@ -0,0 +1,482 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.tanqory.com/theme-artifact/v1/conformance-report.v2.schema.json",
4
+ "title": "Conformance check report v2 (conformance-report.json)",
5
+ "description": "Normative schema for b/<buildId>/conformance-report.json, owned by theme-artifact-v1.md §2.1. Derived from the report @tanqory/theme-conformance emits, extended for security v1.10.8 (B-17): the production shim digest, who produced each result, and CPU attempts. The runner ships a copy of this file; where the two differ, this one wins.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "format",
10
+ "abiVersion",
11
+ "limitsVersion",
12
+ "passed",
13
+ "runner",
14
+ "artifact",
15
+ "suites",
16
+ "measurements",
17
+ "globals",
18
+ "startedAt",
19
+ "finishedAt",
20
+ "determinism",
21
+ "selfCheck",
22
+ "shimDigest"
23
+ ],
24
+ "properties": {
25
+ "format": {
26
+ "const": "tanqory-conformance-report/2"
27
+ },
28
+ "abiVersion": {
29
+ "type": "string",
30
+ "pattern": "^2\\.[0-9]+$"
31
+ },
32
+ "limitsVersion": {
33
+ "type": "string",
34
+ "pattern": "^[0-9]+\\.[0-9]+$"
35
+ },
36
+ "passed": {
37
+ "type": "boolean"
38
+ },
39
+ "runner": {
40
+ "type": "object",
41
+ "additionalProperties": false,
42
+ "required": [
43
+ "name",
44
+ "version",
45
+ "gitHead",
46
+ "workerd",
47
+ "chromium",
48
+ "compatibilityDate",
49
+ "cpuMeasurement",
50
+ "compatibilityFlags"
51
+ ],
52
+ "properties": {
53
+ "name": {
54
+ "type": "string"
55
+ },
56
+ "version": {
57
+ "type": "string"
58
+ },
59
+ "gitHead": {
60
+ "type": "string",
61
+ "pattern": "^[0-9a-f]{40}$",
62
+ "description": "Build commit of the runner (theme-artifact-v1.md §2.1 canonical runner identity)."
63
+ },
64
+ "workerd": {
65
+ "type": "string",
66
+ "pattern": "^1\\.[0-9]{8}\\.[0-9]+$"
67
+ },
68
+ "chromium": {
69
+ "type": [
70
+ "string",
71
+ "null"
72
+ ],
73
+ "description": "Chromium version suite 5 drove; null only when suite 5 launched no browser."
74
+ },
75
+ "compatibilityDate": {
76
+ "type": "string",
77
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
78
+ "description": "Must equal RUNTIME_COMPATIBILITY_DATE exported by @tanqory/theme-abi."
79
+ },
80
+ "cpuMeasurement": {
81
+ "const": "wall-clock-in-isolate",
82
+ "description": "Elapsed time measured inside the isolate: an upper bound on CPU."
83
+ },
84
+ "compatibilityFlags": {
85
+ "type": "array",
86
+ "items": {
87
+ "type": "string"
88
+ },
89
+ "uniqueItems": true,
90
+ "description": "Must equal RUNTIME_COMPATIBILITY_FLAGS exported by @tanqory/theme-abi."
91
+ }
92
+ }
93
+ },
94
+ "artifact": {
95
+ "type": "object",
96
+ "additionalProperties": false,
97
+ "required": [
98
+ "path",
99
+ "kind",
100
+ "manifestDigest",
101
+ "entryDigest",
102
+ "artifactDigest"
103
+ ],
104
+ "properties": {
105
+ "path": {
106
+ "type": "string",
107
+ "not": {
108
+ "pattern": "^(/|[A-Za-z]:[\\\\/]|~)"
109
+ },
110
+ "description": "relative path or directory name — never an absolute local path"
111
+ },
112
+ "kind": {
113
+ "enum": [
114
+ "artifact-dir",
115
+ "theme-dir"
116
+ ]
117
+ },
118
+ "manifestDigest": {
119
+ "$ref": "#/$defs/digest"
120
+ },
121
+ "entryDigest": {
122
+ "$ref": "#/$defs/digest"
123
+ },
124
+ "artifactDigest": {
125
+ "$ref": "#/$defs/digest"
126
+ },
127
+ "name": {
128
+ "type": "string"
129
+ },
130
+ "version": {
131
+ "type": "string"
132
+ }
133
+ }
134
+ },
135
+ "suites": {
136
+ "type": "array",
137
+ "minItems": 9,
138
+ "maxItems": 9,
139
+ "items": {
140
+ "type": "object",
141
+ "additionalProperties": false,
142
+ "required": [
143
+ "id",
144
+ "name",
145
+ "status",
146
+ "checks",
147
+ "durationMs",
148
+ "producedBy"
149
+ ],
150
+ "properties": {
151
+ "id": {
152
+ "type": "integer",
153
+ "minimum": 1,
154
+ "maximum": 9
155
+ },
156
+ "name": {
157
+ "type": "string"
158
+ },
159
+ "status": {
160
+ "$ref": "#/$defs/suiteStatus"
161
+ },
162
+ "reason": {
163
+ "type": "string"
164
+ },
165
+ "durationMs": {
166
+ "type": "number",
167
+ "minimum": 0
168
+ },
169
+ "checks": {
170
+ "type": "array",
171
+ "items": {
172
+ "type": "object",
173
+ "additionalProperties": false,
174
+ "required": [
175
+ "id",
176
+ "status"
177
+ ],
178
+ "properties": {
179
+ "id": {
180
+ "type": "string"
181
+ },
182
+ "status": {
183
+ "$ref": "#/$defs/status"
184
+ },
185
+ "message": {
186
+ "type": "string"
187
+ },
188
+ "details": {}
189
+ }
190
+ }
191
+ },
192
+ "producedBy": {
193
+ "$ref": "#/$defs/producedBy"
194
+ }
195
+ }
196
+ }
197
+ },
198
+ "measurements": {
199
+ "type": "array",
200
+ "items": {
201
+ "type": "object",
202
+ "additionalProperties": false,
203
+ "required": [
204
+ "name",
205
+ "unit",
206
+ "value",
207
+ "budget",
208
+ "hard",
209
+ "status",
210
+ "producedBy"
211
+ ],
212
+ "properties": {
213
+ "name": {
214
+ "type": "string"
215
+ },
216
+ "unit": {
217
+ "enum": [
218
+ "ms",
219
+ "bytes",
220
+ "count",
221
+ "percent"
222
+ ]
223
+ },
224
+ "value": {
225
+ "type": [
226
+ "number",
227
+ "null"
228
+ ]
229
+ },
230
+ "samples": {
231
+ "type": "array",
232
+ "items": {
233
+ "type": "number"
234
+ }
235
+ },
236
+ "budget": {
237
+ "type": [
238
+ "number",
239
+ "null"
240
+ ]
241
+ },
242
+ "hard": {
243
+ "type": [
244
+ "number",
245
+ "null"
246
+ ],
247
+ "description": "null = budget-only row (theme-abi-v2.md §8): never refuses."
248
+ },
249
+ "status": {
250
+ "enum": [
251
+ "ok",
252
+ "budget_exceeded",
253
+ "hard_exceeded",
254
+ "not_measured"
255
+ ]
256
+ },
257
+ "note": {
258
+ "type": "string"
259
+ },
260
+ "producedBy": {
261
+ "$ref": "#/$defs/producedBy"
262
+ },
263
+ "method": {
264
+ "enum": [
265
+ "wall-clock-in-isolate"
266
+ ],
267
+ "description": "CPU rows only."
268
+ },
269
+ "upperBound": {
270
+ "const": true,
271
+ "description": "CPU rows only: the value bounds CPU from above."
272
+ },
273
+ "attempts": {
274
+ "type": "array",
275
+ "minItems": 1,
276
+ "maxItems": 3,
277
+ "items": {
278
+ "$ref": "#/$defs/cpuAttempt"
279
+ },
280
+ "description": "CPU rows only: each attempt is a fresh isolate rendering every sample including the cold one."
281
+ },
282
+ "attemptCount": {
283
+ "type": "integer",
284
+ "minimum": 1,
285
+ "maximum": 3
286
+ }
287
+ }
288
+ }
289
+ },
290
+ "globals": {
291
+ "type": "object",
292
+ "additionalProperties": false,
293
+ "required": [
294
+ "snapshot",
295
+ "deleted",
296
+ "notDeletable",
297
+ "unexpected",
298
+ "enforcement"
299
+ ],
300
+ "properties": {
301
+ "snapshot": {
302
+ "type": "array",
303
+ "items": {
304
+ "type": "string"
305
+ }
306
+ },
307
+ "deleted": {
308
+ "type": "array",
309
+ "items": {
310
+ "type": "string"
311
+ }
312
+ },
313
+ "notDeletable": {
314
+ "type": "array",
315
+ "items": {
316
+ "type": "string"
317
+ }
318
+ },
319
+ "unexpected": {
320
+ "type": "array",
321
+ "items": {
322
+ "type": "string"
323
+ }
324
+ },
325
+ "enforcement": {
326
+ "type": "object",
327
+ "additionalProperties": {
328
+ "enum": [
329
+ "deleted",
330
+ "shadowed",
331
+ "tripwired",
332
+ "absent",
333
+ "unenforced"
334
+ ]
335
+ }
336
+ },
337
+ "shadowed": {
338
+ "type": "array",
339
+ "items": {
340
+ "type": "string"
341
+ },
342
+ "description": "Names made unreachable by an own shadowing property (ABI Appendix C.2)."
343
+ }
344
+ }
345
+ },
346
+ "startedAt": {
347
+ "type": "string",
348
+ "format": "date-time"
349
+ },
350
+ "finishedAt": {
351
+ "type": "string",
352
+ "format": "date-time"
353
+ },
354
+ "determinism": {
355
+ "type": "object",
356
+ "additionalProperties": false,
357
+ "required": [
358
+ "runtimeVersion",
359
+ "compatibilityDate",
360
+ "fixture",
361
+ "outputSha256"
362
+ ],
363
+ "properties": {
364
+ "runtimeVersion": {
365
+ "type": "string",
366
+ "pattern": "^workerd@1\\.[0-9]{8}\\.[0-9]+$"
367
+ },
368
+ "compatibilityDate": {
369
+ "type": "string",
370
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
371
+ },
372
+ "fixture": {
373
+ "type": "string"
374
+ },
375
+ "outputSha256": {
376
+ "oneOf": [
377
+ {
378
+ "$ref": "#/$defs/digest"
379
+ },
380
+ {
381
+ "type": "null"
382
+ }
383
+ ]
384
+ }
385
+ }
386
+ },
387
+ "selfCheck": {
388
+ "type": "object",
389
+ "additionalProperties": false,
390
+ "required": [
391
+ "runner",
392
+ "version",
393
+ "gitHead",
394
+ "workerd",
395
+ "passed"
396
+ ],
397
+ "properties": {
398
+ "runner": {
399
+ "type": "string"
400
+ },
401
+ "version": {
402
+ "type": "string"
403
+ },
404
+ "gitHead": {
405
+ "type": "string",
406
+ "pattern": "^[0-9a-f]{40}$"
407
+ },
408
+ "workerd": {
409
+ "type": "string"
410
+ },
411
+ "passed": {
412
+ "type": "boolean"
413
+ }
414
+ }
415
+ },
416
+ "shimDigest": {
417
+ "type": "string",
418
+ "pattern": "^sha256:[0-9a-f]{64}$",
419
+ "description": "Digest of the production host shim whose bytes produced every result marked production-shim. Defined by capability-security §6.6.3."
420
+ }
421
+ },
422
+ "$defs": {
423
+ "digest": {
424
+ "type": "string",
425
+ "pattern": "^sha256:[0-9a-f]{64}$"
426
+ },
427
+ "status": {
428
+ "enum": [
429
+ "pass",
430
+ "fail",
431
+ "skipped",
432
+ "not_applicable"
433
+ ]
434
+ },
435
+ "suiteStatus": {
436
+ "enum": [
437
+ "pass",
438
+ "fail",
439
+ "incomplete",
440
+ "not_applicable"
441
+ ]
442
+ },
443
+ "producedBy": {
444
+ "enum": [
445
+ "production-shim",
446
+ "static",
447
+ "none",
448
+ "other"
449
+ ],
450
+ "description": "production-shim: every render behind this result ran on the bytes named by shimDigest. static: computed from the artifact bytes, no render. none: the suite did not run (allowed only where it may be not_applicable). other: anything else; satisfies nothing."
451
+ },
452
+ "cpuAttempt": {
453
+ "type": "object",
454
+ "required": [
455
+ "samples",
456
+ "loadAverage"
457
+ ],
458
+ "additionalProperties": false,
459
+ "properties": {
460
+ "samples": {
461
+ "type": "array",
462
+ "minItems": 1,
463
+ "items": {
464
+ "type": "number",
465
+ "minimum": 0
466
+ },
467
+ "description": "Every sample of this attempt in order; the first is the cold one."
468
+ },
469
+ "loadAverage": {
470
+ "type": "array",
471
+ "minItems": 3,
472
+ "maxItems": 3,
473
+ "items": {
474
+ "type": "number",
475
+ "minimum": 0
476
+ },
477
+ "description": "1, 5 and 15 minute load average of the machine when the attempt started."
478
+ }
479
+ }
480
+ }
481
+ }
482
+ }
@@ -0,0 +1,110 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.tanqory.com/theme/storefront-report.v1.schema.json",
4
+ "title": "storefront-report.json — the storefront and budgets tiers (tanqory-storefront-report/1)",
5
+ "description": "Written by `theme-conformance run <dir> --tier storefront|budgets|all` (docs/storefront-tier.md). Separate from conformance-report.json (format 2), which it never changes.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["format", "hooksVersion", "tiers", "passed", "summary", "runner", "artifact", "fixture", "checks", "measurements", "evidenceDir", "startedAt", "finishedAt"],
9
+ "properties": {
10
+ "format": { "const": "tanqory-storefront-report/1" },
11
+ "hooksVersion": { "const": "tq-storefront-hooks/1" },
12
+ "tiers": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/tier" } },
13
+ "passed": { "type": "boolean", "description": "true when no check is fail or incomplete" },
14
+ "summary": {
15
+ "type": "object",
16
+ "additionalProperties": false,
17
+ "required": ["pass", "fail", "warn", "not_applicable", "incomplete"],
18
+ "properties": { "pass": { "$ref": "#/$defs/count" }, "fail": { "$ref": "#/$defs/count" }, "warn": { "$ref": "#/$defs/count" }, "not_applicable": { "$ref": "#/$defs/count" }, "incomplete": { "$ref": "#/$defs/count" } }
19
+ },
20
+ "runner": {
21
+ "type": "object",
22
+ "additionalProperties": false,
23
+ "required": ["name", "version", "gitHead", "workerd", "chromium", "playwright", "shim"],
24
+ "properties": {
25
+ "name": { "type": "string" },
26
+ "version": { "type": "string" },
27
+ "gitHead": { "type": ["string", "null"] },
28
+ "workerd": { "type": "string" },
29
+ "chromium": { "type": ["string", "null"] },
30
+ "playwright": { "type": "string" },
31
+ "shim": { "const": "conformance-harness" }
32
+ }
33
+ },
34
+ "artifact": {
35
+ "type": "object",
36
+ "additionalProperties": false,
37
+ "required": ["path", "manifestDigest", "artifactDigest"],
38
+ "properties": {
39
+ "path": { "type": "string" },
40
+ "name": { "type": "string" },
41
+ "version": { "type": "string" },
42
+ "manifestDigest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
43
+ "artifactDigest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }
44
+ }
45
+ },
46
+ "fixture": {
47
+ "type": "object",
48
+ "additionalProperties": false,
49
+ "required": ["name", "storefront", "languages", "markets"],
50
+ "properties": {
51
+ "name": { "type": "string" },
52
+ "storefront": { "type": "string" },
53
+ "languages": { "type": "array", "items": { "type": "string" } },
54
+ "markets": { "type": "array", "items": { "type": "string" } }
55
+ }
56
+ },
57
+ "checks": { "type": "array", "items": { "$ref": "#/$defs/check" } },
58
+ "measurements": { "type": "array", "items": { "$ref": "#/$defs/measurement" } },
59
+ "evidenceDir": { "type": ["string", "null"] },
60
+ "startedAt": { "type": "string", "format": "date-time" },
61
+ "finishedAt": { "type": "string", "format": "date-time" }
62
+ },
63
+ "$defs": {
64
+ "count": { "type": "integer", "minimum": 0 },
65
+ "tier": { "enum": ["storefront", "budgets"] },
66
+ "check": {
67
+ "type": "object",
68
+ "additionalProperties": false,
69
+ "required": ["id", "tier", "group", "title", "status"],
70
+ "properties": {
71
+ "id": { "type": "string", "pattern": "^[a-z0-9]+(:[a-z0-9-]+)+$" },
72
+ "tier": { "$ref": "#/$defs/tier" },
73
+ "group": { "type": "string" },
74
+ "title": { "type": "string" },
75
+ "status": { "enum": ["pass", "fail", "warn", "not_applicable", "incomplete"] },
76
+ "message": { "type": "string" },
77
+ "route": { "type": "string" },
78
+ "locale": { "type": "string" },
79
+ "viewport": { "enum": ["desktop", "mobile"] },
80
+ "evidence": {
81
+ "type": "object",
82
+ "additionalProperties": false,
83
+ "properties": {
84
+ "selector": { "type": "string" },
85
+ "screenshot": { "type": "string" },
86
+ "url": { "type": "string" },
87
+ "details": {}
88
+ }
89
+ },
90
+ "fixHint": { "type": "string" }
91
+ },
92
+ "if": { "properties": { "status": { "enum": ["fail", "warn", "incomplete"] } } },
93
+ "then": { "properties": { "fixHint": { "type": "string", "minLength": 1 } }, "required": ["fixHint"] }
94
+ },
95
+ "measurement": {
96
+ "type": "object",
97
+ "additionalProperties": false,
98
+ "required": ["name", "unit", "value", "budget", "method", "status"],
99
+ "properties": {
100
+ "name": { "type": "string" },
101
+ "unit": { "enum": ["bytes", "score", "ms", "unitless"] },
102
+ "value": { "type": ["number", "null"] },
103
+ "budget": { "type": ["number", "null"] },
104
+ "method": { "enum": ["static", "runtime", "lab-approximation"] },
105
+ "status": { "enum": ["ok", "over_budget", "not_measured"] },
106
+ "note": { "type": "string" }
107
+ }
108
+ }
109
+ }
110
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://schemas.tanqory.com/theme/x-tanqory-ai.v0.schema.json",
4
+ "title": "x-tanqory-ai profile (draft v0)",
5
+ "description": "DRAFT, owned by the theme-kit / AI-compat work (docs/storefront-tier.md §7). Declared as manifest[\"x-tanqory-ai\"]. It tells Tanqory AI which of the theme's own sections and settings play the roles it fills (hero, header menu, footer menus, brand), so AI can compose any theme without Nova's vocabulary. The storefront tier only WARNS on it until the profile is final.",
6
+ "type": "object",
7
+ "required": ["version", "roles"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "version": { "const": 0 },
11
+ "roles": {
12
+ "type": "object",
13
+ "additionalProperties": false,
14
+ "minProperties": 1,
15
+ "properties": {
16
+ "hero": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/hero" } },
17
+ "headerMenu": { "$ref": "#/$defs/menuRole" },
18
+ "footerMenus": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/menuRole" } },
19
+ "footerBrand": { "$ref": "#/$defs/target" },
20
+ "productGrid": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/resourceRole" } },
21
+ "richText": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/textRole" } }
22
+ }
23
+ }
24
+ },
25
+ "$defs": {
26
+ "key": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,63}$" },
27
+ "target": {
28
+ "type": "object",
29
+ "required": ["component"],
30
+ "properties": {
31
+ "component": { "$ref": "#/$defs/key", "description": "manifest.components key of the section" },
32
+ "block": { "$ref": "#/$defs/key", "description": "manifest.components key of a block inside it, when the role lives on a block" }
33
+ }
34
+ },
35
+ "hero": {
36
+ "allOf": [{ "$ref": "#/$defs/target" }],
37
+ "type": "object",
38
+ "unevaluatedProperties": false,
39
+ "properties": {
40
+ "component": true, "block": true,
41
+ "heading": { "$ref": "#/$defs/key" },
42
+ "subheading": { "$ref": "#/$defs/key" },
43
+ "image": { "$ref": "#/$defs/key" },
44
+ "button": { "$ref": "#/$defs/key" },
45
+ "link": { "$ref": "#/$defs/key" }
46
+ },
47
+ "required": ["heading"]
48
+ },
49
+ "menuRole": {
50
+ "allOf": [{ "$ref": "#/$defs/target" }],
51
+ "type": "object",
52
+ "unevaluatedProperties": false,
53
+ "properties": { "component": true, "block": true, "setting": { "$ref": "#/$defs/key", "description": "a setting of type menu" } },
54
+ "required": ["setting"]
55
+ },
56
+ "resourceRole": {
57
+ "allOf": [{ "$ref": "#/$defs/target" }],
58
+ "type": "object",
59
+ "unevaluatedProperties": false,
60
+ "properties": { "component": true, "block": true, "setting": { "$ref": "#/$defs/key", "description": "a setting of type collection or product" }, "heading": { "$ref": "#/$defs/key" } },
61
+ "required": ["setting"]
62
+ },
63
+ "textRole": {
64
+ "allOf": [{ "$ref": "#/$defs/target" }],
65
+ "type": "object",
66
+ "unevaluatedProperties": false,
67
+ "properties": { "component": true, "block": true, "heading": { "$ref": "#/$defs/key" }, "body": { "$ref": "#/$defs/key" } }
68
+ }
69
+ }
70
+ }