@gradial/aci 0.1.30 → 0.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/bin/aci-darwin-arm64 +0 -0
- package/bin/aci.js +33 -32
- package/dist/astro/assets.d.ts +46 -0
- package/dist/astro/assets.js +51 -0
- package/dist/astro/index.d.ts +2 -0
- package/dist/astro/index.js +8 -0
- package/dist/astro/page.d.ts +88 -0
- package/dist/astro/page.js +117 -0
- package/dist/content/provider.d.ts +7 -0
- package/dist/dev/content-watch.d.ts +1 -0
- package/dist/dev/content-watch.js +1 -1
- package/dist/next/config.d.ts +6 -0
- package/dist/next/config.js +20 -13
- package/dist/next/content-watch.d.ts +1 -0
- package/dist/next/content-watch.js +2 -2
- package/dist/next/index.d.ts +1 -0
- package/dist/next/index.js +1 -0
- package/dist/next/middleware.d.ts +3 -2
- package/dist/next/middleware.js +40 -7
- package/dist/next/page.d.ts +13 -5
- package/dist/next/page.js +42 -17
- package/dist/next/server.d.ts +1 -1
- package/dist/next/server.js +33 -9
- package/dist/providers/s3.d.ts +7 -0
- package/dist/providers/s3.js +20 -0
- package/dist/testing/conformance/checks.d.ts +12 -0
- package/dist/testing/conformance/checks.js +483 -0
- package/dist/testing/conformance/index.d.ts +3 -0
- package/dist/testing/conformance/index.js +2 -0
- package/dist/testing/conformance/preset.d.ts +14 -0
- package/dist/testing/conformance/preset.js +98 -0
- package/dist/testing/conformance/types.d.ts +45 -0
- package/dist/testing/conformance/types.js +7 -0
- package/package.json +17 -9
- package/src/cli/materialize-template.mjs +133 -0
- package/src/cli/validate-content.mjs +0 -0
- package/src/cli/verify-next-cdn-routes.mjs +10 -19
- package/templates/astro/starter-content/src/cms/contracts/components/button.contract.ts +19 -0
- package/templates/astro/starter-content/src/cms/contracts/components/container.contract.ts +19 -0
- package/templates/astro/starter-content/src/cms/contracts/components/featureCard.contract.ts +15 -0
- package/templates/astro/starter-content/src/cms/contracts/components/featureGrid.contract.ts +16 -0
- package/templates/astro/starter-content/src/cms/contracts/components/homeHero.contract.ts +36 -0
- package/templates/astro/starter-content/src/cms/contracts/components/index.ts +21 -0
- package/templates/astro/starter-content/src/cms/contracts/components/statsBar.contract.ts +19 -0
- package/templates/astro/starter-content/src/cms/registry.ts +28 -0
- package/templates/astro/template/{.aci.yaml → .aci.yaml.tmpl} +1 -1
- package/templates/astro/template/README.md.tmpl +53 -0
- package/templates/astro/template/gitignore +12 -0
- package/templates/astro/template/package.json.tmpl +5 -3
- package/templates/astro/template/src/cms/contracts/components/index.ts +3 -0
- package/templates/astro/template/src/cms/registry.ts +3 -26
- package/templates/astro/template/src/pages/[...slug].astro +13 -35
- package/templates/astro/template/tests/conformance.test.ts.tmpl +12 -0
- package/templates/common/.agents/AGENTS.md +3 -5
- package/templates/common/.agents/skills/aci/SKILL.md +72 -23
- package/templates/common/.agents/skills/authoring/SKILL.md +53 -14
- package/templates/common/.agents/skills/authoring/references/block-registry.md +109 -15
- package/templates/common/.agents/skills/authoring/references/contracts.md +23 -7
- package/templates/common/.agents/skills/authoring/references/repo-structure.md +35 -19
- package/templates/common/.agents/skills/authoring/references/sdk-server-functions.md +75 -17
- package/templates/common/.agents/skills/migration/SKILL.md +7 -1
- package/templates/common/.agents/skills/migration/references/canon-migration.md +471 -0
- package/templates/common/.content/config/site.json.tmpl +15 -0
- package/templates/common/.content/pages/home/_index.json +4 -103
- package/templates/common/.nvmrc +1 -0
- package/templates/common/README.md.tmpl +32 -11
- package/templates/common/contracts/components/index.ts +1 -19
- package/templates/common/design-system/tokens/colors.css +34 -10
- package/templates/common/starter-content/.content/config/robots.txt +2 -0
- package/templates/common/starter-content/.content/pages/home/_index.json +112 -0
- package/templates/common/starter-content/.content/schemas/site.schema.json +138 -0
- package/templates/nextjs/starter-content/src/cms/contracts/components/container.contract.ts +19 -0
- package/templates/nextjs/starter-content/src/cms/contracts/components/featureCard.contract.ts +15 -0
- package/templates/nextjs/starter-content/src/cms/contracts/components/featureGrid.contract.ts +16 -0
- package/templates/nextjs/starter-content/src/cms/contracts/components/index.ts +21 -0
- package/templates/nextjs/starter-content/src/cms/contracts/components/siteFooter.contract.ts +45 -0
- package/templates/nextjs/starter-content/src/cms/contracts/components/siteNavigation.contract.ts +30 -0
- package/templates/nextjs/starter-content/src/cms/contracts/components/statsBar.contract.ts +19 -0
- package/templates/nextjs/starter-content/src/cms/registry.ts +28 -0
- package/templates/nextjs/template/{.aci.yaml → .aci.yaml.tmpl} +1 -1
- package/templates/nextjs/template/README.md.tmpl +52 -0
- package/templates/nextjs/template/gitignore +15 -0
- package/templates/nextjs/template/next.config.mjs +1 -6
- package/templates/nextjs/template/package.json.tmpl +5 -5
- package/templates/nextjs/template/src/app/gradial/assets/[...path]/route.ts +1 -4
- package/templates/nextjs/template/src/app/layout.tsx +1 -3
- package/templates/nextjs/template/src/cms/contracts/components/index.ts +1 -13
- package/templates/nextjs/template/src/cms/registry.ts +3 -26
- package/templates/nextjs/template/src/design-system/styles.css +346 -0
- package/templates/nextjs/template/src/design-system/tokens/colors.css +110 -0
- package/templates/nextjs/template/src/design-system/tokens/components.css +86 -0
- package/templates/nextjs/template/src/design-system/tokens/index.css +6 -0
- package/templates/nextjs/template/src/design-system/tokens/radii.css +5 -0
- package/templates/nextjs/template/src/design-system/tokens/shadows.css +9 -0
- package/templates/nextjs/template/src/design-system/tokens/spacing.css +26 -0
- package/templates/nextjs/template/src/design-system/tokens/typography.css +32 -0
- package/templates/nextjs/template/src/middleware.ts.tmpl +12 -0
- package/templates/nextjs/template/tests/conformance.test.ts.tmpl +12 -0
- package/templates/nextjs/template/src/app/_components/ConsentManager.tsx +0 -132
- package/templates/nextjs/template/src/cms/contracts/components/container.contract.ts +0 -20
- package/templates/nextjs/template/src/middleware.ts +0 -7
- /package/templates/{nextjs/template → astro/starter-content}/src/cms/contracts/components/siteFooter.contract.ts +0 -0
- /package/templates/{nextjs/template → astro/starter-content}/src/cms/contracts/components/siteNavigation.contract.ts +0 -0
- /package/templates/astro/{template → starter-content}/src/components/chrome/Footer.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/chrome/Header.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/elements/AtomicBlock.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/elements/AtomicBlocks.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/elements/Button.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/elements/ButtonBlock.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/elements/Container.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/elements/Icon.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/elements/Logo.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/elements/RemoteImage.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/sections/ContainerSection.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/sections/FeatureCard.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/sections/FeatureGrid.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/sections/HomeHero.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/components/sections/StatsBar.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/fixtures/atomicBlocks.ts +0 -0
- /package/templates/astro/{template → starter-content}/src/fixtures/composition.ts +0 -0
- /package/templates/astro/{template → starter-content}/src/fixtures/index.ts +0 -0
- /package/templates/astro/{template → starter-content}/src/fixtures/sections.ts +0 -0
- /package/templates/astro/{template → starter-content}/src/render/RenderPage.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/stories/CompositionStoryFrame.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/stories/HomeHero.stories.ts +0 -0
- /package/templates/astro/{template → starter-content}/src/stories/SectionStoryFrame.astro +0 -0
- /package/templates/astro/{template → starter-content}/src/stories/StoryDocFrame.astro +0 -0
- /package/templates/common/{.content → starter-content/.content}/.gradial-dam/blobs/sha256/7f/bf/7fbfc7fe230ff12688c496f660119e41d9725c4504d82e310c15665c73c09292 +0 -0
- /package/templates/common/{.content → starter-content/.content}/.gradial-dam/blobs/sha256/a0/f5/a0f506689de9b15a7055f70103a3f02cd3ba105771ae2de6754df2ede1210d3a +0 -0
- /package/templates/common/{.content → starter-content/.content}/.gradial-dam/blobs/sha256/dd/b7/ddb7e9642be08317bcd4b2bd26b58ba8d0d34dd7239e03e684a4f3634fa3845b +0 -0
- /package/templates/common/{.content → starter-content/.content}/.gradial-dam/blobs/sha256/fb/32/fb3260e8286ea8231ea1c77b9c0be92d6edd9026565731eb14cfdcfd6b1b75b3 +0 -0
- /package/templates/common/{.content → starter-content/.content}/config/site.json +0 -0
- /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_about_hero/asset.json +0 -0
- /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_about_hero/editorial.json +0 -0
- /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_about_hero/governance.json +0 -0
- /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_about_hero/versions/v0001.json +0 -0
- /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_home_hero/asset.json +0 -0
- /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_home_hero/editorial.json +0 -0
- /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_home_hero/governance.json +0 -0
- /package/templates/common/{.content → starter-content/.content}/dam/folders/seed/ast_site_home_hero/versions/v0001.json +0 -0
- /package/templates/common/{.content → starter-content/.content}/fragments/navbar/_index.json +0 -0
- /package/templates/common/{.content → starter-content/.content}/fragments/site-footer/_index.json +0 -0
- /package/templates/common/{.content → starter-content/.content}/pages/about/_index.json +0 -0
- /package/templates/common/{public → starter-content/public}/assets/Dwire-model.png +0 -0
- /package/templates/common/{public → starter-content/public}/assets/seattle.avif +0 -0
- /package/templates/nextjs/{template → starter-content}/src/cms/contracts/components/button.contract.ts +0 -0
- /package/templates/nextjs/{template → starter-content}/src/cms/contracts/components/homeHero.contract.ts +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/chrome/Footer.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/chrome/Header.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/elements/AtomicBlock.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/elements/Button.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/elements/ButtonBlock.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/elements/Container.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/elements/Icon.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/elements/Logo.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/sections/ContainerSection.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/sections/FeatureCard.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/sections/FeatureGrid.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/sections/HomeHero.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/components/sections/StatsBar.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/stories/Button.stories.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/stories/Header.stories.tsx +0 -0
- /package/templates/nextjs/{template → starter-content}/src/stories/HomeHero.stories.tsx +0 -0
|
@@ -7,13 +7,19 @@ across preview, local file, and deployed S3 modes. **Always use these
|
|
|
7
7
|
functions instead of directly importing `FileContentProvider` or
|
|
8
8
|
`S3ContentProvider`.** The SDK handles the resolution chain automatically.
|
|
9
9
|
|
|
10
|
-
### `createPage(registry)`
|
|
10
|
+
### `createPage(registry, options?)`
|
|
11
11
|
|
|
12
12
|
The catch-all route handler for Next.js App Router. Owns param
|
|
13
13
|
normalization, content loading via render input, metadata generation,
|
|
14
14
|
`notFound` handling, layout resolution, and block rendering via the
|
|
15
15
|
registry.
|
|
16
16
|
|
|
17
|
+
Path shape: in production, middleware rewrites to `/__r/{releaseId}/routes/{...slug}`.
|
|
18
|
+
The SDK's `resolveRouteAndRelease` decomposes `['__r', releaseId, 'routes', ...pathSegments]`.
|
|
19
|
+
In local dev (`ACI_CONTENT_PROVIDER=file`), requests pass through unrewritten, so `/`
|
|
20
|
+
arrives with an empty/undefined slug. The filesystem uses an **optional catch-all**
|
|
21
|
+
`[[...slug]]` to handle both shapes.
|
|
22
|
+
|
|
17
23
|
```tsx
|
|
18
24
|
// src/app/[[...slug]]/page.tsx
|
|
19
25
|
import { createPage } from '@gradial/aci/next';
|
|
@@ -30,20 +36,32 @@ page regions or layout fragment defaults), and renders blocks via the
|
|
|
30
36
|
registry. The `main` slot is wrapped in `<main>`; other slots render as
|
|
31
37
|
fragments.
|
|
32
38
|
|
|
33
|
-
### `withAci(nextConfig
|
|
39
|
+
### `withAci(nextConfig?, options?)`
|
|
34
40
|
|
|
35
|
-
Next.js config wrapper.
|
|
36
|
-
|
|
41
|
+
Next.js config wrapper. Owns all canonical SDK behavior: output mode,
|
|
42
|
+
outputFileTracingRoot, base-path/build-mode/dist-dir env injection, CDN
|
|
43
|
+
headers, asset rewrites (`/.gradial-dam` prefix), content-watch plugin,
|
|
44
|
+
and public-path scanning. Repos should pass a bare `withAci()` call and
|
|
45
|
+
rely on SDK defaults.
|
|
37
46
|
|
|
38
47
|
```ts
|
|
39
48
|
// next.config.ts
|
|
40
|
-
import { withAci } from '@gradial/aci/next';
|
|
41
|
-
|
|
49
|
+
import { withAci } from '@gradial/aci/next/config';
|
|
50
|
+
|
|
51
|
+
export default withAci();
|
|
52
|
+
```
|
|
42
53
|
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
For site-specific non-CMS routes, pass `passthroughRoutes`:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
export default withAci({
|
|
58
|
+
passthroughRoutes: ['/api/*', '/admin/*'],
|
|
59
|
+
});
|
|
45
60
|
```
|
|
46
61
|
|
|
62
|
+
Do not manually configure outputFileTracing, base-path, build-mode, dist-dir,
|
|
63
|
+
or custom rewrites/redirects for ACI concerns. The SDK handles these.
|
|
64
|
+
|
|
47
65
|
### `getSiteConfig<T>()`
|
|
48
66
|
|
|
49
67
|
Loads the site configuration. Checks the render input header first
|
|
@@ -95,6 +113,38 @@ const previewRelease = await isPreviewMode();
|
|
|
95
113
|
if (previewRelease) { /* preview-specific logic */ }
|
|
96
114
|
```
|
|
97
115
|
|
|
116
|
+
### `createGradialMiddleware(config)`
|
|
117
|
+
|
|
118
|
+
Creates Next.js middleware for ACI sites. Requires explicit `siteId`.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
// src/middleware.ts
|
|
122
|
+
import { createGradialMiddleware } from '@gradial/aci/next/middleware';
|
|
123
|
+
|
|
124
|
+
export default createGradialMiddleware({ siteId: 'your-tenant-id' });
|
|
125
|
+
export { config } from '@gradial/aci/next/middleware';
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The SDK exports a canonical middleware matcher via the `config` export. Repos
|
|
129
|
+
should re-export it verbatim. Do not hand-roll custom matcher patterns unless
|
|
130
|
+
site-specific static paths require exclusions.
|
|
131
|
+
|
|
132
|
+
**Config interface:**
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
export interface GradialMiddlewareConfig {
|
|
136
|
+
siteId: string; // REQUIRED
|
|
137
|
+
edgeConfig?: string;
|
|
138
|
+
previewSignKey?: string;
|
|
139
|
+
deploymentId?: string;
|
|
140
|
+
deploymentProtectionBypass?: string;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The middleware rewrites public URLs to `/__r/{releaseId}/routes/{path}` for
|
|
145
|
+
the app-level route. The SDK extracts releaseId and resolves the content route
|
|
146
|
+
internally.
|
|
147
|
+
|
|
98
148
|
### `DevRefresh`
|
|
99
149
|
|
|
100
150
|
React component for dev-mode content refresh. Connects to the SDK's
|
|
@@ -108,8 +158,8 @@ import { DevRefresh } from '@gradial/aci/next';
|
|
|
108
158
|
<DevRefresh />
|
|
109
159
|
```
|
|
110
160
|
|
|
111
|
-
Only active in development
|
|
112
|
-
in production.
|
|
161
|
+
**Mandatory** for Next.js repos. Only active in development
|
|
162
|
+
(`NODE_ENV !== 'production'`). Renders `null` in production.
|
|
113
163
|
|
|
114
164
|
### Error Classes
|
|
115
165
|
|
|
@@ -158,15 +208,25 @@ app code.** Always use `getPage()`, `getSiteConfig()`, `getFragment()`,
|
|
|
158
208
|
`getLayout()`, or `getRenderInput()` from `@gradial/aci/next`. The SDK
|
|
159
209
|
handles the resolution chain automatically.
|
|
160
210
|
|
|
161
|
-
The only exception is the asset route handler
|
|
162
|
-
(`src/app/gradial/assets/[
|
|
211
|
+
The only exception is the transitional asset route handler
|
|
212
|
+
(`src/app/gradial/assets/[...path]/route.ts`), which directly
|
|
163
213
|
uses `FileContentProvider` for local asset serving and
|
|
164
|
-
`getReleaseAssetResponse` for S3 assets.
|
|
214
|
+
`getReleaseAssetResponse` for S3 assets. The preferred path is to use no
|
|
215
|
+
app-level asset route at all (`withAci()` handles rewrites for Next.js;
|
|
216
|
+
CloudFront function rewrite for Astro). DAM derivative assets are
|
|
217
|
+
content-addressed and globally shared — staged once at `{keyPrefix}/.gradial-dam/`
|
|
218
|
+
and shared across all releases.
|
|
165
219
|
|
|
166
220
|
## Layout.tsx Pattern
|
|
167
221
|
|
|
222
|
+
The root layout is minimal: import CSS, optionally load site config, and
|
|
223
|
+
include `<DevRefresh />`. Chrome (Header/Footer) is **not** in layout.tsx —
|
|
224
|
+
it is CMS-managed via layout fragment defaults and rendered by `createPage`.
|
|
225
|
+
|
|
168
226
|
```tsx
|
|
169
227
|
import { DevRefresh, getSiteConfig } from '@gradial/aci/next';
|
|
228
|
+
import type { ReactNode } from 'react';
|
|
229
|
+
import '@/design-system/styles.css';
|
|
170
230
|
|
|
171
231
|
export default async function Layout({ children }: { children: ReactNode }) {
|
|
172
232
|
const siteConfig = await getSiteConfig<SiteConfig>().catch(() => null);
|
|
@@ -181,10 +241,8 @@ export default async function Layout({ children }: { children: ReactNode }) {
|
|
|
181
241
|
}
|
|
182
242
|
```
|
|
183
243
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
should be minimal — import CSS, optionally load site config for
|
|
187
|
-
metadata/fonts, and render `<DevRefresh />`.
|
|
244
|
+
`<DevRefresh />` is **mandatory** for Next.js repos. It provides dev-mode
|
|
245
|
+
content hot-reload.
|
|
188
246
|
|
|
189
247
|
For sites that need site config in the layout (e.g., for fonts or
|
|
190
248
|
metadata), use `getSiteConfig<SiteConfig>()` with a `.catch(() => null)`
|
|
@@ -134,11 +134,17 @@ discipline rules, and interactivity approach.
|
|
|
134
134
|
Read `references/selector-map.md` for the source-to-target selector
|
|
135
135
|
mapping format that tracks every migrated element.
|
|
136
136
|
|
|
137
|
+
## Deep Dive: Canon Migration
|
|
138
|
+
|
|
139
|
+
Read `references/canon-migration.md` for per-repo migration guidance to the
|
|
140
|
+
frontend canon. This document provides specific migration steps for each repo
|
|
141
|
+
based on the survey divergence matrix (honeywell, optimum, bnc, website-v2).
|
|
142
|
+
|
|
137
143
|
## Validation Gates
|
|
138
144
|
|
|
139
145
|
Before considering any change complete:
|
|
140
146
|
|
|
141
|
-
1. Run `npm run aci:
|
|
147
|
+
1. Run `npm run aci:compile` — contract + content compile (validates content)
|
|
142
148
|
2. Run `npm run typecheck && npm run build` — CI build steps
|
|
143
149
|
3. Run visual regression comparisons
|
|
144
150
|
4. Verify Storybook stories render correctly
|
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
# Canon Migration Reference
|
|
2
|
+
|
|
3
|
+
This document provides repo-specific migration guidance to the frontend canon.
|
|
4
|
+
Use it alongside the canonical spec (`tasks/frontend-canon-decisions.md`) and
|
|
5
|
+
survey divergence matrix (`tasks/frontend-canon-survey.md`).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## General Migration Steps (All Repos)
|
|
10
|
+
|
|
11
|
+
### 1. Update SDK Version
|
|
12
|
+
|
|
13
|
+
All repos to `@gradial/aci` version `^0.1.31` (caret range, no exact pinning).
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @gradial/aci@^0.1.31
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 2. Update Zod Version
|
|
20
|
+
|
|
21
|
+
All repos to `zod` version `^4.0.0` (latest major, caret range).
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install zod@^4.0.0
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 3. Bare `withAci()` Config
|
|
28
|
+
|
|
29
|
+
Simplify framework config to bare `withAci()` call:
|
|
30
|
+
|
|
31
|
+
**Next.js:**
|
|
32
|
+
```ts
|
|
33
|
+
// next.config.ts
|
|
34
|
+
import { withAci } from '@gradial/aci/next/config';
|
|
35
|
+
export default withAci();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Astro:**
|
|
39
|
+
```mjs
|
|
40
|
+
// astro.config.mjs
|
|
41
|
+
import { withAci } from '@gradial/aci/astro';
|
|
42
|
+
export default defineConfig({
|
|
43
|
+
integrations: [withAci()],
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Delete manual env-var plumbing, outputFileTracing, custom rewrites/redirects
|
|
48
|
+
for ACI concerns.
|
|
49
|
+
|
|
50
|
+
### 4. Middleware: Require `siteId`
|
|
51
|
+
|
|
52
|
+
Update middleware to pass explicit `siteId`:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
// src/middleware.ts
|
|
56
|
+
import { createGradialMiddleware } from '@gradial/aci/next/middleware';
|
|
57
|
+
export { config } from '@gradial/aci/next/middleware';
|
|
58
|
+
export default createGradialMiddleware({ siteId: 'your-tenant-id' });
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Re-export the SDK's canonical matcher via `config`. Delete custom matchers
|
|
62
|
+
unless site-specific static paths require exclusions.
|
|
63
|
+
|
|
64
|
+
### 5. Path Shape: `[[...slug]]` (Optional Catch-All)
|
|
65
|
+
|
|
66
|
+
Ensure the filesystem route is `[[...slug]]` (optional catch-all):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# If the repo has a required catch-all, rename to optional:
|
|
70
|
+
mv src/app/\[...slug\] src/app/\[\[...slug\]\]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Update `.aci.yaml`:
|
|
74
|
+
```yaml
|
|
75
|
+
routes:
|
|
76
|
+
cmsManaged: "/[[...slug]]"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Production middleware always rewrites to `/__r/{releaseId}/routes/{path}` so
|
|
80
|
+
slug is non-empty there, but file-provider local dev passes requests
|
|
81
|
+
unrewritten so `/` arrives with an empty slug. A required catch-all 404s
|
|
82
|
+
the dev homepage.
|
|
83
|
+
|
|
84
|
+
### 6. DevRefresh Mandated
|
|
85
|
+
|
|
86
|
+
Add `<DevRefresh />` to the root layout:
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
// src/app/layout.tsx
|
|
90
|
+
import { DevRefresh } from '@gradial/aci/next';
|
|
91
|
+
|
|
92
|
+
export default function Layout({ children }: { children: ReactNode }) {
|
|
93
|
+
return (
|
|
94
|
+
<html lang="en">
|
|
95
|
+
<body>
|
|
96
|
+
{children}
|
|
97
|
+
<DevRefresh />
|
|
98
|
+
</body>
|
|
99
|
+
</html>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 7. Layout Contracts: Use SDK Helpers
|
|
105
|
+
|
|
106
|
+
Replace plain object literals with SDK helpers:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
// src/cms/contracts/layouts/index.ts
|
|
110
|
+
import { defineLayoutContract, slot, fragmentDefault } from '@gradial/aci';
|
|
111
|
+
|
|
112
|
+
export default [
|
|
113
|
+
defineLayoutContract({
|
|
114
|
+
name: 'default',
|
|
115
|
+
slots: [
|
|
116
|
+
slot('header'),
|
|
117
|
+
slot('main', true),
|
|
118
|
+
slot('footer'),
|
|
119
|
+
],
|
|
120
|
+
defaults: {
|
|
121
|
+
header: fragmentDefault('navbar'),
|
|
122
|
+
footer: fragmentDefault('site-footer'),
|
|
123
|
+
},
|
|
124
|
+
}),
|
|
125
|
+
];
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 8. Content Compilation: Standardize CLI Command
|
|
129
|
+
|
|
130
|
+
Update `package.json`:
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"scripts": {
|
|
135
|
+
"content:compile": "aci content compile --content .content --out .aci/compiled"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Replace bespoke scripts like `gradial-aci build --skip-code ...` with the
|
|
141
|
+
standard command.
|
|
142
|
+
|
|
143
|
+
### 9. Storybook: Upgrade to v10
|
|
144
|
+
|
|
145
|
+
For repos on Storybook 9, upgrade to Storybook 10:
|
|
146
|
+
|
|
147
|
+
**Next.js:**
|
|
148
|
+
```bash
|
|
149
|
+
npx storybook@latest upgrade
|
|
150
|
+
npm install --save-dev @storybook/nextjs-vite
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Astro:**
|
|
154
|
+
```bash
|
|
155
|
+
npx storybook@latest upgrade
|
|
156
|
+
npm install --save-dev @storybook-astro/framework
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 10. Replace `aci doctor` with Testing Preset
|
|
160
|
+
|
|
161
|
+
Delete references to `npm run aci:doctor` and `aci doctor` commands. Add the
|
|
162
|
+
SDK testing preset to your CI test suite:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
// tests/conformance.test.ts
|
|
166
|
+
import { conformancePreset } from '@gradial/aci/testing';
|
|
167
|
+
|
|
168
|
+
conformancePreset({
|
|
169
|
+
framework: 'next',
|
|
170
|
+
siteId: 'your-tenant-id',
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Repo-Specific Migration Notes
|
|
177
|
+
|
|
178
|
+
### Honeywell Aerospace (aci-honeywell-aerospace)
|
|
179
|
+
|
|
180
|
+
**Most divergent Next.js repo.** Requires the most comprehensive migration.
|
|
181
|
+
|
|
182
|
+
#### Critical Changes
|
|
183
|
+
|
|
184
|
+
1. **Replace Custom Page Entry with `createPage`**
|
|
185
|
+
|
|
186
|
+
Delete `src/app/[[...slug]]/page.tsx` (60+ line custom implementation) and
|
|
187
|
+
replace with canonical SDK pattern:
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
// src/app/[[...slug]]/page.tsx
|
|
191
|
+
import { createPage } from '@gradial/aci/next/page';
|
|
192
|
+
import { registry } from '@/cms/registry';
|
|
193
|
+
|
|
194
|
+
const page = createPage(registry);
|
|
195
|
+
export const dynamic = 'force-dynamic';
|
|
196
|
+
export const generateMetadata = page.generateMetadata;
|
|
197
|
+
export default page.default;
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
This eliminates:
|
|
201
|
+
- Custom `resolveRouteFromParams`
|
|
202
|
+
- Custom `loadPage`/`loadSiteConfig` via `src/lib/content.ts`
|
|
203
|
+
- Custom `<CmsPage>` render component
|
|
204
|
+
- `generateStaticParams` with direct `FileContentProvider` imports
|
|
205
|
+
|
|
206
|
+
2. **Adopt `createRegistry()` (Delete Hand-Rolled Map)**
|
|
207
|
+
|
|
208
|
+
Replace the hand-rolled `Record<string, ComponentType<any>>` map in
|
|
209
|
+
`src/components/cms/renderBlock.tsx` with a typed registry:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
// src/cms/registry.ts
|
|
213
|
+
import { createRegistry } from '@gradial/aci';
|
|
214
|
+
import { heroContract } from './contracts/components/hero.contract';
|
|
215
|
+
import { Hero } from '@/components/sections/Hero';
|
|
216
|
+
// ... import all contracts and components
|
|
217
|
+
|
|
218
|
+
export const registry = createRegistry([
|
|
219
|
+
[heroContract, Hero],
|
|
220
|
+
// ... all other [contract, component] tuples
|
|
221
|
+
]);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
The contracts already exist in `src/cms/contracts/` — wire them into the
|
|
225
|
+
registry and delete the hand-rolled map.
|
|
226
|
+
|
|
227
|
+
3. **Delete Custom Content Provider**
|
|
228
|
+
|
|
229
|
+
Delete `src/lib/content.ts` (thin wrapper over SDK server functions). Use
|
|
230
|
+
SDK server functions directly:
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
import { getSiteConfig, getPage } from '@gradial/aci/next';
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
4. **Remove Custom Asset Route**
|
|
237
|
+
|
|
238
|
+
Delete `src/app/gradial/assets/[releaseId]/[...path]/route.ts` (with extra
|
|
239
|
+
`[releaseId]` segment). Replace with standard path:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
// src/app/gradial/assets/[...path]/route.ts
|
|
243
|
+
export { GET, runtime, dynamic } from '@gradial/aci/next/asset-route';
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The SDK asset-route handler resolves releaseId internally. No need for an
|
|
247
|
+
explicit path segment.
|
|
248
|
+
|
|
249
|
+
5. **Delete `content-assets` Route and `.gradial-dam` Rewrite**
|
|
250
|
+
|
|
251
|
+
Delete `src/app/content-assets/[...key]/route.ts` and remove the
|
|
252
|
+
`.gradial-dam` rewrite from `next.config.ts`. The SDK asset route handles
|
|
253
|
+
both dev-mode file serving and deployed S3 serving.
|
|
254
|
+
|
|
255
|
+
6. **Delete Runtime `layouts.ts`**
|
|
256
|
+
|
|
257
|
+
Delete `src/cms/layouts.ts` (runtime layout definition duplicating the
|
|
258
|
+
contract-side definition). `createPage` reads layouts from the contract/
|
|
259
|
+
compiled data, not a runtime definition.
|
|
260
|
+
|
|
261
|
+
7. **Update Layout Contract Defaults**
|
|
262
|
+
|
|
263
|
+
Replace raw `{kind: 'fragment-ref' as const, ...}` objects with
|
|
264
|
+
`fragmentDefault()`:
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
defaults: {
|
|
268
|
+
header: fragmentDefault('navbar'),
|
|
269
|
+
footer: fragmentDefault('site-footer'),
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
8. **Update `.aci.yaml` siteId**
|
|
274
|
+
|
|
275
|
+
Change `siteId: site_nextjs` (generic/wrong) to `siteId: honeywell-aerospace`
|
|
276
|
+
(matches tenant name in infrastructure).
|
|
277
|
+
|
|
278
|
+
#### Risk Mitigation
|
|
279
|
+
|
|
280
|
+
- Verify `createPage` handles the honeywell component set without regressions.
|
|
281
|
+
- Test the full page render pipeline after migrating from custom page entry.
|
|
282
|
+
- Ensure all contracts are correctly wired into the new typed registry.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
### BNC (aci-bnc)
|
|
287
|
+
|
|
288
|
+
**Cleanest follower.** Minimal divergence.
|
|
289
|
+
|
|
290
|
+
#### Required Changes
|
|
291
|
+
|
|
292
|
+
1. **Update Layout Contract Style**
|
|
293
|
+
|
|
294
|
+
Replace plain object literals with SDK helpers:
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
// src/cms/contracts/layouts/index.ts
|
|
298
|
+
import { defineLayoutContract, slot, fragmentDefault } from '@gradial/aci';
|
|
299
|
+
|
|
300
|
+
export default [
|
|
301
|
+
defineLayoutContract({
|
|
302
|
+
name: 'default',
|
|
303
|
+
slots: [
|
|
304
|
+
slot('header'),
|
|
305
|
+
slot('main', true),
|
|
306
|
+
slot('footer'),
|
|
307
|
+
],
|
|
308
|
+
defaults: {
|
|
309
|
+
header: fragmentDefault('navbar'),
|
|
310
|
+
footer: fragmentDefault('site-footer'),
|
|
311
|
+
},
|
|
312
|
+
}),
|
|
313
|
+
];
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
2. **Add `siteId` to Middleware**
|
|
317
|
+
|
|
318
|
+
Update middleware to pass explicit `siteId`:
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
export default createGradialMiddleware({ siteId: 'bnc' });
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
3. **General Migration Steps**
|
|
325
|
+
|
|
326
|
+
Apply all general migration steps (SDK version, Zod version, Storybook
|
|
327
|
+
upgrade, etc.).
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
### Optimum (aci-optimum)
|
|
332
|
+
|
|
333
|
+
**Only Astro repo in production.** Needs Astro-specific patterns.
|
|
334
|
+
|
|
335
|
+
#### Required Changes
|
|
336
|
+
|
|
337
|
+
1. **Replace Manual Page Entry with `getPageData()`**
|
|
338
|
+
|
|
339
|
+
Replace the ~60-line manual page entry in `src/pages/[...slug].astro` with
|
|
340
|
+
the SDK's `getPageData()` helper (the Astro equivalent of Next.js `createPage`):
|
|
341
|
+
|
|
342
|
+
```astro
|
|
343
|
+
---
|
|
344
|
+
// src/pages/[...slug].astro
|
|
345
|
+
import { getGradialStaticPaths, getPageData, createRenderChildren } from '@gradial/aci/astro';
|
|
346
|
+
import { registry } from '../cms/registry';
|
|
347
|
+
import SiteLayout from '../layouts/SiteLayout.astro';
|
|
348
|
+
|
|
349
|
+
export const getStaticPaths = getGradialStaticPaths;
|
|
350
|
+
|
|
351
|
+
const data = await getPageData(Astro);
|
|
352
|
+
const renderChildren = createRenderChildren(registry);
|
|
353
|
+
---
|
|
354
|
+
<!-- render data.layout.slots via renderChildren -->
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
This eliminates all direct `FileContentProvider` imports and manual
|
|
358
|
+
layout/slot resolution from the page entry.
|
|
359
|
+
|
|
360
|
+
For DAM asset URLs, use `damAssetUrl()` from `@gradial/aci/astro`:
|
|
361
|
+
|
|
362
|
+
```astro
|
|
363
|
+
---
|
|
364
|
+
import { damAssetUrl } from '@gradial/aci/astro';
|
|
365
|
+
---
|
|
366
|
+
<img src={damAssetUrl('images/hero.webp')} alt="Hero" />
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
2. **CloudFront Asset Behavior (Infrastructure Change)**
|
|
370
|
+
|
|
371
|
+
DAM derivative assets are content-addressed and globally shared — staged once
|
|
372
|
+
at the hosting bucket's global `.gradial-dam/` location and shared across all
|
|
373
|
+
releases. The existing CloudFront function in
|
|
374
|
+
`infra/modules/hosting-cloudfront-site/function.js.tftpl` already handles the
|
|
375
|
+
rewrite automatically, rewriting `/.gradial-dam/*` requests to
|
|
376
|
+
`{keyPrefix}/.gradial-dam/*` with no release lookup.
|
|
377
|
+
|
|
378
|
+
**No infrastructure changes are needed** — the CloudFront function rewrite is
|
|
379
|
+
already in place and handles DAM asset serving automatically with immutable
|
|
380
|
+
caching (`max-age=31536000`).
|
|
381
|
+
|
|
382
|
+
3. **Update Layout Contract Defaults**
|
|
383
|
+
|
|
384
|
+
Replace raw inline objects with `fragmentDefault()`:
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
defaults: {
|
|
388
|
+
header: fragmentDefault('navbar'),
|
|
389
|
+
footer: fragmentDefault('site-footer'),
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
4. **General Migration Steps**
|
|
394
|
+
|
|
395
|
+
Apply all general migration steps (SDK version, Zod version, Storybook
|
|
396
|
+
upgrade, etc.).
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
### Website-v2 (gradial/website-v2)
|
|
401
|
+
|
|
402
|
+
**Golden reference (Next.js).** Needs only minor updates.
|
|
403
|
+
|
|
404
|
+
#### Required Changes
|
|
405
|
+
|
|
406
|
+
1. **SDK Version Bump**
|
|
407
|
+
|
|
408
|
+
Bump from `^0.1.28` to `^0.1.31`. Test on gradial-dev first (has the most
|
|
409
|
+
content/components and potential for breakage).
|
|
410
|
+
|
|
411
|
+
2. **General Migration Steps**
|
|
412
|
+
|
|
413
|
+
Apply all general migration steps. Website-v2 is already close to the canon;
|
|
414
|
+
the main task is updating to the latest SDK and conformance preset.
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
### Website-v2-Astro (gradial/website-v2-astro)
|
|
419
|
+
|
|
420
|
+
**MISNAMED — Actually Next.js.** Despite the name, this repo is a Next.js 15
|
|
421
|
+
app, not Astro. It mirrors website-v2's structure.
|
|
422
|
+
|
|
423
|
+
#### Required Changes
|
|
424
|
+
|
|
425
|
+
Same as website-v2 (it's a near-clone). Treat as a Next.js repo, not an Astro
|
|
426
|
+
repo.
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## Conformance Validation
|
|
431
|
+
|
|
432
|
+
After migration, validate conformance using the SDK testing preset:
|
|
433
|
+
|
|
434
|
+
```ts
|
|
435
|
+
import { conformancePreset } from '@gradial/aci/testing';
|
|
436
|
+
|
|
437
|
+
conformancePreset({
|
|
438
|
+
framework: 'next',
|
|
439
|
+
siteId: 'your-tenant-id',
|
|
440
|
+
});
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
The preset validates (default checks):
|
|
444
|
+
- `config` -- `withAci()` present in config
|
|
445
|
+
- `registry` -- `createRegistry()` usage (no hand-rolled maps)
|
|
446
|
+
- `pageEntry` -- `createPage(registry)` usage in catch-all route
|
|
447
|
+
- `middleware` -- `createGradialMiddleware({ siteId })` with correct siteId
|
|
448
|
+
- `noFileContentProvider` -- no direct `FileContentProvider` imports in app code
|
|
449
|
+
- `noCustomContent` -- no `src/lib/content.ts` shim
|
|
450
|
+
- `noLegacyAssetRoute` -- no `[releaseId]` segment in asset route path
|
|
451
|
+
- `sdkVersion` -- SDK version >= 0.1.31
|
|
452
|
+
|
|
453
|
+
Optional (disabled by default, shell out):
|
|
454
|
+
- `buildSucceeds` -- full build completes
|
|
455
|
+
- `contentCompile` -- content compilation succeeds
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
## Spec Ambiguities (Veto Pending)
|
|
460
|
+
|
|
461
|
+
The following interpretations from the spec may need clarification:
|
|
462
|
+
|
|
463
|
+
| Ruling | Interpretation | Risk |
|
|
464
|
+
|--------|----------------|------|
|
|
465
|
+
| 7 (Asset routes) | `withAci()` for Next.js; CloudFront for Astro. Asset-route export stays transitional. | May want immediate deletion |
|
|
466
|
+
| 11 (Content compile) | npm-wrapped Go CLI: `npx @gradial/aci content compile` | May mean new TS-native command |
|
|
467
|
+
| 12 (Slug shape) | `[[...slug]]` optional — file-provider dev needs empty slug for `/` | N/A (resolved) |
|
|
468
|
+
| 15 (Zod version) | zod 4.x caret range | May mean pin exact minor |
|
|
469
|
+
|
|
470
|
+
> **Note:** If any of these interpretations are incorrect, the implementing
|
|
471
|
+
> workstreams (A/B/C) will also need guidance. Flag ambiguities early.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$type": "site",
|
|
3
|
+
"id": "{{siteName}}",
|
|
4
|
+
"status": "published",
|
|
5
|
+
"title": "{{siteName}}",
|
|
6
|
+
"domain": "localhost",
|
|
7
|
+
"defaultLocale": "en-us",
|
|
8
|
+
"locales": ["en-us"],
|
|
9
|
+
"overlayResolution": ["locale"],
|
|
10
|
+
"brandHref": "/",
|
|
11
|
+
"seo": {
|
|
12
|
+
"title": "{{siteName}}",
|
|
13
|
+
"description": "An ACI site."
|
|
14
|
+
}
|
|
15
|
+
}
|