@gradial/aci 0.1.48 → 0.1.51-ssr.2
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 +13 -20
- package/dist/astro/assets.d.ts +6 -6
- package/dist/astro/assets.js +6 -6
- package/dist/astro/index.d.ts +0 -2
- package/dist/astro/index.js +0 -4
- package/dist/cli/emit-error-pages.mjs +0 -1
- package/dist/cli/verify-next-cdn-routes.mjs +3 -4
- package/dist/collect/aci.js +1 -1
- package/dist/collect/aci.js.sha256 +1 -1
- package/dist/collect/webvitals.d.ts +0 -3
- package/dist/collect/webvitals.js +11 -21
- package/dist/content/cache.d.ts +1 -9
- package/dist/content/cache.js +2 -37
- package/dist/content/error-pages.d.ts +1 -2
- package/dist/content/index.d.ts +0 -1
- package/dist/content/index.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/internal/domain/edge/identity.d.ts +14 -0
- package/dist/internal/domain/edge/identity.js +214 -0
- package/dist/internal/domain/edge/index.d.ts +4 -0
- package/dist/internal/domain/edge/index.js +6 -0
- package/dist/internal/domain/edge/personalization-core.d.ts +24 -0
- package/dist/{edge → internal/domain/edge}/personalization-core.js +165 -64
- package/dist/internal/domain/edge/record/codec.d.ts +71 -0
- package/dist/internal/domain/edge/record/codec.js +401 -0
- package/dist/internal/domain/edge/resolve.d.ts +2 -0
- package/dist/internal/domain/edge/resolve.js +76 -0
- package/dist/{next/personalization-host.d.ts → internal/domain/edge/types.d.ts} +110 -61
- package/dist/internal/domain/edge/types.js +7 -0
- package/dist/internal/platform/collectionstore/errors.d.ts +5 -0
- package/dist/internal/platform/collectionstore/errors.js +7 -0
- package/dist/next/config.d.ts +0 -8
- package/dist/next/config.js +3 -78
- package/dist/next/error-pages.d.ts +2 -3
- package/dist/next/error-pages.js +5 -5
- package/dist/next/error-seat.d.ts +2 -3
- package/dist/next/index.d.ts +2 -2
- package/dist/next/index.js +1 -2
- package/dist/next/page.d.ts +3 -13
- package/dist/next/page.js +39 -51
- package/dist/next/server.d.ts +12 -32
- package/dist/next/server.js +66 -295
- package/dist/providers/object.d.ts +24 -0
- package/dist/providers/object.js +105 -0
- package/dist/providers/vercel-object-reader.d.ts +20 -0
- package/dist/providers/vercel-object-reader.js +45 -0
- package/dist/testing/conformance/checks.d.ts +1 -1
- package/dist/testing/conformance/checks.js +14 -144
- package/dist/testing/conformance/index.d.ts +1 -1
- package/dist/testing/conformance/index.js +1 -1
- package/dist/testing/conformance/preset.js +1 -1
- package/dist/testing/conformance/types.d.ts +1 -1
- package/dist/types/config.d.ts +0 -4
- package/dist/types/index.d.ts +0 -2
- package/dist/types/index.js +0 -2
- package/dist/types/page.d.ts +0 -10
- package/package.json +11 -35
- package/src/cli/emit-error-pages.mjs +0 -1
- package/src/cli/verify-next-cdn-routes.mjs +8 -11
- package/src/types/config.ts +0 -5
- package/src/types/index.ts +0 -2
- package/src/types/page.ts +0 -11
- package/templates/astro/template/.aci.yaml.tmpl +0 -11
- package/templates/common/.agents/skills/aci/SKILL.md +8 -9
- package/templates/common/.agents/skills/authoring/SKILL.md +3 -4
- package/templates/common/.agents/skills/authoring/references/block-registry.md +13 -36
- package/templates/common/.agents/skills/authoring/references/contracts.md +10 -17
- package/templates/common/.agents/skills/authoring/references/repo-structure.md +2 -2
- package/templates/common/.agents/skills/authoring/references/sdk-server-functions.md +45 -95
- package/templates/common/.agents/skills/migration/references/canon-migration.md +17 -37
- package/templates/nextjs/template/.aci.yaml.tmpl +0 -11
- package/templates/nextjs/template/README.md.tmpl +0 -1
- package/templates/nextjs/template/src/app/[[...slug]]/page.tsx +1 -1
- package/dist/content/assets.d.ts +0 -18
- package/dist/content/assets.js +0 -66
- package/dist/edge/personalization-core.d.ts +0 -11
- package/dist/internal/render-proof.d.ts +0 -1
- package/dist/internal/render-proof.js +0 -197
- package/dist/next/asset-route.d.ts +0 -10
- package/dist/next/asset-route.js +0 -45
- package/dist/next/collect-route.d.ts +0 -19
- package/dist/next/collect-route.js +0 -422
- 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 -462
- package/dist/next/personalization-host.js +0 -257
- 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/providers/s3.d.ts +0 -47
- package/dist/providers/s3.js +0 -434
- package/dist/types/render-mode.d.ts +0 -2
- package/dist/types/render-mode.js +0 -1
- package/dist/types/renderer.d.ts +0 -71
- package/dist/types/renderer.js +0 -1
- package/src/types/render-mode.ts +0 -10
- package/src/types/renderer.ts +0 -83
- package/templates/nextjs/starter-content/src/middleware.ts +0 -41
- package/templates/nextjs/template/src/app/gradial/assets/[...path]/route.ts +0 -1
- package/templates/nextjs/template/src/middleware.ts +0 -41
- package/templates/nextjs/template/src/middleware.ts.tmpl +0 -40
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
const RENDER_PROOF_VERSION = 'gradial.aci.renderProof.v1';
|
|
2
|
-
const RENDER_PROOF_KEYS = [
|
|
3
|
-
'version',
|
|
4
|
-
'releaseId',
|
|
5
|
-
'route',
|
|
6
|
-
'contentRef',
|
|
7
|
-
'contentSha256',
|
|
8
|
-
'variantKey',
|
|
9
|
-
];
|
|
10
|
-
const MAX_RENDER_PROOF_CONTENT_BYTES = 4096;
|
|
11
|
-
const receiptBrand = Symbol('aci.verified-page-receipt');
|
|
12
|
-
const renderProofReceipts = new WeakMap();
|
|
13
|
-
/** @internal */
|
|
14
|
-
export const selectVerifiedPage = Symbol('aci.select-verified-page');
|
|
15
|
-
/** @internal */
|
|
16
|
-
export function createVerifiedPageReceipt(value) {
|
|
17
|
-
// Selection itself must fail if the coupled marker cannot be emitted.
|
|
18
|
-
// `getPage` also uses this capability and intentionally discards the
|
|
19
|
-
// receipt, so deferring the size check to React would permit markerless
|
|
20
|
-
// success on that public server loader.
|
|
21
|
-
validateVerifiedPageReceipt(value);
|
|
22
|
-
return Object.freeze({
|
|
23
|
-
...value,
|
|
24
|
-
[receiptBrand]: true,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
/** @internal */
|
|
28
|
-
export function validateVerifiedPageReceipt(value) {
|
|
29
|
-
encodeRenderProofContent(toRenderProof(value));
|
|
30
|
-
}
|
|
31
|
-
/** @internal */
|
|
32
|
-
export function attachRenderProofReceipt(input, receipt) {
|
|
33
|
-
if (receipt[receiptBrand] !== true) {
|
|
34
|
-
throw new Error('ACI render proof integrity error: unverified receipt');
|
|
35
|
-
}
|
|
36
|
-
renderProofReceipts.set(input, receipt);
|
|
37
|
-
}
|
|
38
|
-
/** @internal */
|
|
39
|
-
export function renderProofContentFor(input) {
|
|
40
|
-
const receipt = renderProofReceipts.get(input);
|
|
41
|
-
return receipt ? encodeRenderProofContent(toRenderProof(receipt)) : null;
|
|
42
|
-
}
|
|
43
|
-
/** @internal */
|
|
44
|
-
export function encodeRenderProofContent(proof) {
|
|
45
|
-
validateRenderProof(proof);
|
|
46
|
-
const canonicalJSON = JSON.stringify({
|
|
47
|
-
version: proof.version,
|
|
48
|
-
releaseId: proof.releaseId,
|
|
49
|
-
route: proof.route,
|
|
50
|
-
contentRef: proof.contentRef,
|
|
51
|
-
contentSha256: proof.contentSha256,
|
|
52
|
-
variantKey: proof.variantKey,
|
|
53
|
-
});
|
|
54
|
-
const content = Buffer.from(canonicalJSON, 'utf8').toString('base64url');
|
|
55
|
-
if (content.length < 1 || content.length > MAX_RENDER_PROOF_CONTENT_BYTES) {
|
|
56
|
-
throw new Error(`ACI render proof integrity error: marker content is ${content.length} bytes`);
|
|
57
|
-
}
|
|
58
|
-
return content;
|
|
59
|
-
}
|
|
60
|
-
/** @internal */
|
|
61
|
-
export function decodeRenderProofContent(content) {
|
|
62
|
-
if (content.length < 1
|
|
63
|
-
|| content.length > MAX_RENDER_PROOF_CONTENT_BYTES
|
|
64
|
-
|| !/^[A-Za-z0-9_-]+$/.test(content)) {
|
|
65
|
-
throw new Error('ACI render proof integrity error: invalid marker encoding');
|
|
66
|
-
}
|
|
67
|
-
const bytes = Buffer.from(content, 'base64url');
|
|
68
|
-
if (bytes.toString('base64url') !== content) {
|
|
69
|
-
throw new Error('ACI render proof integrity error: non-canonical base64url');
|
|
70
|
-
}
|
|
71
|
-
let canonicalJSON = '';
|
|
72
|
-
try {
|
|
73
|
-
canonicalJSON = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
|
|
74
|
-
}
|
|
75
|
-
catch (cause) {
|
|
76
|
-
throw integrityError('marker is not valid UTF-8', cause);
|
|
77
|
-
}
|
|
78
|
-
let decoded;
|
|
79
|
-
try {
|
|
80
|
-
decoded = JSON.parse(canonicalJSON);
|
|
81
|
-
}
|
|
82
|
-
catch (cause) {
|
|
83
|
-
throw integrityError('marker is not valid JSON', cause);
|
|
84
|
-
}
|
|
85
|
-
if (!isRecord(decoded)) {
|
|
86
|
-
throw new Error('ACI render proof integrity error: marker must be an object');
|
|
87
|
-
}
|
|
88
|
-
if (!sameKeys(Object.keys(decoded), RENDER_PROOF_KEYS)) {
|
|
89
|
-
throw new Error('ACI render proof integrity error: marker keys are not canonical');
|
|
90
|
-
}
|
|
91
|
-
const proof = {
|
|
92
|
-
version: decoded.version,
|
|
93
|
-
releaseId: decoded.releaseId,
|
|
94
|
-
route: decoded.route,
|
|
95
|
-
contentRef: decoded.contentRef,
|
|
96
|
-
contentSha256: decoded.contentSha256,
|
|
97
|
-
variantKey: decoded.variantKey,
|
|
98
|
-
};
|
|
99
|
-
validateRenderProof(proof);
|
|
100
|
-
if (JSON.stringify(proof) !== canonicalJSON) {
|
|
101
|
-
throw new Error('ACI render proof integrity error: marker JSON is not canonical');
|
|
102
|
-
}
|
|
103
|
-
return Object.freeze(proof);
|
|
104
|
-
}
|
|
105
|
-
function toRenderProof(receipt) {
|
|
106
|
-
return {
|
|
107
|
-
version: RENDER_PROOF_VERSION,
|
|
108
|
-
releaseId: receipt.releaseId,
|
|
109
|
-
route: receipt.route,
|
|
110
|
-
contentRef: receipt.contentRef,
|
|
111
|
-
contentSha256: receipt.contentSha256,
|
|
112
|
-
variantKey: receipt.variantKey,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
function validateRenderProof(proof) {
|
|
116
|
-
if (!isRecord(proof)) {
|
|
117
|
-
throw new Error('ACI render proof integrity error: proof must be an object');
|
|
118
|
-
}
|
|
119
|
-
for (const key of RENDER_PROOF_KEYS) {
|
|
120
|
-
if (typeof proof[key] !== 'string') {
|
|
121
|
-
throw new Error(`ACI render proof integrity error: ${key} must be a string`);
|
|
122
|
-
}
|
|
123
|
-
if (hasUnpairedSurrogate(proof[key])) {
|
|
124
|
-
throw new Error(`ACI render proof integrity error: ${key} has invalid Unicode`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
if (proof.version !== RENDER_PROOF_VERSION) {
|
|
128
|
-
throw new Error('ACI render proof integrity error: unsupported version');
|
|
129
|
-
}
|
|
130
|
-
if (Buffer.byteLength(proof.releaseId, 'ascii') > 128
|
|
131
|
-
|| !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(proof.releaseId)) {
|
|
132
|
-
throw new Error('ACI render proof integrity error: invalid releaseId');
|
|
133
|
-
}
|
|
134
|
-
if (Buffer.byteLength(proof.route, 'utf8') > 2048
|
|
135
|
-
|| !isCanonicalRoute(proof.route)) {
|
|
136
|
-
throw new Error('ACI render proof integrity error: invalid route');
|
|
137
|
-
}
|
|
138
|
-
if (Buffer.byteLength(proof.contentRef, 'utf8') > 2048
|
|
139
|
-
|| !isCleanContentRef(proof.contentRef)) {
|
|
140
|
-
throw new Error('ACI render proof integrity error: invalid contentRef');
|
|
141
|
-
}
|
|
142
|
-
if (!/^[0-9a-f]{64}$/.test(proof.contentSha256)) {
|
|
143
|
-
throw new Error('ACI render proof integrity error: invalid contentSha256');
|
|
144
|
-
}
|
|
145
|
-
if (Buffer.byteLength(proof.variantKey, 'utf8') > 1024
|
|
146
|
-
|| /[\u0000-\u001f\u007f]/.test(proof.variantKey)) {
|
|
147
|
-
throw new Error('ACI render proof integrity error: invalid variantKey');
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
function isCanonicalRoute(route) {
|
|
151
|
-
if (route === '/')
|
|
152
|
-
return true;
|
|
153
|
-
if (!route.startsWith('/')
|
|
154
|
-
|| route.startsWith('//')
|
|
155
|
-
|| route.endsWith('/')
|
|
156
|
-
|| /[\u0000-\u001f\u007f]/.test(route)) {
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
return route.slice(1).split('/').every((segment) => (segment !== '' && segment !== '.' && segment !== '..'));
|
|
160
|
-
}
|
|
161
|
-
function isCleanContentRef(ref) {
|
|
162
|
-
if (!ref
|
|
163
|
-
|| ref.startsWith('/')
|
|
164
|
-
|| ref.endsWith('/')
|
|
165
|
-
|| ref.includes('\\')
|
|
166
|
-
|| /[\u0000-\u001f\u007f]/.test(ref)) {
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
return ref.split('/').every((segment) => (segment !== '' && segment !== '.' && segment !== '..'));
|
|
170
|
-
}
|
|
171
|
-
function isRecord(value) {
|
|
172
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
173
|
-
}
|
|
174
|
-
function sameKeys(actual, expected) {
|
|
175
|
-
return actual.length === expected.length
|
|
176
|
-
&& actual.every((key, index) => key === expected[index]);
|
|
177
|
-
}
|
|
178
|
-
function hasUnpairedSurrogate(value) {
|
|
179
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
180
|
-
const code = value.charCodeAt(index);
|
|
181
|
-
if (code >= 0xd800 && code <= 0xdbff) {
|
|
182
|
-
const next = value.charCodeAt(index + 1);
|
|
183
|
-
if (!(next >= 0xdc00 && next <= 0xdfff))
|
|
184
|
-
return true;
|
|
185
|
-
index += 1;
|
|
186
|
-
}
|
|
187
|
-
else if (code >= 0xdc00 && code <= 0xdfff) {
|
|
188
|
-
return true;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
function integrityError(message, cause) {
|
|
194
|
-
const error = new Error(`ACI render proof integrity error: ${message}`);
|
|
195
|
-
error.cause = cause;
|
|
196
|
-
return error;
|
|
197
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
type AssetRouteContext = {
|
|
2
|
-
params: Promise<AssetRouteParams>;
|
|
3
|
-
};
|
|
4
|
-
type AssetRouteParams = {
|
|
5
|
-
path?: string[];
|
|
6
|
-
};
|
|
7
|
-
export declare const runtime = "nodejs";
|
|
8
|
-
export declare const dynamic = "force-dynamic";
|
|
9
|
-
export declare function GET(_request: Request, { params }: AssetRouteContext): Promise<Response>;
|
|
10
|
-
export {};
|
package/dist/next/asset-route.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { FileContentProvider } from '../providers/file.js';
|
|
2
|
-
import { getDamAssetResponse, getReleaseAssetResponse, isDamAssetPath, resolveReleaseId, } from './server.js';
|
|
3
|
-
export const runtime = 'nodejs';
|
|
4
|
-
export const dynamic = 'force-dynamic';
|
|
5
|
-
export async function GET(_request, { params }) {
|
|
6
|
-
const resolvedParams = await params;
|
|
7
|
-
const assetPath = '/' + (resolvedParams.path || []).join('/');
|
|
8
|
-
if (assetPath === '/') {
|
|
9
|
-
return new Response('asset not found', { status: 404 });
|
|
10
|
-
}
|
|
11
|
-
const local = await localAssetResponse(assetPath);
|
|
12
|
-
if (local) {
|
|
13
|
-
return local;
|
|
14
|
-
}
|
|
15
|
-
// DAM assets are global (not release-scoped): serve them from the hosting
|
|
16
|
-
// bucket root without resolving a release.
|
|
17
|
-
if (isDamAssetPath(assetPath)) {
|
|
18
|
-
try {
|
|
19
|
-
return await getDamAssetResponse(assetPath);
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
return new Response('dam asset not found', { status: 404 });
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
try {
|
|
26
|
-
const releaseId = await resolveReleaseId();
|
|
27
|
-
return await getReleaseAssetResponse(releaseId, assetPath);
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return new Response('asset not found', { status: 404 });
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
async function localAssetResponse(assetPath) {
|
|
34
|
-
const localRoot = process.env.ACI_LOCAL_ASSET_ROOT;
|
|
35
|
-
if (localRoot) {
|
|
36
|
-
const response = await new FileContentProvider(localRoot).fetchRaw(assetPath);
|
|
37
|
-
if (response.ok)
|
|
38
|
-
return response;
|
|
39
|
-
}
|
|
40
|
-
if (process.env.ACI_CONTENT_PROVIDER !== 'file') {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
const response = await new FileContentProvider().fetchRaw(assetPath);
|
|
44
|
-
return response.ok ? response : null;
|
|
45
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { type IdentitySigningKeys, type PersonalizationCollectionStore } from './personalization-host.js';
|
|
2
|
-
export interface PersonalizationCollectRouteConfig {
|
|
3
|
-
siteId: string;
|
|
4
|
-
store: PersonalizationCollectionStore;
|
|
5
|
-
identityKeys: IdentitySigningKeys;
|
|
6
|
-
/**
|
|
7
|
-
* Claims verify keys (kid -> secret) for withdrawal EVIDENCE
|
|
8
|
-
* (anonymous-experiments REQ-6): suppression fires only when the request
|
|
9
|
-
* presents a signature-verified aci_claims cookie — presence alone is
|
|
10
|
-
* spoofable, and under universal minting an unverified trigger would
|
|
11
|
-
* suppress every reject-all visitor. Empty = evidence never verifies =
|
|
12
|
-
* suppression disabled (fails safe).
|
|
13
|
-
*/
|
|
14
|
-
claimsKeys?: Record<string, string>;
|
|
15
|
-
retentionSeconds?: number;
|
|
16
|
-
secureCookies?: boolean;
|
|
17
|
-
now?: () => Date;
|
|
18
|
-
}
|
|
19
|
-
export declare function createPersonalizationCollectRoute(config: PersonalizationCollectRouteConfig): (request: Request) => Promise<Response>;
|