@gradial/aci 0.1.52-rc.8 → 0.1.52
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.
- package/CHANGELOG.md +126 -0
- package/README.md +86 -5
- package/dist/astro/error-page.js +1 -0
- package/dist/astro/index.js +4 -0
- package/dist/astro/page.d.ts +5 -2
- package/dist/astro/page.js +35 -23
- package/dist/astro/preview.js +2 -17
- package/dist/audience-data-models.d.ts +308 -197
- package/dist/audience-data-models.js +313 -51
- package/dist/cli/compile-registry.mjs +6 -34
- package/dist/cli/mintlify-render.mjs +8 -0
- package/dist/collect/aci.js +1 -1
- package/dist/collect/aci.js.sha256 +1 -1
- package/dist/collect/api.d.ts +6 -7
- package/dist/collect/api.js +21 -8
- package/dist/collect/assignments.d.ts +7 -9
- package/dist/collect/assignments.js +23 -32
- package/dist/collect/batcher.d.ts +9 -7
- package/dist/collect/batcher.js +6 -5
- package/dist/collect/consent/envelope.d.ts +7 -1
- package/dist/collect/consent/envelope.js +3 -1
- package/dist/collect/consent/mapping.d.ts +2 -0
- package/dist/collect/consent/mapping.js +1 -0
- package/dist/collect/consenthold.d.ts +38 -0
- package/dist/collect/consenthold.js +82 -0
- package/dist/collect/declarative.js +7 -5
- package/dist/collect/gapbuffer.d.ts +13 -4
- package/dist/collect/gapbuffer.js +21 -10
- package/dist/collect/index.js +78 -21
- package/dist/collect/pageviews.d.ts +11 -11
- package/dist/collect/pageviews.js +27 -22
- package/dist/consent-banner/index.d.ts +17 -0
- package/dist/consent-banner/index.js +23 -0
- package/dist/content/index.d.ts +2 -1
- package/dist/content/index.js +4 -1
- package/dist/content/provider.d.ts +16 -2
- package/dist/content/provider.js +5 -1
- package/dist/content/resolve-slots.d.ts +24 -2
- package/dist/content/resolve-slots.js +127 -21
- package/dist/content/types.d.ts +5 -1
- package/dist/edge/expression-capabilities.v1.d.ts +106 -0
- package/dist/edge/expression-capabilities.v1.js +165 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +0 -1
- package/dist/internal/domain/edge/identity.d.ts +47 -4
- package/dist/internal/domain/edge/identity.js +130 -26
- package/dist/internal/domain/edge/index.d.ts +1 -1
- package/dist/internal/domain/edge/index.js +1 -1
- package/dist/internal/domain/edge/mimic_token.d.ts +14 -0
- package/dist/internal/domain/edge/mimic_token.js +125 -0
- package/dist/internal/domain/edge/personalization-core.d.ts +61 -22
- package/dist/internal/domain/edge/personalization-core.js +790 -200
- package/dist/internal/domain/edge/personalization_index.d.ts +17 -0
- package/dist/internal/domain/edge/personalization_index.js +55 -0
- package/dist/internal/domain/edge/resolve.js +76 -39
- package/dist/internal/domain/edge/testdata/flat_only_validator_v1.d.ts +10 -0
- package/dist/internal/domain/edge/testdata/flat_only_validator_v1.js +253 -0
- package/dist/internal/domain/edge/types.d.ts +82 -78
- package/dist/internal/domain/edge/types.js +3 -3
- package/dist/internal/domain/edge/variant_key.d.ts +4 -0
- package/dist/internal/domain/edge/variant_key.js +56 -0
- package/dist/internal/platform/collectionstore/errors.d.ts +24 -0
- package/dist/internal/platform/collectionstore/errors.js +48 -0
- package/dist/mintlify/blocks.d.ts +6 -0
- package/dist/mintlify/blocks.js +201 -0
- package/dist/mintlify/config.d.ts +3 -0
- package/dist/mintlify/config.js +77 -0
- package/dist/mintlify/index.d.ts +3 -0
- package/dist/mintlify/index.js +2 -0
- package/dist/mintlify/json.d.ts +8 -0
- package/dist/mintlify/json.js +37 -0
- package/dist/mintlify/materialize.d.ts +14 -0
- package/dist/mintlify/materialize.js +254 -0
- package/dist/mintlify/types.d.ts +74 -0
- package/dist/mintlify/types.js +1 -0
- package/dist/mintlify/validate.d.ts +7 -0
- package/dist/mintlify/validate.js +256 -0
- package/dist/next/assignments-navigation.d.ts +4 -0
- package/dist/next/assignments-navigation.js +18 -0
- package/dist/next/assignments-script.d.ts +3 -2
- package/dist/next/assignments-script.js +5 -5
- package/dist/next/error-pages.d.ts +4 -0
- package/dist/next/error-pages.js +4 -0
- package/dist/next/error-seat-payload.d.ts +2 -1
- package/dist/next/error-seat-payload.js +14 -24
- package/dist/next/error-seat.js +7 -2
- package/dist/next/index.d.ts +1 -1
- package/dist/next/index.js +3 -1
- package/dist/next/page.d.ts +2 -1
- package/dist/next/page.js +15 -4
- package/dist/next/release-context.d.ts +30 -0
- package/dist/next/release-context.js +56 -0
- package/dist/next/render.d.ts +1 -1
- package/dist/next/render.js +15 -5
- package/dist/next/server.d.ts +9 -3
- package/dist/next/server.js +17 -32
- package/dist/preview/core.d.ts +1 -0
- package/dist/preview/core.js +27 -0
- package/dist/react/VideoPlayer.d.ts +3 -3
- package/dist/react/index.d.ts +3 -3
- package/dist/registry.d.ts +4 -2
- package/dist/testing/conformance/checks.d.ts +2 -2
- package/dist/testing/conformance/checks.js +2 -0
- package/dist/testing/conformance/index.d.ts +1 -0
- package/dist/testing/conformance/index.js +1 -0
- package/dist/testing/conformance/next-stubs.d.ts +6 -0
- package/dist/testing/conformance/next-stubs.js +9 -0
- package/dist/testing/conformance/preset.d.ts +3 -2
- package/dist/testing/conformance/preset.js +15 -8
- package/dist/testing/conformance/root-identity.d.ts +31 -0
- package/dist/testing/conformance/root-identity.js +361 -0
- package/dist/testing/conformance/stubs/next-image.d.ts +7 -0
- package/dist/testing/conformance/stubs/next-image.js +5 -0
- package/dist/testing/conformance/stubs/next-link.d.ts +7 -0
- package/dist/testing/conformance/stubs/next-link.js +4 -0
- package/dist/testing/conformance/types.d.ts +5 -2
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +4 -3
- package/dist/types/block-ref.js +2 -2
- package/dist/types/component.d.ts +9 -0
- package/dist/types/config.d.ts +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.js +0 -1
- package/dist/types/page.d.ts +0 -1
- package/migrations/conformance-registry.md +22 -0
- package/migrations/experiment-goal-ids.md +43 -0
- package/package.json +21 -7
- package/src/cli/compile-registry.mjs +6 -30
- package/src/cli/mintlify-render.mjs +9 -0
- package/src/types/block-ref.test.ts +16 -1
- package/src/types/block-ref.ts +2 -2
- package/src/types/component.ts +10 -0
- package/src/types/config.ts +0 -1
- package/src/types/index.ts +0 -1
- package/src/types/page.ts +0 -1
- package/templates/astro/starter-content/src/components/chrome/Footer.astro +5 -3
- package/templates/astro/starter-content/src/components/chrome/Header.astro +5 -3
- package/templates/astro/starter-content/src/components/elements/Button.astro +5 -2
- package/templates/astro/starter-content/src/components/elements/ButtonBlock.astro +5 -3
- package/templates/astro/starter-content/src/components/sections/ContainerSection.astro +4 -3
- package/templates/astro/starter-content/src/components/sections/FeatureCard.astro +4 -3
- package/templates/astro/starter-content/src/components/sections/FeatureGrid.astro +4 -3
- package/templates/astro/starter-content/src/components/sections/HomeHero.astro +5 -3
- package/templates/astro/starter-content/src/components/sections/PersonalizationChoice.astro +4 -3
- package/templates/astro/starter-content/src/components/sections/StatsBar.astro +4 -3
- package/templates/astro/starter-content/src/fixtures/sections.ts +1 -1
- package/templates/astro/starter-content/src/stories/CompositionStoryFrame.astro +7 -2
- package/templates/astro/template/.aci.yaml.tmpl +0 -1
- package/templates/astro/template/package.json.tmpl +5 -5
- package/templates/astro/template/src/layouts/SiteLayout.astro +2 -2
- package/templates/common/.agents/skills/aci/SKILL.md +58 -1
- package/templates/common/.agents/skills/authoring/SKILL.md +194 -42
- package/templates/common/.agents/skills/authoring/references/block-registry.md +19 -3
- package/templates/common/.agents/skills/authoring/references/contracts.md +9 -30
- package/templates/common/.agents/skills/authoring/references/repo-structure.md +5 -4
- package/templates/common/.agents/skills/authoring/references/sdk-server-functions.md +3 -3
- package/templates/common/.agents/skills/dam-delivery/SKILL.md +216 -0
- package/templates/common/.agents/skills/dam-delivery/references/permalink-grammar.md +167 -0
- package/templates/common/.agents/skills/migration/references/canon-migration.md +18 -67
- package/templates/common/.agents/skills/migration/references/selector-map.md +1 -1
- package/templates/common/.content/fragments/navbar/_index.json +24 -0
- package/templates/common/.content/fragments/site-footer/_index.json +61 -0
- package/templates/common/.content/pages/404/_index.json +4 -2
- package/templates/common/.content/pages/_index.json +0 -1
- package/templates/common/.content/pages/error/_index.json +4 -2
- package/templates/common/.content/schemas/site.schema.json +11 -1
- package/templates/common/.content/templates/error.json +24 -0
- package/templates/common/.content/templates/home.json +28 -0
- package/templates/common/.content/templates/site.json +8 -0
- package/templates/common/.content/templates/standard.json +24 -0
- package/templates/common/.nvmrc +1 -1
- package/templates/common/starter-content/.content/config/site.json +1 -1
- package/templates/common/starter-content/.content/dam/README.md +74 -0
- package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000101}/asset.json +1 -1
- package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000102}/asset.json +1 -1
- package/templates/common/starter-content/.content/pages/404/_index.json +1 -2
- package/templates/common/starter-content/.content/pages/{home/_index.json → _index.json} +14 -3
- package/templates/common/starter-content/.content/pages/about/_index.json +2 -2
- package/templates/common/starter-content/.content/pages/error/_index.json +1 -2
- package/templates/common/starter-content/.content/patterns/components/button.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/container.json +8 -3
- package/templates/common/starter-content/.content/patterns/components/feature_card.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/feature_grid.json +5 -3
- package/templates/common/starter-content/.content/patterns/components/home_hero.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/personalization_choice.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/site-footer.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/site-navigation.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/stats_bar.json +2 -2
- package/templates/common/starter-content/.content/schemas/site.schema.json +11 -1
- package/templates/nextjs/starter-content/src/components/chrome/Footer.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/chrome/Header.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/elements/Button.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/elements/ButtonBlock.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/sections/ContainerSection.tsx +4 -2
- package/templates/nextjs/starter-content/src/components/sections/FeatureCard.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/sections/FeatureGrid.tsx +4 -2
- package/templates/nextjs/starter-content/src/components/sections/HomeHero.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/sections/PersonalizationChoice.tsx +4 -2
- package/templates/nextjs/starter-content/src/components/sections/StatsBar.tsx +4 -3
- package/templates/nextjs/template/.aci.yaml +0 -1
- package/templates/nextjs/template/.aci.yaml.tmpl +0 -1
- package/templates/nextjs/template/package.json.tmpl +4 -3
- package/templates/nextjs/template/src/app/_components/c15t-bridge.ts +30 -0
- package/templates/nextjs/template/src/app/_components/c15t-consent-ui.tsx +37 -0
- package/templates/nextjs/template/src/app/_components/consent-manager.css +63 -0
- package/templates/nextjs/template/src/app/_components/consent-manager.tsx +76 -0
- package/templates/nextjs/template/src/app/fonts/inter/OFL.txt +93 -0
- package/templates/nextjs/template/src/app/fonts/inter/inter-latin.woff2 +0 -0
- package/templates/nextjs/template/src/app/fonts/space-grotesk/OFL.txt +93 -0
- package/templates/nextjs/template/src/app/fonts/space-grotesk/space-grotesk-latin.woff2 +0 -0
- package/templates/nextjs/template/src/app/layout.tsx +12 -7
- package/templates/nextjs/template/tests/conformance.test.ts.tmpl +1 -0
- package/dist/define-layout.d.ts +0 -6
- package/dist/define-layout.js +0 -14
- package/dist/edge/personalization-core.d.ts +0 -11
- package/dist/edge/personalization-core.js +0 -269
- package/dist/internal/domain/edge/compose.d.ts +0 -24
- package/dist/internal/domain/edge/compose.js +0 -89
- package/dist/internal/domain/edge/record/codec.d.ts +0 -71
- package/dist/internal/domain/edge/record/codec.js +0 -401
- package/dist/next/collect-route.d.ts +0 -19
- package/dist/next/collect-route.js +0 -459
- package/dist/next/edge-config.d.ts +0 -1
- package/dist/next/edge-config.js +0 -92
- package/dist/next/envelope-digest.d.ts +0 -21
- package/dist/next/envelope-digest.js +0 -58
- package/dist/next/middleware.d.ts +0 -40
- package/dist/next/middleware.js +0 -475
- package/dist/next/personalization-host.d.ts +0 -134
- package/dist/next/personalization-host.js +0 -270
- package/dist/next/root-layout.d.ts +0 -4
- package/dist/next/root-layout.js +0 -5
- package/dist/next/vercel-collect-sdk-route.d.ts +0 -27
- package/dist/next/vercel-collect-sdk-route.js +0 -181
- package/dist/next/vercel-edge-projection-v1.d.ts +0 -24
- package/dist/next/vercel-edge-projection-v1.js +0 -880
- package/dist/next/vercel-personalization.d.ts +0 -4
- package/dist/next/vercel-personalization.js +0 -4
- package/dist/next/vercel-s3-personalization.d.ts +0 -79
- package/dist/next/vercel-s3-personalization.js +0 -570
- package/dist/types/layout.d.ts +0 -24
- package/src/types/layout.ts +0 -29
- package/templates/astro/starter-content/src/render/RenderPage.astro +0 -67
- package/templates/astro/template/src/cms/contracts/layouts/index.ts +0 -18
- package/templates/common/starter-content/.content/patterns/layouts/default.json +0 -14
- package/templates/nextjs/starter-content/src/components/elements/AtomicBlock.tsx +0 -13
- package/templates/nextjs/template/src/cms/contracts/layouts/index.ts +0 -16
- /package/dist/{types/layout.js → cli/mintlify-render.d.mts} +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/editorial.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000101}/governance.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/versions/v0001.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/editorial.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000102}/governance.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/versions/v0001.json +0 -0
|
@@ -14,7 +14,9 @@ description: Author content and build components for ACI sites. Use when creatin
|
|
|
14
14
|
| `.content/config/site.json` | Site metadata, SEO defaults |
|
|
15
15
|
| `.content/config/robots.txt` | Authored crawler rules; publish bundles this file verbatim as `assets/robots.txt` when present |
|
|
16
16
|
| `.content/pages/{slug}/_index.json` | Page content (slug maps to route) |
|
|
17
|
-
| `.content/fragments/{id}/_index.json` | Shared fragments (navbar, footer —
|
|
17
|
+
| `.content/fragments/{id}/_index.json` | Shared fragments (navbar, footer — usable by template defaults) |
|
|
18
|
+
| `.content/templates/{name}.json` | Page templates and global policies: the composition guardrails every page and variant must satisfy (see Page Templates) |
|
|
19
|
+
| `.content/overlays/{dimension}/{value}/pages/{slug}/_index.json` | Page overlays: keyed patches that personalize a page for an audience, locale, or experiment arm |
|
|
18
20
|
| `.aci/schemas/page.schema.json` | Page validation schema (auto-generated from contracts) |
|
|
19
21
|
|
|
20
22
|
### Page Structure
|
|
@@ -26,20 +28,35 @@ Every page JSON requires:
|
|
|
26
28
|
"$type": "page",
|
|
27
29
|
"id": "unique-page-id",
|
|
28
30
|
"status": "published",
|
|
29
|
-
"
|
|
31
|
+
"template": "standard",
|
|
30
32
|
"metadata": {
|
|
31
33
|
"title": "Page Title",
|
|
32
34
|
"description": "Meta description",
|
|
33
35
|
"sitemap": { "visible": true }
|
|
34
36
|
},
|
|
35
37
|
"regions": {
|
|
36
|
-
"main": [
|
|
38
|
+
"main": [
|
|
39
|
+
{
|
|
40
|
+
"$type": "component",
|
|
41
|
+
"id": "page-hero",
|
|
42
|
+
"component": "home_hero",
|
|
43
|
+
"props": {
|
|
44
|
+
"eyebrow": "Eyebrow",
|
|
45
|
+
"headline": "Page headline",
|
|
46
|
+
"description": "One sentence that says what this page is for.",
|
|
47
|
+
"ctaLabel": "Back to home",
|
|
48
|
+
"ctaHref": "/"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
]
|
|
37
52
|
}
|
|
38
53
|
}
|
|
39
54
|
```
|
|
40
55
|
|
|
41
56
|
Base page fields are SDK-owned and included in the generated
|
|
42
|
-
`.aci/schemas/page.schema.json`.
|
|
57
|
+
`.aci/schemas/page.schema.json`. `template` names the page template that
|
|
58
|
+
governs an interior page (see Page Templates); pages under a route a
|
|
59
|
+
template covers omit it.
|
|
43
60
|
|
|
44
61
|
#### Sitemap visibility
|
|
45
62
|
|
|
@@ -67,10 +84,9 @@ the intent clear in content).
|
|
|
67
84
|
|
|
68
85
|
This does **not** add a `noindex` meta tag — it only controls sitemap inclusion.
|
|
69
86
|
|
|
70
|
-
The
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
`regions.main`; chrome comes from the layout's fragment defaults.
|
|
87
|
+
The bound template determines which regions the page can fill. A template may
|
|
88
|
+
provide `header` and `footer` fragment defaults, so pages typically author only
|
|
89
|
+
`regions.main`. There is no authored `layout` field or code layout registry.
|
|
74
90
|
|
|
75
91
|
### Route Mapping
|
|
76
92
|
|
|
@@ -78,19 +94,173 @@ Pages map to URL routes by their folder path under `/pages/`:
|
|
|
78
94
|
|
|
79
95
|
| Page Path | Route |
|
|
80
96
|
|-----------|-------|
|
|
81
|
-
| `/pages/
|
|
97
|
+
| `/pages/_index.json` | `/` |
|
|
82
98
|
| `/pages/about/_index.json` | `/about` |
|
|
83
99
|
| `/pages/products/_index.json` | `/products` |
|
|
84
100
|
| `/pages/products/shoes/_index.json` | `/products/shoes` |
|
|
85
101
|
|
|
86
|
-
The
|
|
102
|
+
The empty slug is the site root. Every named folder maps directly, including
|
|
103
|
+
`/pages/home/_index.json` at `/home`.
|
|
104
|
+
|
|
105
|
+
### Page Templates and Global Policies
|
|
106
|
+
|
|
107
|
+
Composition guardrails live in `.content/templates/<name>.json`. They are
|
|
108
|
+
content, owned by whoever holds policy authority on `/templates/`, and every
|
|
109
|
+
page **and every personalized variant of it** must satisfy them before a
|
|
110
|
+
release can be published. Read the governing template before composing a
|
|
111
|
+
page: a write that breaks a guardrail is refused when you make it, with 422
|
|
112
|
+
`<lane>.template_invalid` and a `template/*` diagnostic naming the exact
|
|
113
|
+
block.
|
|
114
|
+
|
|
115
|
+
**How to read a refusal.** Each entry under `details.diagnostics` carries the
|
|
116
|
+
rule id, the document and JSON pointer to fix (`documentRef`, `jsonPointer`),
|
|
117
|
+
and in `details`: `template` (the governing document), `variant` (empty for
|
|
118
|
+
the base page), `expected` and `found`, and `trigger` — which paths of your
|
|
119
|
+
own batch caused the check. The list is capped at 100; `details.diagnosticCount`
|
|
120
|
+
is the real total. You are refused only for what your batch breaks: a page
|
|
121
|
+
that already failed before your write never blocks you, and fixing it is
|
|
122
|
+
someone with authority over `/pages/`.
|
|
123
|
+
|
|
124
|
+
**Check before you write.** `POST /v1/content/validate` takes the same
|
|
125
|
+
`changes` body as a branch write and returns the same verdict without
|
|
126
|
+
committing anything — use it to try a composition or a template edit.
|
|
127
|
+
`aci validate` runs the same evaluator over a local tree, and `POST
|
|
128
|
+
/v1/branches/{name}/coherence/check` over a branch. A promote to `live` is
|
|
129
|
+
judged the same way against `live`: a page must travel with the template it
|
|
130
|
+
needs, so widen the promote set when `template/not-found` comes back.
|
|
131
|
+
|
|
132
|
+
**Publish is still the guarantee.** A write is judged for the variant its own
|
|
133
|
+
path names. Two overlays that are each valid but violate together under a
|
|
134
|
+
wider variant are caught by the release preflight, which refuses the publish
|
|
135
|
+
with `publish.template_invalid` naming that variant; fix either overlay.
|
|
136
|
+
|
|
137
|
+
Two kinds of document, told apart by `$type`; the file stem is the name:
|
|
138
|
+
|
|
139
|
+
| Document | Kind | What it says |
|
|
140
|
+
|----------|------|--------------|
|
|
141
|
+
| `site.json` | `globalPolicy` | Applies to every page: `counts` (per-component `min`/`max` over the effective page, including nested blocks and rendered fragment placements). A `pageTemplate` may carry `counts` too, scoped to the pages it governs. |
|
|
142
|
+
| `home.json` | `pageTemplate` | Covers `routes: ["/"]`: `main` is exactly home_hero, feature_grid, personalization_choice, stats_bar, container, in that order. |
|
|
143
|
+
| `standard.json` | `pageTemplate` | Declared by interior pages: `main` starts with a home_hero, then `closed: false` admits anything after it. |
|
|
144
|
+
| `error.json` | `pageTemplate` | Covers `/404` and `/error`: a single home_hero. |
|
|
145
|
+
|
|
146
|
+
**Which template governs a page.** A page under a route a template's
|
|
147
|
+
`routes` covers is governed by that template and needs no declaration
|
|
148
|
+
(`/`, `/404`, `/error` in the starter). Every other page declares its
|
|
149
|
+
template with a root `"template": "<name>"` (the starter's `/about`
|
|
150
|
+
declares `standard`). An undeclared, uncovered page produces `template/unbound`
|
|
151
|
+
even without a global policy. Write/probe and promote gates refuse newly
|
|
152
|
+
introduced violations; publish refuses every unbound page. Route patterns are public
|
|
153
|
+
routes; a trailing `/*` covers every deeper route. A declaration on a
|
|
154
|
+
covered page must name the covering template.
|
|
155
|
+
|
|
156
|
+
**Steps.** A region rule is an ordered `sequence` of steps. Each step names
|
|
157
|
+
the inline `component`(s) it accepts, or the shared `fragment` ids
|
|
158
|
+
(`"fragment": ["faq-block"]`, or `"fragment": "*"` for any fragment no other
|
|
159
|
+
step names), or both, with `min`/`max` occurrences (default exactly one).
|
|
160
|
+
A step listing several components accepts any of them in any order up to
|
|
161
|
+
`max`. `closed: true` (the default) means nothing may follow the last step.
|
|
162
|
+
Template steps must be unambiguous: two adjacent optional steps may not
|
|
163
|
+
accept the same component. Only the keys shown here are accepted — a
|
|
164
|
+
misspelled key is refused as `template/invalid`, so a guardrail can never
|
|
165
|
+
switch itself off silently. A step may declare `"lock": "structure"`: variants
|
|
166
|
+
may change props, but must preserve the complete step assignment (ids,
|
|
167
|
+
components, order, fragment references, and nested block structure). Nested
|
|
168
|
+
blocks inside each locked top-level block need non-empty, distinct ids. The
|
|
169
|
+
comparison baseline includes the default-locale overlay; the home hero is locked.
|
|
170
|
+
|
|
171
|
+
A template that exercises the grammar, for an interior article page that
|
|
172
|
+
declares it with `"template": "article"`:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"$type": "pageTemplate",
|
|
177
|
+
"name": "article",
|
|
178
|
+
"description": "A hero, one to six body sections, then an optional shared promo.",
|
|
179
|
+
"regions": [
|
|
180
|
+
{
|
|
181
|
+
"name": "main",
|
|
182
|
+
"closed": false,
|
|
183
|
+
"sequence": [
|
|
184
|
+
{ "id": "hero", "component": "home_hero" },
|
|
185
|
+
{ "id": "body", "component": ["feature_grid", "stats_bar", "container"], "min": 1, "max": 6 },
|
|
186
|
+
{ "id": "promo", "fragment": "*", "min": 0 }
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
],
|
|
190
|
+
"counts": [{ "component": "stats_bar", "max": 1 }]
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Shared fragments.** Sequence steps match a reference by its fragment id.
|
|
195
|
+
Counts include its rendered component tree once per placement. A structure lock
|
|
196
|
+
also protects that tree: fragment overlays may personalize props but cannot
|
|
197
|
+
swap components or rendered block identities. Fragment edits and overlays
|
|
198
|
+
revalidate referencing pages. Refusals name the source fragment or overlay and
|
|
199
|
+
the page placement (`details.page`, `referencePointer`).
|
|
200
|
+
|
|
201
|
+
**Defaults count when rendered.** Template default fragments fill an absent or
|
|
202
|
+
empty region. They participate in sequence rules, counts, structure locks, and
|
|
203
|
+
component validation just like explicit placements. A populated page region
|
|
204
|
+
replaces its defaults; the unused defaults are not counted.
|
|
205
|
+
|
|
206
|
+
**Nested rules belong to component contracts today.** Templates match the
|
|
207
|
+
region's top-level sequence; they do not define a grammar inside a container's
|
|
208
|
+
props. Give a page type its own contract, for example `blog_body` with
|
|
209
|
+
`content: blockRefArray([featureCardContract, statsBarContract])`, and bind it to
|
|
210
|
+
the existing `ContainerSection` renderer. A blog template step names `blog_body`;
|
|
211
|
+
the compiled component contract limits its nested children. Register that
|
|
212
|
+
contract in both the compile-time contracts list and runtime registry. Compile
|
|
213
|
+
and publish enforce component schemas in addition to template rules; the
|
|
214
|
+
template evaluator itself does not read contracts. Never hand-edit `/patterns/`.
|
|
215
|
+
Nested step grammars remain deferred; use this contract pattern for allowed
|
|
216
|
+
child types, not for arbitrary nested ordering rules.
|
|
217
|
+
|
|
218
|
+
**Overlays keep the page's shape.** A page overlay personalizes a page with
|
|
219
|
+
keyed patches — an object under `regions.<region>` keyed by block `id`
|
|
220
|
+
that changes props:
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"$type": "page-overlay",
|
|
225
|
+
"regions": {
|
|
226
|
+
"main": {
|
|
227
|
+
"personalization-choice": {
|
|
228
|
+
"props": { "title": "Red preference active" }
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
An overlay may not carry a root `template` key (the binding comes from
|
|
236
|
+
route coverage and the base page; `template/binding-immutable`). Changing a
|
|
237
|
+
block's `component` or replacing a region with an array is legal only when
|
|
238
|
+
the result still satisfies the template — a swap the template does not
|
|
239
|
+
allow is refused naming the overlay and the variant.
|
|
240
|
+
|
|
241
|
+
**Reading a refusal.** Every `template/*` diagnostic carries `documentRef`
|
|
242
|
+
and `jsonPointer` (the overlay that patched the failing block, else the
|
|
243
|
+
page, and the block), and `details` with the governing `template`, its
|
|
244
|
+
`description`, the `step`, `expected` (the tokens the step accepts, as
|
|
245
|
+
`component:<name>` / `fragment:<id>`), `found`, `resolvedPointer` (the
|
|
246
|
+
location in the composed variant), `variant` (the dimension key, empty for
|
|
247
|
+
the base), and `overlays` (every overlay the variant applied, in order). `template/sequence` is a block in
|
|
248
|
+
the wrong place; `template/too-few` is a missing mandatory step;
|
|
249
|
+
`template/count` is a policy bound exceeded; `template/mismatch`,
|
|
250
|
+
`template/unbound`, and `template/not-found` are binding problems.
|
|
251
|
+
`template/locked-changed` means a locked step changed structure: preserve ids
|
|
252
|
+
and use a keyed props patch. `template/locked-missing` identifies a removed
|
|
253
|
+
locked token. `template/base-invalid` requires repairing the base page before
|
|
254
|
+
its variants can pass release validation. Fix the
|
|
255
|
+
page or overlay the diagnostic names, or, with policy authority, loosen the
|
|
256
|
+
template and republish.
|
|
87
257
|
|
|
88
258
|
### Content Rules
|
|
89
259
|
|
|
90
260
|
- Never hard-code content inside component code. All content lives in JSON.
|
|
91
261
|
- Migrate copy verbatim. Do not paraphrase, summarize, or invent.
|
|
92
262
|
- Global elements (header, footer, nav) are CMS-managed fragments in
|
|
93
|
-
`.content/fragments/`, rendered via
|
|
263
|
+
`.content/fragments/`, rendered via template fragment defaults. They are
|
|
94
264
|
not hardcoded in framework layout files.
|
|
95
265
|
- Use `$ref:` prefixes for cross-references between content documents.
|
|
96
266
|
|
|
@@ -259,7 +429,7 @@ Sites bind their error pages in `site.json` via `errorPages`:
|
|
|
259
429
|
|
|
260
430
|
- Each binding is a route path resolving to an **ordinary content page**
|
|
261
431
|
(`.content/pages/404/_index.json`, `.content/pages/error/_index.json`) —
|
|
262
|
-
authored with normal
|
|
432
|
+
authored with normal templates and components like any other page.
|
|
263
433
|
`notFound` serves unknown routes with HTTP 404; `catchAll` serves
|
|
264
434
|
application errors (500-class).
|
|
265
435
|
- Error pages stay out of discovery: set `metadata.sitemap.visible: false`
|
|
@@ -486,7 +656,7 @@ framework.
|
|
|
486
656
|
#### 5. Add content
|
|
487
657
|
|
|
488
658
|
```json
|
|
489
|
-
// .content/pages/
|
|
659
|
+
// .content/pages/_index.json (inside regions.main)
|
|
490
660
|
{
|
|
491
661
|
"$type": "component",
|
|
492
662
|
"id": "features",
|
|
@@ -551,39 +721,21 @@ type Props = ContentProps & { className?: string };
|
|
|
551
721
|
runtime components — they are the wiring point.
|
|
552
722
|
4. Use `@gradial/aci` as the SDK package. Do not use `@baremetal/runtime`.
|
|
553
723
|
|
|
554
|
-
###
|
|
724
|
+
### Template Composition
|
|
555
725
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
```ts
|
|
561
|
-
// src/cms/contracts/layouts/index.ts
|
|
562
|
-
import { defineLayoutContract, slot, fragmentDefault } from '@gradial/aci';
|
|
563
|
-
|
|
564
|
-
export default [
|
|
565
|
-
defineLayoutContract({
|
|
566
|
-
name: 'default',
|
|
567
|
-
slots: [
|
|
568
|
-
slot('header'), // filled by fragment default
|
|
569
|
-
slot('main', true), // filled by page regions (required)
|
|
570
|
-
slot('footer'), // filled by fragment default
|
|
571
|
-
],
|
|
572
|
-
defaults: {
|
|
573
|
-
header: fragmentDefault('navbar'),
|
|
574
|
-
footer: fragmentDefault('site-footer'),
|
|
575
|
-
},
|
|
576
|
-
}),
|
|
577
|
-
];
|
|
578
|
-
```
|
|
726
|
+
Templates under `.content/templates/<name>.json` define ordered regions,
|
|
727
|
+
placement policy, requiredness, and optional fragment defaults. They are the
|
|
728
|
+
only authored page-composition contract; do not create a TypeScript layout
|
|
729
|
+
contract or add `layoutRegistry` to `.aci.yaml`.
|
|
579
730
|
|
|
580
731
|
Fragment content lives in `.content/fragments/{id}/_index.json` and retains
|
|
581
|
-
the resource envelope `"$type": "fragment"
|
|
582
|
-
`
|
|
732
|
+
the resource envelope `"$type": "fragment"`; its `block` declares
|
|
733
|
+
`"$type": "component"`, `component`, and `props`. Place a shared fragment in
|
|
734
|
+
a page region with `"$fragment:<id>"` or use it as a template default. Chrome components (Header, Footer) are registered in the registry
|
|
583
735
|
alongside page components.
|
|
584
736
|
|
|
585
|
-
|
|
586
|
-
|
|
737
|
+
Bind each page with `template`, unless route configuration supplies the
|
|
738
|
+
template binding.
|
|
587
739
|
|
|
588
740
|
## Component Tiers
|
|
589
741
|
|
|
@@ -693,7 +845,7 @@ slot configuration, nested dot paths, and runtime image rendering rules.
|
|
|
693
845
|
|
|
694
846
|
Read `references/contracts.md` for the full contract file structure,
|
|
695
847
|
`defineComponentContract` API, `.aci.yaml` config reference, plain
|
|
696
|
-
|
|
848
|
+
template documents and component contract barrel patterns.
|
|
697
849
|
|
|
698
850
|
## Deep Dive: Design System
|
|
699
851
|
|
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
The component registry maps contract names to runtime components. It is built
|
|
4
4
|
using `createRegistry` from `@gradial/aci` with raw `[contract, component]` tuples.
|
|
5
5
|
|
|
6
|
+
Every registered component must extend `RootIdentityProps` (exported from
|
|
7
|
+
`@gradial/aci`) and spread the rest of its props onto its root element. The
|
|
8
|
+
renderer passes `data-aci-block` and `data-aci-component` to every block so
|
|
9
|
+
analytics can join events to content; a component that does not declare the
|
|
10
|
+
type fails `createRegistry` typecheck with
|
|
11
|
+
`<id>: props type must extend RootIdentityProps from @gradial/aci`, and one
|
|
12
|
+
that does not spread fails the `rootIdentity` conformance check under
|
|
13
|
+
`npm test`.
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
export function StatsBar({ stats = [], ...root }: ContentProps & RootIdentityProps) {
|
|
17
|
+
return <section {...root} className="…">…</section>;
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
6
21
|
The tuple form provides **type-level validation** — the component must accept
|
|
7
22
|
at least the props derived from the contract's Zod schema. If you register a
|
|
8
23
|
component with the wrong prop type, TypeScript will fail at the call site.
|
|
@@ -51,7 +66,7 @@ the compiler invokes this route with an isolated render input; hosted CMS
|
|
|
51
66
|
traffic is served from the resulting immutable HTML and does not enter Next.
|
|
52
67
|
|
|
53
68
|
Chrome (Header/Footer) is **not** in `layout.tsx`. It is CMS-managed via
|
|
54
|
-
|
|
69
|
+
template fragment defaults. The `layout.tsx` file is minimal and includes
|
|
55
70
|
`<DevRefresh />`:
|
|
56
71
|
|
|
57
72
|
```tsx
|
|
@@ -83,8 +98,9 @@ export const generateMetadata = page.generateMetadata;
|
|
|
83
98
|
export default page.default;
|
|
84
99
|
```
|
|
85
100
|
|
|
86
|
-
`createPage` loads the
|
|
87
|
-
regions or
|
|
101
|
+
`createPage` loads the compiler's template-derived render envelope, resolves
|
|
102
|
+
all regions (filling from page regions or template fragment defaults), and
|
|
103
|
+
renders blocks via the registry.
|
|
88
104
|
The `main` slot is wrapped in `<main>`; other slots render as fragments.
|
|
89
105
|
|
|
90
106
|
## Custom Server Composition
|
|
@@ -59,43 +59,23 @@ import { buttonContract } from './button.contract';
|
|
|
59
59
|
export default [heroContract, buttonContract];
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
##
|
|
62
|
+
## Template Composition
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
```ts
|
|
67
|
-
// src/cms/contracts/layouts/index.ts
|
|
68
|
-
import { defineLayoutContract, slot, fragmentDefault } from '@gradial/aci';
|
|
69
|
-
|
|
70
|
-
export default [
|
|
71
|
-
defineLayoutContract({
|
|
72
|
-
name: 'marketing',
|
|
73
|
-
slots: [
|
|
74
|
-
slot('header'),
|
|
75
|
-
slot('main', true),
|
|
76
|
-
slot('footer'),
|
|
77
|
-
],
|
|
78
|
-
defaults: {
|
|
79
|
-
header: fragmentDefault('site-header'),
|
|
80
|
-
footer: fragmentDefault('site-footer'),
|
|
81
|
-
},
|
|
82
|
-
}),
|
|
83
|
-
];
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Content pages reference layouts by name:
|
|
64
|
+
Templates under `.content/templates/<name>.json` are the sole authored
|
|
65
|
+
page-composition contract. Content pages reference templates by name:
|
|
87
66
|
|
|
88
67
|
```json
|
|
89
68
|
{
|
|
90
|
-
"
|
|
69
|
+
"template": "marketing",
|
|
91
70
|
"regions": {
|
|
92
71
|
"main": [...]
|
|
93
72
|
}
|
|
94
73
|
}
|
|
95
74
|
```
|
|
96
75
|
|
|
97
|
-
|
|
98
|
-
|
|
76
|
+
Templates define ordered regions, placement policy, requiredness, and defaults.
|
|
77
|
+
The `header` and `footer` regions can be filled automatically by fragment
|
|
78
|
+
defaults when the page does not provide blocks for them.
|
|
99
79
|
|
|
100
80
|
## Multiple Runtime Mappings
|
|
101
81
|
|
|
@@ -119,7 +99,6 @@ source:
|
|
|
119
99
|
publicDir: "public" # Astro only
|
|
120
100
|
|
|
121
101
|
componentRegistry: ./src/cms/contracts/components/index.ts
|
|
122
|
-
layoutRegistry: ./src/cms/contracts/layouts/index.ts
|
|
123
102
|
|
|
124
103
|
# Optional for custom renderers; Astro/Next use framework conventions.
|
|
125
104
|
# rendererEntry: ./src/cms/renderer.ts
|
|
@@ -145,7 +124,6 @@ rendererProtocol: stdio-json
|
|
|
145
124
|
| `source.outDir` | Build output directory (Astro) |
|
|
146
125
|
| `source.publicDir` | Public assets directory (Astro) |
|
|
147
126
|
| `componentRegistry` | Path to component contract barrel |
|
|
148
|
-
| `layoutRegistry` | Path to layout contract barrel |
|
|
149
127
|
| `rendererEntry` | Optional renderer entry override; omit for framework conventions |
|
|
150
128
|
| `routes.cmsManaged` | Catch-all route pattern for CMS pages |
|
|
151
129
|
| `rendererProtocol` | Renderer communication protocol |
|
|
@@ -159,7 +137,8 @@ rendererProtocol: stdio-json
|
|
|
159
137
|
|
|
160
138
|
### Rules
|
|
161
139
|
|
|
162
|
-
- `componentRegistry`
|
|
140
|
+
- `componentRegistry` points to a contract-only module. Do not add
|
|
141
|
+
`layoutRegistry`; page composition lives in `.content/templates`.
|
|
163
142
|
- No secrets in `.aci.yaml`, docs, fixtures, or generated files.
|
|
164
143
|
- The `cmsManaged` route pattern should match the filesystem: use `/[[...slug]]`
|
|
165
144
|
(optional catch-all) for Next.js repos so local `/` arrives with an empty
|
|
@@ -27,8 +27,11 @@ tsconfig.json TypeScript config
|
|
|
27
27
|
home/_index.json Homepage (route /)
|
|
28
28
|
about/_index.json About page (route /about) (starter content only)
|
|
29
29
|
fragments/
|
|
30
|
-
navbar/_index.json Navbar fragment (
|
|
31
|
-
site-footer/_index.json Footer fragment (
|
|
30
|
+
navbar/_index.json Navbar fragment (template default)
|
|
31
|
+
site-footer/_index.json Footer fragment (template default)
|
|
32
|
+
templates/
|
|
33
|
+
home.json Page composition contract
|
|
34
|
+
standard.json Page composition contract
|
|
32
35
|
src/
|
|
33
36
|
cms/
|
|
34
37
|
contracts/
|
|
@@ -42,8 +45,6 @@ src/
|
|
|
42
45
|
siteNavigation.contract.ts Site navigation contract (starter content only)
|
|
43
46
|
siteFooter.contract.ts Site footer contract (starter content only)
|
|
44
47
|
index.ts Component contract barrel
|
|
45
|
-
layouts/
|
|
46
|
-
index.ts Layout contract barrel (plain objects)
|
|
47
48
|
registry.ts Component registry — createRegistry([contract, component] tuples)
|
|
48
49
|
components/
|
|
49
50
|
elements/ Small reusable components + atomic content blocks
|
|
@@ -30,8 +30,8 @@ export const generateMetadata = page.generateMetadata;
|
|
|
30
30
|
export default page.default;
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
`createPage` loads the
|
|
34
|
-
page regions or
|
|
33
|
+
`createPage` loads the compiler's template-derived render envelope, resolves
|
|
34
|
+
all regions (filling from page regions or template fragment defaults), and renders blocks via the
|
|
35
35
|
registry. The `main` slot is wrapped in `<main>`; other slots render as
|
|
36
36
|
fragments.
|
|
37
37
|
|
|
@@ -177,7 +177,7 @@ and shared across all releases.
|
|
|
177
177
|
|
|
178
178
|
The root layout is minimal: import CSS, optionally load site config, and
|
|
179
179
|
include `<DevRefresh />`. Chrome (Header/Footer) is **not** in layout.tsx —
|
|
180
|
-
it is CMS-managed via
|
|
180
|
+
it is CMS-managed via template fragment defaults and rendered by `createPage`.
|
|
181
181
|
|
|
182
182
|
```tsx
|
|
183
183
|
import { DevRefresh, getSiteConfig } from '@gradial/aci/next';
|