@gradial/aci 0.1.52-rc.8 → 0.1.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +126 -0
- package/README.md +86 -5
- package/dist/astro/error-page.js +1 -0
- package/dist/astro/index.js +4 -0
- package/dist/astro/page.d.ts +5 -2
- package/dist/astro/page.js +35 -23
- package/dist/astro/preview.js +2 -17
- package/dist/audience-data-models.d.ts +308 -197
- package/dist/audience-data-models.js +313 -51
- package/dist/cli/compile-registry.mjs +6 -34
- package/dist/cli/mintlify-render.mjs +8 -0
- package/dist/collect/aci.js +1 -1
- package/dist/collect/aci.js.sha256 +1 -1
- package/dist/collect/api.d.ts +6 -7
- package/dist/collect/api.js +21 -8
- package/dist/collect/assignments.d.ts +7 -9
- package/dist/collect/assignments.js +23 -32
- package/dist/collect/batcher.d.ts +9 -7
- package/dist/collect/batcher.js +6 -5
- package/dist/collect/consent/envelope.d.ts +7 -1
- package/dist/collect/consent/envelope.js +3 -1
- package/dist/collect/consent/mapping.d.ts +2 -0
- package/dist/collect/consent/mapping.js +1 -0
- package/dist/collect/consenthold.d.ts +38 -0
- package/dist/collect/consenthold.js +82 -0
- package/dist/collect/declarative.js +7 -5
- package/dist/collect/gapbuffer.d.ts +13 -4
- package/dist/collect/gapbuffer.js +21 -10
- package/dist/collect/index.js +78 -21
- package/dist/collect/pageviews.d.ts +11 -11
- package/dist/collect/pageviews.js +27 -22
- package/dist/consent-banner/index.d.ts +17 -0
- package/dist/consent-banner/index.js +23 -0
- package/dist/content/index.d.ts +2 -1
- package/dist/content/index.js +4 -1
- package/dist/content/provider.d.ts +16 -2
- package/dist/content/provider.js +5 -1
- package/dist/content/resolve-slots.d.ts +24 -2
- package/dist/content/resolve-slots.js +127 -21
- package/dist/content/types.d.ts +5 -1
- package/dist/edge/expression-capabilities.v1.d.ts +106 -0
- package/dist/edge/expression-capabilities.v1.js +165 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +0 -1
- package/dist/internal/domain/edge/identity.d.ts +47 -4
- package/dist/internal/domain/edge/identity.js +130 -26
- package/dist/internal/domain/edge/index.d.ts +1 -1
- package/dist/internal/domain/edge/index.js +1 -1
- package/dist/internal/domain/edge/mimic_token.d.ts +14 -0
- package/dist/internal/domain/edge/mimic_token.js +125 -0
- package/dist/internal/domain/edge/personalization-core.d.ts +61 -22
- package/dist/internal/domain/edge/personalization-core.js +790 -200
- package/dist/internal/domain/edge/personalization_index.d.ts +17 -0
- package/dist/internal/domain/edge/personalization_index.js +55 -0
- package/dist/internal/domain/edge/resolve.js +76 -39
- package/dist/internal/domain/edge/testdata/flat_only_validator_v1.d.ts +10 -0
- package/dist/internal/domain/edge/testdata/flat_only_validator_v1.js +253 -0
- package/dist/internal/domain/edge/types.d.ts +82 -78
- package/dist/internal/domain/edge/types.js +3 -3
- package/dist/internal/domain/edge/variant_key.d.ts +4 -0
- package/dist/internal/domain/edge/variant_key.js +56 -0
- package/dist/internal/platform/collectionstore/errors.d.ts +24 -0
- package/dist/internal/platform/collectionstore/errors.js +48 -0
- package/dist/mintlify/blocks.d.ts +6 -0
- package/dist/mintlify/blocks.js +201 -0
- package/dist/mintlify/config.d.ts +3 -0
- package/dist/mintlify/config.js +77 -0
- package/dist/mintlify/index.d.ts +3 -0
- package/dist/mintlify/index.js +2 -0
- package/dist/mintlify/json.d.ts +8 -0
- package/dist/mintlify/json.js +37 -0
- package/dist/mintlify/materialize.d.ts +14 -0
- package/dist/mintlify/materialize.js +254 -0
- package/dist/mintlify/types.d.ts +74 -0
- package/dist/mintlify/types.js +1 -0
- package/dist/mintlify/validate.d.ts +7 -0
- package/dist/mintlify/validate.js +256 -0
- package/dist/next/assignments-navigation.d.ts +4 -0
- package/dist/next/assignments-navigation.js +18 -0
- package/dist/next/assignments-script.d.ts +3 -2
- package/dist/next/assignments-script.js +5 -5
- package/dist/next/error-pages.d.ts +4 -0
- package/dist/next/error-pages.js +4 -0
- package/dist/next/error-seat-payload.d.ts +2 -1
- package/dist/next/error-seat-payload.js +14 -24
- package/dist/next/error-seat.js +7 -2
- package/dist/next/index.d.ts +1 -1
- package/dist/next/index.js +3 -1
- package/dist/next/page.d.ts +2 -1
- package/dist/next/page.js +15 -4
- package/dist/next/release-context.d.ts +30 -0
- package/dist/next/release-context.js +56 -0
- package/dist/next/render.d.ts +1 -1
- package/dist/next/render.js +15 -5
- package/dist/next/server.d.ts +9 -3
- package/dist/next/server.js +17 -32
- package/dist/preview/core.d.ts +1 -0
- package/dist/preview/core.js +27 -0
- package/dist/react/VideoPlayer.d.ts +3 -3
- package/dist/react/index.d.ts +3 -3
- package/dist/registry.d.ts +4 -2
- package/dist/testing/conformance/checks.d.ts +2 -2
- package/dist/testing/conformance/checks.js +2 -0
- package/dist/testing/conformance/index.d.ts +1 -0
- package/dist/testing/conformance/index.js +1 -0
- package/dist/testing/conformance/next-stubs.d.ts +6 -0
- package/dist/testing/conformance/next-stubs.js +9 -0
- package/dist/testing/conformance/preset.d.ts +3 -2
- package/dist/testing/conformance/preset.js +15 -8
- package/dist/testing/conformance/root-identity.d.ts +31 -0
- package/dist/testing/conformance/root-identity.js +361 -0
- package/dist/testing/conformance/stubs/next-image.d.ts +7 -0
- package/dist/testing/conformance/stubs/next-image.js +5 -0
- package/dist/testing/conformance/stubs/next-link.d.ts +7 -0
- package/dist/testing/conformance/stubs/next-link.js +4 -0
- package/dist/testing/conformance/types.d.ts +5 -2
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +4 -3
- package/dist/types/block-ref.js +2 -2
- package/dist/types/component.d.ts +9 -0
- package/dist/types/config.d.ts +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.js +0 -1
- package/dist/types/page.d.ts +0 -1
- package/migrations/conformance-registry.md +22 -0
- package/migrations/experiment-goal-ids.md +43 -0
- package/package.json +21 -7
- package/src/cli/compile-registry.mjs +6 -30
- package/src/cli/mintlify-render.mjs +9 -0
- package/src/types/block-ref.test.ts +16 -1
- package/src/types/block-ref.ts +2 -2
- package/src/types/component.ts +10 -0
- package/src/types/config.ts +0 -1
- package/src/types/index.ts +0 -1
- package/src/types/page.ts +0 -1
- package/templates/astro/starter-content/src/components/chrome/Footer.astro +5 -3
- package/templates/astro/starter-content/src/components/chrome/Header.astro +5 -3
- package/templates/astro/starter-content/src/components/elements/Button.astro +5 -2
- package/templates/astro/starter-content/src/components/elements/ButtonBlock.astro +5 -3
- package/templates/astro/starter-content/src/components/sections/ContainerSection.astro +4 -3
- package/templates/astro/starter-content/src/components/sections/FeatureCard.astro +4 -3
- package/templates/astro/starter-content/src/components/sections/FeatureGrid.astro +4 -3
- package/templates/astro/starter-content/src/components/sections/HomeHero.astro +5 -3
- package/templates/astro/starter-content/src/components/sections/PersonalizationChoice.astro +4 -3
- package/templates/astro/starter-content/src/components/sections/StatsBar.astro +4 -3
- package/templates/astro/starter-content/src/fixtures/sections.ts +1 -1
- package/templates/astro/starter-content/src/stories/CompositionStoryFrame.astro +7 -2
- package/templates/astro/template/.aci.yaml.tmpl +0 -1
- package/templates/astro/template/package.json.tmpl +5 -5
- package/templates/astro/template/src/layouts/SiteLayout.astro +2 -2
- package/templates/common/.agents/skills/aci/SKILL.md +58 -1
- package/templates/common/.agents/skills/authoring/SKILL.md +194 -42
- package/templates/common/.agents/skills/authoring/references/block-registry.md +19 -3
- package/templates/common/.agents/skills/authoring/references/contracts.md +9 -30
- package/templates/common/.agents/skills/authoring/references/repo-structure.md +5 -4
- package/templates/common/.agents/skills/authoring/references/sdk-server-functions.md +3 -3
- package/templates/common/.agents/skills/dam-delivery/SKILL.md +216 -0
- package/templates/common/.agents/skills/dam-delivery/references/permalink-grammar.md +167 -0
- package/templates/common/.agents/skills/migration/references/canon-migration.md +18 -67
- package/templates/common/.agents/skills/migration/references/selector-map.md +1 -1
- package/templates/common/.content/fragments/navbar/_index.json +24 -0
- package/templates/common/.content/fragments/site-footer/_index.json +61 -0
- package/templates/common/.content/pages/404/_index.json +4 -2
- package/templates/common/.content/pages/_index.json +0 -1
- package/templates/common/.content/pages/error/_index.json +4 -2
- package/templates/common/.content/schemas/site.schema.json +11 -1
- package/templates/common/.content/templates/error.json +24 -0
- package/templates/common/.content/templates/home.json +28 -0
- package/templates/common/.content/templates/site.json +8 -0
- package/templates/common/.content/templates/standard.json +24 -0
- package/templates/common/.nvmrc +1 -1
- package/templates/common/starter-content/.content/config/site.json +1 -1
- package/templates/common/starter-content/.content/dam/README.md +74 -0
- package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000101}/asset.json +1 -1
- package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000102}/asset.json +1 -1
- package/templates/common/starter-content/.content/pages/404/_index.json +1 -2
- package/templates/common/starter-content/.content/pages/{home/_index.json → _index.json} +14 -3
- package/templates/common/starter-content/.content/pages/about/_index.json +2 -2
- package/templates/common/starter-content/.content/pages/error/_index.json +1 -2
- package/templates/common/starter-content/.content/patterns/components/button.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/container.json +8 -3
- package/templates/common/starter-content/.content/patterns/components/feature_card.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/feature_grid.json +5 -3
- package/templates/common/starter-content/.content/patterns/components/home_hero.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/personalization_choice.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/site-footer.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/site-navigation.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/stats_bar.json +2 -2
- package/templates/common/starter-content/.content/schemas/site.schema.json +11 -1
- package/templates/nextjs/starter-content/src/components/chrome/Footer.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/chrome/Header.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/elements/Button.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/elements/ButtonBlock.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/sections/ContainerSection.tsx +4 -2
- package/templates/nextjs/starter-content/src/components/sections/FeatureCard.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/sections/FeatureGrid.tsx +4 -2
- package/templates/nextjs/starter-content/src/components/sections/HomeHero.tsx +4 -3
- package/templates/nextjs/starter-content/src/components/sections/PersonalizationChoice.tsx +4 -2
- package/templates/nextjs/starter-content/src/components/sections/StatsBar.tsx +4 -3
- package/templates/nextjs/template/.aci.yaml +0 -1
- package/templates/nextjs/template/.aci.yaml.tmpl +0 -1
- package/templates/nextjs/template/package.json.tmpl +4 -3
- package/templates/nextjs/template/src/app/_components/c15t-bridge.ts +30 -0
- package/templates/nextjs/template/src/app/_components/c15t-consent-ui.tsx +37 -0
- package/templates/nextjs/template/src/app/_components/consent-manager.css +63 -0
- package/templates/nextjs/template/src/app/_components/consent-manager.tsx +76 -0
- package/templates/nextjs/template/src/app/fonts/inter/OFL.txt +93 -0
- package/templates/nextjs/template/src/app/fonts/inter/inter-latin.woff2 +0 -0
- package/templates/nextjs/template/src/app/fonts/space-grotesk/OFL.txt +93 -0
- package/templates/nextjs/template/src/app/fonts/space-grotesk/space-grotesk-latin.woff2 +0 -0
- package/templates/nextjs/template/src/app/layout.tsx +12 -7
- package/templates/nextjs/template/tests/conformance.test.ts.tmpl +1 -0
- package/dist/define-layout.d.ts +0 -6
- package/dist/define-layout.js +0 -14
- package/dist/edge/personalization-core.d.ts +0 -11
- package/dist/edge/personalization-core.js +0 -269
- package/dist/internal/domain/edge/compose.d.ts +0 -24
- package/dist/internal/domain/edge/compose.js +0 -89
- package/dist/internal/domain/edge/record/codec.d.ts +0 -71
- package/dist/internal/domain/edge/record/codec.js +0 -401
- package/dist/next/collect-route.d.ts +0 -19
- package/dist/next/collect-route.js +0 -459
- package/dist/next/edge-config.d.ts +0 -1
- package/dist/next/edge-config.js +0 -92
- package/dist/next/envelope-digest.d.ts +0 -21
- package/dist/next/envelope-digest.js +0 -58
- package/dist/next/middleware.d.ts +0 -40
- package/dist/next/middleware.js +0 -475
- package/dist/next/personalization-host.d.ts +0 -134
- package/dist/next/personalization-host.js +0 -270
- package/dist/next/root-layout.d.ts +0 -4
- package/dist/next/root-layout.js +0 -5
- package/dist/next/vercel-collect-sdk-route.d.ts +0 -27
- package/dist/next/vercel-collect-sdk-route.js +0 -181
- package/dist/next/vercel-edge-projection-v1.d.ts +0 -24
- package/dist/next/vercel-edge-projection-v1.js +0 -880
- package/dist/next/vercel-personalization.d.ts +0 -4
- package/dist/next/vercel-personalization.js +0 -4
- package/dist/next/vercel-s3-personalization.d.ts +0 -79
- package/dist/next/vercel-s3-personalization.js +0 -570
- package/dist/types/layout.d.ts +0 -24
- package/src/types/layout.ts +0 -29
- package/templates/astro/starter-content/src/render/RenderPage.astro +0 -67
- package/templates/astro/template/src/cms/contracts/layouts/index.ts +0 -18
- package/templates/common/starter-content/.content/patterns/layouts/default.json +0 -14
- package/templates/nextjs/starter-content/src/components/elements/AtomicBlock.tsx +0 -13
- package/templates/nextjs/template/src/cms/contracts/layouts/index.ts +0 -16
- /package/dist/{types/layout.js → cli/mintlify-render.d.mts} +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/editorial.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000101}/governance.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/versions/v0001.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/editorial.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000102}/governance.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/versions/v0001.json +0 -0
|
@@ -32,13 +32,15 @@ if (isMainModule()) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
async function compileRegistry(options) {
|
|
35
|
-
|
|
35
|
+
if (options.layouts) {
|
|
36
|
+
throw new Error('--layouts is retired; author page composition under /templates instead');
|
|
37
|
+
}
|
|
38
|
+
const required = ['components', 'output'];
|
|
36
39
|
for (const key of required) {
|
|
37
40
|
if (!options[key]) throw new Error(`missing --${key}`);
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
const components = await loadDefaultArray(options.components, 'component registry');
|
|
41
|
-
const layouts = await loadDefaultArray(options.layouts, 'layout registry');
|
|
42
44
|
const dataModels = options.data
|
|
43
45
|
? await loadDefaultArray(options.data, 'data model registry')
|
|
44
46
|
: [];
|
|
@@ -68,9 +70,6 @@ async function compileRegistry(options) {
|
|
|
68
70
|
});
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
const seenLayouts = new Set();
|
|
72
|
-
const layoutEntries = layouts.map((layout, index) => validateLayout(layout, index, seenLayouts));
|
|
73
|
-
|
|
74
73
|
const seenDataModels = new Set();
|
|
75
74
|
const dataModelEntries = [];
|
|
76
75
|
if (dataModels.length > 0) {
|
|
@@ -104,7 +103,6 @@ async function compileRegistry(options) {
|
|
|
104
103
|
manifestVersion: '1',
|
|
105
104
|
generatedAt: new Date().toISOString(),
|
|
106
105
|
components: componentEntries,
|
|
107
|
-
layouts: layoutEntries,
|
|
108
106
|
dataModels: dataModelEntries,
|
|
109
107
|
};
|
|
110
108
|
const registryPath = path.join(outDir, 'registry.json');
|
|
@@ -118,7 +116,7 @@ async function compileRegistry(options) {
|
|
|
118
116
|
|
|
119
117
|
async function loadDefaultArray(modulePath, label) {
|
|
120
118
|
const mod = await import(pathToFileURL(path.resolve(modulePath)).href);
|
|
121
|
-
const value = mod.default ?? mod.registry ?? mod.components ?? mod.
|
|
119
|
+
const value = mod.default ?? mod.registry ?? mod.components ?? mod.dataModels;
|
|
122
120
|
if (!Array.isArray(value)) throw new Error(`${label} must export an array`);
|
|
123
121
|
return value;
|
|
124
122
|
}
|
|
@@ -390,27 +388,6 @@ function unwrapSchema(schema) {
|
|
|
390
388
|
return current;
|
|
391
389
|
}
|
|
392
390
|
|
|
393
|
-
function validateLayout(layout, index, seen) {
|
|
394
|
-
if (!layout || typeof layout !== 'object') throw new Error(`layouts[${index}] must be an object`);
|
|
395
|
-
if (!layout.name) throw new Error(`layouts[${index}].name is required`);
|
|
396
|
-
if (seen.has(layout.name)) throw new Error(`duplicate layout name ${layout.name}`);
|
|
397
|
-
seen.add(layout.name);
|
|
398
|
-
if (!Array.isArray(layout.slots)) throw new Error(`layouts[${index}].slots must be an array`);
|
|
399
|
-
const slots = [];
|
|
400
|
-
const seenSlots = new Set();
|
|
401
|
-
for (const [slotIndex, slot] of layout.slots.entries()) {
|
|
402
|
-
if (!slot?.name) throw new Error(`layouts[${index}].slots[${slotIndex}].name is required`);
|
|
403
|
-
if (seenSlots.has(slot.name)) throw new Error(`duplicate slot name ${slot.name} in layout ${layout.name}`);
|
|
404
|
-
seenSlots.add(slot.name);
|
|
405
|
-
slots.push({ name: slot.name, required: Boolean(slot.required) });
|
|
406
|
-
}
|
|
407
|
-
const entry = { name: layout.name, slots };
|
|
408
|
-
if (layout.defaults && typeof layout.defaults === 'object') {
|
|
409
|
-
entry.defaults = layout.defaults;
|
|
410
|
-
}
|
|
411
|
-
return entry;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
391
|
function compileSchema(schema, name) {
|
|
415
392
|
const toJSONSchema = z.toJSONSchema;
|
|
416
393
|
if (typeof toJSONSchema !== 'function') {
|
|
@@ -505,13 +482,12 @@ async function generatePageSchema(schemaDir, componentEntries, outDir) {
|
|
|
505
482
|
$id: 'https://baremetal.local/schemas/page.schema.json',
|
|
506
483
|
title: 'bare-metal Page',
|
|
507
484
|
type: 'object',
|
|
508
|
-
required: ['$type', 'id', 'status', '
|
|
485
|
+
required: ['$type', 'id', 'status', 'metadata', 'regions'],
|
|
509
486
|
additionalProperties: true,
|
|
510
487
|
properties: {
|
|
511
488
|
$type: { const: 'page' },
|
|
512
489
|
id: { type: 'string', minLength: 1 },
|
|
513
490
|
status: { type: 'string', minLength: 1 },
|
|
514
|
-
layout: { type: 'string', minLength: 1 },
|
|
515
491
|
metadata: {
|
|
516
492
|
type: 'object',
|
|
517
493
|
required: ['title'],
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { loadCompiledMintlifySource, materializeMintlifySite } from '../../dist/mintlify/index.js';
|
|
3
|
+
|
|
4
|
+
const [sourceArg, compiledArg, outputArg] = process.argv.slice(2);
|
|
5
|
+
if (!sourceArg || !compiledArg || !outputArg) {
|
|
6
|
+
throw new Error('Mintlify renderer requires content, compiled, and output directories');
|
|
7
|
+
}
|
|
8
|
+
const source = await loadCompiledMintlifySource(path.resolve(sourceArg), path.resolve(compiledArg));
|
|
9
|
+
await materializeMintlifySite({ ...source, outputDir: path.resolve(outputArg) });
|
|
@@ -4,7 +4,7 @@ import { z } from 'zod';
|
|
|
4
4
|
|
|
5
5
|
import { compileSchema } from '../compiler/zod-to-jsonschema.js';
|
|
6
6
|
import { defineComponentContract } from '../define-component.js';
|
|
7
|
-
import { blockRefArray } from './block-ref.js';
|
|
7
|
+
import { blockRef, blockRefArray } from './block-ref.js';
|
|
8
8
|
|
|
9
9
|
const childContract = defineComponentContract({
|
|
10
10
|
id: 'child',
|
|
@@ -43,3 +43,18 @@ test('compiled block-reference schema exposes the component discriminator', () =
|
|
|
43
43
|
assert.equal(compiled.items?.required?.includes('$type'), true);
|
|
44
44
|
assert.equal(compiled.items?.additionalProperties, false);
|
|
45
45
|
});
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
test('block-reference contracts enforce allowed child IDs at runtime and in compiled schemas', () => {
|
|
49
|
+
const other = defineComponentContract({ id: 'other', props: z.object({}) });
|
|
50
|
+
const allowed = { $type: 'component', id: 'child-1', component: 'child', props: { label: 'Hello' } };
|
|
51
|
+
const disallowed = { ...allowed, component: 'button' };
|
|
52
|
+
for (const multiple of [false, true]) {
|
|
53
|
+
const schema = multiple ? blockRefArray([childContract, other]) : blockRef([childContract, other]);
|
|
54
|
+
assert.equal(schema.safeParse(multiple ? [allowed] : allowed).success, true);
|
|
55
|
+
assert.equal(schema.safeParse(multiple ? [disallowed] : disallowed).success, false, 'a nested component outside the contract must be refused');
|
|
56
|
+
const compiled = compileSchema(schema) as any;
|
|
57
|
+
const block = multiple ? compiled.items : compiled;
|
|
58
|
+
assert.deepEqual(block.properties.component.enum, ['child', 'other'], 'published JSON Schema must enforce the same finite child set');
|
|
59
|
+
}
|
|
60
|
+
});
|
package/src/types/block-ref.ts
CHANGED
|
@@ -50,7 +50,7 @@ export function blockRefArray<const T extends readonly ComponentContract[]>(
|
|
|
50
50
|
contracts: T,
|
|
51
51
|
): z.ZodArray<z.ZodType<BlockRefUnion<T>>> {
|
|
52
52
|
return attachMeta(
|
|
53
|
-
z.array(blockRefBase) as unknown as z.ZodArray<z.ZodType<BlockRefUnion<T>>>,
|
|
53
|
+
z.array(blockRefBase.extend({ component: z.enum(contracts.map((c) => c.id)) })) as unknown as z.ZodArray<z.ZodType<BlockRefUnion<T>>>,
|
|
54
54
|
contracts.map((c) => c.id),
|
|
55
55
|
true,
|
|
56
56
|
);
|
|
@@ -60,7 +60,7 @@ export function blockRef<const T extends readonly ComponentContract[]>(
|
|
|
60
60
|
contracts: T,
|
|
61
61
|
): z.ZodType<BlockRefUnion<T>> {
|
|
62
62
|
return attachMeta(
|
|
63
|
-
blockRefBase as unknown as z.ZodType<BlockRefUnion<T>>,
|
|
63
|
+
blockRefBase.extend({ component: z.enum(contracts.map((c) => c.id)) }) as unknown as z.ZodType<BlockRefUnion<T>>,
|
|
64
64
|
contracts.map((c) => c.id),
|
|
65
65
|
false,
|
|
66
66
|
);
|
package/src/types/component.ts
CHANGED
|
@@ -23,6 +23,16 @@ export interface ComponentValidationIssue {
|
|
|
23
23
|
severity?: 'error' | 'warning';
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Root identity props the SDK renderers inject into every page and fragment
|
|
28
|
+
* block (sdk I-19, ADR 0051). A component spreads them onto its own root
|
|
29
|
+
* element; the starter conformance test fails a component that drops them.
|
|
30
|
+
*/
|
|
31
|
+
export interface RootIdentityProps {
|
|
32
|
+
'data-aci-block'?: string;
|
|
33
|
+
'data-aci-component'?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
26
36
|
export interface ComponentDefinition<TId extends string = string, TSchema = unknown> {
|
|
27
37
|
id: TId;
|
|
28
38
|
displayName?: string;
|
package/src/types/config.ts
CHANGED
package/src/types/index.ts
CHANGED
package/src/types/page.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Container from '../elements/Container.astro';
|
|
3
|
+
import type { RootIdentityProps } from '@gradial/aci';
|
|
3
4
|
import Logo from '../elements/Logo.astro';
|
|
4
5
|
|
|
5
6
|
interface FooterLink {
|
|
@@ -21,7 +22,7 @@ interface FooterColumn {
|
|
|
21
22
|
links?: FooterLink[];
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
interface Props {
|
|
25
|
+
interface Props extends RootIdentityProps {
|
|
25
26
|
brandHref: string;
|
|
26
27
|
brandLabel?: string;
|
|
27
28
|
brandLogo?: { src: string; alt?: string } | null;
|
|
@@ -38,7 +39,8 @@ const {
|
|
|
38
39
|
social = [],
|
|
39
40
|
columns = [],
|
|
40
41
|
legalLinks = [],
|
|
41
|
-
copyright = ''
|
|
42
|
+
copyright = '',
|
|
43
|
+
...root
|
|
42
44
|
} = Astro.props;
|
|
43
45
|
|
|
44
46
|
function columnGroups(column: FooterColumn): FooterGroup[] {
|
|
@@ -54,7 +56,7 @@ function columnGroups(column: FooterColumn): FooterGroup[] {
|
|
|
54
56
|
}
|
|
55
57
|
---
|
|
56
58
|
|
|
57
|
-
<footer class="bm-footer [font-family:var(--font-family-base)] text-fg" id="footer">
|
|
59
|
+
<footer {...root} class="bm-footer [font-family:var(--font-family-base)] text-fg" id="footer">
|
|
58
60
|
<Container className="py-[var(--spacing-footer-y)]">
|
|
59
61
|
<div class="grid gap-12 pb-24 md:grid-cols-[var(--footer-grid-columns)] lg:gap-24">
|
|
60
62
|
<a href={brandHref} class="self-start">
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Button from '../elements/Button.astro';
|
|
3
|
+
import type { RootIdentityProps } from '@gradial/aci';
|
|
3
4
|
import Container from '../elements/Container.astro';
|
|
4
5
|
import Icon from '../elements/Icon.astro';
|
|
5
6
|
import Logo from '../elements/Logo.astro';
|
|
@@ -14,7 +15,7 @@ interface UtilityItem extends NavItem {
|
|
|
14
15
|
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
interface Props {
|
|
18
|
+
interface Props extends RootIdentityProps {
|
|
18
19
|
brandHref: string;
|
|
19
20
|
brandLabel?: string;
|
|
20
21
|
brandLogo?: { src: string; alt?: string } | null;
|
|
@@ -27,11 +28,12 @@ const {
|
|
|
27
28
|
brandLabel = 'Gradial',
|
|
28
29
|
brandLogo = null,
|
|
29
30
|
navigation = [],
|
|
30
|
-
utilities = []
|
|
31
|
+
utilities = [],
|
|
32
|
+
...root
|
|
31
33
|
} = Astro.props;
|
|
32
34
|
---
|
|
33
35
|
|
|
34
|
-
<header class="bm-header sticky top-0 z-[var(--z-header)] [font-family:var(--font-family-base)] text-fg">
|
|
36
|
+
<header {...root} class="bm-header sticky top-0 z-[var(--z-header)] [font-family:var(--font-family-base)] text-fg">
|
|
35
37
|
<a
|
|
36
38
|
href="#content-main"
|
|
37
39
|
class="sr-only focus:not-sr-only focus:absolute focus:left-4 focus:top-4 focus:z-10 focus:rounded-button focus:bg-white focus:px-4 focus:py-2 focus:text-black"
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
2
|
+
import type { RootIdentityProps } from '@gradial/aci';
|
|
3
|
+
|
|
4
|
+
interface Props extends RootIdentityProps {
|
|
3
5
|
href: string;
|
|
4
6
|
variant?: 'primary' | 'secondary' | 'tertiary' | 'outline' | 'ghost';
|
|
5
7
|
className?: string;
|
|
@@ -7,7 +9,7 @@ interface Props {
|
|
|
7
9
|
rel?: string;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
|
-
const { href, variant = 'primary', className = '', target, rel } = Astro.props;
|
|
12
|
+
const { href, variant = 'primary', className = '', target, rel, ...root } = Astro.props;
|
|
11
13
|
|
|
12
14
|
const variantTokens = {
|
|
13
15
|
primary: {
|
|
@@ -41,6 +43,7 @@ const tokenStyle = `background-color: ${variantTokens.background}; border-color:
|
|
|
41
43
|
---
|
|
42
44
|
|
|
43
45
|
<a
|
|
46
|
+
{...root}
|
|
44
47
|
class={`inline-flex min-h-10 items-center justify-center rounded-button border px-[var(--spacing-button-x)] py-[var(--spacing-button-y)] [font-family:var(--font-family-base)] text-[length:var(--text-button)] font-[var(--font-weight-semibold)] leading-button transition duration-200 hover:opacity-85 ${className}`}
|
|
45
48
|
href={href}
|
|
46
49
|
target={target}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Button from '../elements/Button.astro';
|
|
3
3
|
import Icon from '../elements/Icon.astro';
|
|
4
|
+
import type { RootIdentityProps } from '@gradial/aci';
|
|
4
5
|
import type { ContentProps } from '../../cms/contracts/components/button.contract';
|
|
5
6
|
|
|
6
|
-
type Props = ContentProps;
|
|
7
|
+
type Props = ContentProps & RootIdentityProps;
|
|
7
8
|
|
|
8
9
|
const {
|
|
9
10
|
label,
|
|
@@ -12,13 +13,14 @@ const {
|
|
|
12
13
|
newWindow = false,
|
|
13
14
|
icon = '',
|
|
14
15
|
iconPosition = 'before',
|
|
15
|
-
className = ''
|
|
16
|
+
className = '',
|
|
17
|
+
...root
|
|
16
18
|
} = Astro.props;
|
|
17
19
|
const target = newWindow ? '_blank' : undefined;
|
|
18
20
|
const rel = newWindow ? 'noreferrer' : undefined;
|
|
19
21
|
---
|
|
20
22
|
|
|
21
|
-
<Button {href} {variant} {target} {rel} {className}>
|
|
23
|
+
<Button {href} {variant} {target} {rel} {className} {...root}>
|
|
22
24
|
{icon && iconPosition === 'before' ? <Icon name={icon} className="mr-2 size-4" /> : null}
|
|
23
25
|
<span>{label}</span>
|
|
24
26
|
{icon && iconPosition === 'after' ? <Icon name={icon} className="ml-2 size-4" /> : null}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Container from '../elements/Container.astro';
|
|
3
|
+
import type { RootIdentityProps } from '@gradial/aci';
|
|
3
4
|
import type { RenderChildren, RenderableBlock } from '@gradial/aci/astro';
|
|
4
5
|
|
|
5
|
-
interface Props {
|
|
6
|
+
interface Props extends RootIdentityProps {
|
|
6
7
|
theme?: 'auto' | 'light' | 'dark';
|
|
7
8
|
className?: string;
|
|
8
9
|
content?: any[];
|
|
9
10
|
renderChildren?: RenderChildren;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
const { theme = 'auto', className = '', content, renderChildren } = Astro.props;
|
|
13
|
+
const { theme = 'auto', className = '', content, renderChildren, ...root } = Astro.props;
|
|
13
14
|
const children: RenderableBlock[] = content && renderChildren ? renderChildren(content) : [];
|
|
14
15
|
const buttonCount = content?.filter((b: any) => b.component === 'button').length ?? 0;
|
|
15
16
|
const layout = buttonCount === 1
|
|
@@ -17,7 +18,7 @@ const layout = buttonCount === 1
|
|
|
17
18
|
: 'flex-col items-center sm:flex-row sm:justify-center sm:gap-4';
|
|
18
19
|
---
|
|
19
20
|
|
|
20
|
-
<section class={`theme-${theme} relative overflow-hidden py-[var(--spacing-section-y)] ${className}`}>
|
|
21
|
+
<section {...root} class={`theme-${theme} relative overflow-hidden py-[var(--spacing-section-y)] ${className}`}>
|
|
21
22
|
{theme === 'dark' ? (
|
|
22
23
|
<div class="pointer-events-none absolute inset-0 bg-[image:var(--gradient-hero-base)] opacity-30"></div>
|
|
23
24
|
) : null}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Icon from '../elements/Icon.astro';
|
|
3
|
+
import type { RootIdentityProps } from '@gradial/aci';
|
|
3
4
|
|
|
4
|
-
interface Props {
|
|
5
|
+
interface Props extends RootIdentityProps {
|
|
5
6
|
icon?: string;
|
|
6
7
|
title: string;
|
|
7
8
|
description?: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
const { icon = '', title = '', description = '' } = Astro.props;
|
|
11
|
+
const { icon = '', title = '', description = '', ...root } = Astro.props;
|
|
11
12
|
---
|
|
12
13
|
|
|
13
|
-
<div class="rounded-card border border-[var(--color-edge-space)] bg-[var(--color-space-surface)] p-[var(--spacing-card)] transition-all duration-[var(--transition-duration-fast)] hover:border-[var(--color-edge-space-strong)] hover:bg-[var(--color-space-raised)] hover:shadow-[var(--shadow-card-default)]">
|
|
14
|
+
<div {...root} class="rounded-card border border-[var(--color-edge-space)] bg-[var(--color-space-surface)] p-[var(--spacing-card)] transition-all duration-[var(--transition-duration-fast)] hover:border-[var(--color-edge-space-strong)] hover:bg-[var(--color-space-raised)] hover:shadow-[var(--shadow-card-default)]">
|
|
14
15
|
{icon ? (
|
|
15
16
|
<div class="mb-6 flex h-12 w-12 items-center justify-center rounded-button bg-[color-mix(in_srgb,var(--color-brand-blue)_12%,transparent)] text-[var(--color-brand-blue-light)]">
|
|
16
17
|
<Icon name={icon} className="h-6 w-6" />
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Container from '../elements/Container.astro';
|
|
3
|
+
import type { RootIdentityProps } from '@gradial/aci';
|
|
3
4
|
import type { RenderChildren, RenderableBlock } from '@gradial/aci/astro';
|
|
4
5
|
|
|
5
|
-
interface Props {
|
|
6
|
+
interface Props extends RootIdentityProps {
|
|
6
7
|
title?: string;
|
|
7
8
|
subtitle?: string;
|
|
8
9
|
features?: any[];
|
|
9
10
|
renderChildren?: RenderChildren;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
const { title = '', subtitle = '', features, renderChildren } = Astro.props;
|
|
13
|
+
const { title = '', subtitle = '', features, renderChildren, ...root } = Astro.props;
|
|
13
14
|
const children: RenderableBlock[] = features && renderChildren ? renderChildren(features) : [];
|
|
14
15
|
const count = features?.length ?? 0;
|
|
15
16
|
const cols = count <= 2 ? 'sm:grid-cols-2' : 'sm:grid-cols-2 lg:grid-cols-3';
|
|
16
17
|
---
|
|
17
18
|
|
|
18
|
-
<section class="theme-dark py-[var(--spacing-section-y)] bg-[var(--color-space-deep)]">
|
|
19
|
+
<section {...root} class="theme-dark py-[var(--spacing-section-y)] bg-[var(--color-space-deep)]">
|
|
19
20
|
<Container>
|
|
20
21
|
<div class="mb-12 max-w-[var(--max-width-container-narrow)]">
|
|
21
22
|
{title ? (
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Button from '../elements/Button.astro';
|
|
3
3
|
import Container from '../elements/Container.astro';
|
|
4
|
-
import { imageAttrs, type Image } from '@gradial/aci';
|
|
4
|
+
import { imageAttrs, type Image, type RootIdentityProps } from '@gradial/aci';
|
|
5
5
|
|
|
6
|
-
interface Props {
|
|
6
|
+
interface Props extends RootIdentityProps {
|
|
7
7
|
eyebrow?: string;
|
|
8
8
|
headline: string;
|
|
9
9
|
description?: string;
|
|
@@ -18,7 +18,8 @@ const {
|
|
|
18
18
|
description = '',
|
|
19
19
|
ctaLabel,
|
|
20
20
|
ctaHref,
|
|
21
|
-
image
|
|
21
|
+
image,
|
|
22
|
+
...root
|
|
22
23
|
} = Astro.props;
|
|
23
24
|
|
|
24
25
|
const imgAttrs = image ? imageAttrs(image, {
|
|
@@ -29,6 +30,7 @@ const imgAttrs = image ? imageAttrs(image, {
|
|
|
29
30
|
---
|
|
30
31
|
|
|
31
32
|
<section
|
|
33
|
+
{...root}
|
|
32
34
|
class="theme-dark relative min-h-[var(--height-hero-min)] overflow-hidden bg-black text-fg"
|
|
33
35
|
aria-label={image?.alt || headline}
|
|
34
36
|
>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
---
|
|
2
|
+
import type { RootIdentityProps } from '@gradial/aci';
|
|
2
3
|
import type { ContentProps } from '../../cms/contracts/components/personalizationChoice.contract';
|
|
3
4
|
|
|
4
|
-
type Props = ContentProps;
|
|
5
|
+
type Props = ContentProps & RootIdentityProps;
|
|
5
6
|
|
|
6
|
-
const { title, description, redLabel, blueLabel, refreshLabel } = Astro.props;
|
|
7
|
+
const { title, description, redLabel, blueLabel, refreshLabel, ...root } = Astro.props;
|
|
7
8
|
---
|
|
8
9
|
|
|
9
|
-
<section class="border-y border-[var(--color-border)] bg-[var(--color-surface)] py-[var(--spacing-section-y)]">
|
|
10
|
+
<section {...root} class="border-y border-[var(--color-border)] bg-[var(--color-surface)] py-[var(--spacing-section-y)]">
|
|
10
11
|
<div class="mx-auto max-w-[var(--layout-content-max)] px-[var(--layout-gutter)] text-center">
|
|
11
12
|
<h2 class="text-[length:var(--text-h2)] font-[var(--font-weight-semibold)] text-[var(--color-fg)]">{title}</h2>
|
|
12
13
|
{description ? <p class="mx-auto mt-3 max-w-2xl text-[var(--color-fg-muted)]">{description}</p> : null}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Container from '../elements/Container.astro';
|
|
3
|
+
import type { RootIdentityProps } from '@gradial/aci';
|
|
3
4
|
|
|
4
5
|
interface Stat {
|
|
5
6
|
label: string;
|
|
@@ -7,14 +8,14 @@ interface Stat {
|
|
|
7
8
|
suffix?: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
interface Props {
|
|
11
|
+
interface Props extends RootIdentityProps {
|
|
11
12
|
stats?: Stat[];
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
const { stats = [] } = Astro.props;
|
|
15
|
+
const { stats = [], ...root } = Astro.props;
|
|
15
16
|
---
|
|
16
17
|
|
|
17
|
-
<section class="theme-dark border-y border-[var(--color-edge-space)] bg-[var(--color-space-surface)] py-[var(--spacing-section-y)]">
|
|
18
|
+
<section {...root} class="theme-dark border-y border-[var(--color-edge-space)] bg-[var(--color-space-surface)] py-[var(--spacing-section-y)]">
|
|
18
19
|
<Container>
|
|
19
20
|
<div class="grid gap-8 sm:grid-cols-2 lg:grid-cols-4">
|
|
20
21
|
{stats.map((stat) => (
|
|
@@ -25,7 +25,7 @@ export const sectionStoryFixtures: SectionStoryFixture[] = [
|
|
|
25
25
|
ctaHref: '/docs',
|
|
26
26
|
image: {
|
|
27
27
|
$type: 'gradial.image',
|
|
28
|
-
assetId: '
|
|
28
|
+
assetId: '3Ih26etWBTYfnAd0EjD0pP2h902',
|
|
29
29
|
versionId: 'v0001',
|
|
30
30
|
alt: 'Seattle skyline at dusk',
|
|
31
31
|
sources: [
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { KernelPageBlock } from '@gradial/aci/content';
|
|
3
|
-
import
|
|
3
|
+
import { createRenderChildren } from '@gradial/aci/astro';
|
|
4
|
+
import { registry } from '../cms/registry';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
block: KernelPageBlock;
|
|
@@ -8,8 +9,12 @@ interface Props {
|
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
const { block, direction = 'ltr' } = Astro.props;
|
|
12
|
+
// Stories render through the same seam as pages so the frame carries the
|
|
13
|
+
// block's root identity (sdk I-19, ADR 0051).
|
|
14
|
+
const [child] = createRenderChildren(registry)([block]);
|
|
15
|
+
const Comp = child.Component as any;
|
|
11
16
|
---
|
|
12
17
|
|
|
13
18
|
<div dir={direction}>
|
|
14
|
-
{
|
|
19
|
+
{Comp ? <Comp {...child.props} /> : null}
|
|
15
20
|
</div>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"build:storybook": "storybook build"
|
|
15
15
|
},
|
|
16
16
|
"engines": {
|
|
17
|
-
"node": ">=
|
|
17
|
+
"node": ">=24",
|
|
18
18
|
"npm": ">=10"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"tsx": "^4.20.0",
|
|
32
32
|
"typescript": "5.9.3",
|
|
33
33
|
"vite": "^7.2.7",
|
|
34
|
-
"storybook": "
|
|
35
|
-
"@storybook-astro/framework": "
|
|
36
|
-
"@storybook/addon-docs": "
|
|
37
|
-
"@storybook/builder-vite": "
|
|
34
|
+
"storybook": "10.5.10",
|
|
35
|
+
"@storybook-astro/framework": "1.11.0",
|
|
36
|
+
"@storybook/addon-docs": "10.5.10",
|
|
37
|
+
"@storybook/builder-vite": "10.5.10"
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -48,8 +48,8 @@ const { title, description, canonical, siteName = 'Gradial', collectTag, assignm
|
|
|
48
48
|
// island (@astrojs/react + @c15t/react) or any setup built on
|
|
49
49
|
// c15t's createConsentManagerStore; this bridge picks it up either
|
|
50
50
|
// way. Without a c15t setup the poll gives up silently and only the
|
|
51
|
-
// JS consent API (aci('consent', …)
|
|
52
|
-
//
|
|
51
|
+
// JS consent API (aci('consent', …)) writes envelopes — it is live
|
|
52
|
+
// under every preset, including c15t.
|
|
53
53
|
//
|
|
54
54
|
// Consents are mirrored only after a real visitor decision
|
|
55
55
|
// (consentInfo set), never for pre-decision defaults, so the SDK
|
|
@@ -152,6 +152,56 @@ Optional (disabled by default):
|
|
|
152
152
|
|
|
153
153
|
## Troubleshooting
|
|
154
154
|
|
|
155
|
+
### Deploying a starter to a hosted Vercel tenant
|
|
156
|
+
|
|
157
|
+
Run the CLI from the starter repository root (where `.aci.yaml` lives), or
|
|
158
|
+
pass `--site-dir .` from that directory. Do not pass an absolute site path
|
|
159
|
+
from another working directory: older CLI versions can serialize it as a
|
|
160
|
+
`../../../tmp/...` source folder, which makes the server-side build fail with
|
|
161
|
+
a generic HTTP 500. The source ref must also be a pushed, cloneable branch;
|
|
162
|
+
`ref: HEAD` from a detached worktree is not cloneable by the build service.
|
|
163
|
+
|
|
164
|
+
The hosted publish sequence is:
|
|
165
|
+
|
|
166
|
+
1. `GRADIAL_CODE_SOURCE_TOKEN="$(gh auth token)" aci code-build --site-dir . --branch <test-branch> ...`
|
|
167
|
+
2. `aci branch land <test-branch>` to move the artifact link to `main`.
|
|
168
|
+
3. Promote `/config/site.json` and the content paths needed by the release.
|
|
169
|
+
4. Run `aci release publish --activate ...`.
|
|
170
|
+
|
|
171
|
+
Match the tenant rendering mode to the starter's actual route capability. A
|
|
172
|
+
Next starter with `dynamicParams = false` and no release-scoped runtime route
|
|
173
|
+
is an SSG starter and must use `rendering.mode = "ssg"`; `ssr` is only valid
|
|
174
|
+
when the frontend can resolve arbitrary host release routes at request time.
|
|
175
|
+
A mismatch can build successfully but then fail SSG rendering or return a
|
|
176
|
+
live Next 404 after the host rewrites a CMS page.
|
|
177
|
+
|
|
178
|
+
Injected platform functions must be dependency-closed inside their own
|
|
179
|
+
`.vercel/output/functions/<name>.func` mount. A prebuilt Vercel deploy does not
|
|
180
|
+
install a function-local `package.json` after upload. Native dependencies such
|
|
181
|
+
as `sharp` therefore belong to the host-function artifact, built for Vercel's
|
|
182
|
+
Linux/x64 runtime and injected beside the handler; never add them to the
|
|
183
|
+
starter's `package.json` merely to make a platform function resolve.
|
|
184
|
+
|
|
185
|
+
Publish validates `refs/heads/live`, not only `main`. If `main` deletes a
|
|
186
|
+
stale incompatible page or fragment that was previously promoted, promote
|
|
187
|
+
that same path from `main` with `aci promote --path ... --yes`; because the
|
|
188
|
+
source path is absent, the promote records a delete on `live`. This is the
|
|
189
|
+
API-safe way to remove old live content—direct writes to `live` are forbidden.
|
|
190
|
+
|
|
191
|
+
The same rule applies to breaking DAM identifier changes: every
|
|
192
|
+
`dam.assetRef` in `live` is resolved during publish, so one legacy identifier
|
|
193
|
+
blocks the release. Update the reference on a candidate branch through
|
|
194
|
+
`aci content push`, land it, and promote that exact content path before
|
|
195
|
+
publishing again. Do not weaken identifier validation or reactivate an old
|
|
196
|
+
release to bypass the content migration.
|
|
197
|
+
|
|
198
|
+
Legacy assets themselves are replaced through the product API, not rewritten
|
|
199
|
+
in storage: download or retain the needed source bytes, upload them again so
|
|
200
|
+
DAM creates fresh canonical IDs, approve them, replace every content reference,
|
|
201
|
+
then land, promote, and publish the affected paths. This is the supported
|
|
202
|
+
breaking cutover for pre-public tenants; there is no `ast_` alias or bulk
|
|
203
|
+
object-store migration path.
|
|
204
|
+
|
|
155
205
|
### "Unknown component" error during content compile
|
|
156
206
|
|
|
157
207
|
The content JSON references a `component` name that is not in the contract
|
|
@@ -194,10 +244,10 @@ If a value doesn't survive the round-trip, check:
|
|
|
194
244
|
|------|---------|
|
|
195
245
|
| `.aci.yaml` | ACI config: contract paths, framework, routes, capabilities |
|
|
196
246
|
| `src/cms/contracts/components/index.ts` | Component contract barrel |
|
|
197
|
-
| `src/cms/contracts/layouts/index.ts` | Layout contract barrel |
|
|
198
247
|
| `src/cms/registry.ts` | Component registry (`createRegistry` with `[contract, component]` tuples) |
|
|
199
248
|
| `src/components/` | Runtime component implementations |
|
|
200
249
|
| `src/design-system/` | Design tokens and global styles |
|
|
250
|
+
| `.content/templates/` | Page composition contracts |
|
|
201
251
|
| `.content/` | Local content for development |
|
|
202
252
|
|
|
203
253
|
## Deep Dive: Authoring
|
|
@@ -209,3 +259,10 @@ development, design tokens, and the full contract/runtime split.
|
|
|
209
259
|
|
|
210
260
|
Read `.agents/skills/migration/SKILL.md` for reverse-engineering a live
|
|
211
261
|
site or design into ACI.
|
|
262
|
+
|
|
263
|
+
## Deep Dive: DAM Delivery
|
|
264
|
+
|
|
265
|
+
Read `.agents/skills/dam-delivery/SKILL.md` for public DAM asset links
|
|
266
|
+
(`/dam/{assetId}`): how to shape an image with the `w`, `h`, `fit`, `fm`,
|
|
267
|
+
`q` query, what makes a link serve or stop serving, and when to use a
|
|
268
|
+
link instead of a pre-baked derivative.
|