@gradial/aci 0.1.52-rc.9 → 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.
Files changed (254) hide show
  1. package/CHANGELOG.md +126 -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 -197
  9. package/dist/audience-data-models.js +313 -51
  10. package/dist/cli/compile-registry.mjs +6 -34
  11. package/dist/cli/mintlify-render.mjs +8 -0
  12. package/dist/collect/aci.js +1 -1
  13. package/dist/collect/aci.js.sha256 +1 -1
  14. package/dist/collect/api.d.ts +6 -7
  15. package/dist/collect/api.js +21 -8
  16. package/dist/collect/assignments.d.ts +7 -9
  17. package/dist/collect/assignments.js +23 -32
  18. package/dist/collect/batcher.d.ts +9 -7
  19. package/dist/collect/batcher.js +6 -5
  20. package/dist/collect/consent/envelope.d.ts +7 -1
  21. package/dist/collect/consent/envelope.js +3 -1
  22. package/dist/collect/consent/mapping.d.ts +2 -0
  23. package/dist/collect/consent/mapping.js +1 -0
  24. package/dist/collect/consenthold.d.ts +38 -0
  25. package/dist/collect/consenthold.js +82 -0
  26. package/dist/collect/declarative.js +7 -5
  27. package/dist/collect/gapbuffer.d.ts +13 -4
  28. package/dist/collect/gapbuffer.js +21 -10
  29. package/dist/collect/index.js +78 -21
  30. package/dist/collect/pageviews.d.ts +11 -11
  31. package/dist/collect/pageviews.js +27 -22
  32. package/dist/consent-banner/index.d.ts +17 -0
  33. package/dist/consent-banner/index.js +23 -0
  34. package/dist/content/index.d.ts +2 -1
  35. package/dist/content/index.js +4 -1
  36. package/dist/content/provider.d.ts +16 -2
  37. package/dist/content/provider.js +5 -1
  38. package/dist/content/resolve-slots.d.ts +24 -2
  39. package/dist/content/resolve-slots.js +127 -21
  40. package/dist/content/types.d.ts +5 -1
  41. package/dist/edge/expression-capabilities.v1.d.ts +106 -0
  42. package/dist/edge/expression-capabilities.v1.js +165 -0
  43. package/dist/index.d.ts +1 -2
  44. package/dist/index.js +0 -1
  45. package/dist/internal/domain/edge/identity.d.ts +47 -4
  46. package/dist/internal/domain/edge/identity.js +130 -26
  47. package/dist/internal/domain/edge/index.d.ts +1 -1
  48. package/dist/internal/domain/edge/index.js +1 -1
  49. package/dist/internal/domain/edge/mimic_token.d.ts +14 -0
  50. package/dist/internal/domain/edge/mimic_token.js +125 -0
  51. package/dist/internal/domain/edge/personalization-core.d.ts +61 -22
  52. package/dist/internal/domain/edge/personalization-core.js +790 -200
  53. package/dist/internal/domain/edge/personalization_index.d.ts +17 -0
  54. package/dist/internal/domain/edge/personalization_index.js +55 -0
  55. package/dist/internal/domain/edge/resolve.js +76 -39
  56. package/dist/internal/domain/edge/testdata/flat_only_validator_v1.d.ts +10 -0
  57. package/dist/internal/domain/edge/testdata/flat_only_validator_v1.js +253 -0
  58. package/dist/internal/domain/edge/types.d.ts +82 -78
  59. package/dist/internal/domain/edge/types.js +3 -3
  60. package/dist/internal/domain/edge/variant_key.d.ts +4 -0
  61. package/dist/internal/domain/edge/variant_key.js +56 -0
  62. package/dist/internal/platform/collectionstore/errors.d.ts +24 -0
  63. package/dist/internal/platform/collectionstore/errors.js +48 -0
  64. package/dist/mintlify/blocks.d.ts +6 -0
  65. package/dist/mintlify/blocks.js +201 -0
  66. package/dist/mintlify/config.d.ts +3 -0
  67. package/dist/mintlify/config.js +77 -0
  68. package/dist/mintlify/index.d.ts +3 -0
  69. package/dist/mintlify/index.js +2 -0
  70. package/dist/mintlify/json.d.ts +8 -0
  71. package/dist/mintlify/json.js +37 -0
  72. package/dist/mintlify/materialize.d.ts +14 -0
  73. package/dist/mintlify/materialize.js +254 -0
  74. package/dist/mintlify/types.d.ts +74 -0
  75. package/dist/mintlify/types.js +1 -0
  76. package/dist/mintlify/validate.d.ts +7 -0
  77. package/dist/mintlify/validate.js +256 -0
  78. package/dist/next/assignments-navigation.d.ts +4 -0
  79. package/dist/next/assignments-navigation.js +18 -0
  80. package/dist/next/assignments-script.d.ts +3 -2
  81. package/dist/next/assignments-script.js +5 -5
  82. package/dist/next/error-pages.d.ts +4 -0
  83. package/dist/next/error-pages.js +4 -0
  84. package/dist/next/error-seat-payload.d.ts +2 -1
  85. package/dist/next/error-seat-payload.js +14 -24
  86. package/dist/next/error-seat.js +7 -2
  87. package/dist/next/index.d.ts +1 -1
  88. package/dist/next/index.js +3 -1
  89. package/dist/next/page.d.ts +2 -1
  90. package/dist/next/page.js +15 -4
  91. package/dist/next/release-context.d.ts +30 -0
  92. package/dist/next/release-context.js +56 -0
  93. package/dist/next/render.d.ts +1 -1
  94. package/dist/next/render.js +15 -5
  95. package/dist/next/server.d.ts +9 -3
  96. package/dist/next/server.js +17 -32
  97. package/dist/preview/core.d.ts +1 -0
  98. package/dist/preview/core.js +27 -0
  99. package/dist/react/VideoPlayer.d.ts +3 -3
  100. package/dist/react/index.d.ts +3 -3
  101. package/dist/registry.d.ts +4 -2
  102. package/dist/testing/conformance/checks.d.ts +2 -2
  103. package/dist/testing/conformance/checks.js +2 -0
  104. package/dist/testing/conformance/index.d.ts +1 -0
  105. package/dist/testing/conformance/index.js +1 -0
  106. package/dist/testing/conformance/next-stubs.d.ts +6 -0
  107. package/dist/testing/conformance/next-stubs.js +9 -0
  108. package/dist/testing/conformance/preset.d.ts +3 -2
  109. package/dist/testing/conformance/preset.js +15 -8
  110. package/dist/testing/conformance/root-identity.d.ts +31 -0
  111. package/dist/testing/conformance/root-identity.js +361 -0
  112. package/dist/testing/conformance/stubs/next-image.d.ts +7 -0
  113. package/dist/testing/conformance/stubs/next-image.js +5 -0
  114. package/dist/testing/conformance/stubs/next-link.d.ts +7 -0
  115. package/dist/testing/conformance/stubs/next-link.js +4 -0
  116. package/dist/testing/conformance/types.d.ts +5 -2
  117. package/dist/testing/index.d.ts +1 -1
  118. package/dist/testing/index.js +4 -3
  119. package/dist/types/block-ref.js +2 -2
  120. package/dist/types/component.d.ts +9 -0
  121. package/dist/types/config.d.ts +0 -1
  122. package/dist/types/index.d.ts +0 -1
  123. package/dist/types/index.js +0 -1
  124. package/dist/types/page.d.ts +0 -1
  125. package/migrations/conformance-registry.md +22 -0
  126. package/migrations/experiment-goal-ids.md +43 -0
  127. package/package.json +21 -7
  128. package/src/cli/compile-registry.mjs +6 -30
  129. package/src/cli/mintlify-render.mjs +9 -0
  130. package/src/types/block-ref.test.ts +16 -1
  131. package/src/types/block-ref.ts +2 -2
  132. package/src/types/component.ts +10 -0
  133. package/src/types/config.ts +0 -1
  134. package/src/types/index.ts +0 -1
  135. package/src/types/page.ts +0 -1
  136. package/templates/astro/starter-content/src/components/chrome/Footer.astro +5 -3
  137. package/templates/astro/starter-content/src/components/chrome/Header.astro +5 -3
  138. package/templates/astro/starter-content/src/components/elements/Button.astro +5 -2
  139. package/templates/astro/starter-content/src/components/elements/ButtonBlock.astro +5 -3
  140. package/templates/astro/starter-content/src/components/sections/ContainerSection.astro +4 -3
  141. package/templates/astro/starter-content/src/components/sections/FeatureCard.astro +4 -3
  142. package/templates/astro/starter-content/src/components/sections/FeatureGrid.astro +4 -3
  143. package/templates/astro/starter-content/src/components/sections/HomeHero.astro +5 -3
  144. package/templates/astro/starter-content/src/components/sections/PersonalizationChoice.astro +4 -3
  145. package/templates/astro/starter-content/src/components/sections/StatsBar.astro +4 -3
  146. package/templates/astro/starter-content/src/fixtures/sections.ts +1 -1
  147. package/templates/astro/starter-content/src/stories/CompositionStoryFrame.astro +7 -2
  148. package/templates/astro/template/.aci.yaml.tmpl +0 -1
  149. package/templates/astro/template/package.json.tmpl +5 -5
  150. package/templates/astro/template/src/layouts/SiteLayout.astro +2 -2
  151. package/templates/common/.agents/skills/aci/SKILL.md +58 -1
  152. package/templates/common/.agents/skills/authoring/SKILL.md +194 -42
  153. package/templates/common/.agents/skills/authoring/references/block-registry.md +19 -3
  154. package/templates/common/.agents/skills/authoring/references/contracts.md +9 -30
  155. package/templates/common/.agents/skills/authoring/references/repo-structure.md +5 -4
  156. package/templates/common/.agents/skills/authoring/references/sdk-server-functions.md +3 -3
  157. package/templates/common/.agents/skills/dam-delivery/SKILL.md +216 -0
  158. package/templates/common/.agents/skills/dam-delivery/references/permalink-grammar.md +167 -0
  159. package/templates/common/.agents/skills/migration/references/canon-migration.md +18 -67
  160. package/templates/common/.agents/skills/migration/references/selector-map.md +1 -1
  161. package/templates/common/.content/fragments/navbar/_index.json +24 -0
  162. package/templates/common/.content/fragments/site-footer/_index.json +61 -0
  163. package/templates/common/.content/pages/404/_index.json +4 -2
  164. package/templates/common/.content/pages/_index.json +0 -1
  165. package/templates/common/.content/pages/error/_index.json +4 -2
  166. package/templates/common/.content/schemas/site.schema.json +11 -1
  167. package/templates/common/.content/templates/error.json +24 -0
  168. package/templates/common/.content/templates/home.json +28 -0
  169. package/templates/common/.content/templates/site.json +8 -0
  170. package/templates/common/.content/templates/standard.json +24 -0
  171. package/templates/common/.nvmrc +1 -1
  172. package/templates/common/starter-content/.content/config/site.json +1 -1
  173. package/templates/common/starter-content/.content/dam/README.md +74 -0
  174. package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000101}/asset.json +1 -1
  175. package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000102}/asset.json +1 -1
  176. package/templates/common/starter-content/.content/pages/404/_index.json +1 -2
  177. package/templates/common/starter-content/.content/pages/{home/_index.json → _index.json} +14 -3
  178. package/templates/common/starter-content/.content/pages/about/_index.json +2 -2
  179. package/templates/common/starter-content/.content/pages/error/_index.json +1 -2
  180. package/templates/common/starter-content/.content/patterns/components/button.json +2 -2
  181. package/templates/common/starter-content/.content/patterns/components/container.json +8 -3
  182. package/templates/common/starter-content/.content/patterns/components/feature_card.json +2 -2
  183. package/templates/common/starter-content/.content/patterns/components/feature_grid.json +5 -3
  184. package/templates/common/starter-content/.content/patterns/components/home_hero.json +2 -2
  185. package/templates/common/starter-content/.content/patterns/components/personalization_choice.json +2 -2
  186. package/templates/common/starter-content/.content/patterns/components/site-footer.json +2 -2
  187. package/templates/common/starter-content/.content/patterns/components/site-navigation.json +2 -2
  188. package/templates/common/starter-content/.content/patterns/components/stats_bar.json +2 -2
  189. package/templates/common/starter-content/.content/schemas/site.schema.json +11 -1
  190. package/templates/nextjs/starter-content/src/components/chrome/Footer.tsx +4 -3
  191. package/templates/nextjs/starter-content/src/components/chrome/Header.tsx +4 -3
  192. package/templates/nextjs/starter-content/src/components/elements/Button.tsx +4 -3
  193. package/templates/nextjs/starter-content/src/components/elements/ButtonBlock.tsx +4 -3
  194. package/templates/nextjs/starter-content/src/components/sections/ContainerSection.tsx +4 -2
  195. package/templates/nextjs/starter-content/src/components/sections/FeatureCard.tsx +4 -3
  196. package/templates/nextjs/starter-content/src/components/sections/FeatureGrid.tsx +4 -2
  197. package/templates/nextjs/starter-content/src/components/sections/HomeHero.tsx +4 -3
  198. package/templates/nextjs/starter-content/src/components/sections/PersonalizationChoice.tsx +4 -2
  199. package/templates/nextjs/starter-content/src/components/sections/StatsBar.tsx +4 -3
  200. package/templates/nextjs/template/.aci.yaml +0 -1
  201. package/templates/nextjs/template/.aci.yaml.tmpl +0 -1
  202. package/templates/nextjs/template/package.json.tmpl +4 -3
  203. package/templates/nextjs/template/src/app/_components/c15t-bridge.ts +30 -0
  204. package/templates/nextjs/template/src/app/_components/c15t-consent-ui.tsx +37 -0
  205. package/templates/nextjs/template/src/app/_components/consent-manager.css +63 -0
  206. package/templates/nextjs/template/src/app/_components/consent-manager.tsx +76 -0
  207. package/templates/nextjs/template/src/app/fonts/inter/OFL.txt +93 -0
  208. package/templates/nextjs/template/src/app/fonts/inter/inter-latin.woff2 +0 -0
  209. package/templates/nextjs/template/src/app/fonts/space-grotesk/OFL.txt +93 -0
  210. package/templates/nextjs/template/src/app/fonts/space-grotesk/space-grotesk-latin.woff2 +0 -0
  211. package/templates/nextjs/template/src/app/layout.tsx +12 -7
  212. package/templates/nextjs/template/tests/conformance.test.ts.tmpl +1 -0
  213. package/dist/define-layout.d.ts +0 -6
  214. package/dist/define-layout.js +0 -14
  215. package/dist/edge/personalization-core.d.ts +0 -11
  216. package/dist/edge/personalization-core.js +0 -269
  217. package/dist/internal/domain/edge/compose.d.ts +0 -24
  218. package/dist/internal/domain/edge/compose.js +0 -89
  219. package/dist/internal/domain/edge/record/codec.d.ts +0 -71
  220. package/dist/internal/domain/edge/record/codec.js +0 -401
  221. package/dist/next/collect-route.d.ts +0 -19
  222. package/dist/next/collect-route.js +0 -459
  223. package/dist/next/edge-config.d.ts +0 -1
  224. package/dist/next/edge-config.js +0 -92
  225. package/dist/next/envelope-digest.d.ts +0 -21
  226. package/dist/next/envelope-digest.js +0 -58
  227. package/dist/next/middleware.d.ts +0 -40
  228. package/dist/next/middleware.js +0 -475
  229. package/dist/next/personalization-host.d.ts +0 -134
  230. package/dist/next/personalization-host.js +0 -270
  231. package/dist/next/root-layout.d.ts +0 -4
  232. package/dist/next/root-layout.js +0 -5
  233. package/dist/next/vercel-collect-sdk-route.d.ts +0 -27
  234. package/dist/next/vercel-collect-sdk-route.js +0 -181
  235. package/dist/next/vercel-edge-projection-v1.d.ts +0 -24
  236. package/dist/next/vercel-edge-projection-v1.js +0 -880
  237. package/dist/next/vercel-personalization.d.ts +0 -4
  238. package/dist/next/vercel-personalization.js +0 -4
  239. package/dist/next/vercel-s3-personalization.d.ts +0 -79
  240. package/dist/next/vercel-s3-personalization.js +0 -570
  241. package/dist/types/layout.d.ts +0 -24
  242. package/src/types/layout.ts +0 -29
  243. package/templates/astro/starter-content/src/render/RenderPage.astro +0 -67
  244. package/templates/astro/template/src/cms/contracts/layouts/index.ts +0 -18
  245. package/templates/common/starter-content/.content/patterns/layouts/default.json +0 -14
  246. package/templates/nextjs/starter-content/src/components/elements/AtomicBlock.tsx +0 -13
  247. package/templates/nextjs/template/src/cms/contracts/layouts/index.ts +0 -16
  248. /package/dist/{types/layout.js → cli/mintlify-render.d.mts} +0 -0
  249. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/editorial.json +0 -0
  250. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000101}/governance.json +0 -0
  251. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/versions/v0001.json +0 -0
  252. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/editorial.json +0 -0
  253. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000102}/governance.json +0 -0
  254. /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/versions/v0001.json +0 -0
@@ -1,26 +1,132 @@
1
- export async function resolveSlots(layout, pageRegions, getFragment) {
2
- const resolved = {};
3
- for (const slot of layout.slots) {
4
- const pageBlocks = pageRegions[slot.name];
5
- if (pageBlocks && pageBlocks.length > 0) {
6
- resolved[slot.name] = pageBlocks;
7
- continue;
1
+ /**
2
+ * Shared Go/TS limit contract (sdk I-21). These values are pinned against
3
+ * internal/domain/content/compiler/testdata/limit-conformance.v1.json by
4
+ * limit-conformance.test.ts (TS) and limit_conformance_test.go (Go); the
5
+ * compiler's MaxFragmentDepth/MaxExpandedBlocks must match.
6
+ */
7
+ /** Bounds a selected fragment reference chain, counting its root fragment. */
8
+ export const MAX_FRAGMENT_DEPTH = 10;
9
+ /** Bounds rendered component occurrences per page, including repeated placements. */
10
+ export const MAX_EXPANDED_BLOCKS = 4096;
11
+ /** Failures in a selected fragment are never eligible for local-content fallback. */
12
+ export class FragmentResolutionError extends Error {
13
+ constructor(message, options) {
14
+ super(message, options);
15
+ this.name = 'FragmentResolutionError';
16
+ }
17
+ }
18
+ // Runtime-only provenance keeps each fragment placement's authored IDs in its
19
+ // own validation scope. It is never emitted into compiled JSON or HTML.
20
+ export const fragmentRootScope = Symbol('aci.fragment-root-scope');
21
+ export function preserveFragmentScope(source, target) {
22
+ return Object.hasOwn(source, fragmentRootScope)
23
+ ? Object.defineProperty(target, fragmentRootScope, { value: true })
24
+ : target;
25
+ }
26
+ export async function resolveSlots(plan, pageRegions, getFragment) {
27
+ return resolveAsync(walkSlots(plan, pageRegions), getFragment);
28
+ }
29
+ /** The config-time error seat uses the identical traversal with synchronous file reads. */
30
+ export function resolveSlotsSync(plan, pageRegions, getFragment) {
31
+ const walk = walkSlots(plan, pageRegions);
32
+ let step = walk.next();
33
+ while (!step.done) {
34
+ let fragment;
35
+ try {
36
+ fragment = getFragment(step.value);
8
37
  }
9
- const defaults = layout.defaults?.[slot.name];
10
- if (defaults?.length) {
11
- const blocks = [];
12
- for (const ref of defaults) {
13
- const fragment = await getFragment(ref.fragmentId);
14
- const block = fragment.block ?? { component: fragment.component ?? '', props: fragment.props };
15
- blocks.push({
16
- $type: 'component',
17
- id: fragment.id ?? fragment.fragmentId ?? ref.fragmentId,
18
- component: block.component,
19
- props: block.props || {},
20
- });
21
- }
22
- resolved[slot.name] = blocks;
38
+ catch (cause) {
39
+ throw bindingError(step.value, cause);
23
40
  }
41
+ step = walk.next(fragment);
42
+ }
43
+ return step.value;
44
+ }
45
+ /** Resolve compiled references through the exact fragment bindings selected for this page. */
46
+ export async function resolveFragmentNodes(nodes, getFragment) {
47
+ return resolveAsync(walkNodes(nodes, { blocks: 0 }), getFragment);
48
+ }
49
+ async function resolveAsync(walk, getFragment) {
50
+ let step = walk.next();
51
+ while (!step.done) {
52
+ let fragment;
53
+ try {
54
+ fragment = await getFragment(step.value);
55
+ }
56
+ catch (cause) {
57
+ throw bindingError(step.value, cause);
58
+ }
59
+ step = walk.next(fragment);
60
+ }
61
+ return step.value;
62
+ }
63
+ function bindingError(id, cause) {
64
+ return new FragmentResolutionError(`ACI fragment ${id} selected binding failed: ${String(cause)}`, { cause });
65
+ }
66
+ function* walkSlots(plan, pageRegions) {
67
+ const resolved = {};
68
+ const state = { blocks: 0 };
69
+ for (const slot of plan.slots) {
70
+ const pageBlocks = pageRegions[slot.name];
71
+ const nodes = pageBlocks?.length ? pageBlocks : plan.defaults?.[slot.name];
72
+ if (nodes?.length)
73
+ resolved[slot.name] = yield* walkNodes(nodes, state);
24
74
  }
25
75
  return resolved;
26
76
  }
77
+ function* walkNodes(nodes, state) {
78
+ const blocks = [];
79
+ for (const node of nodes)
80
+ blocks.push((yield* walkValue(node, [], state)));
81
+ return blocks;
82
+ }
83
+ // Active ancestry belongs to each placement, while the block budget belongs to
84
+ // the whole rendered page. A repeated fragment in another branch is valid.
85
+ function* walkValue(value, ancestry, state) {
86
+ if (Array.isArray(value)) {
87
+ const result = [];
88
+ for (const child of value)
89
+ result.push(yield* walkValue(child, ancestry, state));
90
+ return result;
91
+ }
92
+ if (value === null || typeof value !== 'object')
93
+ return value;
94
+ const node = value;
95
+ if (node.kind === 'fragment-ref') {
96
+ const id = node.fragmentId;
97
+ if (typeof id !== 'string' || !id)
98
+ throw new FragmentResolutionError('ACI fragment reference has no fragmentId');
99
+ const chain = [...ancestry, id];
100
+ if (ancestry.includes(id))
101
+ throw new FragmentResolutionError(`ACI fragment cycle: ${chain.join(' -> ')}`);
102
+ if (chain.length > MAX_FRAGMENT_DEPTH)
103
+ throw new FragmentResolutionError(`ACI fragment depth exceeds ${MAX_FRAGMENT_DEPTH}: ${chain.join(' -> ')}`);
104
+ const fragment = yield id;
105
+ const block = (yield* walkValue(fragmentToBlock(fragment, id), chain, state));
106
+ return Object.defineProperty(block, fragmentRootScope, { value: true });
107
+ }
108
+ const isBlock = node.$type === 'component'
109
+ || (typeof node.component === 'string' && node.component.length > 0
110
+ && node.props !== null && typeof node.props === 'object' && !Array.isArray(node.props));
111
+ if (isBlock && ++state.blocks > MAX_EXPANDED_BLOCKS) {
112
+ throw new FragmentResolutionError(`ACI rendered page exceeds ${MAX_EXPANDED_BLOCKS} component blocks`);
113
+ }
114
+ const result = {};
115
+ for (const [key, child] of Object.entries(node))
116
+ result[key] = yield* walkValue(child, ancestry, state);
117
+ return preserveFragmentScope(node, result);
118
+ }
119
+ /** Use the same fragment root identity for layout defaults and region placements. */
120
+ export function fragmentToBlock(fragment, id) {
121
+ const block = fragment?.block ?? fragment;
122
+ if (!block || typeof block.component !== 'string' || !block.component
123
+ || (block.props !== undefined && (typeof block.props !== 'object' || block.props === null || Array.isArray(block.props)))) {
124
+ throw new FragmentResolutionError(`ACI fragment ${id} has no component block`);
125
+ }
126
+ return {
127
+ $type: 'component',
128
+ id: fragment.id ?? fragment.fragmentId ?? id,
129
+ component: block.component,
130
+ props: block.props || {},
131
+ };
132
+ }
@@ -1,4 +1,5 @@
1
1
  import type { ExperimentAssignmentContext, SitePersonalizationConfig } from './personalization.js';
2
+ import type { FragmentRefNode } from '../types/page.js';
2
3
  export type ButtonVariant = 'primary' | 'secondary' | 'tertiary' | 'outline' | 'ghost';
3
4
  export interface KernelImage {
4
5
  src: string;
@@ -47,6 +48,7 @@ export interface KernelPageBlock {
47
48
  component: string;
48
49
  props: Record<string, unknown>;
49
50
  }
51
+ export type KernelPageNode = KernelPageBlock | FragmentRefNode;
50
52
  export interface KernelAtomicBlock {
51
53
  $type: 'component';
52
54
  id: string;
@@ -59,7 +61,7 @@ export interface KernelPage {
59
61
  status: string;
60
62
  layout: string;
61
63
  metadata: KernelPageSeo;
62
- regions: Record<string, KernelPageBlock[]>;
64
+ regions: Record<string, KernelPageNode[]>;
63
65
  /**
64
66
  * Build-time experiment assignment context (personalization-reporting
65
67
  * design/04); present only on experiment variant payloads. The starters
@@ -110,6 +112,8 @@ export interface KernelRouteMetadata {
110
112
  }
111
113
  export interface RenderInput<TPage extends KernelPage = KernelPage, TSiteConfig extends KernelSiteConfig = KernelSiteConfig> {
112
114
  route: string;
115
+ /** Selected render tuple. Unpersonalized renders explicitly use "base". */
116
+ variantKey: string;
113
117
  domain: string;
114
118
  locale: string;
115
119
  siteConfig: TSiteConfig;
@@ -0,0 +1,106 @@
1
+ export declare const expressionCapabilities: {
2
+ readonly schemaVersion: 1;
3
+ readonly contract: "personalization-expression";
4
+ readonly maxConditions: 64;
5
+ readonly maxDepth: 5;
6
+ readonly maxInValues: 32;
7
+ readonly grammars: {
8
+ readonly number: "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?([eE][+-]?[0-9]+)?$";
9
+ readonly timestamp: "^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(\\.\\d{1,9})?(Z|[+-]\\d{2}:\\d{2})$";
10
+ };
11
+ readonly operators: readonly [{
12
+ readonly name: "equals";
13
+ readonly operand: "scalar";
14
+ readonly compact: "eq";
15
+ }, {
16
+ readonly name: "contains";
17
+ readonly operand: "scalar";
18
+ readonly compact: "ct";
19
+ }, {
20
+ readonly name: "startsWith";
21
+ readonly operand: "scalar";
22
+ readonly compact: "sw";
23
+ }, {
24
+ readonly name: "exists";
25
+ readonly operand: "optionalBoolean";
26
+ readonly compact: "ex";
27
+ }, {
28
+ readonly name: "greaterThan";
29
+ readonly operand: "number";
30
+ readonly compact: "gt";
31
+ }, {
32
+ readonly name: "greaterThanOrEqual";
33
+ readonly operand: "number";
34
+ readonly compact: "ge";
35
+ }, {
36
+ readonly name: "lessThan";
37
+ readonly operand: "number";
38
+ readonly compact: "lt";
39
+ }, {
40
+ readonly name: "lessThanOrEqual";
41
+ readonly operand: "number";
42
+ readonly compact: "le";
43
+ }, {
44
+ readonly name: "before";
45
+ readonly operand: "timestamp";
46
+ readonly compact: "bf";
47
+ }, {
48
+ readonly name: "after";
49
+ readonly operand: "timestamp";
50
+ readonly compact: "af";
51
+ }, {
52
+ readonly name: "between";
53
+ readonly operand: "range";
54
+ readonly compact: "bt";
55
+ readonly range: {
56
+ readonly memberTypes: readonly ["number", "timestamp"];
57
+ readonly homogeneous: true;
58
+ readonly inclusive: true;
59
+ };
60
+ }, {
61
+ readonly name: "in";
62
+ readonly operand: "scalarList";
63
+ readonly compact: "in";
64
+ readonly maxValues: 32;
65
+ }];
66
+ readonly scopes: readonly [{
67
+ readonly scope: "request";
68
+ readonly allowsEmpty: false;
69
+ readonly fields: readonly [{
70
+ readonly field: "referrer";
71
+ }, {
72
+ readonly field: "query.*";
73
+ }, {
74
+ readonly field: "header.*";
75
+ }, {
76
+ readonly field: "cookie.*";
77
+ }, {
78
+ readonly field: "geo.*";
79
+ }, {
80
+ readonly field: "utm.*";
81
+ }, {
82
+ readonly field: "device.class";
83
+ readonly operators: readonly ["equals", "in", "exists"];
84
+ readonly values: readonly ["desktop", "mobile", "tablet", "unknown"];
85
+ }, {
86
+ readonly field: "time.now";
87
+ readonly operators: readonly ["before", "after", "between", "exists"];
88
+ readonly instant: true;
89
+ }, {
90
+ readonly field: "audience.memberships";
91
+ readonly operators: readonly ["equals", "in", "exists"];
92
+ }];
93
+ }, {
94
+ readonly scope: "event";
95
+ readonly allowsEmpty: true;
96
+ readonly fields: readonly [{
97
+ readonly field: "referrer";
98
+ }, {
99
+ readonly field: "page.path";
100
+ }, {
101
+ readonly field: "properties.*";
102
+ }, {
103
+ readonly field: "utm.*";
104
+ }];
105
+ }];
106
+ };
@@ -0,0 +1,165 @@
1
+ // GENERATED by scripts/generate-expression-capabilities.go — DO NOT EDIT.
2
+ // Regenerate: make expression-capabilities
3
+ //
4
+ // The published capability discovery schema for the personalization
5
+ // expression contract (ADR 0038), generated from the Go vocabulary tables
6
+ // and drift-gated in CI against the canonical JSON artifact at
7
+ // internal/domain/personalization/expression/schema/.
8
+ export const expressionCapabilities = {
9
+ "schemaVersion": 1,
10
+ "contract": "personalization-expression",
11
+ "maxConditions": 64,
12
+ "maxDepth": 5,
13
+ "maxInValues": 32,
14
+ "grammars": {
15
+ "number": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?([eE][+-]?[0-9]+)?$",
16
+ "timestamp": "^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(\\.\\d{1,9})?(Z|[+-]\\d{2}:\\d{2})$"
17
+ },
18
+ "operators": [
19
+ {
20
+ "name": "equals",
21
+ "operand": "scalar",
22
+ "compact": "eq"
23
+ },
24
+ {
25
+ "name": "contains",
26
+ "operand": "scalar",
27
+ "compact": "ct"
28
+ },
29
+ {
30
+ "name": "startsWith",
31
+ "operand": "scalar",
32
+ "compact": "sw"
33
+ },
34
+ {
35
+ "name": "exists",
36
+ "operand": "optionalBoolean",
37
+ "compact": "ex"
38
+ },
39
+ {
40
+ "name": "greaterThan",
41
+ "operand": "number",
42
+ "compact": "gt"
43
+ },
44
+ {
45
+ "name": "greaterThanOrEqual",
46
+ "operand": "number",
47
+ "compact": "ge"
48
+ },
49
+ {
50
+ "name": "lessThan",
51
+ "operand": "number",
52
+ "compact": "lt"
53
+ },
54
+ {
55
+ "name": "lessThanOrEqual",
56
+ "operand": "number",
57
+ "compact": "le"
58
+ },
59
+ {
60
+ "name": "before",
61
+ "operand": "timestamp",
62
+ "compact": "bf"
63
+ },
64
+ {
65
+ "name": "after",
66
+ "operand": "timestamp",
67
+ "compact": "af"
68
+ },
69
+ {
70
+ "name": "between",
71
+ "operand": "range",
72
+ "compact": "bt",
73
+ "range": {
74
+ "memberTypes": [
75
+ "number",
76
+ "timestamp"
77
+ ],
78
+ "homogeneous": true,
79
+ "inclusive": true
80
+ }
81
+ },
82
+ {
83
+ "name": "in",
84
+ "operand": "scalarList",
85
+ "compact": "in",
86
+ "maxValues": 32
87
+ }
88
+ ],
89
+ "scopes": [
90
+ {
91
+ "scope": "request",
92
+ "allowsEmpty": false,
93
+ "fields": [
94
+ {
95
+ "field": "referrer"
96
+ },
97
+ {
98
+ "field": "query.*"
99
+ },
100
+ {
101
+ "field": "header.*"
102
+ },
103
+ {
104
+ "field": "cookie.*"
105
+ },
106
+ {
107
+ "field": "geo.*"
108
+ },
109
+ {
110
+ "field": "utm.*"
111
+ },
112
+ {
113
+ "field": "device.class",
114
+ "operators": [
115
+ "equals",
116
+ "in",
117
+ "exists"
118
+ ],
119
+ "values": [
120
+ "desktop",
121
+ "mobile",
122
+ "tablet",
123
+ "unknown"
124
+ ]
125
+ },
126
+ {
127
+ "field": "time.now",
128
+ "operators": [
129
+ "before",
130
+ "after",
131
+ "between",
132
+ "exists"
133
+ ],
134
+ "instant": true
135
+ },
136
+ {
137
+ "field": "audience.memberships",
138
+ "operators": [
139
+ "equals",
140
+ "in",
141
+ "exists"
142
+ ]
143
+ }
144
+ ]
145
+ },
146
+ {
147
+ "scope": "event",
148
+ "allowsEmpty": true,
149
+ "fields": [
150
+ {
151
+ "field": "referrer"
152
+ },
153
+ {
154
+ "field": "page.path"
155
+ },
156
+ {
157
+ "field": "properties.*"
158
+ },
159
+ {
160
+ "field": "utm.*"
161
+ }
162
+ ]
163
+ }
164
+ ]
165
+ };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  export { defineComponentContract } from './define-component.js';
2
- export { defineLayoutContract, slot, fragmentDefault } from './define-layout.js';
3
2
  export { createRegistry, registryLookup } from './registry.js';
4
3
  export type { Registry, RegistryEntry, AnyComponent } from './registry.js';
5
4
  export { blockRef, blockRefArray } from './types/block-ref.js';
6
5
  export type { BlockRef, BlockRefEntry, BlockRefMeta, BlockRefUnion } from './types/block-ref.js';
7
- export type { ComponentContract, ComponentContractID, ComponentContractValidator, ComponentRegistry, ComponentValidationContext, ComponentValidationIssue, InferComponentProps, } from './types/component.js';
6
+ export type { ComponentContract, ComponentContractID, ComponentContractValidator, ComponentRegistry, ComponentValidationContext, ComponentValidationIssue, InferComponentProps, RootIdentityProps, } from './types/component.js';
8
7
  export { ImageSchema, imageAttrs, primaryImageSource, type Image, type ImageSource, type ImageAttrs, type ImageSlotContract, type SlotOutput, } from './types/image.js';
9
8
  export { LinkSchema, type Link, type LinkTarget, type LinkResolverContext, resolveLink, resolveHref, assertSafeHref, normalizeLinkRel, } from './types/link.js';
10
9
  export { HeadingSchema, InlineContentSchema, RichTextValueSchema, type Heading, type InlineContent, type RichTextValue, } from './types/rich-text.js';
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  export { defineComponentContract } from './define-component.js';
2
- export { defineLayoutContract, slot, fragmentDefault } from './define-layout.js';
3
2
  export { createRegistry, registryLookup } from './registry.js';
4
3
  export { blockRef, blockRefArray } from './types/block-ref.js';
5
4
  export { ImageSchema, imageAttrs, primaryImageSource, } from './types/image.js';
@@ -1,14 +1,57 @@
1
- import type { IdentitySigningKeys, SigningKey, CookieMutation, ConsentSnapshot, ConsentSignals } from './types.js';
1
+ import type { IdentitySigningKeys, SigningKey, ConsentSnapshot, ConsentSignals } from './types.js';
2
2
  export declare const DEFAULT_IDENTITY_TTL_SECONDS: number;
3
3
  export declare function parseCookieHeader(value: string | null): Map<string, string>;
4
4
  export declare function consentSignals(request: Request, cookies: Map<string, string>): ConsentSignals;
5
+ export declare function identityIssuancePermitted(consent: ConsentSignals, country: string, optOutCountries: readonly string[]): boolean;
5
6
  export declare function parseConsent(raw: string, decodeCookieValue?: boolean): ConsentSnapshot | null;
6
7
  export declare function trimConsentWhitespace(value: string): string;
7
8
  export declare function verifyIdentityCookie(value: string, keys: IdentitySigningKeys): Promise<string | null>;
8
9
  export declare function signIdentity(rawID: string, key: SigningKey): Promise<string>;
9
10
  export declare function randomIdentity(random?: (length: number) => Uint8Array): string;
10
11
  export declare function identityHashHex(namespace: string, value: string): Promise<string>;
11
- export declare function sha256Hex(value: string): Promise<string>;
12
12
  export declare function verifyClaims(value: string, keys: Record<string, string>, now: Date): Promise<Record<string, unknown> | null>;
13
- export declare function cookieMutation(name: string, value: string, maxAge: number, now: Date, secure: boolean, httpOnly: boolean): CookieMutation;
14
- export declare function expireCookie(name: string, secure: boolean): CookieMutation;
13
+ export declare function verifyClaimsEvidence(value: string, keys: Record<string, string>, now: Date): Promise<Record<string, unknown> | null>;
14
+ /**
15
+ * The minting path that signed an aci_claims value: 'aci' claims contain
16
+ * first-party memberships only; 'edge' claims are the minted first-party ∪
17
+ * external union and require a matching live b2 receipt on a
18
+ * provider-enabled release.
19
+ */
20
+ export type ClaimsIssuer = 'aci' | 'edge';
21
+ /**
22
+ * Exposes the payload's `iss` marker. Malformed/unknown markers — and
23
+ * pre-0059 unmarked payloads — yield undefined; since the §6 cutover,
24
+ * verifyClaims rejects those payloads outright, so a verified payload always
25
+ * carries a marker. The marker identifies the minting path; it does not
26
+ * grant membership by itself.
27
+ */
28
+ export declare function claimsIssuer(payload: Record<string, unknown> | null): ClaimsIssuer | undefined;
29
+ /** audience.MaxClaimsCookieBytes — the hard 1 KiB aci_claims budget. */
30
+ export declare const MAX_CLAIMS_COOKIE_BYTES = 1024;
31
+ /** audience.DefaultClaimsTTL — the 24-hour signed-lifetime ceiling. */
32
+ export declare const DEFAULT_CLAIMS_TTL_SECONDS: number;
33
+ /**
34
+ * Mint rejection: oversize, a malformed key, or a missing issuer marker.
35
+ * Callers fail closed on it — the edge never truncates or subsets
36
+ * memberships to fit (ADR 0059 §2/§3).
37
+ */
38
+ export declare class ClaimsMintError extends Error {
39
+ readonly name = "ClaimsMintError";
40
+ }
41
+ /**
42
+ * Mints one signed aci_claims value: v1.{kid}.{base64url(payload)}.{hmac},
43
+ * byte-identical to Go's ClaimsIssuer.IssueClaims — payload field order is
44
+ * aud (omitted when empty), seg (omitted when empty), iat, exp, iss, and the
45
+ * TTL clamps to the 24-hour ceiling. The exact bytes are pinned against the
46
+ * Go golden in claims_contract.test.ts. Issuance requires an explicit issuer
47
+ * marker; the marker identifies the minting path, it does not grant
48
+ * membership by itself.
49
+ */
50
+ export declare function issueClaims(memberships: {
51
+ aud?: string[];
52
+ seg?: string[];
53
+ }, issuer: ClaimsIssuer, key: SigningKey, now: Date, ttlSeconds?: number): Promise<string>;
54
+ export declare function verifyHMAC(value: string, signature: string, secret: string): Promise<boolean>;
55
+ export declare function hmacSHA256(value: string, secret: string): Promise<string>;
56
+ export declare function base64URLEncode(bytes: Uint8Array): string;
57
+ export declare function base64URLDecode(value: string): Uint8Array;