@gradial/aci 0.1.52-rc.2 → 0.1.52-rc.21

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.
Files changed (123) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +4 -4
  3. package/dist/astro/preview.js +2 -17
  4. package/dist/audience-data-models.d.ts +289 -16
  5. package/dist/audience-data-models.js +99 -2
  6. package/dist/cli/compile-registry.d.mts +5 -1
  7. package/dist/cli/compile-registry.mjs +25 -10
  8. package/dist/cli/validate-content.d.mts +31 -1
  9. package/dist/cli/validate-content.mjs +50 -12
  10. package/dist/collect/aci.js +1 -1
  11. package/dist/collect/aci.js.sha256 +1 -1
  12. package/dist/collect/api.d.ts +3 -7
  13. package/dist/collect/api.js +2 -8
  14. package/dist/collect/batcher.d.ts +6 -5
  15. package/dist/collect/batcher.js +6 -5
  16. package/dist/collect/index.js +1 -1
  17. package/dist/content/provider.d.ts +1 -0
  18. package/dist/content/resolve-slots.d.ts +9 -2
  19. package/dist/content/resolve-slots.js +5 -3
  20. package/dist/content/types.d.ts +2 -0
  21. package/dist/edge/expression-capabilities.v1.d.ts +106 -0
  22. package/dist/edge/expression-capabilities.v1.js +165 -0
  23. package/dist/internal/domain/edge/compose.d.ts +24 -0
  24. package/dist/internal/domain/edge/compose.js +89 -0
  25. package/dist/internal/domain/edge/identity.js +1 -1
  26. package/dist/internal/domain/edge/index.d.ts +2 -0
  27. package/dist/internal/domain/edge/index.js +2 -0
  28. package/dist/internal/domain/edge/mimic_token.d.ts +13 -0
  29. package/dist/internal/domain/edge/mimic_token.js +58 -0
  30. package/dist/internal/domain/edge/personalization-core.d.ts +69 -5
  31. package/dist/internal/domain/edge/personalization-core.js +693 -58
  32. package/dist/internal/domain/edge/record/codec.d.ts +5 -2
  33. package/dist/internal/domain/edge/record/codec.js +85 -12
  34. package/dist/internal/domain/edge/resolve.js +38 -18
  35. package/dist/internal/domain/edge/testdata/flat_only_validator_v1.d.ts +10 -0
  36. package/dist/internal/domain/edge/testdata/flat_only_validator_v1.js +253 -0
  37. package/dist/internal/domain/edge/types.d.ts +52 -9
  38. package/dist/internal/domain/edge/types.js +3 -3
  39. package/dist/mimic/core.d.ts +2 -0
  40. package/dist/mimic/core.js +31 -0
  41. package/dist/next/error-seat-payload.js +1 -1
  42. package/dist/next/hosted-page-target.d.ts +7 -0
  43. package/dist/next/hosted-page-target.js +39 -0
  44. package/dist/next/index.d.ts +0 -1
  45. package/dist/next/index.js +0 -1
  46. package/dist/next/page.d.ts +29 -6
  47. package/dist/next/page.js +47 -25
  48. package/dist/next/server.js +28 -1
  49. package/dist/next/vercel-edge-projection-v1.d.ts +0 -9
  50. package/dist/next/vercel-edge-projection-v1.js +9 -539
  51. package/dist/preview/core.d.ts +1 -0
  52. package/dist/preview/core.js +27 -0
  53. package/dist/providers/s3.js +4 -3
  54. package/dist/react/VideoPlayer.d.ts +1 -1
  55. package/dist/react/index.d.ts +1 -1
  56. package/dist/types/block-ref.d.ts +2 -0
  57. package/dist/types/block-ref.js +1 -0
  58. package/package.json +16 -7
  59. package/src/cli/compile-registry.mjs +24 -10
  60. package/src/cli/validate-content.mjs +52 -13
  61. package/src/types/block-ref.test.ts +45 -0
  62. package/src/types/block-ref.ts +2 -0
  63. package/templates/astro/starter-content/src/fixtures/atomicBlocks.ts +7 -6
  64. package/templates/astro/starter-content/src/fixtures/composition.ts +3 -2
  65. package/templates/astro/starter-content/src/fixtures/sections.ts +2 -1
  66. package/templates/astro/template/package.json.tmpl +1 -1
  67. package/templates/astro/template/src/layouts/SiteLayout.astro +2 -2
  68. package/templates/common/.agents/skills/aci/SKILL.md +6 -0
  69. package/templates/common/.agents/skills/authoring/SKILL.md +11 -3
  70. package/templates/common/.agents/skills/authoring/references/block-slots.md +3 -0
  71. package/templates/common/.agents/skills/dam-delivery/SKILL.md +228 -0
  72. package/templates/common/.agents/skills/dam-delivery/references/parameter-contract.md +107 -0
  73. package/templates/common/.agents/skills/dam-delivery/references/permalink-grammar.md +131 -0
  74. package/templates/common/.content/pages/{home/_index.json → _index.json} +10 -0
  75. package/templates/common/.content/schemas/site.schema.json +1 -1
  76. package/templates/common/.nvmrc +1 -1
  77. package/templates/common/starter-content/.content/.rules-baseline.json +8 -0
  78. package/templates/common/starter-content/.content/config/site.json +1 -1
  79. package/templates/common/starter-content/.content/content-rules/no-public-resource-paths.json +6 -0
  80. package/templates/common/starter-content/.content/fragments/navbar/_index.json +23 -20
  81. package/templates/common/starter-content/.content/fragments/site-footer/_index.json +59 -56
  82. package/templates/common/starter-content/.content/pages/404/_index.json +1 -0
  83. package/templates/common/starter-content/.content/pages/about/_index.json +3 -0
  84. package/templates/common/starter-content/.content/pages/error/_index.json +1 -0
  85. package/templates/common/starter-content/.content/pages/home/_index.json +9 -0
  86. package/templates/common/starter-content/.content/patterns/components/button.json +55 -0
  87. package/templates/common/starter-content/.content/patterns/components/container.json +62 -0
  88. package/templates/common/starter-content/.content/patterns/components/feature_card.json +30 -0
  89. package/templates/common/starter-content/.content/patterns/components/feature_grid.json +57 -0
  90. package/templates/common/starter-content/.content/patterns/components/home_hero.json +142 -0
  91. package/templates/common/starter-content/.content/patterns/components/personalization_choice.json +42 -0
  92. package/templates/common/starter-content/.content/patterns/components/site-footer.json +203 -0
  93. package/templates/common/starter-content/.content/patterns/components/site-navigation.json +115 -0
  94. package/templates/common/starter-content/.content/patterns/components/stats_bar.json +45 -0
  95. package/templates/common/starter-content/.content/patterns/layouts/default.json +14 -0
  96. package/templates/common/starter-content/.content/schemas/site.schema.json +1 -1
  97. package/templates/nextjs/template/.aci.yaml +10 -0
  98. package/templates/nextjs/template/package.json.tmpl +4 -3
  99. package/templates/nextjs/template/src/app/_components/c15t-bridge.ts +30 -0
  100. package/templates/nextjs/template/src/app/_components/c15t-consent-ui.tsx +37 -0
  101. package/templates/nextjs/template/src/app/_components/consent-manager.css +63 -0
  102. package/templates/nextjs/template/src/app/_components/consent-manager.tsx +76 -0
  103. package/templates/nextjs/template/src/app/layout.tsx +2 -0
  104. package/dist/edge/personalization-core.d.ts +0 -11
  105. package/dist/edge/personalization-core.js +0 -269
  106. package/dist/next/collect-route.d.ts +0 -19
  107. package/dist/next/collect-route.js +0 -459
  108. package/dist/next/envelope-digest.d.ts +0 -21
  109. package/dist/next/envelope-digest.js +0 -58
  110. package/dist/next/middleware.d.ts +0 -40
  111. package/dist/next/middleware.js +0 -475
  112. package/dist/next/personalization-host.d.ts +0 -134
  113. package/dist/next/personalization-host.js +0 -270
  114. package/dist/next/root-layout.d.ts +0 -4
  115. package/dist/next/root-layout.js +0 -5
  116. package/dist/next/vercel-collect-sdk-route.d.ts +0 -27
  117. package/dist/next/vercel-collect-sdk-route.js +0 -181
  118. package/dist/next/vercel-personalization.d.ts +0 -4
  119. package/dist/next/vercel-personalization.js +0 -4
  120. package/dist/next/vercel-s3-personalization.d.ts +0 -79
  121. package/dist/next/vercel-s3-personalization.js +0 -570
  122. /package/templates/common/.content/overlays/audience/preference-blue/pages/{home/_index.json → _index.json} +0 -0
  123. /package/templates/common/.content/overlays/audience/preference-red/pages/{home/_index.json → _index.json} +0 -0
@@ -1,27 +1,20 @@
1
- import { createHash } from 'node:crypto';
2
- import { inflateRawSync } from 'node:zlib';
3
- export const VERCEL_EDGE_PROJECTION_SCHEMA_V1 = 'gradial.vercel.edgeRoutes.v1';
4
- export const VERCEL_EDGE_PROJECTION_ENCODING_V1 = 'gzip+base64';
5
- export const MAX_VERCEL_EDGE_MANIFEST_BYTES_V1 = 1 << 20;
1
+ // The v1 Vercel Edge Config release-state contract read by the Next SSR
2
+ // server (next/server.ts): the active-release pointer and the per-deployment
3
+ // compatibility clamp. Values are canonical Go-encoded JSON strings; decoding
4
+ // is strict — byte-for-byte canonical form, exact fields, bounded size.
5
+ //
6
+ // The v1 edge-route projection decoder that used to live here served the
7
+ // retired SDK Next personalization-host lane (ADR 0041); the platform-owned
8
+ // edge router (internal/domain/hosting) is the only route-projection consumer
9
+ // now, and it reads route partitions, not Edge Config.
6
10
  const ACTIVE_RELEASE_V1_PREFIX = 'activeReleaseV1_';
7
- const EDGE_ROUTES_V1_PREFIX = 'edgeRoutesV1_';
8
11
  const MAX_EDGE_CONFIG_VALUE_BYTES = 65_536;
9
12
  const MAX_JSON_DEPTH = 64;
10
- const SHA256_HEX = /^[0-9a-f]{64}$/;
11
13
  const POSITIVE_DECIMAL = /^[1-9][0-9]*$/;
12
14
  const MAX_INT64 = 9223372036854775807n;
13
- const CANONICAL_BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
14
- const NORMALIZED_GZIP_HEADER = Buffer.from([
15
- 0x1f, 0x8b, 0x08, 0x00, 0x00,
16
- 0x00, 0x00, 0x00, 0x02, 0xff,
17
- ]);
18
- const textDecoder = new TextDecoder('utf-8', { fatal: true });
19
15
  export function activeReleaseV1Key(siteId) {
20
16
  return `${ACTIVE_RELEASE_V1_PREFIX}${edgeKeySegment(siteId)}`;
21
17
  }
22
- export function edgeRoutesV1Key(siteId, releaseId) {
23
- return `${EDGE_ROUTES_V1_PREFIX}${edgeKeySegment(siteId)}_${edgeKeySegment(releaseId)}`;
24
- }
25
18
  export function deploymentCompatibilityKey(siteId, deploymentId) {
26
19
  return `deploymentCompatibility_${edgeKeySegment(siteId)}_${edgeKeySegment(deploymentId)}`;
27
20
  }
@@ -86,89 +79,6 @@ export function clampDeploymentCompatibleReleaseV1(active, compatibility) {
86
79
  }
87
80
  return active.releaseId;
88
81
  }
89
- export function decodeEdgeRouteProjectionV1(value, expected) {
90
- const envelope = parseEnvelope(value);
91
- const expectedSiteId = requiredIdentity(expected.siteId, 'expected site ID');
92
- const expectedReleaseId = requiredIdentity(expected.releaseId, 'expected release ID');
93
- if (envelope.siteId !== expectedSiteId
94
- || envelope.releaseId !== expectedReleaseId) {
95
- throw new Error(`v1 edge projection identity mismatch: got `
96
- + `${envelope.siteId}/${envelope.releaseId}, `
97
- + `want ${expectedSiteId}/${expectedReleaseId}`);
98
- }
99
- const compressed = decodeCanonicalBase64(envelope.payload);
100
- const runtimeBytes = inflateOneNormalizedGzipMember(compressed, envelope.uncompressedLength);
101
- const runtimeDigest = sha256(runtimeBytes);
102
- if (runtimeDigest !== envelope.runtimeSha256) {
103
- throw new Error(`v1 edge projection runtime digest mismatch: got ${runtimeDigest}, `
104
- + `want ${envelope.runtimeSha256}`);
105
- }
106
- let runtimeJSON;
107
- try {
108
- runtimeJSON = textDecoder.decode(runtimeBytes);
109
- }
110
- catch (error) {
111
- throw new Error('v1 edge projection runtime payload is not valid UTF-8', {
112
- cause: error,
113
- });
114
- }
115
- assertCanonicalJSONSyntax(runtimeJSON, 'v1 edge projection runtime payload');
116
- let parsed;
117
- try {
118
- parsed = JSON.parse(runtimeJSON);
119
- }
120
- catch (error) {
121
- throw new Error('v1 edge projection runtime payload is malformed JSON', {
122
- cause: error,
123
- });
124
- }
125
- const decoded = validateRuntimeProjection(parsed, {
126
- siteId: expectedSiteId,
127
- releaseId: expectedReleaseId,
128
- });
129
- if (canonicalRuntimeProjectionJSON(parsed) !== runtimeJSON) {
130
- throw new Error('v1 edge projection runtime payload is not the canonical Go encoding');
131
- }
132
- return decoded;
133
- }
134
- function parseEnvelope(value) {
135
- const record = parseCanonicalJSONStringRecord(value, 'v1 edge projection envelope');
136
- const orderedKeys = [
137
- 'schemaVersion',
138
- 'encoding',
139
- 'siteId',
140
- 'releaseId',
141
- 'sourceSha256',
142
- 'uncompressedLength',
143
- 'runtimeSha256',
144
- 'payload',
145
- ];
146
- assertExactKeys(record, orderedKeys, [], 'v1 edge projection envelope');
147
- if (Object.keys(record).some((key, index) => key !== orderedKeys[index])) {
148
- throw new Error('v1 edge projection envelope fields are not canonical');
149
- }
150
- const envelope = {
151
- schemaVersion: requiredString(record.schemaVersion, 'v1 edge projection schema version'),
152
- encoding: requiredString(record.encoding, 'v1 edge projection encoding'),
153
- siteId: requiredIdentity(record.siteId, 'v1 edge projection site ID'),
154
- releaseId: requiredIdentity(record.releaseId, 'v1 edge projection release ID'),
155
- sourceSha256: requiredSHA256(record.sourceSha256, 'v1 edge projection source digest'),
156
- uncompressedLength: requiredPositiveSafeInteger(record.uncompressedLength, 'v1 edge projection uncompressed length'),
157
- runtimeSha256: requiredSHA256(record.runtimeSha256, 'v1 edge projection runtime digest'),
158
- payload: requiredString(record.payload, 'v1 edge projection payload'),
159
- };
160
- if (envelope.schemaVersion !== VERCEL_EDGE_PROJECTION_SCHEMA_V1) {
161
- throw new Error(`unsupported v1 edge projection schema ${JSON.stringify(envelope.schemaVersion)}`);
162
- }
163
- if (envelope.encoding !== VERCEL_EDGE_PROJECTION_ENCODING_V1) {
164
- throw new Error(`unsupported v1 edge projection encoding ${JSON.stringify(envelope.encoding)}`);
165
- }
166
- if (envelope.uncompressedLength > MAX_VERCEL_EDGE_MANIFEST_BYTES_V1) {
167
- throw new Error(`v1 edge projection declares ${envelope.uncompressedLength} bytes, `
168
- + `maximum ${MAX_VERCEL_EDGE_MANIFEST_BYTES_V1}`);
169
- }
170
- return envelope;
171
- }
172
82
  function parseCanonicalJSONStringRecord(value, label) {
173
83
  if (typeof value !== 'string') {
174
84
  throw new Error(`${label} must be a canonical JSON string`);
@@ -190,374 +100,6 @@ function parseCanonicalJSONStringRecord(value, label) {
190
100
  }
191
101
  return record;
192
102
  }
193
- function decodeCanonicalBase64(value) {
194
- if (value.length === 0
195
- || value.length % 4 !== 0
196
- || !CANONICAL_BASE64.test(value)) {
197
- throw new Error('v1 edge projection payload is not canonical padded base64');
198
- }
199
- const decoded = Buffer.from(value, 'base64');
200
- if (decoded.toString('base64') !== value) {
201
- throw new Error('v1 edge projection payload is not canonical padded base64');
202
- }
203
- return decoded;
204
- }
205
- function inflateOneNormalizedGzipMember(compressed, declaredLength) {
206
- if (compressed.length < NORMALIZED_GZIP_HEADER.length + 8
207
- || !compressed.subarray(0, NORMALIZED_GZIP_HEADER.length)
208
- .equals(NORMALIZED_GZIP_HEADER)) {
209
- throw new Error('v1 edge projection gzip header is not normalized');
210
- }
211
- let result;
212
- try {
213
- result = inflateRawSync(compressed.subarray(NORMALIZED_GZIP_HEADER.length), {
214
- info: true,
215
- maxOutputLength: declaredLength,
216
- });
217
- }
218
- catch (error) {
219
- throw new Error('v1 edge projection gzip payload is corrupt or oversized', {
220
- cause: error,
221
- });
222
- }
223
- const deflateBytes = result.engine.bytesWritten;
224
- const trailerOffset = NORMALIZED_GZIP_HEADER.length + deflateBytes;
225
- if (!Number.isSafeInteger(deflateBytes)
226
- || deflateBytes <= 0
227
- || trailerOffset + 8 !== compressed.length) {
228
- throw new Error('v1 edge projection must contain exactly one gzip member with no trailing bytes');
229
- }
230
- if (result.buffer.byteLength !== declaredLength) {
231
- throw new Error(`v1 edge projection decompressed length is ${result.buffer.byteLength}, `
232
- + `want ${declaredLength}`);
233
- }
234
- const expectedCRC = compressed.readUInt32LE(trailerOffset);
235
- const actualCRC = crc32(result.buffer);
236
- if (actualCRC !== expectedCRC) {
237
- throw new Error(`v1 edge projection gzip CRC32 is ${hex32(actualCRC)}, `
238
- + `want ${hex32(expectedCRC)}`);
239
- }
240
- const expectedSize = compressed.readUInt32LE(trailerOffset + 4);
241
- if (expectedSize !== result.buffer.byteLength) {
242
- throw new Error(`v1 edge projection gzip size is ${expectedSize}, `
243
- + `want ${result.buffer.byteLength}`);
244
- }
245
- return result.buffer;
246
- }
247
- function validateRuntimeProjection(value, expected) {
248
- const record = requiredRecord(value, 'v1 edge runtime projection');
249
- assertExactKeys(record, ['manifestVersion', 'releaseId', 'siteId', 'routes'], ['experiments', 'collectSdk'], 'v1 edge runtime projection');
250
- const manifestVersion = requiredString(record.manifestVersion, 'v1 edge runtime manifest version');
251
- if (manifestVersion !== 'gradial.edge.v1') {
252
- throw new Error(`unsupported v1 edge runtime manifest version ${JSON.stringify(manifestVersion)}`);
253
- }
254
- const releaseId = requiredIdentity(record.releaseId, 'v1 edge runtime release ID');
255
- const siteId = requiredIdentity(record.siteId, 'v1 edge runtime site ID');
256
- if (siteId !== expected.siteId || releaseId !== expected.releaseId) {
257
- throw new Error(`v1 edge runtime identity mismatch: got ${siteId}/${releaseId}, `
258
- + `want ${expected.siteId}/${expected.releaseId}`);
259
- }
260
- const routesRecord = requiredRecord(record.routes, 'v1 edge runtime routes');
261
- const routes = {};
262
- for (const [routeKey, routeValue] of Object.entries(routesRecord)) {
263
- defineOwnEnumerable(routes, routeKey, validateRoute(routeKey, routeValue));
264
- }
265
- let experiments;
266
- if (Object.prototype.hasOwnProperty.call(record, 'experiments')) {
267
- const experimentsRecord = requiredRecord(record.experiments, 'v1 edge runtime experiments');
268
- experiments = {};
269
- for (const [experimentKey, experimentValue] of Object.entries(experimentsRecord)) {
270
- const experiment = validateExperiment(experimentValue);
271
- if (experiment.id !== experimentKey) {
272
- throw new Error(`v1 edge runtime experiment ${JSON.stringify(experimentKey)} `
273
- + `has identity ${JSON.stringify(experiment.id)}`);
274
- }
275
- defineOwnEnumerable(experiments, experimentKey, experiment);
276
- }
277
- if (Object.keys(experiments).length === 0) {
278
- throw new Error('v1 edge runtime experiments must be omitted when empty');
279
- }
280
- }
281
- let collectSdk;
282
- if (Object.prototype.hasOwnProperty.call(record, 'collectSdk')) {
283
- collectSdk = validateCollectSDK(record.collectSdk);
284
- }
285
- return {
286
- manifestVersion,
287
- releaseId,
288
- siteId,
289
- routes,
290
- ...(experiments ? { experiments } : {}),
291
- ...(collectSdk ? { collectSdk } : {}),
292
- };
293
- }
294
- function validateRoute(routeKey, value) {
295
- const record = requiredRecord(value, `v1 edge route ${JSON.stringify(routeKey)}`);
296
- assertExactKeys(record, ['pattern', 'priority', 'dispatch'], ['variants'], `v1 edge route ${JSON.stringify(routeKey)}`);
297
- const pattern = requiredString(record.pattern, 'v1 edge route pattern');
298
- if (pattern !== routeKey) {
299
- throw new Error(`v1 edge route ${JSON.stringify(routeKey)} has pattern `
300
- + `${JSON.stringify(pattern)}`);
301
- }
302
- let variants;
303
- if (Object.prototype.hasOwnProperty.call(record, 'variants')) {
304
- const variantsRecord = requiredRecord(record.variants, `v1 edge route ${JSON.stringify(routeKey)} variants`);
305
- variants = {};
306
- for (const [variantKey, variantValue] of Object.entries(variantsRecord)) {
307
- defineOwnEnumerable(variants, variantKey, validateVariant(variantKey, variantValue));
308
- }
309
- if (Object.keys(variants).length === 0) {
310
- throw new Error(`v1 edge route ${JSON.stringify(routeKey)} variants must be omitted when empty`);
311
- }
312
- }
313
- return {
314
- pattern,
315
- priority: requiredSafeInteger(record.priority, 'v1 edge route priority'),
316
- dispatch: validateDispatch(record.dispatch),
317
- ...(variants ? { variants } : {}),
318
- };
319
- }
320
- function validateVariant(mapKey, value) {
321
- const record = requiredRecord(value, `v1 edge variant ${JSON.stringify(mapKey)}`);
322
- assertExactKeys(record, ['variantKey', 'priority', 'dispatch'], ['variantValues', 'rule'], `v1 edge variant ${JSON.stringify(mapKey)}`);
323
- const variantKey = requiredString(record.variantKey, 'v1 edge variant key');
324
- if (variantKey !== mapKey) {
325
- throw new Error(`v1 edge variant ${JSON.stringify(mapKey)} has identity `
326
- + `${JSON.stringify(variantKey)}`);
327
- }
328
- let variantValues;
329
- if (Object.prototype.hasOwnProperty.call(record, 'variantValues')) {
330
- const values = requiredRecord(record.variantValues, `v1 edge variant ${JSON.stringify(mapKey)} values`);
331
- variantValues = {};
332
- for (const [key, item] of Object.entries(values)) {
333
- defineOwnEnumerable(variantValues, key, requiredString(item, `v1 edge variant value ${JSON.stringify(key)}`));
334
- }
335
- if (Object.keys(variantValues).length === 0) {
336
- throw new Error(`v1 edge variant ${JSON.stringify(mapKey)} values must be omitted when empty`);
337
- }
338
- }
339
- return {
340
- variantKey,
341
- ...(variantValues ? { variantValues } : {}),
342
- priority: requiredSafeInteger(record.priority, 'v1 edge variant priority'),
343
- ...(Object.prototype.hasOwnProperty.call(record, 'rule')
344
- ? { rule: validateRule(record.rule) }
345
- : {}),
346
- dispatch: validateDispatch(record.dispatch),
347
- };
348
- }
349
- function validateDispatch(value) {
350
- const record = requiredRecord(value, 'v1 edge dispatch');
351
- assertExactKeys(record, ['kind'], ['artifactPath', 'contentPath'], 'v1 edge dispatch');
352
- return {
353
- kind: requiredString(record.kind, 'v1 edge dispatch kind'),
354
- ...(Object.prototype.hasOwnProperty.call(record, 'artifactPath')
355
- ? {
356
- artifactPath: requiredString(record.artifactPath, 'v1 edge dispatch artifact path'),
357
- }
358
- : {}),
359
- ...(Object.prototype.hasOwnProperty.call(record, 'contentPath')
360
- ? {
361
- contentPath: requiredString(record.contentPath, 'v1 edge dispatch content path'),
362
- }
363
- : {}),
364
- };
365
- }
366
- function validateRule(value) {
367
- const record = requiredRecord(value, 'v1 edge variant rule');
368
- assertExactKeys(record, [], ['all', 'any'], 'v1 edge variant rule');
369
- const rule = {};
370
- if (Object.prototype.hasOwnProperty.call(record, 'all')) {
371
- const all = validateConditions(record.all, 'all');
372
- if (all.length === 0) {
373
- throw new Error('v1 edge rule all must be omitted when empty');
374
- }
375
- rule.all = all;
376
- }
377
- if (Object.prototype.hasOwnProperty.call(record, 'any')) {
378
- const any = validateConditions(record.any, 'any');
379
- if (any.length === 0) {
380
- throw new Error('v1 edge rule any must be omitted when empty');
381
- }
382
- rule.any = any;
383
- }
384
- return rule;
385
- }
386
- function validateConditions(value, group) {
387
- if (!Array.isArray(value)) {
388
- throw new Error(`v1 edge rule ${group} must be an array`);
389
- }
390
- return value.map((item, index) => {
391
- const record = requiredRecord(item, `v1 edge rule ${group}[${index}]`);
392
- assertExactKeys(record, ['field', 'operator'], ['value'], `v1 edge rule ${group}[${index}]`);
393
- return {
394
- field: requiredString(record.field, 'v1 edge rule field'),
395
- operator: requiredString(record.operator, 'v1 edge rule operator'),
396
- ...(Object.prototype.hasOwnProperty.call(record, 'value')
397
- ? {
398
- value: requiredRuntimeRuleScalar(record.value, 'v1 edge rule value'),
399
- }
400
- : {}),
401
- };
402
- });
403
- }
404
- function validateExperiment(value) {
405
- const record = requiredRecord(value, 'v1 edge experiment');
406
- assertExactKeys(record, [
407
- 'id',
408
- 'status',
409
- 'kind',
410
- 'priority',
411
- 'allocationVersion',
412
- 'salt',
413
- 'arms',
414
- ], [], 'v1 edge experiment');
415
- if (!Array.isArray(record.arms)) {
416
- throw new Error('v1 edge experiment arms must be an array');
417
- }
418
- const armIDs = new Set();
419
- const arms = record.arms.map((value, index) => {
420
- const arm = requiredRecord(value, `v1 edge experiment arm ${index}`);
421
- assertExactKeys(arm, ['id', 'role', 'allocationBasisPoints'], ['variantKey'], `v1 edge experiment arm ${index}`);
422
- const id = requiredString(arm.id, 'v1 edge experiment arm ID');
423
- if (armIDs.has(id)) {
424
- throw new Error(`duplicate v1 edge experiment arm ID ${JSON.stringify(id)}`);
425
- }
426
- armIDs.add(id);
427
- const role = requiredString(arm.role, 'v1 edge experiment arm role');
428
- return {
429
- id,
430
- role,
431
- allocationBasisPoints: requiredBoundedInteger(arm.allocationBasisPoints, 0, 10_000, 'v1 edge experiment arm allocation'),
432
- variantKey: Object.prototype.hasOwnProperty.call(arm, 'variantKey')
433
- ? requiredString(arm.variantKey, 'v1 edge experiment arm variant key')
434
- : '',
435
- };
436
- });
437
- return {
438
- id: requiredString(record.id, 'v1 edge experiment ID'),
439
- status: requiredString(record.status, 'v1 edge experiment status'),
440
- kind: requiredString(record.kind, 'v1 edge experiment kind'),
441
- priority: requiredSafeInteger(record.priority, 'v1 edge experiment priority'),
442
- allocationVersion: optionalString(record.allocationVersion, 'v1 edge experiment allocation version'),
443
- salt: optionalString(record.salt, 'v1 edge experiment assignment salt'),
444
- arms,
445
- };
446
- }
447
- function validateCollectSDK(value) {
448
- const record = requiredRecord(value, 'v1 edge collect SDK');
449
- assertExactKeys(record, ['hash', 'path'], [], 'v1 edge collect SDK');
450
- const hash = requiredSHA256(record.hash, 'v1 edge collect SDK hash');
451
- const path = requiredString(record.path, 'v1 edge collect SDK path');
452
- const expectedPath = `_aci/aci.${hash}.js`;
453
- if (path !== expectedPath) {
454
- throw new Error(`v1 edge collect SDK path ${JSON.stringify(path)} must equal `
455
- + `${JSON.stringify(expectedPath)}`);
456
- }
457
- return { hash, path };
458
- }
459
- function canonicalRuntimeProjectionJSON(value) {
460
- const record = requiredRecord(value, 'v1 edge runtime projection');
461
- return encodeCanonicalJSONNode(canonicalObject([
462
- ['manifestVersion', canonicalUnknownNode(record.manifestVersion)],
463
- ['releaseId', canonicalUnknownNode(record.releaseId)],
464
- ['siteId', canonicalUnknownNode(record.siteId)],
465
- [
466
- 'routes',
467
- canonicalSortedMap(requiredRecord(record.routes, 'v1 edge runtime routes'), canonicalRouteNode),
468
- ],
469
- ...optionalCanonicalEntry(record, 'experiments', (experiments) => (canonicalSortedMap(requiredRecord(experiments, 'v1 edge runtime experiments'), canonicalExperimentNode))),
470
- ...optionalCanonicalEntry(record, 'collectSdk', canonicalCollectSDKNode),
471
- ]));
472
- }
473
- function canonicalRouteNode(value) {
474
- const record = requiredRecord(value, 'v1 edge route');
475
- return canonicalObject([
476
- ['pattern', canonicalUnknownNode(record.pattern)],
477
- ['priority', canonicalUnknownNode(record.priority)],
478
- ['dispatch', canonicalDispatchNode(record.dispatch)],
479
- ...optionalCanonicalEntry(record, 'variants', (variants) => (canonicalSortedMap(requiredRecord(variants, 'v1 edge route variants'), canonicalVariantNode))),
480
- ]);
481
- }
482
- function canonicalVariantNode(value) {
483
- const record = requiredRecord(value, 'v1 edge variant');
484
- return canonicalObject([
485
- ['variantKey', canonicalUnknownNode(record.variantKey)],
486
- ...optionalCanonicalEntry(record, 'variantValues', (values) => (canonicalSortedMap(requiredRecord(values, 'v1 edge variant values'), canonicalUnknownNode))),
487
- ['priority', canonicalUnknownNode(record.priority)],
488
- ...optionalCanonicalEntry(record, 'rule', canonicalRuleNode),
489
- ['dispatch', canonicalDispatchNode(record.dispatch)],
490
- ]);
491
- }
492
- function canonicalDispatchNode(value) {
493
- const record = requiredRecord(value, 'v1 edge dispatch');
494
- return canonicalObject([
495
- ['kind', canonicalUnknownNode(record.kind)],
496
- ...optionalCanonicalEntry(record, 'artifactPath', canonicalUnknownNode),
497
- ...optionalCanonicalEntry(record, 'contentPath', canonicalUnknownNode),
498
- ]);
499
- }
500
- function canonicalRuleNode(value) {
501
- const record = requiredRecord(value, 'v1 edge rule');
502
- return canonicalObject([
503
- ...optionalCanonicalEntry(record, 'all', canonicalConditionArrayNode),
504
- ...optionalCanonicalEntry(record, 'any', canonicalConditionArrayNode),
505
- ]);
506
- }
507
- function canonicalConditionArrayNode(value) {
508
- if (!Array.isArray(value)) {
509
- throw new Error('v1 edge rule conditions must be an array');
510
- }
511
- return value.map((condition) => {
512
- const record = requiredRecord(condition, 'v1 edge rule condition');
513
- return canonicalObject([
514
- ['field', canonicalUnknownNode(record.field)],
515
- ['operator', canonicalUnknownNode(record.operator)],
516
- ...optionalCanonicalEntry(record, 'value', canonicalUnknownNode),
517
- ]);
518
- });
519
- }
520
- function canonicalExperimentNode(value) {
521
- const record = requiredRecord(value, 'v1 edge experiment');
522
- if (!Array.isArray(record.arms)) {
523
- throw new Error('v1 edge experiment arms must be an array');
524
- }
525
- return canonicalObject([
526
- ['id', canonicalUnknownNode(record.id)],
527
- ['status', canonicalUnknownNode(record.status)],
528
- ['kind', canonicalUnknownNode(record.kind)],
529
- ['priority', canonicalUnknownNode(record.priority)],
530
- ['allocationVersion', canonicalUnknownNode(record.allocationVersion)],
531
- ['salt', canonicalUnknownNode(record.salt)],
532
- [
533
- 'arms',
534
- record.arms.map((armValue) => {
535
- const arm = requiredRecord(armValue, 'v1 edge experiment arm');
536
- return canonicalObject([
537
- ['id', canonicalUnknownNode(arm.id)],
538
- ['role', canonicalUnknownNode(arm.role)],
539
- [
540
- 'allocationBasisPoints',
541
- canonicalUnknownNode(arm.allocationBasisPoints),
542
- ],
543
- ...optionalCanonicalEntry(arm, 'variantKey', canonicalUnknownNode),
544
- ]);
545
- }),
546
- ],
547
- ]);
548
- }
549
- function canonicalCollectSDKNode(value) {
550
- const record = requiredRecord(value, 'v1 edge collect SDK');
551
- return canonicalObject([
552
- ['hash', canonicalUnknownNode(record.hash)],
553
- ['path', canonicalUnknownNode(record.path)],
554
- ]);
555
- }
556
- function optionalCanonicalEntry(record, key, encode) {
557
- return Object.prototype.hasOwnProperty.call(record, key)
558
- ? [[key, encode(record[key])]]
559
- : [];
560
- }
561
103
  function canonicalSortedMap(record, encode) {
562
104
  const entries = Object.entries(record)
563
105
  .sort(([left], [right]) => Buffer.compare(Buffer.from(left, 'utf8'), Buffer.from(right, 'utf8')))
@@ -630,26 +172,12 @@ function requiredRecord(value, label) {
630
172
  }
631
173
  return value;
632
174
  }
633
- function defineOwnEnumerable(record, key, value) {
634
- Object.defineProperty(record, key, {
635
- value,
636
- enumerable: true,
637
- configurable: true,
638
- writable: true,
639
- });
640
- }
641
175
  function requiredString(value, label) {
642
176
  if (typeof value !== 'string' || value.length === 0) {
643
177
  throw new Error(`${label} must be a non-empty string`);
644
178
  }
645
179
  return value;
646
180
  }
647
- function optionalString(value, label) {
648
- if (typeof value !== 'string') {
649
- throw new Error(`${label} must be a string`);
650
- }
651
- return value;
652
- }
653
181
  function requiredIdentity(value, label) {
654
182
  const result = requiredString(value, label);
655
183
  if (result === '.'
@@ -660,34 +188,6 @@ function requiredIdentity(value, label) {
660
188
  }
661
189
  return result;
662
190
  }
663
- function requiredSHA256(value, label) {
664
- const digest = requiredString(value, label);
665
- if (!SHA256_HEX.test(digest)) {
666
- throw new Error(`${label} must be lowercase SHA-256`);
667
- }
668
- return digest;
669
- }
670
- function requiredRuntimeRuleScalar(value, label) {
671
- if (value === null
672
- || typeof value === 'string'
673
- || typeof value === 'boolean'
674
- || (typeof value === 'number' && Number.isFinite(value))) {
675
- return value;
676
- }
677
- throw new Error(`${label} must be a JSON string, number, boolean, or null`);
678
- }
679
- function requiredSafeInteger(value, label) {
680
- if (typeof value !== 'number' || !Number.isSafeInteger(value)) {
681
- throw new Error(`${label} must be a safe integer`);
682
- }
683
- return value;
684
- }
685
- function requiredPositiveSafeInteger(value, label) {
686
- const result = requiredSafeInteger(value, label);
687
- if (result <= 0)
688
- throw new Error(`${label} must be positive`);
689
- return result;
690
- }
691
191
  function requiredPositiveDecimalBigInt(value, label) {
692
192
  if (typeof value !== 'string' || !POSITIVE_DECIMAL.test(value)) {
693
193
  throw new Error(`${label} must be a canonical positive decimal string`);
@@ -698,39 +198,9 @@ function requiredPositiveDecimalBigInt(value, label) {
698
198
  }
699
199
  return result;
700
200
  }
701
- function requiredBoundedInteger(value, minimum, maximum, label) {
702
- const result = requiredSafeInteger(value, label);
703
- if (result < minimum || result > maximum) {
704
- throw new Error(`${label} must be between ${minimum} and ${maximum}`);
705
- }
706
- return result;
707
- }
708
- function sha256(value) {
709
- return createHash('sha256').update(value).digest('hex');
710
- }
711
201
  function edgeKeySegment(value) {
712
202
  return value.replace(/[^A-Za-z0-9_-]/gu, '_');
713
203
  }
714
- function hex32(value) {
715
- return value.toString(16).padStart(8, '0');
716
- }
717
- const CRC32_TABLE = new Uint32Array(256);
718
- for (let index = 0; index < CRC32_TABLE.length; index += 1) {
719
- let value = index;
720
- for (let bit = 0; bit < 8; bit += 1) {
721
- value = (value & 1) !== 0
722
- ? (value >>> 1) ^ 0xedb88320
723
- : value >>> 1;
724
- }
725
- CRC32_TABLE[index] = value >>> 0;
726
- }
727
- function crc32(value) {
728
- let result = 0xffffffff;
729
- for (const byte of value) {
730
- result = CRC32_TABLE[(result ^ byte) & 0xff] ^ (result >>> 8);
731
- }
732
- return (result ^ 0xffffffff) >>> 0;
733
- }
734
204
  function assertCanonicalJSONSyntax(value, label) {
735
205
  let index = 0;
736
206
  function parseValue(depth) {
@@ -37,6 +37,7 @@ export interface PreviewCookie {
37
37
  export declare const PREVIEW_TOKEN_COOKIE = "aci_preview";
38
38
  export declare const PREVIEW_RELEASE_COOKIE = "aci_preview_release";
39
39
  export declare function validatePreviewToken(token: string, signKey: string): Promise<PreviewClaims | null>;
40
+ export declare function parseCookies(header: string): Map<string, string>;
40
41
  export declare function extractPreviewToken(source: PreviewTokenSource): string | undefined;
41
42
  export declare function previewSignKey(): string | undefined;
42
43
  export declare function resolvePreviewContext(options: PreviewResolveOptions): Promise<PreviewContext>;
@@ -18,6 +18,33 @@ export async function validatePreviewToken(token, signKey) {
18
18
  return null;
19
19
  }
20
20
  }
21
+ // parseCookies is the SDK-side raw Cookie-header parser for callers that only
22
+ // have the header string (the Astro integration; Next hands us its own parsed
23
+ // cookies). It is deliberately not the canonical edge parser
24
+ // (internal/domain/edge/identity.ts parseCookieHeader): SDK source cannot
25
+ // import internal/domain/edge — assemble-dist re-roots the emitted tree and
26
+ // the relative specifier depth changes — and framework cookie writers
27
+ // URI-encode values, so this one decodes them (falling back to the raw value
28
+ // on a malformed escape rather than throwing mid-request).
29
+ export function parseCookies(header) {
30
+ const cookies = new Map();
31
+ for (const part of header.split(';')) {
32
+ const separator = part.indexOf('=');
33
+ if (separator < 0)
34
+ continue;
35
+ const name = part.slice(0, separator).trim();
36
+ if (!name)
37
+ continue;
38
+ const value = part.slice(separator + 1).trim();
39
+ try {
40
+ cookies.set(name, decodeURIComponent(value));
41
+ }
42
+ catch {
43
+ cookies.set(name, value);
44
+ }
45
+ }
46
+ return cookies;
47
+ }
21
48
  export function extractPreviewToken(source) {
22
49
  const query = source.query?.get('preview_token');
23
50
  if (query)
@@ -78,12 +78,13 @@ export class S3ContentProvider {
78
78
  }
79
79
  async getLayout(name) {
80
80
  const manifest = await this.manifest();
81
- const layouts = manifest.layouts;
82
- if (!layouts || !layouts[name]) {
81
+ const entry = manifest.layouts?.[name];
82
+ if (!entry) {
83
83
  throw new LayoutNotFoundError(name);
84
84
  }
85
+ const ref = entry.payloadRef;
85
86
  try {
86
- return await this.getJSON(`layouts/${name}.json`);
87
+ return await this.getJSON(ref);
87
88
  }
88
89
  catch (error) {
89
90
  throw new LayoutNotFoundError(name, error);
@@ -25,7 +25,6 @@ export declare function VideoPlayer({ video, ...attrs }: VideoPlayerProps): impo
25
25
  } | undefined | undefined;
26
26
  children?: import("react").ReactNode;
27
27
  className?: string | undefined | undefined;
28
- lang?: string | undefined | undefined;
29
28
  crossOrigin?: "" | "anonymous" | "use-credentials" | undefined;
30
29
  defaultChecked?: boolean | undefined | undefined;
31
30
  defaultValue?: string | number | readonly string[] | undefined;
@@ -38,6 +37,7 @@ export declare function VideoPlayer({ video, ...attrs }: VideoPlayerProps): impo
38
37
  contextMenu?: string | undefined | undefined;
39
38
  draggable?: (boolean | "true" | "false") | undefined;
40
39
  enterKeyHint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
40
+ lang?: string | undefined | undefined;
41
41
  nonce?: string | undefined | undefined;
42
42
  spellCheck?: (boolean | "true" | "false") | undefined;
43
43
  tabIndex?: number | undefined | undefined;