@gradial/aci 0.1.52-rc.3 → 0.1.52-rc.34-e2e.1
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 +80 -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 -194
- package/dist/audience-data-models.js +314 -51
- package/dist/cli/compile-registry.d.mts +5 -1
- package/dist/cli/compile-registry.mjs +31 -46
- package/dist/cli/mintlify-render.mjs +8 -0
- package/dist/cli/validate-content.d.mts +31 -1
- package/dist/cli/validate-content.mjs +50 -12
- 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 +67 -20
- 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 +33 -4
- package/dist/content/resolve-slots.js +127 -19
- package/dist/content/types.d.ts +7 -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/compose.d.ts +24 -0
- package/dist/internal/domain/edge/compose.js +89 -0
- package/dist/internal/domain/edge/identity.d.ts +5 -0
- package/dist/internal/domain/edge/identity.js +50 -14
- package/dist/internal/domain/edge/index.d.ts +2 -0
- package/dist/internal/domain/edge/index.js +2 -0
- 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 +789 -198
- package/dist/internal/domain/edge/personalization_index.d.ts +17 -0
- package/dist/internal/domain/edge/personalization_index.js +56 -0
- package/dist/internal/domain/edge/record/codec.d.ts +6 -32
- package/dist/internal/domain/edge/record/codec.js +86 -168
- 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 +93 -41
- package/dist/internal/domain/edge/types.js +3 -3
- package/dist/internal/domain/edge/variant_key.d.ts +3 -0
- package/dist/internal/domain/edge/variant_key.js +44 -0
- package/dist/internal/platform/collectionstore/errors.d.ts +24 -0
- package/dist/internal/platform/collectionstore/errors.js +48 -0
- package/dist/mimic/core.d.ts +2 -0
- package/dist/mimic/core.js +31 -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/hosted-page-target.d.ts +7 -0
- package/dist/next/hosted-page-target.js +39 -0
- package/dist/next/index.d.ts +1 -1
- package/dist/next/index.js +3 -1
- package/dist/next/page.d.ts +29 -6
- package/dist/next/page.js +47 -25
- package/dist/next/release-context.d.ts +29 -0
- package/dist/next/release-context.js +55 -0
- package/dist/next/render.d.ts +1 -1
- package/dist/next/render.js +15 -5
- package/dist/next/server.d.ts +8 -0
- package/dist/next/server.js +44 -3
- package/dist/next/vercel-edge-projection-v1.d.ts +0 -9
- package/dist/next/vercel-edge-projection-v1.js +9 -539
- 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/VideoPlayer.js +2 -2
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +2 -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.d.ts +2 -0
- package/dist/types/block-ref.js +3 -2
- package/dist/types/component.d.ts +9 -0
- package/dist/types/config.d.ts +0 -1
- package/dist/types/image.d.ts +54 -17
- package/dist/types/image.js +102 -18
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.js +0 -1
- package/dist/types/media.d.ts +14 -6
- package/dist/types/page.d.ts +0 -1
- package/dist/types/video.d.ts +7 -3
- package/migrations/conformance-registry.md +22 -0
- package/package.json +21 -7
- package/src/cli/compile-registry.mjs +30 -42
- package/src/cli/mintlify-render.mjs +9 -0
- package/src/cli/validate-content.mjs +52 -13
- package/src/types/block-ref.test.ts +60 -0
- package/src/types/block-ref.ts +4 -2
- package/src/types/component.ts +10 -0
- package/src/types/config.ts +0 -1
- package/src/types/image.ts +133 -29
- package/src/types/index.ts +0 -1
- package/src/types/page.ts +0 -1
- package/src/types/video.ts +1 -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/atomicBlocks.ts +7 -6
- package/templates/astro/starter-content/src/fixtures/composition.ts +3 -2
- package/templates/astro/starter-content/src/fixtures/sections.ts +3 -3
- 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 +203 -43
- package/templates/common/.agents/skills/authoring/references/block-registry.md +19 -3
- package/templates/common/.agents/skills/authoring/references/block-slots.md +3 -0
- 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 +217 -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/{home/_index.json → _index.json} +10 -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/.rules-baseline.json +8 -0
- package/templates/common/starter-content/.content/config/site.json +1 -1
- package/templates/common/starter-content/.content/content-rules/no-public-resource-paths.json +6 -0
- package/templates/common/starter-content/.content/dam/README.md +74 -0
- package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/asset.json +1 -1
- package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000101}/governance.json +2 -1
- package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/asset.json +1 -1
- package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000102}/governance.json +2 -1
- package/templates/common/starter-content/.content/fragments/navbar/_index.json +23 -20
- package/templates/common/starter-content/.content/fragments/site-footer/_index.json +59 -56
- package/templates/common/starter-content/.content/pages/404/_index.json +2 -2
- package/templates/common/starter-content/.content/pages/{home/_index.json → _index.json} +23 -3
- package/templates/common/starter-content/.content/pages/about/_index.json +5 -2
- package/templates/common/starter-content/.content/pages/error/_index.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/button.json +55 -0
- package/templates/common/starter-content/.content/patterns/components/container.json +67 -0
- package/templates/common/starter-content/.content/patterns/components/feature_card.json +30 -0
- package/templates/common/starter-content/.content/patterns/components/feature_grid.json +59 -0
- package/templates/common/starter-content/.content/patterns/components/home_hero.json +151 -0
- package/templates/common/starter-content/.content/patterns/components/personalization_choice.json +42 -0
- package/templates/common/starter-content/.content/patterns/components/site-footer.json +203 -0
- package/templates/common/starter-content/.content/patterns/components/site-navigation.json +115 -0
- package/templates/common/starter-content/.content/patterns/components/stats_bar.json +45 -0
- 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 +9 -0
- 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/next/collect-route.d.ts +0 -19
- package/dist/next/collect-route.js +0 -459
- 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-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/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/.content/overlays/audience/preference-blue/pages/{home/_index.json → _index.json} +0 -0
- /package/templates/common/.content/overlays/audience/preference-red/pages/{home/_index.json → _index.json} +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_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_about_hero → 000000000000000000000000102}/versions/v0001.json +0 -0
package/dist/next/page.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { notFound } from 'next/navigation.js';
|
|
3
|
+
import { headers } from 'next/headers.js';
|
|
3
4
|
import { Fragment } from 'react';
|
|
4
5
|
import { PageNotFoundError, getRenderInput, getLayout, getFragment, } from './server.js';
|
|
6
|
+
import { MIMIC_BANNER_HEADER, decodeMimicBanner } from '../mimic/core.js';
|
|
5
7
|
import { routeMetadataForContent, resolveSlots, } from '../content/index.js';
|
|
6
8
|
import { renderBlocks } from './render.js';
|
|
7
9
|
import { AssignmentsScript } from './assignments-script.js';
|
|
8
10
|
import { CollectScript } from './collect-script.js';
|
|
9
11
|
import { renderProofContentFor } from '../internal/render-proof.js';
|
|
12
|
+
import { parseHostedPageTarget } from './hosted-page-target.js';
|
|
10
13
|
/**
|
|
11
14
|
* Creates the catch-all route handler for a Next.js ACI site.
|
|
12
15
|
*
|
|
@@ -28,12 +31,10 @@ import { renderProofContentFor } from '../internal/render-proof.js';
|
|
|
28
31
|
* the collect script tag exactly once per page (design/04 contract tag).
|
|
29
32
|
*
|
|
30
33
|
* Release-scoped routes (production): the middleware rewrites a public URL
|
|
31
|
-
* to `/__r/{releaseId}/
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* The `routes` namespace segment leaves room for future siblings under
|
|
36
|
-
* the release prefix (e.g. `/__r/{releaseId}/assets/*`).
|
|
34
|
+
* to `/__r/{releaseId}/{targetRef}`. The target ref selects the exact immutable
|
|
35
|
+
* base or variant page while its prefix identifies the logical public route.
|
|
36
|
+
* createPage passes both identities to the content loader, giving each target
|
|
37
|
+
* a distinct CDN cache key without sending selection headers into Next.
|
|
37
38
|
*
|
|
38
39
|
* Dev pass-through (ACI_CONTENT_PROVIDER=file): the middleware passes
|
|
39
40
|
* requests through unrewritten, so `/` arrives with an empty/undefined
|
|
@@ -49,8 +50,9 @@ import { renderProofContentFor } from '../internal/render-proof.js';
|
|
|
49
50
|
export function createPage(registry, options) {
|
|
50
51
|
const dynamic = 'force-dynamic';
|
|
51
52
|
async function generateMetadata({ params }) {
|
|
52
|
-
const { route, releaseId } = await resolveRouteAndRelease(params);
|
|
53
|
-
const
|
|
53
|
+
const { route, releaseId, pageRef } = await resolveRouteAndRelease(params);
|
|
54
|
+
const fetchConfig = { releaseId, pageRef };
|
|
55
|
+
const input = await getRenderInput(route, fetchConfig);
|
|
54
56
|
const meta = routeMetadataForContent(input.siteConfig, input.page);
|
|
55
57
|
return {
|
|
56
58
|
title: meta.title,
|
|
@@ -64,8 +66,8 @@ export function createPage(registry, options) {
|
|
|
64
66
|
};
|
|
65
67
|
}
|
|
66
68
|
async function CatchAllPage({ params }) {
|
|
67
|
-
const { route, releaseId } = await resolveRouteAndRelease(params);
|
|
68
|
-
const fetchConfig = { releaseId };
|
|
69
|
+
const { route, releaseId, pageRef } = await resolveRouteAndRelease(params);
|
|
70
|
+
const fetchConfig = { releaseId, pageRef };
|
|
69
71
|
try {
|
|
70
72
|
const input = await getRenderInput(route, fetchConfig);
|
|
71
73
|
if (!input.page)
|
|
@@ -84,9 +86,9 @@ export function createPage(registry, options) {
|
|
|
84
86
|
}
|
|
85
87
|
return (_jsx(Fragment, { children: renderedBlocks }, slot.name));
|
|
86
88
|
}));
|
|
87
|
-
return (_jsxs(_Fragment, { children: [renderProofContent
|
|
89
|
+
return (_jsxs(_Fragment, { children: [renderedSlots.filter(Boolean), _jsx(AssignmentsScript, { page: input.page }), _jsx(CollectScript, { siteConfig: input.siteConfig }), _jsx(MimicBanner, { html: await readMimicBannerHTML() }), renderProofContent
|
|
88
90
|
? _jsx("meta", { name: "aci-render-proof", content: renderProofContent })
|
|
89
|
-
: null
|
|
91
|
+
: null] }));
|
|
90
92
|
}
|
|
91
93
|
catch (error) {
|
|
92
94
|
if (error instanceof PageNotFoundError)
|
|
@@ -105,19 +107,18 @@ export function createPage(registry, options) {
|
|
|
105
107
|
*
|
|
106
108
|
* Two shapes are supported:
|
|
107
109
|
*
|
|
108
|
-
* 1. **Rewritten (production):** middleware rewrites a public URL to
|
|
109
|
-
* `/__r/{releaseId}
|
|
110
|
-
* `['__r', releaseId, '
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* under the same release prefix).
|
|
110
|
+
* 1. **Rewritten (production):** middleware rewrites a public URL to the exact
|
|
111
|
+
* selected target under `/__r/{releaseId}`. A root variant therefore has
|
|
112
|
+
* `['__r', releaseId, '__variant', variantKey]`. The full suffix selects the
|
|
113
|
+
* immutable page object; the segments before the reserved `__variant`
|
|
114
|
+
* namespace form the logical public route.
|
|
114
115
|
*
|
|
115
116
|
* 2. **Dev pass-through (ACI_CONTENT_PROVIDER=file):** middleware passes
|
|
116
117
|
* requests through unrewritten, so the slug is the raw public path
|
|
117
118
|
* segments (possibly empty/undefined for `/`). No releaseId is present;
|
|
118
119
|
* the file provider serves content from disk.
|
|
119
120
|
*/
|
|
120
|
-
async function resolveRouteAndRelease(params) {
|
|
121
|
+
export async function resolveRouteAndRelease(params) {
|
|
121
122
|
const resolved = await params;
|
|
122
123
|
const slug = resolved.slug ?? [];
|
|
123
124
|
if (slug.length >= 2 && slug[0] === '__r') {
|
|
@@ -125,13 +126,14 @@ async function resolveRouteAndRelease(params) {
|
|
|
125
126
|
if (!releaseId || releaseId.includes('/') || releaseId === '.' || releaseId === '..') {
|
|
126
127
|
return { route: '/' };
|
|
127
128
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (rest.length === 0)
|
|
131
|
-
return { route: '/', releaseId };
|
|
132
|
-
if (rest.some((s) => s === '' || s === '.' || s === '..'))
|
|
129
|
+
const target = parseHostedPageTarget(slug.slice(2));
|
|
130
|
+
if (!target)
|
|
133
131
|
return { route: '/' };
|
|
134
|
-
return {
|
|
132
|
+
return {
|
|
133
|
+
route: target.route,
|
|
134
|
+
releaseId,
|
|
135
|
+
pageRef: target.pageRef,
|
|
136
|
+
};
|
|
135
137
|
}
|
|
136
138
|
const route = routeFromSlug(slug);
|
|
137
139
|
return { route };
|
|
@@ -141,3 +143,23 @@ function routeFromSlug(slug) {
|
|
|
141
143
|
return '/';
|
|
142
144
|
return `/${slug.join('/')}/`;
|
|
143
145
|
}
|
|
146
|
+
// The middleware emits the banner HTML in a reserved request header only
|
|
147
|
+
// after validating a signed mimic token; viewer-forged copies are stripped at
|
|
148
|
+
// the dispatch gate (specs/features/audience-mimic REQ-4). The header read
|
|
149
|
+
// happens here (the page already awaits request-scoped data) so the banner
|
|
150
|
+
// itself stays a synchronous leaf.
|
|
151
|
+
async function readMimicBannerHTML() {
|
|
152
|
+
try {
|
|
153
|
+
const current = await headers();
|
|
154
|
+
return decodeMimicBanner(current.get(MIMIC_BANNER_HEADER) || '');
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// headers() has no request context in static generation and unit tests.
|
|
158
|
+
return '';
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function MimicBanner({ html }) {
|
|
162
|
+
if (!html)
|
|
163
|
+
return null;
|
|
164
|
+
return _jsx("div", { dangerouslySetInnerHTML: { __html: html } });
|
|
165
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The release identity of a request the hosting router rewrote to
|
|
3
|
+
* `/__r/{releaseId}/…`. The catch-all reads the release from that path; Next
|
|
4
|
+
* code that receives no route params (the not-found seat, release-less SDK
|
|
5
|
+
* reads such as a secondary `getPage('/blog')`) reads it from this header.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors the router's signer byte for byte
|
|
8
|
+
* (internal/domain/hosting/runtime/edgeoutput/vercel_middleware.ts):
|
|
9
|
+
* `v1.<base64url HMAC-SHA256>.<releaseId>`, keyed by the deployment's
|
|
10
|
+
* ACI_INTERNAL_ARTIFACT_SECRET over "gradial.release-context.v1\n" +
|
|
11
|
+
* releaseId. The router strips any inbound copy, but requests under /api,
|
|
12
|
+
* /assets, /_astro, /_next and /favicon.ico bypass the router and reach Next
|
|
13
|
+
* with the visitor's own headers — so presence alone proves nothing and an
|
|
14
|
+
* unverifiable value selects no release.
|
|
15
|
+
*/
|
|
16
|
+
export declare const RELEASE_CONTEXT_HEADER = "x-aci-release-context";
|
|
17
|
+
/** Returns the release a context value names when its signature verifies. */
|
|
18
|
+
export declare function verifyReleaseContext(value: string, secret: string): string | null;
|
|
19
|
+
export interface RoutedRelease {
|
|
20
|
+
/** The verified release the router dispatched this request to. */
|
|
21
|
+
releaseId?: string;
|
|
22
|
+
/** Why a present context was not used; it never selects a release. */
|
|
23
|
+
rejected?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Reads the routed release of the current request. Outside a request scope
|
|
27
|
+
* (build, static generation, tooling) or without the header there is none.
|
|
28
|
+
*/
|
|
29
|
+
export declare function routedRelease(): Promise<RoutedRelease>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { headers } from 'next/headers.js';
|
|
3
|
+
/**
|
|
4
|
+
* The release identity of a request the hosting router rewrote to
|
|
5
|
+
* `/__r/{releaseId}/…`. The catch-all reads the release from that path; Next
|
|
6
|
+
* code that receives no route params (the not-found seat, release-less SDK
|
|
7
|
+
* reads such as a secondary `getPage('/blog')`) reads it from this header.
|
|
8
|
+
*
|
|
9
|
+
* Mirrors the router's signer byte for byte
|
|
10
|
+
* (internal/domain/hosting/runtime/edgeoutput/vercel_middleware.ts):
|
|
11
|
+
* `v1.<base64url HMAC-SHA256>.<releaseId>`, keyed by the deployment's
|
|
12
|
+
* ACI_INTERNAL_ARTIFACT_SECRET over "gradial.release-context.v1\n" +
|
|
13
|
+
* releaseId. The router strips any inbound copy, but requests under /api,
|
|
14
|
+
* /assets, /_astro, /_next and /favicon.ico bypass the router and reach Next
|
|
15
|
+
* with the visitor's own headers — so presence alone proves nothing and an
|
|
16
|
+
* unverifiable value selects no release.
|
|
17
|
+
*/
|
|
18
|
+
export const RELEASE_CONTEXT_HEADER = 'x-aci-release-context';
|
|
19
|
+
const SECRET_ENV = 'ACI_INTERNAL_ARTIFACT_SECRET';
|
|
20
|
+
const MESSAGE_PREFIX = 'gradial.release-context.v1\n';
|
|
21
|
+
const RELEASE_CONTEXT_PATTERN = /^v1\.([A-Za-z0-9_-]{43})\.([A-Za-z0-9][A-Za-z0-9._-]{0,127})$/;
|
|
22
|
+
/** Returns the release a context value names when its signature verifies. */
|
|
23
|
+
export function verifyReleaseContext(value, secret) {
|
|
24
|
+
const match = RELEASE_CONTEXT_PATTERN.exec(value);
|
|
25
|
+
if (!match || !secret)
|
|
26
|
+
return null;
|
|
27
|
+
const [, signature, releaseId] = match;
|
|
28
|
+
const expected = createHmac('sha256', secret).update(MESSAGE_PREFIX + releaseId).digest();
|
|
29
|
+
const actual = Buffer.from(signature, 'base64url');
|
|
30
|
+
if (actual.length !== expected.length || !timingSafeEqual(actual, expected))
|
|
31
|
+
return null;
|
|
32
|
+
return releaseId;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Reads the routed release of the current request. Outside a request scope
|
|
36
|
+
* (build, static generation, tooling) or without the header there is none.
|
|
37
|
+
*/
|
|
38
|
+
export async function routedRelease() {
|
|
39
|
+
let value;
|
|
40
|
+
try {
|
|
41
|
+
value = (await headers()).get(RELEASE_CONTEXT_HEADER);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// headers() has no request context in static generation and unit tests.
|
|
45
|
+
return {};
|
|
46
|
+
}
|
|
47
|
+
if (!value)
|
|
48
|
+
return {};
|
|
49
|
+
const secret = process.env[SECRET_ENV]?.trim() || '';
|
|
50
|
+
if (!secret) {
|
|
51
|
+
return { rejected: `${SECRET_ENV} is not configured, so the routed release context cannot be verified` };
|
|
52
|
+
}
|
|
53
|
+
const releaseId = verifyReleaseContext(value, secret);
|
|
54
|
+
return releaseId ? { releaseId } : { rejected: 'the routed release context failed verification' };
|
|
55
|
+
}
|
package/dist/next/render.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReactElement } from 'react';
|
|
2
2
|
import type { KernelPageBlock } from '../content/types.js';
|
|
3
3
|
import type { Registry } from '../registry.js';
|
|
4
|
-
export declare function renderBlock(block: KernelPageBlock, registry: Registry, extraProps?: Record<string, unknown>): Promise<ReactElement>;
|
|
4
|
+
export declare function renderBlock(block: KernelPageBlock, registry: Registry, key: string, extraProps?: Record<string, unknown>): Promise<ReactElement>;
|
|
5
5
|
export declare function renderBlocks(blocks: readonly KernelPageBlock[], registry: Registry, extraProps?: Record<string, unknown>): Promise<ReactElement[]>;
|
package/dist/next/render.js
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
export async function renderBlock(block, registry, extraProps) {
|
|
2
|
+
export async function renderBlock(block, registry, key, extraProps) {
|
|
3
3
|
const entry = registry.find((r) => r.id === block.component);
|
|
4
4
|
if (!entry) {
|
|
5
|
-
return (_jsxs("div", { className: "mx-auto my-4 max-w-[var(--max-width-container)] rounded-card border-2 border-red-600 bg-red-50 px-5 py-4 font-mono text-sm leading-relaxed text-red-900", children: [_jsx("strong", { children: "Unknown block:" }), " ", _jsx("code", { children: block.component }), _jsx("br", {}), _jsxs("span", { className: "text-red-800 opacity-70", children: ["id: ", block.id] })] },
|
|
5
|
+
return (_jsxs("div", { className: "mx-auto my-4 max-w-[var(--max-width-container)] rounded-card border-2 border-red-600 bg-red-50 px-5 py-4 font-mono text-sm leading-relaxed text-red-900", children: [_jsx("strong", { children: "Unknown block:" }), " ", _jsx("code", { children: block.component }), _jsx("br", {}), _jsxs("span", { className: "text-red-800 opacity-70", children: ["id: ", block.id] })] }, key));
|
|
6
6
|
}
|
|
7
7
|
const Component = entry.component;
|
|
8
8
|
const hasBlockSlots = !!entry.contract.blockSlots;
|
|
9
|
-
|
|
9
|
+
// sdk I-19 (ADR 0051): root identity props are applied last so neither
|
|
10
|
+
// content props nor tenant slotProps can overwrite them.
|
|
11
|
+
const componentProps = {
|
|
12
|
+
...block.props,
|
|
13
|
+
...extraProps,
|
|
14
|
+
'data-aci-block': block.id,
|
|
15
|
+
'data-aci-component': block.component,
|
|
16
|
+
};
|
|
10
17
|
if (hasBlockSlots) {
|
|
11
18
|
componentProps.renderChildren = (blocks) => renderBlocks(blocks, registry, extraProps);
|
|
12
19
|
}
|
|
13
|
-
return _jsx(Component, { ...componentProps },
|
|
20
|
+
return _jsx(Component, { ...componentProps }, key);
|
|
14
21
|
}
|
|
15
22
|
export async function renderBlocks(blocks, registry, extraProps) {
|
|
16
|
-
|
|
23
|
+
// Sibling keys are index+id composites: one fragment placed twice repeats
|
|
24
|
+
// its authored block id, and React reconciliation keys must be unique per
|
|
25
|
+
// sibling (ADR 0051 covers analytics identity, not reconciliation).
|
|
26
|
+
return Promise.all(blocks.map((block, index) => renderBlock(block, registry, `${index}:${block.id}`, extraProps)));
|
|
17
27
|
}
|
package/dist/next/server.d.ts
CHANGED
|
@@ -54,4 +54,12 @@ export declare class DamAssetNotFoundError extends Error {
|
|
|
54
54
|
constructor(assetPath: string, cause?: unknown);
|
|
55
55
|
}
|
|
56
56
|
export declare function getDamAssetResponse(assetPath: string, config?: FetchConfig): Promise<Response>;
|
|
57
|
+
/**
|
|
58
|
+
* The release a read uses: the caller's explicit release (the catch-all passes
|
|
59
|
+
* the one its `/__r/{releaseId}` path names), else the release the hosting
|
|
60
|
+
* router dispatched this request to (release-context.ts — the same release,
|
|
61
|
+
* for code such as the not-found seat that receives no route params), else a
|
|
62
|
+
* process pin. A routed release outranks the pin because the catch-all of the
|
|
63
|
+
* same request renders the routed release regardless of the pin.
|
|
64
|
+
*/
|
|
57
65
|
export declare function resolveReleaseId(config?: FetchConfig): Promise<string>;
|
package/dist/next/server.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { headers } from 'next/headers.js';
|
|
2
2
|
import { FragmentNotFoundError, LayoutNotFoundError, PageNotFoundError, } from '../content/provider.js';
|
|
3
|
+
import { ObjectContentProvider } from '../providers/object.js';
|
|
3
4
|
import { normalizeRoute } from '../content/routes.js';
|
|
4
5
|
import { getCachedManifest, getCachedSiteConfig } from '../content/cache.js';
|
|
5
6
|
import { S3ContentProvider } from '../providers/s3.js';
|
|
7
|
+
import { VercelReleaseObjectReader } from '../providers/vercel-object-reader.js';
|
|
6
8
|
import { GRADIAL_RENDER_INPUT_HEADER, getPendingRenderInput } from '../runtime/page.js';
|
|
7
9
|
import { attachRenderProofReceipt, selectVerifiedPage, } from '../internal/render-proof.js';
|
|
8
10
|
import { getUncachedEdgeConfigValue } from './edge-config.js';
|
|
11
|
+
import { routedRelease } from './release-context.js';
|
|
9
12
|
import { activeReleaseV1Key, clampDeploymentCompatibleReleaseV1, decodeActiveReleaseV1, decodeDeploymentCompatibilityV1, deploymentCompatibilityKey, } from './vercel-edge-projection-v1.js';
|
|
10
13
|
export { FragmentNotFoundError, PageNotFoundError, LayoutNotFoundError };
|
|
11
|
-
const releaseObjectReaderSymbol = Symbol.for('aci.
|
|
14
|
+
const releaseObjectReaderSymbol = Symbol.for('@gradial/aci.release-object-reader');
|
|
15
|
+
const objectProviders = new WeakMap();
|
|
16
|
+
let vercelReleaseObjectReader;
|
|
12
17
|
export function setReleaseObjectReader(reader) {
|
|
13
18
|
const scope = globalThis;
|
|
14
19
|
if (reader)
|
|
@@ -40,8 +45,9 @@ export async function getFragment(name, config = {}) {
|
|
|
40
45
|
const runtimeInput = await getPageRuntimeRenderInput();
|
|
41
46
|
if (runtimeInput) {
|
|
42
47
|
const fragments = runtimeInput.fragments || {};
|
|
43
|
-
if (name
|
|
48
|
+
if (Object.hasOwn(fragments, name))
|
|
44
49
|
return fragments[name];
|
|
50
|
+
throw new FragmentNotFoundError(name, new Error('fragment is not bound by the selected page'));
|
|
45
51
|
}
|
|
46
52
|
const provider = await resolveProviderWithFallback(config);
|
|
47
53
|
return await provider.getFragment(name);
|
|
@@ -287,15 +293,27 @@ async function safeResponseText(res) {
|
|
|
287
293
|
return '';
|
|
288
294
|
}
|
|
289
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* The release a read uses: the caller's explicit release (the catch-all passes
|
|
298
|
+
* the one its `/__r/{releaseId}` path names), else the release the hosting
|
|
299
|
+
* router dispatched this request to (release-context.ts — the same release,
|
|
300
|
+
* for code such as the not-found seat that receives no route params), else a
|
|
301
|
+
* process pin. A routed release outranks the pin because the catch-all of the
|
|
302
|
+
* same request renders the routed release regardless of the pin.
|
|
303
|
+
*/
|
|
290
304
|
export async function resolveReleaseId(config = {}) {
|
|
291
305
|
if (config.releaseId)
|
|
292
306
|
return config.releaseId;
|
|
307
|
+
const routed = await routedRelease();
|
|
308
|
+
if (routed.releaseId)
|
|
309
|
+
return routed.releaseId;
|
|
293
310
|
if (process.env.ACI_RELEASE_ID)
|
|
294
311
|
return process.env.ACI_RELEASE_ID;
|
|
295
312
|
const activeReleaseId = await activeReleaseFromEdgeConfig(config);
|
|
296
313
|
if (activeReleaseId)
|
|
297
314
|
return activeReleaseId;
|
|
298
|
-
throw new Error('ACI release ID is required. Pass releaseId from the release-scoped route or set ACI_RELEASE_ID.'
|
|
315
|
+
throw new Error('ACI release ID is required. Pass releaseId from the release-scoped route or set ACI_RELEASE_ID.'
|
|
316
|
+
+ (routed.rejected ? ` The request carried a release context that was not used: ${routed.rejected}.` : ''));
|
|
299
317
|
}
|
|
300
318
|
async function resolveS3Provider(config) {
|
|
301
319
|
const releaseId = await resolveReleaseId(config);
|
|
@@ -339,6 +357,29 @@ async function resolveS3Provider(config) {
|
|
|
339
357
|
}
|
|
340
358
|
async function resolveProviderWithFallback(config) {
|
|
341
359
|
const injected = getInjectedReader();
|
|
360
|
+
const pageRef = config.pageRef;
|
|
361
|
+
const hostedReaderConfigured = injected || config.roleArn || process.env.AWS_ROLE_ARN;
|
|
362
|
+
if (pageRef && hostedReaderConfigured) {
|
|
363
|
+
const releaseId = config.releaseId || process.env.ACI_RELEASE_ID || 'test';
|
|
364
|
+
let provider = objectProviders.get(config);
|
|
365
|
+
if (!provider) {
|
|
366
|
+
if (!injected && !vercelReleaseObjectReader) {
|
|
367
|
+
vercelReleaseObjectReader = new VercelReleaseObjectReader({
|
|
368
|
+
bucket: config.bucket,
|
|
369
|
+
keyPrefix: config.keyPrefix,
|
|
370
|
+
region: config.region,
|
|
371
|
+
roleArn: config.roleArn,
|
|
372
|
+
endpoint: config.endpoint,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
const reader = injected || vercelReleaseObjectReader;
|
|
376
|
+
if (!reader)
|
|
377
|
+
throw new Error('ACI hosted page reader is unavailable');
|
|
378
|
+
provider = new ObjectContentProvider({ releaseId, pageRef, reader });
|
|
379
|
+
objectProviders.set(config, provider);
|
|
380
|
+
}
|
|
381
|
+
return provider;
|
|
382
|
+
}
|
|
342
383
|
if (injected) {
|
|
343
384
|
const releaseId = config.releaseId || process.env.ACI_RELEASE_ID || 'test';
|
|
344
385
|
return new InjectedReaderProvider(releaseId, injected);
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import type { EdgeRouteManifest } from './personalization-host.js';
|
|
2
|
-
export declare const VERCEL_EDGE_PROJECTION_SCHEMA_V1 = "gradial.vercel.edgeRoutes.v1";
|
|
3
|
-
export declare const VERCEL_EDGE_PROJECTION_ENCODING_V1 = "gzip+base64";
|
|
4
|
-
export declare const MAX_VERCEL_EDGE_MANIFEST_BYTES_V1: number;
|
|
5
1
|
export interface ActiveReleasePointerV1 {
|
|
6
2
|
releaseId: string;
|
|
7
3
|
sequence: bigint;
|
|
@@ -13,12 +9,7 @@ export interface DeploymentCompatibilityV1 {
|
|
|
13
9
|
maxSequence?: bigint;
|
|
14
10
|
}
|
|
15
11
|
export declare function activeReleaseV1Key(siteId: string): string;
|
|
16
|
-
export declare function edgeRoutesV1Key(siteId: string, releaseId: string): string;
|
|
17
12
|
export declare function deploymentCompatibilityKey(siteId: string, deploymentId: string): string;
|
|
18
13
|
export declare function decodeActiveReleaseV1(value: unknown): ActiveReleasePointerV1;
|
|
19
14
|
export declare function decodeDeploymentCompatibilityV1(value: unknown): DeploymentCompatibilityV1;
|
|
20
15
|
export declare function clampDeploymentCompatibleReleaseV1(active: ActiveReleasePointerV1, compatibility: DeploymentCompatibilityV1): string;
|
|
21
|
-
export declare function decodeEdgeRouteProjectionV1(value: unknown, expected: {
|
|
22
|
-
siteId: string;
|
|
23
|
-
releaseId: string;
|
|
24
|
-
}): EdgeRouteManifest;
|