@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.
- 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
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conformance check: rootIdentity (ADR 0051).
|
|
3
|
+
*
|
|
4
|
+
* The ACI renderer passes every block `data-aci-block` and
|
|
5
|
+
* `data-aci-component` as props; a component must spread them onto the
|
|
6
|
+
* element it returns. The registry type constraint proves a component
|
|
7
|
+
* declares the props. This check proves it renders them, by rendering every
|
|
8
|
+
* registered component through the SDK's own seam and reading the root of
|
|
9
|
+
* the markup.
|
|
10
|
+
*
|
|
11
|
+
* Next: components are rendered with react-dom/server from the site's own
|
|
12
|
+
* node_modules; next/link and next/image are stubbed (see next-stubs.ts)
|
|
13
|
+
* because their CommonJS interop objects cannot render outside Next.
|
|
14
|
+
* Astro: components cannot be rendered outside Astro, so the built site's
|
|
15
|
+
* HTML is scanned for every authored block id instead (building first when
|
|
16
|
+
* `dist/` is absent).
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
19
|
+
import { createRequire } from 'node:module';
|
|
20
|
+
import { join, relative, resolve } from 'node:path';
|
|
21
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
22
|
+
import { execSync } from 'node:child_process';
|
|
23
|
+
const CHECK = 'rootIdentity';
|
|
24
|
+
const LABEL = 'components render data-aci-block on their root element';
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Pure core (unit-tested with in-memory registries)
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Render each block through the SDK renderer and report every component
|
|
30
|
+
* whose root element lacks the identity attributes. `blocks` are the blocks
|
|
31
|
+
* to exercise; registry entries not covered by a block are probed with empty
|
|
32
|
+
* props so an unused component cannot hide a forgotten spread.
|
|
33
|
+
*/
|
|
34
|
+
export async function findRootIdentityFailures(registry, blocks, react, fileFor = () => undefined) {
|
|
35
|
+
const { renderBlock } = await import('../../next/render.js');
|
|
36
|
+
const failures = new Map();
|
|
37
|
+
const covered = new Set();
|
|
38
|
+
const probe = async (block, contentBacked) => {
|
|
39
|
+
if (failures.has(block.component))
|
|
40
|
+
return;
|
|
41
|
+
const element = await renderBlock(block, registry, `probe:${block.id}`);
|
|
42
|
+
let html;
|
|
43
|
+
try {
|
|
44
|
+
html = await markupFor(element, react);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
// A component the content never uses is probed with empty props; if it
|
|
48
|
+
// needs real props to render, that proves nothing about identity, so
|
|
49
|
+
// it is skipped rather than reported. Content-backed renders that
|
|
50
|
+
// throw are real failures.
|
|
51
|
+
if (!contentBacked)
|
|
52
|
+
return;
|
|
53
|
+
failures.set(block.component, {
|
|
54
|
+
component: block.component,
|
|
55
|
+
file: fileFor(block.component),
|
|
56
|
+
missing: [`render threw: ${err instanceof Error ? err.message : String(err)}`],
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const root = rootAttributes(html);
|
|
61
|
+
const missing = [];
|
|
62
|
+
if (root.block !== block.id)
|
|
63
|
+
missing.push('data-aci-block');
|
|
64
|
+
if (root.component !== block.component)
|
|
65
|
+
missing.push('data-aci-component');
|
|
66
|
+
if (missing.length > 0) {
|
|
67
|
+
failures.set(block.component, { component: block.component, file: fileFor(block.component), missing });
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
for (const block of blocks) {
|
|
71
|
+
if (!registry.some((entry) => entry.id === block.component))
|
|
72
|
+
continue;
|
|
73
|
+
covered.add(block.component);
|
|
74
|
+
await probe(block, true);
|
|
75
|
+
}
|
|
76
|
+
for (const entry of registry) {
|
|
77
|
+
if (covered.has(entry.id))
|
|
78
|
+
continue;
|
|
79
|
+
await probe({ $type: 'component', id: `probe-${entry.id}`, component: entry.id, props: {} }, false);
|
|
80
|
+
}
|
|
81
|
+
return [...failures.values()];
|
|
82
|
+
}
|
|
83
|
+
/** The failure message: one line of what, the list, one line of fix. */
|
|
84
|
+
export function formatRootIdentityFailures(failures, framework) {
|
|
85
|
+
const width = Math.max(...failures.map((f) => f.component.length), 0);
|
|
86
|
+
const lines = failures.map((f) => {
|
|
87
|
+
const note = f.missing.length === 1 && f.missing[0].startsWith('data-aci-') && f.missing[0] !== 'data-aci-block'
|
|
88
|
+
? `(missing ${f.missing[0]})`
|
|
89
|
+
: f.missing[0]?.startsWith('render threw') ? `(${f.missing[0]})` : '';
|
|
90
|
+
return [' ' + f.component.padEnd(width), f.file, note].filter(Boolean).join(' ');
|
|
91
|
+
});
|
|
92
|
+
const fix = framework === 'next'
|
|
93
|
+
? [
|
|
94
|
+
'Fix: extend RootIdentityProps and spread the rest props onto the root:',
|
|
95
|
+
' function StatsBar({ stats, ...root }: StatsBarProps) { return <section {...root} …',
|
|
96
|
+
]
|
|
97
|
+
: [
|
|
98
|
+
'Fix: extend RootIdentityProps and spread the rest props onto the root:',
|
|
99
|
+
' const { stats, ...root } = Astro.props; <section {...root} …',
|
|
100
|
+
];
|
|
101
|
+
return [
|
|
102
|
+
`${CHECK}: ${failures.length} component${failures.length === 1 ? '' : 's'} do${failures.length === 1 ? 'es' : ''} not render data-aci-block on their root element`,
|
|
103
|
+
'',
|
|
104
|
+
...lines,
|
|
105
|
+
'',
|
|
106
|
+
...fix,
|
|
107
|
+
].join('\n');
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Slot components are async server components in Next; react-dom/server
|
|
111
|
+
* cannot render those, so the element the SDK produced is unwrapped by
|
|
112
|
+
* awaiting the component function directly.
|
|
113
|
+
*/
|
|
114
|
+
async function markupFor(element, react) {
|
|
115
|
+
const el = element;
|
|
116
|
+
const type = el.type;
|
|
117
|
+
if (typeof type === 'function' && type.constructor?.name === 'AsyncFunction') {
|
|
118
|
+
const resolved = await type(el.props);
|
|
119
|
+
return react.renderToStaticMarkup(resolved);
|
|
120
|
+
}
|
|
121
|
+
return react.renderToStaticMarkup(element);
|
|
122
|
+
}
|
|
123
|
+
function rootAttributes(html) {
|
|
124
|
+
// react-dom hoists resource hints (<link rel="preload">, <meta>) ahead of
|
|
125
|
+
// the component's markup; they are not the root element.
|
|
126
|
+
const body = html.trim().replace(/^(?:<(?:link|meta)\b[^>]*\/?>\s*)+/i, '');
|
|
127
|
+
const root = /^<([a-z][a-z0-9-]*)([^>]*)>/i.exec(body);
|
|
128
|
+
if (!root)
|
|
129
|
+
return {};
|
|
130
|
+
const attrs = root[2];
|
|
131
|
+
return {
|
|
132
|
+
block: /\sdata-aci-block="([^"]*)"/.exec(attrs)?.[1],
|
|
133
|
+
component: /\sdata-aci-component="([^"]*)"/.exec(attrs)?.[1],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
// Site integration
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
export async function checkRootIdentity(ctx) {
|
|
140
|
+
return ctx.framework === 'next' ? checkNextRootIdentity(ctx) : checkAstroRootIdentity(ctx);
|
|
141
|
+
}
|
|
142
|
+
async function checkNextRootIdentity(ctx) {
|
|
143
|
+
if (!ctx.registry?.trim()) {
|
|
144
|
+
return [fail(`${CHECK}: set the conformance registry option to the render registry module used by the app`)];
|
|
145
|
+
}
|
|
146
|
+
const registryFile = resolve(ctx.rootDir, ctx.registry);
|
|
147
|
+
if (!existsSync(registryFile) || !statSync(registryFile).isFile()) {
|
|
148
|
+
return [fail(`${CHECK}: registry module does not exist: ${ctx.registry}`)];
|
|
149
|
+
}
|
|
150
|
+
const siteRequire = createRequire(join(ctx.rootDir, 'package.json'));
|
|
151
|
+
let react;
|
|
152
|
+
try {
|
|
153
|
+
react = siteRequire('react-dom/server');
|
|
154
|
+
// The site's tsconfig may keep `jsx: preserve` for Next, in which case
|
|
155
|
+
// the test transform emits classic React.createElement calls.
|
|
156
|
+
globalThis.React = siteRequire('react');
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
return [fail(`${CHECK}: cannot load react-dom/server from the site (${err instanceof Error ? err.message : String(err)})`)];
|
|
160
|
+
}
|
|
161
|
+
const { register } = await import('node:module');
|
|
162
|
+
register(stubHookURL());
|
|
163
|
+
let mod;
|
|
164
|
+
try {
|
|
165
|
+
mod = (await import(pathToFileURL(registryFile).href));
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
return [fail(`${CHECK}: cannot load ${relative(ctx.rootDir, registryFile)} (${err instanceof Error ? err.message : String(err)})`)];
|
|
169
|
+
}
|
|
170
|
+
const registry = Object.values(mod).find(isRegistry);
|
|
171
|
+
if (!registry) {
|
|
172
|
+
return [fail(`${CHECK}: ${relative(ctx.rootDir, registryFile)} does not export the createRegistry result`)];
|
|
173
|
+
}
|
|
174
|
+
const source = readFileSync(registryFile, 'utf8');
|
|
175
|
+
const failures = await findRootIdentityFailures(registry, compiledBlocks(ctx.rootDir), react, componentFileResolver(source, registry));
|
|
176
|
+
if (failures.length === 0) {
|
|
177
|
+
return [ok(`${registry.length} registered components`)];
|
|
178
|
+
}
|
|
179
|
+
return [fail(formatRootIdentityFailures(failures, 'next'))];
|
|
180
|
+
}
|
|
181
|
+
async function checkAstroRootIdentity(ctx) {
|
|
182
|
+
const distDir = join(ctx.rootDir, 'dist');
|
|
183
|
+
if (!existsSync(distDir) || distIsStale(distDir, [join(ctx.rootDir, 'src'), join(ctx.rootDir, '.content')])) {
|
|
184
|
+
try {
|
|
185
|
+
execSync('npm run build', { cwd: ctx.rootDir, stdio: 'pipe', timeout: 300_000, env: { ...process.env, NODE_ENV: 'production' } });
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
const stderr = err instanceof Error && 'stderr' in err ? String(err.stderr).slice(0, 500) : String(err);
|
|
189
|
+
return [fail(`${CHECK}: npm run build failed, cannot scan dist/ (${stderr})`)];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const authored = astroAuthoredBlocks(join(ctx.rootDir, '.content'));
|
|
193
|
+
if (authored.length === 0) {
|
|
194
|
+
return [fail(`${CHECK}: no authored blocks found under .content/pages`)];
|
|
195
|
+
}
|
|
196
|
+
const html = walkHTML(distDir).map((file) => readFileSync(file, 'utf8')).join('\n');
|
|
197
|
+
const missing = authored.filter(({ id, component }) => {
|
|
198
|
+
const pattern = new RegExp(`<[a-z][^>]*(?:data-aci-block="${escapeRegExp(id)}"[^>]*data-aci-component="${escapeRegExp(component)}"` +
|
|
199
|
+
`|data-aci-component="${escapeRegExp(component)}"[^>]*data-aci-block="${escapeRegExp(id)}")`);
|
|
200
|
+
return !pattern.test(html);
|
|
201
|
+
});
|
|
202
|
+
if (missing.length === 0) {
|
|
203
|
+
return [ok(`${authored.length} authored blocks found on component roots in dist/`)];
|
|
204
|
+
}
|
|
205
|
+
const byComponent = new Map();
|
|
206
|
+
for (const m of missing) {
|
|
207
|
+
if (!byComponent.has(m.component))
|
|
208
|
+
byComponent.set(m.component, { component: m.component, missing: ['data-aci-block'] });
|
|
209
|
+
}
|
|
210
|
+
return [fail(formatRootIdentityFailures([...byComponent.values()], 'astro'))];
|
|
211
|
+
}
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
// Helpers
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
/** The stub hook next to this module: compiled `.js` in dist, `.ts` when run from source. */
|
|
216
|
+
function stubHookURL() {
|
|
217
|
+
const js = new URL('./next-stubs.js', import.meta.url);
|
|
218
|
+
if (existsSync(fileURLToPath(js)))
|
|
219
|
+
return js;
|
|
220
|
+
return new URL('./next-stubs.ts', import.meta.url);
|
|
221
|
+
}
|
|
222
|
+
function ok(detail) {
|
|
223
|
+
return { name: CHECK, label: LABEL, ok: true, detail };
|
|
224
|
+
}
|
|
225
|
+
// A failure's label is the message itself so the test runner prints it
|
|
226
|
+
// without a generic prefix; the check name is the first word of the message.
|
|
227
|
+
function fail(message) {
|
|
228
|
+
return { name: CHECK, label: message, ok: false };
|
|
229
|
+
}
|
|
230
|
+
function isRegistry(value) {
|
|
231
|
+
return Array.isArray(value) && value.length > 0
|
|
232
|
+
&& value.every((e) => e && typeof e === 'object' && typeof e.id === 'string' && 'component' in e && 'contract' in e);
|
|
233
|
+
}
|
|
234
|
+
/** Map a registered component id to the import path the registry file names for it. */
|
|
235
|
+
function componentFileResolver(registrySource, registry) {
|
|
236
|
+
const imports = new Map();
|
|
237
|
+
for (const m of registrySource.matchAll(/import\s+(?:\{([^}]*)\}|(\w+))\s+from\s+['"]([^'"]+)['"]/g)) {
|
|
238
|
+
const names = (m[1] ?? m[2]).split(',').map((n) => n.trim().split(/\s+as\s+/).pop()).filter(Boolean);
|
|
239
|
+
for (const name of names)
|
|
240
|
+
imports.set(name, m[3]);
|
|
241
|
+
}
|
|
242
|
+
const byId = new Map();
|
|
243
|
+
for (const entry of registry) {
|
|
244
|
+
const fn = entry.component;
|
|
245
|
+
const file = typeof fn === 'function' && fn.name ? imports.get(fn.name) : undefined;
|
|
246
|
+
if (file)
|
|
247
|
+
byId.set(entry.id, file);
|
|
248
|
+
}
|
|
249
|
+
return (component) => byId.get(component);
|
|
250
|
+
}
|
|
251
|
+
/** Blocks from the site's compiled content, when `npm run content:compile` has run. */
|
|
252
|
+
function compiledBlocks(rootDir) {
|
|
253
|
+
const compiled = join(rootDir, '.aci', 'compiled');
|
|
254
|
+
if (!existsSync(compiled))
|
|
255
|
+
return [];
|
|
256
|
+
const blocks = [];
|
|
257
|
+
const routes = join(compiled, 'routes');
|
|
258
|
+
if (existsSync(routes)) {
|
|
259
|
+
for (const file of walkJSON(routes)) {
|
|
260
|
+
const doc = JSON.parse(readFileSync(file, 'utf8'));
|
|
261
|
+
for (const region of Object.values(doc.regions ?? {}))
|
|
262
|
+
blocks.push(...region);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const fragments = join(compiled, 'fragments');
|
|
266
|
+
if (existsSync(fragments)) {
|
|
267
|
+
for (const file of walkJSON(fragments)) {
|
|
268
|
+
const doc = JSON.parse(readFileSync(file, 'utf8'));
|
|
269
|
+
if (doc.block) {
|
|
270
|
+
const id = file.slice(fragments.length + 1).replace(/\.json$/, '');
|
|
271
|
+
blocks.push({ $type: 'component', id, component: doc.block.component, props: doc.block.props });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return blocks;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Every block the Astro scan must find in dist/: page blocks by their own id,
|
|
279
|
+
* plus fragments (navbar, footer) by fragment id, which is the block id the
|
|
280
|
+
* renderer synthesizes when a layout slot default places them.
|
|
281
|
+
*/
|
|
282
|
+
export function astroAuthoredBlocks(contentDir) {
|
|
283
|
+
const out = authoredBlocks(join(contentDir, 'pages'));
|
|
284
|
+
const fragmentsDir = join(contentDir, 'fragments');
|
|
285
|
+
if (existsSync(fragmentsDir)) {
|
|
286
|
+
for (const entry of readdirSync(fragmentsDir, { withFileTypes: true })) {
|
|
287
|
+
if (!entry.isDirectory())
|
|
288
|
+
continue;
|
|
289
|
+
const file = join(fragmentsDir, entry.name, '_index.json');
|
|
290
|
+
if (!existsSync(file))
|
|
291
|
+
continue;
|
|
292
|
+
const doc = JSON.parse(readFileSync(file, 'utf8'));
|
|
293
|
+
const component = doc.block?.component;
|
|
294
|
+
if (typeof component === 'string' && component !== '') {
|
|
295
|
+
out.push({ id: doc.fragmentId ?? entry.name, component });
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return out;
|
|
300
|
+
}
|
|
301
|
+
/** dist/ is stale when any source or content file is newer than its newest output. */
|
|
302
|
+
function distIsStale(distDir, inputs) {
|
|
303
|
+
const newest = (dir) => {
|
|
304
|
+
if (!existsSync(dir))
|
|
305
|
+
return 0;
|
|
306
|
+
let max = 0;
|
|
307
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
308
|
+
const full = join(dir, entry.name);
|
|
309
|
+
max = Math.max(max, entry.isDirectory() ? newest(full) : statSync(full).mtimeMs);
|
|
310
|
+
}
|
|
311
|
+
return max;
|
|
312
|
+
};
|
|
313
|
+
const built = newest(distDir);
|
|
314
|
+
return inputs.some((dir) => newest(dir) > built);
|
|
315
|
+
}
|
|
316
|
+
function authoredBlocks(pagesDir) {
|
|
317
|
+
if (!existsSync(pagesDir))
|
|
318
|
+
return [];
|
|
319
|
+
const out = [];
|
|
320
|
+
const collect = (value) => {
|
|
321
|
+
if (Array.isArray(value)) {
|
|
322
|
+
value.forEach(collect);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
if (!value || typeof value !== 'object')
|
|
326
|
+
return;
|
|
327
|
+
const node = value;
|
|
328
|
+
if (typeof node.component === 'string' && node.props && typeof node.props === 'object' && typeof node.id === 'string' && node.id !== '') {
|
|
329
|
+
out.push({ id: node.id, component: node.component });
|
|
330
|
+
}
|
|
331
|
+
Object.values(node).forEach(collect);
|
|
332
|
+
};
|
|
333
|
+
for (const file of walkJSON(pagesDir)) {
|
|
334
|
+
if (!file.endsWith('_index.json'))
|
|
335
|
+
continue;
|
|
336
|
+
const doc = JSON.parse(readFileSync(file, 'utf8'));
|
|
337
|
+
if (doc.$type === 'page')
|
|
338
|
+
collect(doc.regions);
|
|
339
|
+
}
|
|
340
|
+
return out;
|
|
341
|
+
}
|
|
342
|
+
function walkJSON(dir) {
|
|
343
|
+
return walkExt(dir, '.json');
|
|
344
|
+
}
|
|
345
|
+
function walkHTML(dir) {
|
|
346
|
+
return walkExt(dir, '.html');
|
|
347
|
+
}
|
|
348
|
+
function walkExt(dir, ext) {
|
|
349
|
+
const out = [];
|
|
350
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
351
|
+
const full = join(dir, entry.name);
|
|
352
|
+
if (entry.isDirectory())
|
|
353
|
+
out.push(...walkExt(full, ext));
|
|
354
|
+
else if (entry.name.endsWith(ext))
|
|
355
|
+
out.push(full);
|
|
356
|
+
}
|
|
357
|
+
return out;
|
|
358
|
+
}
|
|
359
|
+
function escapeRegExp(value) {
|
|
360
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
361
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createElement } from 'react';
|
|
2
|
+
export default function Image({ src, alt, ...rest }) {
|
|
3
|
+
const source = typeof src === 'object' && src !== null && 'src' in src ? String(src.src) : String(src);
|
|
4
|
+
return createElement('img', { src: source, alt: alt ?? '', ...rest });
|
|
5
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export default function Link({ href, children, ...rest }: {
|
|
3
|
+
href: unknown;
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
} & Record<string, unknown>): import("react").ReactElement<{
|
|
6
|
+
href: string;
|
|
7
|
+
}, string | import("react").JSXElementConstructor<any>>;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
/** Supported framework identifiers. */
|
|
8
8
|
export type ConformanceFramework = 'next' | 'astro';
|
|
9
9
|
/** Individual check names that can be enabled/disabled. */
|
|
10
|
-
export type ConformanceCheckName = 'config' | 'registry' | 'pageEntry' | 'middleware' | 'noFileContentProvider' | 'noCustomContent' | 'noRequestTimeAssetRoute' | 'buildSucceeds' | 'contentCompile' | 'sdkVersion';
|
|
10
|
+
export type ConformanceCheckName = 'config' | 'registry' | 'pageEntry' | 'middleware' | 'noFileContentProvider' | 'noCustomContent' | 'noRequestTimeAssetRoute' | 'buildSucceeds' | 'contentCompile' | 'sdkVersion' | 'rootIdentity';
|
|
11
11
|
/**
|
|
12
12
|
* Options for the conformance preset.
|
|
13
13
|
*
|
|
@@ -29,6 +29,8 @@ export interface ConformancePresetOptions {
|
|
|
29
29
|
* check verifies .aci.yaml does NOT declare a siteId.
|
|
30
30
|
*/
|
|
31
31
|
siteId?: string;
|
|
32
|
+
/** Render registry module, relative to rootDir (or absolute). Required for Next rootIdentity. */
|
|
33
|
+
registry?: string;
|
|
32
34
|
/** Root directory of the site project. Defaults to process.cwd(). */
|
|
33
35
|
rootDir?: string;
|
|
34
36
|
/**
|
|
@@ -51,11 +53,12 @@ export interface ConformanceResult {
|
|
|
51
53
|
failures: ConformanceCheckResult[];
|
|
52
54
|
}
|
|
53
55
|
/** A conformance check function. */
|
|
54
|
-
export type ConformanceCheckFn = (ctx: ConformanceContext) => ConformanceCheckResult[]
|
|
56
|
+
export type ConformanceCheckFn = (ctx: ConformanceContext) => ConformanceCheckResult[] | Promise<ConformanceCheckResult[]>;
|
|
55
57
|
/** Context passed to each check function. */
|
|
56
58
|
export interface ConformanceContext {
|
|
57
59
|
framework: ConformanceFramework;
|
|
58
60
|
/** Canonical siteId from options, or '' when not provided. */
|
|
59
61
|
siteId: string;
|
|
60
62
|
rootDir: string;
|
|
63
|
+
registry?: string;
|
|
61
64
|
}
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export declare class FixtureContentProvider implements ContentProvider {
|
|
|
17
17
|
getFragment<T = unknown>(id: string): Promise<T>;
|
|
18
18
|
getLayout<T = unknown>(name: string): Promise<T>;
|
|
19
19
|
listRoutes(): Promise<RouteEntry[]>;
|
|
20
|
-
loadRenderInput(route
|
|
20
|
+
loadRenderInput(route: string | undefined, options: RenderInputOptions): Promise<RenderInput>;
|
|
21
21
|
resolveRouteMetadata(route?: string): Promise<KernelRouteMetadata>;
|
|
22
22
|
}
|
|
23
23
|
export declare function createFixtureContentProvider(options?: FixtureContentProviderOptions): FixtureContentProvider;
|
package/dist/testing/index.js
CHANGED
|
@@ -53,13 +53,14 @@ export class FixtureContentProvider {
|
|
|
53
53
|
return [...this.pages.entries()]
|
|
54
54
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
55
55
|
.map(([routePath, page]) => ({
|
|
56
|
-
slug: routePath === '/' ? '
|
|
56
|
+
slug: routePath === '/' ? '' : routePath.replace(/^\//, ''),
|
|
57
57
|
path: routePath,
|
|
58
|
-
|
|
58
|
+
variantKey: 'base',
|
|
59
|
+
payloadRef: routePath === '/' ? 'routes/index.json' : `routes/${routePath.replace(/^\//, '')}.json`,
|
|
59
60
|
digest: '',
|
|
60
61
|
}));
|
|
61
62
|
}
|
|
62
|
-
async loadRenderInput(route = '/', options
|
|
63
|
+
async loadRenderInput(route = '/', options) {
|
|
63
64
|
return loadRenderInput(this, route, options);
|
|
64
65
|
}
|
|
65
66
|
async resolveRouteMetadata(route = '/') {
|
package/dist/types/block-ref.js
CHANGED
|
@@ -16,10 +16,10 @@ function attachMeta(schema, allowed, multiple) {
|
|
|
16
16
|
return schema;
|
|
17
17
|
}
|
|
18
18
|
export function blockRefArray(contracts) {
|
|
19
|
-
return attachMeta(z.array(blockRefBase), contracts.map((c) => c.id), true);
|
|
19
|
+
return attachMeta(z.array(blockRefBase.extend({ component: z.enum(contracts.map((c) => c.id)) })), contracts.map((c) => c.id), true);
|
|
20
20
|
}
|
|
21
21
|
export function blockRef(contracts) {
|
|
22
|
-
return attachMeta(blockRefBase, contracts.map((c) => c.id), false);
|
|
22
|
+
return attachMeta(blockRefBase.extend({ component: z.enum(contracts.map((c) => c.id)) }), contracts.map((c) => c.id), false);
|
|
23
23
|
}
|
|
24
24
|
export function getBlockRefMeta(schema) {
|
|
25
25
|
if (schema && typeof schema === 'object' && BLOCK_REF_KEY in schema) {
|
|
@@ -18,6 +18,15 @@ export interface ComponentValidationIssue {
|
|
|
18
18
|
message: string;
|
|
19
19
|
severity?: 'error' | 'warning';
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Root identity props the SDK renderers inject into every page and fragment
|
|
23
|
+
* block (sdk I-19, ADR 0051). A component spreads them onto its own root
|
|
24
|
+
* element; the starter conformance test fails a component that drops them.
|
|
25
|
+
*/
|
|
26
|
+
export interface RootIdentityProps {
|
|
27
|
+
'data-aci-block'?: string;
|
|
28
|
+
'data-aci-component'?: string;
|
|
29
|
+
}
|
|
21
30
|
export interface ComponentDefinition<TId extends string = string, TSchema = unknown> {
|
|
22
31
|
id: TId;
|
|
23
32
|
displayName?: string;
|
package/dist/types/config.d.ts
CHANGED
package/dist/types/index.d.ts
CHANGED
package/dist/types/index.js
CHANGED
package/dist/types/page.d.ts
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Designate the render registry for Next conformance
|
|
2
|
+
|
|
3
|
+
Set `registry` in the site's conformance options to the module its page entry
|
|
4
|
+
uses to create the ACI page:
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { conformancePreset } from '@gradial/aci/testing';
|
|
8
|
+
|
|
9
|
+
conformancePreset({
|
|
10
|
+
framework: 'next',
|
|
11
|
+
registry: 'src/cms/registry.ts',
|
|
12
|
+
});
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Paths resolve against `rootDir`, which defaults to the test process's current
|
|
16
|
+
working directory. Absolute paths also work. Use the app's full render registry,
|
|
17
|
+
including every registered component. The named module must export the registry.
|
|
18
|
+
|
|
19
|
+
Run the site's `npm test`. The `rootIdentity` check renders components from the
|
|
20
|
+
named module and fails if a rendered root omits its ACI identity attributes.
|
|
21
|
+
Missing configuration or a missing module fails before importing site code.
|
|
22
|
+
Astro's existing authored-block scan does not require this option.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Secondary experiment goals use goalIds
|
|
2
|
+
|
|
3
|
+
`goalIds` is the supported field for secondary experiment goal links. The
|
|
4
|
+
API rejects an experiment document containing `goalRefs`, including an empty
|
|
5
|
+
array or `null`, rather than silently discarding its saved goal links. The
|
|
6
|
+
SDK authoring model no longer declares `goalRefs`.
|
|
7
|
+
|
|
8
|
+
## Convert the field
|
|
9
|
+
|
|
10
|
+
In experiment `props`, replace reference strings with the corresponding bare
|
|
11
|
+
goal IDs and remove `goalRefs` entirely.
|
|
12
|
+
|
|
13
|
+
Before:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"goalRefs": ["$ref:data/conversion-goals/request-demo"]
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
After:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"goalIds": ["request-demo"]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Preserve the linked goal set and the primary goal. `primaryGoalId` and
|
|
30
|
+
`primaryGoalRef` remain supported; this migration concerns only the secondary
|
|
31
|
+
list.
|
|
32
|
+
|
|
33
|
+
## Upgrade existing content
|
|
34
|
+
|
|
35
|
+
Check experiment documents, seeds, templates, and authoring integrations for
|
|
36
|
+
`goalRefs`. If any existing content uses it, submit the spelling change
|
|
37
|
+
through the normal content API while the preceding API version still accepts
|
|
38
|
+
both spellings, and validate the resulting experiment before upgrading the
|
|
39
|
+
API image that retires `goalRefs`. Existing horizon and settled-goal rules
|
|
40
|
+
continue to apply.
|
|
41
|
+
|
|
42
|
+
If no document or authoring integration uses `goalRefs`, no content migration
|
|
43
|
+
is needed. Use `goalIds` for new secondary-goal links.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradial/aci",
|
|
3
|
-
"version": "0.1.52
|
|
3
|
+
"version": "0.1.52",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/gradial/bare-metal-go.git",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"templates/nextjs",
|
|
21
21
|
"templates/astro",
|
|
22
22
|
"CHANGELOG.md",
|
|
23
|
+
"migrations",
|
|
23
24
|
"README.md"
|
|
24
25
|
],
|
|
25
26
|
"bin": {
|
|
@@ -41,6 +42,14 @@
|
|
|
41
42
|
"types": "./dist/compiler/index.d.ts",
|
|
42
43
|
"import": "./dist/compiler/index.js"
|
|
43
44
|
},
|
|
45
|
+
"./expression-capabilities": {
|
|
46
|
+
"types": "./dist/edge/expression-capabilities.v1.d.ts",
|
|
47
|
+
"import": "./dist/edge/expression-capabilities.v1.js"
|
|
48
|
+
},
|
|
49
|
+
"./mintlify": {
|
|
50
|
+
"types": "./dist/mintlify/index.d.ts",
|
|
51
|
+
"import": "./dist/mintlify/index.js"
|
|
52
|
+
},
|
|
44
53
|
"./providers/file": {
|
|
45
54
|
"types": "./dist/providers/file.d.ts",
|
|
46
55
|
"import": "./dist/providers/file.js"
|
|
@@ -76,6 +85,11 @@
|
|
|
76
85
|
"import": "./dist/next/error-seat.js",
|
|
77
86
|
"default": "./dist/next/error-seat.js"
|
|
78
87
|
},
|
|
88
|
+
"./next/asset-route": {
|
|
89
|
+
"types": "./dist/next/asset-route.d.ts",
|
|
90
|
+
"import": "./dist/next/asset-route.js",
|
|
91
|
+
"default": "./dist/next/asset-route.js"
|
|
92
|
+
},
|
|
79
93
|
"./next/server": {
|
|
80
94
|
"types": "./dist/next/server.d.ts",
|
|
81
95
|
"import": "./dist/next/server.js",
|
|
@@ -146,11 +160,11 @@
|
|
|
146
160
|
"zod": "^4.0.0"
|
|
147
161
|
},
|
|
148
162
|
"optionalDependencies": {
|
|
149
|
-
"@gradial/aci-cli-darwin-arm64": "0.1.52
|
|
150
|
-
"@gradial/aci-cli-darwin-x64": "0.1.52
|
|
151
|
-
"@gradial/aci-cli-linux-arm64": "0.1.52
|
|
152
|
-
"@gradial/aci-cli-linux-x64": "0.1.52
|
|
153
|
-
"@gradial/aci-cli-win32-arm64": "0.1.52
|
|
154
|
-
"@gradial/aci-cli-win32-x64": "0.1.52
|
|
163
|
+
"@gradial/aci-cli-darwin-arm64": "0.1.52",
|
|
164
|
+
"@gradial/aci-cli-darwin-x64": "0.1.52",
|
|
165
|
+
"@gradial/aci-cli-linux-arm64": "0.1.52",
|
|
166
|
+
"@gradial/aci-cli-linux-x64": "0.1.52",
|
|
167
|
+
"@gradial/aci-cli-win32-arm64": "0.1.52",
|
|
168
|
+
"@gradial/aci-cli-win32-x64": "0.1.52"
|
|
155
169
|
}
|
|
156
170
|
}
|