@gradial/aci 0.1.52-rc.3 → 0.1.52-rc.33

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 (268) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +86 -5
  3. package/dist/astro/error-page.js +1 -0
  4. package/dist/astro/index.js +4 -0
  5. package/dist/astro/page.d.ts +5 -2
  6. package/dist/astro/page.js +35 -23
  7. package/dist/astro/preview.js +2 -17
  8. package/dist/audience-data-models.d.ts +308 -194
  9. package/dist/audience-data-models.js +314 -51
  10. package/dist/cli/compile-registry.d.mts +5 -1
  11. package/dist/cli/compile-registry.mjs +31 -44
  12. package/dist/cli/mintlify-render.mjs +8 -0
  13. package/dist/cli/validate-content.d.mts +31 -1
  14. package/dist/cli/validate-content.mjs +50 -12
  15. package/dist/collect/aci.js +1 -1
  16. package/dist/collect/aci.js.sha256 +1 -1
  17. package/dist/collect/api.d.ts +6 -7
  18. package/dist/collect/api.js +21 -8
  19. package/dist/collect/assignments.d.ts +7 -9
  20. package/dist/collect/assignments.js +23 -32
  21. package/dist/collect/batcher.d.ts +9 -7
  22. package/dist/collect/batcher.js +6 -5
  23. package/dist/collect/consent/envelope.d.ts +7 -1
  24. package/dist/collect/consent/envelope.js +3 -1
  25. package/dist/collect/consent/mapping.d.ts +2 -0
  26. package/dist/collect/consent/mapping.js +1 -0
  27. package/dist/collect/consenthold.d.ts +38 -0
  28. package/dist/collect/consenthold.js +82 -0
  29. package/dist/collect/declarative.js +7 -5
  30. package/dist/collect/gapbuffer.d.ts +13 -4
  31. package/dist/collect/gapbuffer.js +21 -10
  32. package/dist/collect/index.js +67 -20
  33. package/dist/collect/pageviews.d.ts +11 -11
  34. package/dist/collect/pageviews.js +27 -22
  35. package/dist/consent-banner/index.d.ts +17 -0
  36. package/dist/consent-banner/index.js +23 -0
  37. package/dist/content/index.d.ts +2 -1
  38. package/dist/content/index.js +4 -1
  39. package/dist/content/provider.d.ts +16 -2
  40. package/dist/content/provider.js +5 -1
  41. package/dist/content/resolve-slots.d.ts +33 -4
  42. package/dist/content/resolve-slots.js +127 -19
  43. package/dist/content/types.d.ts +7 -1
  44. package/dist/edge/expression-capabilities.v1.d.ts +106 -0
  45. package/dist/edge/expression-capabilities.v1.js +165 -0
  46. package/dist/index.d.ts +1 -2
  47. package/dist/index.js +0 -1
  48. package/dist/internal/domain/edge/compose.d.ts +24 -0
  49. package/dist/internal/domain/edge/compose.js +89 -0
  50. package/dist/internal/domain/edge/identity.d.ts +5 -0
  51. package/dist/internal/domain/edge/identity.js +50 -14
  52. package/dist/internal/domain/edge/index.d.ts +2 -0
  53. package/dist/internal/domain/edge/index.js +2 -0
  54. package/dist/internal/domain/edge/mimic_token.d.ts +14 -0
  55. package/dist/internal/domain/edge/mimic_token.js +125 -0
  56. package/dist/internal/domain/edge/personalization-core.d.ts +61 -22
  57. package/dist/internal/domain/edge/personalization-core.js +789 -198
  58. package/dist/internal/domain/edge/personalization_index.d.ts +17 -0
  59. package/dist/internal/domain/edge/personalization_index.js +56 -0
  60. package/dist/internal/domain/edge/record/codec.d.ts +6 -32
  61. package/dist/internal/domain/edge/record/codec.js +86 -168
  62. package/dist/internal/domain/edge/resolve.js +76 -39
  63. package/dist/internal/domain/edge/testdata/flat_only_validator_v1.d.ts +10 -0
  64. package/dist/internal/domain/edge/testdata/flat_only_validator_v1.js +253 -0
  65. package/dist/internal/domain/edge/types.d.ts +93 -41
  66. package/dist/internal/domain/edge/types.js +3 -3
  67. package/dist/internal/domain/edge/variant_key.d.ts +3 -0
  68. package/dist/internal/domain/edge/variant_key.js +44 -0
  69. package/dist/internal/platform/collectionstore/errors.d.ts +24 -0
  70. package/dist/internal/platform/collectionstore/errors.js +48 -0
  71. package/dist/mimic/core.d.ts +2 -0
  72. package/dist/mimic/core.js +31 -0
  73. package/dist/mintlify/blocks.d.ts +6 -0
  74. package/dist/mintlify/blocks.js +201 -0
  75. package/dist/mintlify/config.d.ts +3 -0
  76. package/dist/mintlify/config.js +77 -0
  77. package/dist/mintlify/index.d.ts +3 -0
  78. package/dist/mintlify/index.js +2 -0
  79. package/dist/mintlify/json.d.ts +8 -0
  80. package/dist/mintlify/json.js +37 -0
  81. package/dist/mintlify/materialize.d.ts +14 -0
  82. package/dist/mintlify/materialize.js +254 -0
  83. package/dist/mintlify/types.d.ts +74 -0
  84. package/dist/mintlify/types.js +1 -0
  85. package/dist/mintlify/validate.d.ts +7 -0
  86. package/dist/mintlify/validate.js +256 -0
  87. package/dist/next/assignments-navigation.d.ts +4 -0
  88. package/dist/next/assignments-navigation.js +18 -0
  89. package/dist/next/assignments-script.d.ts +3 -2
  90. package/dist/next/assignments-script.js +5 -5
  91. package/dist/next/error-pages.d.ts +4 -0
  92. package/dist/next/error-pages.js +4 -0
  93. package/dist/next/error-seat-payload.d.ts +2 -1
  94. package/dist/next/error-seat-payload.js +14 -24
  95. package/dist/next/error-seat.js +7 -2
  96. package/dist/next/hosted-page-target.d.ts +7 -0
  97. package/dist/next/hosted-page-target.js +39 -0
  98. package/dist/next/index.d.ts +1 -1
  99. package/dist/next/index.js +3 -1
  100. package/dist/next/page.d.ts +29 -6
  101. package/dist/next/page.js +47 -25
  102. package/dist/next/release-context.d.ts +29 -0
  103. package/dist/next/release-context.js +55 -0
  104. package/dist/next/render.d.ts +1 -1
  105. package/dist/next/render.js +15 -5
  106. package/dist/next/server.d.ts +8 -0
  107. package/dist/next/server.js +44 -3
  108. package/dist/next/vercel-edge-projection-v1.d.ts +0 -9
  109. package/dist/next/vercel-edge-projection-v1.js +9 -539
  110. package/dist/preview/core.d.ts +1 -0
  111. package/dist/preview/core.js +27 -0
  112. package/dist/react/VideoPlayer.d.ts +3 -3
  113. package/dist/react/index.d.ts +3 -3
  114. package/dist/registry.d.ts +4 -2
  115. package/dist/testing/conformance/checks.d.ts +2 -2
  116. package/dist/testing/conformance/checks.js +2 -0
  117. package/dist/testing/conformance/index.d.ts +1 -0
  118. package/dist/testing/conformance/index.js +1 -0
  119. package/dist/testing/conformance/next-stubs.d.ts +6 -0
  120. package/dist/testing/conformance/next-stubs.js +9 -0
  121. package/dist/testing/conformance/preset.d.ts +3 -2
  122. package/dist/testing/conformance/preset.js +15 -8
  123. package/dist/testing/conformance/root-identity.d.ts +31 -0
  124. package/dist/testing/conformance/root-identity.js +361 -0
  125. package/dist/testing/conformance/stubs/next-image.d.ts +7 -0
  126. package/dist/testing/conformance/stubs/next-image.js +5 -0
  127. package/dist/testing/conformance/stubs/next-link.d.ts +7 -0
  128. package/dist/testing/conformance/stubs/next-link.js +4 -0
  129. package/dist/testing/conformance/types.d.ts +5 -2
  130. package/dist/testing/index.d.ts +1 -1
  131. package/dist/testing/index.js +4 -3
  132. package/dist/types/block-ref.d.ts +2 -0
  133. package/dist/types/block-ref.js +3 -2
  134. package/dist/types/component.d.ts +9 -0
  135. package/dist/types/config.d.ts +0 -1
  136. package/dist/types/index.d.ts +0 -1
  137. package/dist/types/index.js +0 -1
  138. package/dist/types/page.d.ts +0 -1
  139. package/migrations/conformance-registry.md +22 -0
  140. package/package.json +21 -7
  141. package/src/cli/compile-registry.mjs +30 -40
  142. package/src/cli/mintlify-render.mjs +9 -0
  143. package/src/cli/validate-content.mjs +52 -13
  144. package/src/types/block-ref.test.ts +60 -0
  145. package/src/types/block-ref.ts +4 -2
  146. package/src/types/component.ts +10 -0
  147. package/src/types/config.ts +0 -1
  148. package/src/types/index.ts +0 -1
  149. package/src/types/page.ts +0 -1
  150. package/templates/astro/starter-content/src/components/chrome/Footer.astro +5 -3
  151. package/templates/astro/starter-content/src/components/chrome/Header.astro +5 -3
  152. package/templates/astro/starter-content/src/components/elements/Button.astro +5 -2
  153. package/templates/astro/starter-content/src/components/elements/ButtonBlock.astro +5 -3
  154. package/templates/astro/starter-content/src/components/sections/ContainerSection.astro +4 -3
  155. package/templates/astro/starter-content/src/components/sections/FeatureCard.astro +4 -3
  156. package/templates/astro/starter-content/src/components/sections/FeatureGrid.astro +4 -3
  157. package/templates/astro/starter-content/src/components/sections/HomeHero.astro +5 -3
  158. package/templates/astro/starter-content/src/components/sections/PersonalizationChoice.astro +4 -3
  159. package/templates/astro/starter-content/src/components/sections/StatsBar.astro +4 -3
  160. package/templates/astro/starter-content/src/fixtures/atomicBlocks.ts +7 -6
  161. package/templates/astro/starter-content/src/fixtures/composition.ts +3 -2
  162. package/templates/astro/starter-content/src/fixtures/sections.ts +3 -2
  163. package/templates/astro/starter-content/src/stories/CompositionStoryFrame.astro +7 -2
  164. package/templates/astro/template/.aci.yaml.tmpl +0 -1
  165. package/templates/astro/template/package.json.tmpl +5 -5
  166. package/templates/astro/template/src/layouts/SiteLayout.astro +2 -2
  167. package/templates/common/.agents/skills/aci/SKILL.md +58 -1
  168. package/templates/common/.agents/skills/authoring/SKILL.md +203 -43
  169. package/templates/common/.agents/skills/authoring/references/block-registry.md +19 -3
  170. package/templates/common/.agents/skills/authoring/references/block-slots.md +3 -0
  171. package/templates/common/.agents/skills/authoring/references/contracts.md +9 -30
  172. package/templates/common/.agents/skills/authoring/references/repo-structure.md +5 -4
  173. package/templates/common/.agents/skills/authoring/references/sdk-server-functions.md +3 -3
  174. package/templates/common/.agents/skills/dam-delivery/SKILL.md +214 -0
  175. package/templates/common/.agents/skills/dam-delivery/references/permalink-grammar.md +167 -0
  176. package/templates/common/.agents/skills/migration/references/canon-migration.md +18 -67
  177. package/templates/common/.agents/skills/migration/references/selector-map.md +1 -1
  178. package/templates/common/.content/fragments/navbar/_index.json +24 -0
  179. package/templates/common/.content/fragments/site-footer/_index.json +61 -0
  180. package/templates/common/.content/pages/404/_index.json +4 -2
  181. package/templates/common/.content/pages/{home/_index.json → _index.json} +10 -1
  182. package/templates/common/.content/pages/error/_index.json +4 -2
  183. package/templates/common/.content/schemas/site.schema.json +11 -1
  184. package/templates/common/.content/templates/error.json +24 -0
  185. package/templates/common/.content/templates/home.json +28 -0
  186. package/templates/common/.content/templates/site.json +8 -0
  187. package/templates/common/.content/templates/standard.json +24 -0
  188. package/templates/common/.nvmrc +1 -1
  189. package/templates/common/starter-content/.content/.rules-baseline.json +8 -0
  190. package/templates/common/starter-content/.content/config/site.json +1 -1
  191. package/templates/common/starter-content/.content/content-rules/no-public-resource-paths.json +6 -0
  192. package/templates/common/starter-content/.content/dam/README.md +74 -0
  193. package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/asset.json +1 -1
  194. package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/asset.json +1 -1
  195. package/templates/common/starter-content/.content/fragments/navbar/_index.json +23 -20
  196. package/templates/common/starter-content/.content/fragments/site-footer/_index.json +59 -56
  197. package/templates/common/starter-content/.content/pages/404/_index.json +2 -2
  198. package/templates/common/starter-content/.content/pages/{home/_index.json → _index.json} +23 -3
  199. package/templates/common/starter-content/.content/pages/about/_index.json +5 -2
  200. package/templates/common/starter-content/.content/pages/error/_index.json +2 -2
  201. package/templates/common/starter-content/.content/patterns/components/button.json +55 -0
  202. package/templates/common/starter-content/.content/patterns/components/container.json +67 -0
  203. package/templates/common/starter-content/.content/patterns/components/feature_card.json +30 -0
  204. package/templates/common/starter-content/.content/patterns/components/feature_grid.json +59 -0
  205. package/templates/common/starter-content/.content/patterns/components/home_hero.json +142 -0
  206. package/templates/common/starter-content/.content/patterns/components/personalization_choice.json +42 -0
  207. package/templates/common/starter-content/.content/patterns/components/site-footer.json +203 -0
  208. package/templates/common/starter-content/.content/patterns/components/site-navigation.json +115 -0
  209. package/templates/common/starter-content/.content/patterns/components/stats_bar.json +45 -0
  210. package/templates/common/starter-content/.content/schemas/site.schema.json +11 -1
  211. package/templates/nextjs/starter-content/src/components/chrome/Footer.tsx +4 -3
  212. package/templates/nextjs/starter-content/src/components/chrome/Header.tsx +4 -3
  213. package/templates/nextjs/starter-content/src/components/elements/Button.tsx +4 -3
  214. package/templates/nextjs/starter-content/src/components/elements/ButtonBlock.tsx +4 -3
  215. package/templates/nextjs/starter-content/src/components/sections/ContainerSection.tsx +4 -2
  216. package/templates/nextjs/starter-content/src/components/sections/FeatureCard.tsx +4 -3
  217. package/templates/nextjs/starter-content/src/components/sections/FeatureGrid.tsx +4 -2
  218. package/templates/nextjs/starter-content/src/components/sections/HomeHero.tsx +4 -3
  219. package/templates/nextjs/starter-content/src/components/sections/PersonalizationChoice.tsx +4 -2
  220. package/templates/nextjs/starter-content/src/components/sections/StatsBar.tsx +4 -3
  221. package/templates/nextjs/template/.aci.yaml +9 -0
  222. package/templates/nextjs/template/.aci.yaml.tmpl +0 -1
  223. package/templates/nextjs/template/package.json.tmpl +4 -3
  224. package/templates/nextjs/template/src/app/_components/c15t-bridge.ts +30 -0
  225. package/templates/nextjs/template/src/app/_components/c15t-consent-ui.tsx +37 -0
  226. package/templates/nextjs/template/src/app/_components/consent-manager.css +63 -0
  227. package/templates/nextjs/template/src/app/_components/consent-manager.tsx +76 -0
  228. package/templates/nextjs/template/src/app/fonts/inter/OFL.txt +93 -0
  229. package/templates/nextjs/template/src/app/fonts/inter/inter-latin.woff2 +0 -0
  230. package/templates/nextjs/template/src/app/fonts/space-grotesk/OFL.txt +93 -0
  231. package/templates/nextjs/template/src/app/fonts/space-grotesk/space-grotesk-latin.woff2 +0 -0
  232. package/templates/nextjs/template/src/app/layout.tsx +12 -7
  233. package/templates/nextjs/template/tests/conformance.test.ts.tmpl +1 -0
  234. package/dist/define-layout.d.ts +0 -6
  235. package/dist/define-layout.js +0 -14
  236. package/dist/edge/personalization-core.d.ts +0 -11
  237. package/dist/edge/personalization-core.js +0 -269
  238. package/dist/next/collect-route.d.ts +0 -19
  239. package/dist/next/collect-route.js +0 -459
  240. package/dist/next/envelope-digest.d.ts +0 -21
  241. package/dist/next/envelope-digest.js +0 -58
  242. package/dist/next/middleware.d.ts +0 -40
  243. package/dist/next/middleware.js +0 -475
  244. package/dist/next/personalization-host.d.ts +0 -134
  245. package/dist/next/personalization-host.js +0 -270
  246. package/dist/next/root-layout.d.ts +0 -4
  247. package/dist/next/root-layout.js +0 -5
  248. package/dist/next/vercel-collect-sdk-route.d.ts +0 -27
  249. package/dist/next/vercel-collect-sdk-route.js +0 -181
  250. package/dist/next/vercel-personalization.d.ts +0 -4
  251. package/dist/next/vercel-personalization.js +0 -4
  252. package/dist/next/vercel-s3-personalization.d.ts +0 -79
  253. package/dist/next/vercel-s3-personalization.js +0 -570
  254. package/dist/types/layout.d.ts +0 -24
  255. package/src/types/layout.ts +0 -29
  256. package/templates/astro/starter-content/src/render/RenderPage.astro +0 -67
  257. package/templates/astro/template/src/cms/contracts/layouts/index.ts +0 -18
  258. package/templates/nextjs/starter-content/src/components/elements/AtomicBlock.tsx +0 -13
  259. package/templates/nextjs/template/src/cms/contracts/layouts/index.ts +0 -16
  260. /package/dist/{types/layout.js → cli/mintlify-render.d.mts} +0 -0
  261. /package/templates/common/.content/overlays/audience/preference-blue/pages/{home/_index.json → _index.json} +0 -0
  262. /package/templates/common/.content/overlays/audience/preference-red/pages/{home/_index.json → _index.json} +0 -0
  263. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/editorial.json +0 -0
  264. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000101}/governance.json +0 -0
  265. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/versions/v0001.json +0 -0
  266. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/editorial.json +0 -0
  267. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000102}/governance.json +0 -0
  268. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/versions/v0001.json +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.52-rc.33
4
+
5
+ ### Migration required
6
+
7
+ - Next sites must set `registry` in `conformancePreset` (or
8
+ `runConformanceChecks`) to the render registry module used by their app, for
9
+ example `registry: 'src/cms/registry.ts'`. The default `rootIdentity` check
10
+ fails with configuration guidance when this option is absent. See
11
+ [the registry-selection migration](./migrations/conformance-registry.md).
12
+
13
+ ### Fixed
14
+
15
+ - Next `rootIdentity` imports only the site's explicitly named registry. It no
16
+ longer executes arbitrary source files containing `createRegistry(` or
17
+ silently checks a secondary registry.
18
+
19
+ ## Unreleased
20
+
21
+ **Public API removal:** `visitorProfileDataModel` is gone (see Removed
22
+ below) — delete it from any imports.
23
+
24
+ ### Changed
25
+
26
+ - The audience/experimentation author data models
27
+ (`packages/sdk/src/audience-data-models.ts`) are now generated from the Go
28
+ document readers' contracts (`scripts/generate-data-models.go`, verified in
29
+ CI by `make data-models-verify`) instead of hand-written. This fixes drift
30
+ toward the server contract: `experimentDataModel` gains `horizon` (with the
31
+ ADR 0042/0049 constraints), `promotedArmId`/`promotedAt`, and the
32
+ `eligibility.audienceRef` `$ref:audiences/{id}` grammar; rule and goal
33
+ expressions support nested all/any groups with the kernel's depth and
34
+ condition budgets; goal `eventRule` validates in event scope; segment
35
+ criteria accept the `geo` filter; providers require
36
+ `identity.absencePolicy` and enforce the format↔mapping matrix; ids use the
37
+ shared identifier grammar.
38
+
39
+ ### Fixed
40
+
41
+ - The `dam-delivery` agent skill shipped in the site templates described two
42
+ delivery lanes that no longer exist (signed `/dam/i/…` URLs and `/dam/a/…`
43
+ permalinks). It now describes the one public link, `/dam/{assetId}`, and
44
+ its `w`, `h`, `fit`, `fm`, `q` query. A site scaffolded earlier keeps its
45
+ old copy: replace its `.agents/skills/dam-delivery/` with
46
+ `templates/common/.agents/skills/dam-delivery/` from this package.
47
+
48
+ ### Removed
49
+
50
+ - `visitorProfileDataModel`: the schema had no server-side document contract
51
+ and no consumers. Drop it from imports; `audienceDataModels` no longer
52
+ includes it.
53
+
54
+ ## 0.1.52-rc.7 - 2026-08-19
55
+
56
+ ### Fixed
57
+
58
+ - Resolve Vercel SSR base and variant targets from the immutable `__r` path,
59
+ keeping `__variant` target identity separate from the logical public route.
60
+
3
61
  ## 0.1.45 - 2026-07-29
4
62
 
5
63
  ### Fixed
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Agentic Content Infrastructure SDK
2
2
 
3
- `@gradial/aci` `0.1.52-rc.3` is a pre-1.0 public-surface reset for the ACI
3
+ `@gradial/aci` `0.1.52-rc.33` is a pre-1.0 public-surface reset for the ACI
4
4
  client SDK. Breaking changes from the old `0.1.x` accidental surface are
5
5
  intentional: the root import is framework-neutral, framework runtime behavior is
6
6
  behind explicit subpaths, and the first required customer path is React/Next.
@@ -8,7 +8,7 @@ behind explicit subpaths, and the first required customer path is React/Next.
8
8
  ## Install
9
9
 
10
10
  ```bash
11
- npm install @gradial/aci@0.1.52-rc.3 zod@^4
11
+ npm install @gradial/aci@0.1.52-rc.33 zod@^4
12
12
  ```
13
13
 
14
14
  ## Root Import
@@ -62,6 +62,65 @@ export default withAci(nextConfig, {
62
62
 
63
63
  Astro public subpath is `@gradial/aci/astro`.
64
64
 
65
+ ## Page Templates
66
+
67
+ Pages use content-authored templates for region order, defaults, composition
68
+ rules, and personalization locks. Start with the [page templates guide](docs/page-templates.md),
69
+ including the `blog_body` contract pattern for page-specific container children.
70
+ [Component contracts](docs/component-contracts.md) define props and nested block types.
71
+
72
+ ## Block Root Identity
73
+
74
+ The renderer passes every block two props, `data-aci-block` (the authored
75
+ block id) and `data-aci-component`. A component extends `RootIdentityProps`
76
+ and spreads the rest of its props onto its root element, so analytics can join
77
+ events to content by (page path, block id):
78
+
79
+ ```tsx
80
+ import type { RootIdentityProps } from '@gradial/aci';
81
+
82
+ export function StatsBar({ stats = [], ...root }: ContentProps & RootIdentityProps) {
83
+ return <section {...root} className="…">…</section>;
84
+ }
85
+ ```
86
+
87
+ Three checks make this required: `createRegistry` fails typecheck for a
88
+ component whose props type lacks the keys, the default `rootIdentity`
89
+ conformance check renders every registered component and fails when the root
90
+ lacks the attributes, and publish rejects a release whose rendered HTML is
91
+ missing a block id. `runConformanceChecks` is async; `await` it before reading
92
+ `.passed`.
93
+
94
+ ## Mintlify
95
+
96
+ `@gradial/aci/mintlify` is the Mintlify adapter used automatically by the ACI
97
+ CLI. Mintlify remains the renderer; ACI owns the standard `.content` tree.
98
+ Documents use stable ACI component IDs and an
99
+ ordered recursive block tree: Markdown slices for prose, typed nested Mintlify
100
+ components and stable accessibility-safe anchors for common structures, and
101
+ explicit `mintlify.mdx` nodes for native syntax that has not been promoted to a
102
+ typed contract.
103
+
104
+ The source tree may also contain independently governed snippets, recursive
105
+ `docs.json` `$ref` fragments, and OpenAPI, AsyncAPI, or GraphQL descriptions:
106
+
107
+ ```text
108
+ .content/
109
+ config/site.json
110
+ config/mintlify.json
111
+ pages/**/_index.json
112
+ fragments/**/_index.json
113
+ ```
114
+
115
+ ```bash
116
+ aci content compile
117
+ ```
118
+
119
+ See `starters/mintlify/` for the smallest runnable site. `.aci.yaml` selects
120
+ `framework: mintlify`; no renderer or validation flag is needed. The command
121
+ validates the graph and writes the native project to
122
+ `.aci/compiled/renderers/mintlify/` beside the ordinary compiled manifest.
123
+
65
124
  ## Build-Time Content Provider
66
125
 
67
126
  The file provider reads compiler output while generating complete static pages:
@@ -78,13 +137,13 @@ host bundles select and serve immutable release artifacts.
78
137
  The first RC scaffold path is Next:
79
138
 
80
139
  ```bash
81
- npx @gradial/aci@0.1.52-rc.3 init my-site --template next-starter
140
+ npx @gradial/aci@0.1.52-rc.33 init my-site --template next-starter
82
141
  ```
83
142
 
84
143
  List available templates:
85
144
 
86
145
  ```bash
87
- npx @gradial/aci@0.1.52-rc.3 init --list
146
+ npx @gradial/aci@0.1.52-rc.33 init --list
88
147
  ```
89
148
 
90
149
  ## Personalization: The One-Tag Install
@@ -107,7 +166,7 @@ Tag attributes (the tag is the only per-site configuration surface):
107
166
 
108
167
  | Attribute | Meaning |
109
168
  | --- | --- |
110
- | `data-aci-consent` | CMP preset: `c15t`, `onetrust`, `cookiebot`, `trustarc`, or `manual` (default `manual` — only the JS consent API `aci('consent', …)` writes envelopes) |
169
+ | `data-aci-consent` | CMP preset: `c15t`, `onetrust`, `cookiebot`, `trustarc`, or `manual` (default `manual` — only the JS consent API `aci('consent', …)` writes envelopes). A CMP preset tells the SDK the CMP will decide: until it writes consent, a first-time visitor's events (the exposure and page view included) wait in page memory, are sent once consent is granted, and are dropped on denial or when the page closes undecided. Only name a preset whose CMP is actually wired. Under `manual`, ACI's own consent banner (`ConsentBanner.astro`) plays that role: while it awaits the visitor, first views are held the same way. |
111
170
  | `data-aci-consent-categories` | Flat comma list of CMP categories that imply the personalization purpose (e.g. `measurement,marketing`); each preset ships a sane default |
112
171
  | `data-aci-site` | Optional site ID, debug only — the edge binding is the site authority |
113
172
  | `data-aci-debug` | `1` enables structured `console.debug` diagnostics |
@@ -134,6 +193,28 @@ has no Astro UI package, so the Astro kit ships the bridge only (in
134
193
  `@c15t/react`) or any setup built on c15t's store and the bridge picks it
135
194
  up; until then only the `manual` JS consent API writes envelopes.
136
195
 
196
+ ### Client-side navigation and experiment attribution
197
+
198
+ Next `createPage` includes the completion hook. Custom Next pages must render
199
+ `<AssignmentsScript page={page} />` on every page, including pages without
200
+ experiments. Astro client routing uses `astro:page-load` after the document swap.
201
+ Rebuild sites using the SDK framework integration when upgrading this contract.
202
+
203
+ For another client router, call this command after committing the destination
204
+ page. Pass the new page's complete assignment set, or `[]` for a base page:
205
+
206
+ ```js
207
+ window.aci('navigation-complete', {
208
+ url: window.location.href,
209
+ assignments: page.experiments ?? [],
210
+ });
211
+ ```
212
+
213
+ Changing the URL immediately clears attribution. Events during the transition
214
+ carry no experiment context; the completion hook emits the new exposures and
215
+ page view before subsequent conversions. Query changes count as navigation;
216
+ hash-only changes and duplicate completions do not create another page view.
217
+
137
218
  ## Verify Locally
138
219
 
139
220
  From `packages/sdk`:
@@ -50,6 +50,7 @@ export async function getErrorPageData(astro, kind, options = {}) {
50
50
  if (resolved.route) {
51
51
  const slug = resolved.route.replace(/^\/+|\/+$/g, '');
52
52
  const data = await getPageData({
53
+ isPrerendered: astro.isPrerendered,
53
54
  params: { slug },
54
55
  request: astro.request,
55
56
  url: astro.url,
@@ -61,6 +61,10 @@ export function createRenderChildren(registry) {
61
61
  if (hasBlockSlots) {
62
62
  props.renderChildren = renderChildren;
63
63
  }
64
+ // sdk I-19 (ADR 0051): root identity props are applied last so content
65
+ // props cannot overwrite them. The template spreads them onto the root.
66
+ props['data-aci-block'] = block.id;
67
+ props['data-aci-component'] = block.component;
64
68
  return { Component: entry?.component, props };
65
69
  });
66
70
  }
@@ -31,12 +31,13 @@
31
31
  * iterate slots and render blocks via the registry.
32
32
  */
33
33
  import type { KernelPage, KernelSiteConfig, KernelRouteMetadata, KernelPageBlock } from '../content/types.js';
34
- import type { LayoutEntry } from '../content/provider.js';
34
+ import { type LayoutEntry } from '../content/provider.js';
35
35
  /**
36
36
  * Minimal Astro global shape — only the properties getPageData reads.
37
37
  * This avoids depending on Astro's own types at the SDK level.
38
38
  */
39
39
  export interface AstroGlobal {
40
+ isPrerendered?: boolean;
40
41
  params: {
41
42
  slug?: string;
42
43
  };
@@ -51,6 +52,8 @@ export interface AstroGlobal {
51
52
  export interface PageData {
52
53
  /** Route string (normalized, e.g. "/" or "/about"). */
53
54
  route: string;
55
+ /** Selected render tuple, including the explicit "base" identity. */
56
+ variantKey: string;
54
57
  /** Site configuration. */
55
58
  siteConfig: KernelSiteConfig;
56
59
  /** Page content. */
@@ -91,4 +94,4 @@ export interface GetPageDataOptions {
91
94
  * directly from CloudFront in production (the CDN points at the release
92
95
  * artifacts in S3, no runtime content fetching).
93
96
  */
94
- export declare function getPageData(astro: AstroGlobal, _options?: GetPageDataOptions): Promise<PageData>;
97
+ export declare function getPageData(astro: AstroGlobal, options?: GetPageDataOptions): Promise<PageData>;
@@ -30,11 +30,12 @@
30
30
  * The page template receives a typed data object and only needs to
31
31
  * iterate slots and render blocks via the registry.
32
32
  */
33
+ import { FragmentNotFoundError } from '../content/provider.js';
33
34
  import { normalizeRoute } from '../content/routes.js';
34
35
  import { routeMetadataForContent } from '../content/provider.js';
35
36
  import { resolveSlots } from '../content/resolve-slots.js';
36
37
  import { assignmentsScriptTagHTML, collectScriptTagHTML } from '../content/personalization.js';
37
- import { getPendingRenderInputFromHeaders } from '../runtime/page.js';
38
+ import { GRADIAL_RENDER_INPUT_HEADER, getPendingRenderInputFromHeaders } from '../runtime/page.js';
38
39
  // ---------------------------------------------------------------------------
39
40
  // Implementation
40
41
  // ---------------------------------------------------------------------------
@@ -52,23 +53,25 @@ import { getPendingRenderInputFromHeaders } from '../runtime/page.js';
52
53
  * directly from CloudFront in production (the CDN points at the release
53
54
  * artifacts in S3, no runtime content fetching).
54
55
  */
55
- export async function getPageData(astro, _options) {
56
+ export async function getPageData(astro, options) {
56
57
  const route = normalizeRoute(astro.params.slug ? `/${astro.params.slug}` : '/');
57
- // Check for preview render input first (same as Next.js tier 1)
58
- // Skip during prerender/static generation — request.headers is not available
58
+ // Static Astro generation is explicit; unexpected header access errors and
59
+ // expired render-input IDs must not turn a selected variant into local base.
59
60
  let runtimeInput = null;
60
- try {
61
- runtimeInput = getPendingRenderInputFromHeaders(astro.request.headers);
62
- }
63
- catch {
64
- // Astro throws when accessing request.headers during prerender — this is
65
- // expected and harmless; preview mode is a request-time concern.
61
+ if (!astro.isPrerendered) {
62
+ const headers = astro.request.headers;
63
+ runtimeInput = getPendingRenderInputFromHeaders(headers);
64
+ if (headers.has(GRADIAL_RENDER_INPUT_HEADER) && !runtimeInput) {
65
+ throw new Error(`ACI Astro render input is unavailable for route ${route}; refusing to render local base content`);
66
+ }
66
67
  }
67
68
  let siteConfig;
68
69
  let page;
69
70
  let providerModule = null;
70
71
  let provider = null;
72
+ let variantKey;
71
73
  if (runtimeInput) {
74
+ variantKey = requireVariantKey(runtimeInput.variantKey, route);
72
75
  siteConfig = runtimeInput.siteConfig;
73
76
  page = runtimeInput.page;
74
77
  }
@@ -76,19 +79,23 @@ export async function getPageData(astro, _options) {
76
79
  // Lazy-import FileContentProvider to avoid pulling it in when
77
80
  // preview render input is available
78
81
  providerModule = await import('../providers/file.js');
79
- provider = new providerModule.FileContentProvider();
82
+ provider = new providerModule.FileContentProvider(options?.compiledRoot);
80
83
  [siteConfig, page] = await Promise.all([
81
84
  provider.getSiteConfig(),
82
85
  provider.getPage(route),
83
86
  ]);
87
+ const entry = (await provider.listRoutes()).find((entry) => normalizeRoute(entry.path) === route);
88
+ variantKey = requireVariantKey(entry?.variantKey, route);
84
89
  }
85
90
  const meta = routeMetadataForContent(siteConfig, page);
86
91
  // Resolve layout: prefer render input, fall back to provider
87
- const layout = await resolveLayout(runtimeInput, provider, providerModule, page.layout);
92
+ const layout = await resolveLayout(runtimeInput, provider, page.layout, route);
88
93
  // Resolve slots: page regions filled, then layout fragment defaults
89
94
  const slots = await resolveSlots(layout, page?.regions || {}, async (id) => {
90
- if (runtimeInput?.fragments?.[id]) {
91
- return runtimeInput.fragments[id];
95
+ if (runtimeInput) {
96
+ if (Object.hasOwn(runtimeInput.fragments ?? {}, id))
97
+ return runtimeInput.fragments[id];
98
+ throw new FragmentNotFoundError(id, new Error('fragment is not bound by the selected page'));
92
99
  }
93
100
  const p = provider ?? new (await import('../providers/file.js')).FileContentProvider();
94
101
  return await p.getFragment(id);
@@ -97,22 +104,27 @@ export async function getPageData(astro, _options) {
97
104
  const isPreview = astro.url.searchParams.has('preview_token');
98
105
  const collectTag = isPreview ? '' : collectScriptTagHTML(siteConfig);
99
106
  const assignmentsTag = isPreview ? '' : assignmentsScriptTagHTML(page);
100
- return { route, siteConfig, page, meta, layout, slots, collectTag, assignmentsTag };
107
+ return { route, variantKey, siteConfig, page, meta, layout, slots, collectTag, assignmentsTag };
108
+ }
109
+ function requireVariantKey(value, route) {
110
+ if (typeof value !== 'string' || !value.trim() || value !== value.trim()) {
111
+ throw new Error(`ACI Astro render variant identity is missing or invalid for route ${route}; supply an explicit variantKey ("base" for an unpersonalized render)`);
112
+ }
113
+ return value;
101
114
  }
102
115
  // ---------------------------------------------------------------------------
103
116
  // Internal helpers
104
117
  // ---------------------------------------------------------------------------
105
- async function resolveLayout(runtimeInput, provider, providerModule, layoutName) {
106
- // Check render input first
107
- if (runtimeInput?.layouts?.[layoutName]) {
108
- return runtimeInput.layouts[layoutName];
118
+ async function resolveLayout(runtimeInput, provider, layoutName, route) {
119
+ if (runtimeInput) {
120
+ const layout = runtimeInput.layouts?.[layoutName];
121
+ if (!layout)
122
+ throw new Error(`ACI Astro render input for route ${route} is missing its selected layout ${JSON.stringify(layoutName)}`);
123
+ return layout;
109
124
  }
110
125
  // Fall back to provider
111
126
  if (provider) {
112
127
  return await provider.getLayout(layoutName);
113
128
  }
114
- // Last resort: create a new provider
115
- const mod = providerModule ?? await import('../providers/file.js');
116
- const p = new mod.FileContentProvider();
117
- return await p.getLayout(layoutName);
129
+ throw new Error(`ACI Astro content provider is unavailable for route ${route}`);
118
130
  }
@@ -1,9 +1,9 @@
1
- import { extractPreviewToken, resolvePreviewContext, createPreviewBannerHTML as coreCreatePreviewBannerHTML, createPreviewCookies as coreCreatePreviewCookies, previewSignKey, } from '../preview/core.js';
1
+ import { extractPreviewToken, parseCookies, resolvePreviewContext, createPreviewBannerHTML as coreCreatePreviewBannerHTML, createPreviewCookies as coreCreatePreviewCookies, previewSignKey, } from '../preview/core.js';
2
2
  export async function getPreviewMode(request, siteId) {
3
3
  const url = new URL(request.url);
4
4
  const token = extractPreviewToken({
5
5
  query: url.searchParams,
6
- cookies: parseCookieHeader(request.headers.get('cookie') || ''),
6
+ cookies: parseCookies(request.headers.get('cookie') || ''),
7
7
  authorization: request.headers.get('authorization') || undefined,
8
8
  });
9
9
  if (!token)
@@ -16,18 +16,3 @@ export function createPreviewBannerHTML(releaseId) {
16
16
  export function createPreviewCookies(token, releaseId) {
17
17
  return coreCreatePreviewCookies(token, releaseId);
18
18
  }
19
- function parseCookieHeader(header) {
20
- const cookies = new Map();
21
- for (const part of header.split(';')) {
22
- const trimmed = part.trim();
23
- if (!trimmed)
24
- continue;
25
- const idx = trimmed.indexOf('=');
26
- if (idx < 0)
27
- continue;
28
- const name = trimmed.slice(0, idx).trim();
29
- const value = trimmed.slice(idx + 1).trim();
30
- cookies.set(name, decodeURIComponent(value));
31
- }
32
- return cookies;
33
- }