@gradial/aci 0.1.52-rc.16 → 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 (48) hide show
  1. package/README.md +4 -4
  2. package/dist/astro/preview.js +2 -17
  3. package/dist/audience-data-models.d.ts +193 -16
  4. package/dist/audience-data-models.js +47 -2
  5. package/dist/collect/batcher.d.ts +6 -5
  6. package/dist/collect/batcher.js +6 -5
  7. package/dist/edge/expression-capabilities.v1.d.ts +106 -0
  8. package/dist/edge/expression-capabilities.v1.js +165 -0
  9. package/dist/internal/domain/edge/identity.js +1 -1
  10. package/dist/internal/domain/edge/mimic_token.js +1 -2
  11. package/dist/internal/domain/edge/personalization-core.d.ts +14 -4
  12. package/dist/internal/domain/edge/personalization-core.js +472 -54
  13. package/dist/internal/domain/edge/record/codec.d.ts +5 -2
  14. package/dist/internal/domain/edge/record/codec.js +83 -10
  15. package/dist/internal/domain/edge/resolve.js +13 -2
  16. package/dist/internal/domain/edge/testdata/flat_only_validator_v1.d.ts +10 -0
  17. package/dist/internal/domain/edge/testdata/flat_only_validator_v1.js +253 -0
  18. package/dist/internal/domain/edge/types.d.ts +36 -9
  19. package/dist/internal/domain/edge/types.js +3 -3
  20. package/dist/mimic/core.d.ts +0 -32
  21. package/dist/mimic/core.js +12 -108
  22. package/dist/next/vercel-edge-projection-v1.d.ts +0 -9
  23. package/dist/next/vercel-edge-projection-v1.js +9 -545
  24. package/dist/preview/core.d.ts +1 -0
  25. package/dist/preview/core.js +27 -0
  26. package/dist/react/VideoPlayer.d.ts +1 -1
  27. package/dist/react/index.d.ts +1 -1
  28. package/package.json +16 -7
  29. package/templates/common/.agents/skills/aci/SKILL.md +6 -0
  30. package/templates/common/.agents/skills/dam-delivery/SKILL.md +228 -0
  31. package/templates/common/.agents/skills/dam-delivery/references/parameter-contract.md +107 -0
  32. package/templates/common/.agents/skills/dam-delivery/references/permalink-grammar.md +131 -0
  33. package/dist/edge/personalization-core.d.ts +0 -35
  34. package/dist/edge/personalization-core.js +0 -483
  35. package/dist/next/collect-route.d.ts +0 -25
  36. package/dist/next/collect-route.js +0 -479
  37. package/dist/next/envelope-digest.d.ts +0 -21
  38. package/dist/next/envelope-digest.js +0 -58
  39. package/dist/next/personalization-host.d.ts +0 -138
  40. package/dist/next/personalization-host.js +0 -280
  41. package/dist/next/root-layout.d.ts +0 -4
  42. package/dist/next/root-layout.js +0 -5
  43. package/dist/next/vercel-collect-sdk-route.d.ts +0 -27
  44. package/dist/next/vercel-collect-sdk-route.js +0 -181
  45. package/dist/next/vercel-personalization.d.ts +0 -4
  46. package/dist/next/vercel-personalization.js +0 -4
  47. package/dist/next/vercel-s3-personalization.d.ts +0 -80
  48. package/dist/next/vercel-s3-personalization.js +0 -571
@@ -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,380 +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
- ], ['eligibilityAudienceId'], '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
- ...(Object.prototype.hasOwnProperty.call(record, 'eligibilityAudienceId')
445
- ? {
446
- eligibilityAudienceId: optionalString(record.eligibilityAudienceId, 'v1 edge experiment eligibility audience ID'),
447
- }
448
- : {}),
449
- arms,
450
- };
451
- }
452
- function validateCollectSDK(value) {
453
- const record = requiredRecord(value, 'v1 edge collect SDK');
454
- assertExactKeys(record, ['hash', 'path'], [], 'v1 edge collect SDK');
455
- const hash = requiredSHA256(record.hash, 'v1 edge collect SDK hash');
456
- const path = requiredString(record.path, 'v1 edge collect SDK path');
457
- const expectedPath = `_aci/aci.${hash}.js`;
458
- if (path !== expectedPath) {
459
- throw new Error(`v1 edge collect SDK path ${JSON.stringify(path)} must equal `
460
- + `${JSON.stringify(expectedPath)}`);
461
- }
462
- return { hash, path };
463
- }
464
- function canonicalRuntimeProjectionJSON(value) {
465
- const record = requiredRecord(value, 'v1 edge runtime projection');
466
- return encodeCanonicalJSONNode(canonicalObject([
467
- ['manifestVersion', canonicalUnknownNode(record.manifestVersion)],
468
- ['releaseId', canonicalUnknownNode(record.releaseId)],
469
- ['siteId', canonicalUnknownNode(record.siteId)],
470
- [
471
- 'routes',
472
- canonicalSortedMap(requiredRecord(record.routes, 'v1 edge runtime routes'), canonicalRouteNode),
473
- ],
474
- ...optionalCanonicalEntry(record, 'experiments', (experiments) => (canonicalSortedMap(requiredRecord(experiments, 'v1 edge runtime experiments'), canonicalExperimentNode))),
475
- ...optionalCanonicalEntry(record, 'collectSdk', canonicalCollectSDKNode),
476
- ]));
477
- }
478
- function canonicalRouteNode(value) {
479
- const record = requiredRecord(value, 'v1 edge route');
480
- return canonicalObject([
481
- ['pattern', canonicalUnknownNode(record.pattern)],
482
- ['priority', canonicalUnknownNode(record.priority)],
483
- ['dispatch', canonicalDispatchNode(record.dispatch)],
484
- ...optionalCanonicalEntry(record, 'variants', (variants) => (canonicalSortedMap(requiredRecord(variants, 'v1 edge route variants'), canonicalVariantNode))),
485
- ]);
486
- }
487
- function canonicalVariantNode(value) {
488
- const record = requiredRecord(value, 'v1 edge variant');
489
- return canonicalObject([
490
- ['variantKey', canonicalUnknownNode(record.variantKey)],
491
- ...optionalCanonicalEntry(record, 'variantValues', (values) => (canonicalSortedMap(requiredRecord(values, 'v1 edge variant values'), canonicalUnknownNode))),
492
- ['priority', canonicalUnknownNode(record.priority)],
493
- ...optionalCanonicalEntry(record, 'rule', canonicalRuleNode),
494
- ['dispatch', canonicalDispatchNode(record.dispatch)],
495
- ]);
496
- }
497
- function canonicalDispatchNode(value) {
498
- const record = requiredRecord(value, 'v1 edge dispatch');
499
- return canonicalObject([
500
- ['kind', canonicalUnknownNode(record.kind)],
501
- ...optionalCanonicalEntry(record, 'artifactPath', canonicalUnknownNode),
502
- ...optionalCanonicalEntry(record, 'contentPath', canonicalUnknownNode),
503
- ]);
504
- }
505
- function canonicalRuleNode(value) {
506
- const record = requiredRecord(value, 'v1 edge rule');
507
- return canonicalObject([
508
- ...optionalCanonicalEntry(record, 'all', canonicalConditionArrayNode),
509
- ...optionalCanonicalEntry(record, 'any', canonicalConditionArrayNode),
510
- ]);
511
- }
512
- function canonicalConditionArrayNode(value) {
513
- if (!Array.isArray(value)) {
514
- throw new Error('v1 edge rule conditions must be an array');
515
- }
516
- return value.map((condition) => {
517
- const record = requiredRecord(condition, 'v1 edge rule condition');
518
- return canonicalObject([
519
- ['field', canonicalUnknownNode(record.field)],
520
- ['operator', canonicalUnknownNode(record.operator)],
521
- ...optionalCanonicalEntry(record, 'value', canonicalUnknownNode),
522
- ]);
523
- });
524
- }
525
- function canonicalExperimentNode(value) {
526
- const record = requiredRecord(value, 'v1 edge experiment');
527
- if (!Array.isArray(record.arms)) {
528
- throw new Error('v1 edge experiment arms must be an array');
529
- }
530
- return canonicalObject([
531
- ['id', canonicalUnknownNode(record.id)],
532
- ['status', canonicalUnknownNode(record.status)],
533
- ['kind', canonicalUnknownNode(record.kind)],
534
- ['priority', canonicalUnknownNode(record.priority)],
535
- ['allocationVersion', canonicalUnknownNode(record.allocationVersion)],
536
- ['salt', canonicalUnknownNode(record.salt)],
537
- ...optionalCanonicalEntry(record, 'eligibilityAudienceId', canonicalUnknownNode),
538
- [
539
- 'arms',
540
- record.arms.map((armValue) => {
541
- const arm = requiredRecord(armValue, 'v1 edge experiment arm');
542
- return canonicalObject([
543
- ['id', canonicalUnknownNode(arm.id)],
544
- ['role', canonicalUnknownNode(arm.role)],
545
- [
546
- 'allocationBasisPoints',
547
- canonicalUnknownNode(arm.allocationBasisPoints),
548
- ],
549
- ...optionalCanonicalEntry(arm, 'variantKey', canonicalUnknownNode),
550
- ]);
551
- }),
552
- ],
553
- ]);
554
- }
555
- function canonicalCollectSDKNode(value) {
556
- const record = requiredRecord(value, 'v1 edge collect SDK');
557
- return canonicalObject([
558
- ['hash', canonicalUnknownNode(record.hash)],
559
- ['path', canonicalUnknownNode(record.path)],
560
- ]);
561
- }
562
- function optionalCanonicalEntry(record, key, encode) {
563
- return Object.prototype.hasOwnProperty.call(record, key)
564
- ? [[key, encode(record[key])]]
565
- : [];
566
- }
567
103
  function canonicalSortedMap(record, encode) {
568
104
  const entries = Object.entries(record)
569
105
  .sort(([left], [right]) => Buffer.compare(Buffer.from(left, 'utf8'), Buffer.from(right, 'utf8')))
@@ -636,26 +172,12 @@ function requiredRecord(value, label) {
636
172
  }
637
173
  return value;
638
174
  }
639
- function defineOwnEnumerable(record, key, value) {
640
- Object.defineProperty(record, key, {
641
- value,
642
- enumerable: true,
643
- configurable: true,
644
- writable: true,
645
- });
646
- }
647
175
  function requiredString(value, label) {
648
176
  if (typeof value !== 'string' || value.length === 0) {
649
177
  throw new Error(`${label} must be a non-empty string`);
650
178
  }
651
179
  return value;
652
180
  }
653
- function optionalString(value, label) {
654
- if (typeof value !== 'string') {
655
- throw new Error(`${label} must be a string`);
656
- }
657
- return value;
658
- }
659
181
  function requiredIdentity(value, label) {
660
182
  const result = requiredString(value, label);
661
183
  if (result === '.'
@@ -666,34 +188,6 @@ function requiredIdentity(value, label) {
666
188
  }
667
189
  return result;
668
190
  }
669
- function requiredSHA256(value, label) {
670
- const digest = requiredString(value, label);
671
- if (!SHA256_HEX.test(digest)) {
672
- throw new Error(`${label} must be lowercase SHA-256`);
673
- }
674
- return digest;
675
- }
676
- function requiredRuntimeRuleScalar(value, label) {
677
- if (value === null
678
- || typeof value === 'string'
679
- || typeof value === 'boolean'
680
- || (typeof value === 'number' && Number.isFinite(value))) {
681
- return value;
682
- }
683
- throw new Error(`${label} must be a JSON string, number, boolean, or null`);
684
- }
685
- function requiredSafeInteger(value, label) {
686
- if (typeof value !== 'number' || !Number.isSafeInteger(value)) {
687
- throw new Error(`${label} must be a safe integer`);
688
- }
689
- return value;
690
- }
691
- function requiredPositiveSafeInteger(value, label) {
692
- const result = requiredSafeInteger(value, label);
693
- if (result <= 0)
694
- throw new Error(`${label} must be positive`);
695
- return result;
696
- }
697
191
  function requiredPositiveDecimalBigInt(value, label) {
698
192
  if (typeof value !== 'string' || !POSITIVE_DECIMAL.test(value)) {
699
193
  throw new Error(`${label} must be a canonical positive decimal string`);
@@ -704,39 +198,9 @@ function requiredPositiveDecimalBigInt(value, label) {
704
198
  }
705
199
  return result;
706
200
  }
707
- function requiredBoundedInteger(value, minimum, maximum, label) {
708
- const result = requiredSafeInteger(value, label);
709
- if (result < minimum || result > maximum) {
710
- throw new Error(`${label} must be between ${minimum} and ${maximum}`);
711
- }
712
- return result;
713
- }
714
- function sha256(value) {
715
- return createHash('sha256').update(value).digest('hex');
716
- }
717
201
  function edgeKeySegment(value) {
718
202
  return value.replace(/[^A-Za-z0-9_-]/gu, '_');
719
203
  }
720
- function hex32(value) {
721
- return value.toString(16).padStart(8, '0');
722
- }
723
- const CRC32_TABLE = new Uint32Array(256);
724
- for (let index = 0; index < CRC32_TABLE.length; index += 1) {
725
- let value = index;
726
- for (let bit = 0; bit < 8; bit += 1) {
727
- value = (value & 1) !== 0
728
- ? (value >>> 1) ^ 0xedb88320
729
- : value >>> 1;
730
- }
731
- CRC32_TABLE[index] = value >>> 0;
732
- }
733
- function crc32(value) {
734
- let result = 0xffffffff;
735
- for (const byte of value) {
736
- result = CRC32_TABLE[(result ^ byte) & 0xff] ^ (result >>> 8);
737
- }
738
- return (result ^ 0xffffffff) >>> 0;
739
- }
740
204
  function assertCanonicalJSONSyntax(value, label) {
741
205
  let index = 0;
742
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)
@@ -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;
@@ -34,7 +34,6 @@ export declare function Image({ image, value, ...attrs }: ImageProps): import("r
34
34
  } | undefined | undefined;
35
35
  children?: ReactNode;
36
36
  className?: string | undefined | undefined;
37
- lang?: string | undefined | undefined;
38
37
  crossOrigin?: "" | "anonymous" | "use-credentials" | undefined;
39
38
  fetchPriority?: "high" | "low" | "auto" | undefined | undefined;
40
39
  useMap?: string | undefined | undefined;
@@ -49,6 +48,7 @@ export declare function Image({ image, value, ...attrs }: ImageProps): import("r
49
48
  contextMenu?: string | undefined | undefined;
50
49
  draggable?: (boolean | "true" | "false") | undefined;
51
50
  enterKeyHint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
51
+ lang?: string | undefined | undefined;
52
52
  nonce?: string | undefined | undefined;
53
53
  spellCheck?: (boolean | "true" | "false") | undefined;
54
54
  tabIndex?: number | undefined | undefined;