@astrasyncai/verification-gateway 5.14.0 → 5.15.0

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 (98) hide show
  1. package/README.md +27 -17
  2. package/dist/adapters/express.d.mts +1 -1
  3. package/dist/adapters/express.d.ts +1 -1
  4. package/dist/adapters/express.js +477 -240
  5. package/dist/adapters/express.js.map +1 -1
  6. package/dist/adapters/express.mjs +477 -240
  7. package/dist/adapters/express.mjs.map +1 -1
  8. package/dist/adapters/mcp.d.mts +1 -1
  9. package/dist/adapters/mcp.d.ts +1 -1
  10. package/dist/adapters/mcp.js +20 -6
  11. package/dist/adapters/mcp.js.map +1 -1
  12. package/dist/adapters/mcp.mjs +20 -6
  13. package/dist/adapters/mcp.mjs.map +1 -1
  14. package/dist/adapters/nextjs.d.mts +1 -1
  15. package/dist/adapters/nextjs.d.ts +1 -1
  16. package/dist/adapters/nextjs.js +460 -239
  17. package/dist/adapters/nextjs.js.map +1 -1
  18. package/dist/adapters/nextjs.mjs +460 -239
  19. package/dist/adapters/nextjs.mjs.map +1 -1
  20. package/dist/adapters/sdk.d.mts +18 -10
  21. package/dist/adapters/sdk.d.ts +18 -10
  22. package/dist/adapters/sdk.js +80 -23
  23. package/dist/adapters/sdk.js.map +1 -1
  24. package/dist/adapters/sdk.mjs +80 -23
  25. package/dist/adapters/sdk.mjs.map +1 -1
  26. package/dist/agent/index.js +1 -1
  27. package/dist/agent/index.js.map +1 -1
  28. package/dist/agent/index.mjs +1 -1
  29. package/dist/agent/index.mjs.map +1 -1
  30. package/dist/bin/astrasync-claude-hook.js +55 -11
  31. package/dist/bin/astrasync-codex-hook.js +55 -11
  32. package/dist/bin/astrasync-guard.js +55 -11
  33. package/dist/bin/astrasync.js +288 -33
  34. package/dist/browser/background.js +50 -6
  35. package/dist/browser/background.js.map +1 -1
  36. package/dist/browser/background.mjs +60 -6
  37. package/dist/browser/background.mjs.map +1 -1
  38. package/dist/cli/index.js +1 -1
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/cli/index.mjs +1 -1
  41. package/dist/cli/index.mjs.map +1 -1
  42. package/dist/codex/index.js +55 -11
  43. package/dist/codex/index.js.map +1 -1
  44. package/dist/codex/index.mjs +65 -11
  45. package/dist/codex/index.mjs.map +1 -1
  46. package/dist/cursor/extension.js +55 -11
  47. package/dist/cursor/extension.js.map +1 -1
  48. package/dist/cursor/extension.mjs +65 -11
  49. package/dist/cursor/extension.mjs.map +1 -1
  50. package/dist/edge-config.d.mts +31 -2
  51. package/dist/edge-config.d.ts +31 -2
  52. package/dist/edge-config.js +35 -5
  53. package/dist/edge-config.js.map +1 -1
  54. package/dist/edge-config.mjs +32 -4
  55. package/dist/edge-config.mjs.map +1 -1
  56. package/dist/edge-core/index.d.mts +11 -2
  57. package/dist/edge-core/index.d.ts +11 -2
  58. package/dist/edge-core/index.js +93 -10
  59. package/dist/edge-core/index.js.map +1 -1
  60. package/dist/edge-core/index.mjs +91 -10
  61. package/dist/edge-core/index.mjs.map +1 -1
  62. package/dist/gateway/gateway.js +50 -6
  63. package/dist/gateway/gateway.js.map +1 -1
  64. package/dist/gateway/gateway.mjs +60 -6
  65. package/dist/gateway/gateway.mjs.map +1 -1
  66. package/dist/git-trigger/git-hooks.d.mts +1 -1
  67. package/dist/git-trigger/git-hooks.d.ts +1 -1
  68. package/dist/index.d.mts +1314 -34
  69. package/dist/index.d.ts +1314 -34
  70. package/dist/index.js +5116 -2612
  71. package/dist/index.js.map +1 -1
  72. package/dist/index.mjs +5063 -2614
  73. package/dist/index.mjs.map +1 -1
  74. package/dist/registration/index.d.mts +28 -2
  75. package/dist/registration/index.d.ts +28 -2
  76. package/dist/registration/index.js +18 -3
  77. package/dist/registration/index.js.map +1 -1
  78. package/dist/registration/index.mjs +15 -2
  79. package/dist/registration/index.mjs.map +1 -1
  80. package/dist/transport/index.d.mts +7 -5
  81. package/dist/transport/index.d.ts +7 -5
  82. package/dist/transport/index.js +61 -5
  83. package/dist/transport/index.js.map +1 -1
  84. package/dist/transport/index.mjs +67 -11
  85. package/dist/transport/index.mjs.map +1 -1
  86. package/dist/{types-C_b4QTyO.d.ts → types-DtJjlW4O.d.ts} +104 -10
  87. package/dist/{types-BCkwBA84.d.mts → types-Dxf9DBpr.d.mts} +106 -12
  88. package/dist/{types-BCkwBA84.d.ts → types-Dxf9DBpr.d.ts} +106 -12
  89. package/dist/{types-DlshIIR-.d.mts → types-Eg6VoBNH.d.mts} +104 -10
  90. package/dist/ui/index.d.mts +1 -1
  91. package/dist/ui/index.d.ts +1 -1
  92. package/dist/verify.d.mts +1 -1
  93. package/dist/verify.d.ts +1 -1
  94. package/dist/verify.js +20 -6
  95. package/dist/verify.js.map +1 -1
  96. package/dist/verify.mjs +20 -6
  97. package/dist/verify.mjs.map +1 -1
  98. package/package.json +1 -1
@@ -1,5 +1,419 @@
1
+ // src/metadata-capture.ts
2
+ var CAPTURE_SCHEMA_VERSION = 1;
3
+ var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
4
+ "cookie",
5
+ "set-cookie",
6
+ "x-csrf-token",
7
+ "proxy-authorization",
8
+ "x-astrasync-signature",
9
+ "x-astrasync-secret",
10
+ "x-hub-signature",
11
+ "x-hub-signature-256",
12
+ // Short-lived verify dedupe token — must never persist in stored metadata.
13
+ "x-astra-verified-hop"
14
+ ]);
15
+ var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
16
+ var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
17
+ "authorization",
18
+ "x-api-key",
19
+ "x-goog-api-key",
20
+ "api-key"
21
+ ]);
22
+ function isSignatureHeader(name) {
23
+ return name === "signature" || name.endsWith("-signature") || name.endsWith("-signature-256");
24
+ }
25
+ var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
26
+ "openai-organization",
27
+ "openai-project",
28
+ "openai-version",
29
+ "openai-processing-ms",
30
+ "anthropic-version",
31
+ "anthropic-beta",
32
+ "x-goog-user-project",
33
+ "x-goog-api-client",
34
+ "user-agent",
35
+ "x-agent-card-url",
36
+ "x-agent-provider"
37
+ ]);
38
+ var PLATFORM_HEADER_PREFIXES = [
39
+ "x-goog-",
40
+ "x-stainless-",
41
+ "x-anthropic-",
42
+ "x-openai-",
43
+ "sec-ch-"
44
+ ];
45
+ var KEY_FORMAT_PREFIXES = [
46
+ "sk-ant-api03",
47
+ "sk-ant-api",
48
+ "sk-ant",
49
+ "sk-proj",
50
+ "sk-svcacct",
51
+ "sk-or-v1",
52
+ "sk-or",
53
+ "sk-lf",
54
+ "sk-",
55
+ "gsk_",
56
+ "aiza",
57
+ "ya29",
58
+ "ghp_",
59
+ "gho_",
60
+ "github_pat_",
61
+ "xai-",
62
+ "pplx-",
63
+ "r8_",
64
+ "hf_",
65
+ "astra-",
66
+ "astrae-"
67
+ ];
68
+ var MAX_HEADERS = 64;
69
+ var MAX_HEADER_VALUE_BYTES = 1024;
70
+ var MAX_TOTAL_BYTES = 16 * 1024;
71
+ function byteLength(s) {
72
+ let bytes = 0;
73
+ for (let i = 0; i < s.length; i++) {
74
+ const code = s.charCodeAt(i);
75
+ if (code < 128) bytes += 1;
76
+ else if (code < 2048) bytes += 2;
77
+ else if (code >= 55296 && code <= 56319) {
78
+ bytes += 4;
79
+ i++;
80
+ } else bytes += 3;
81
+ }
82
+ return bytes;
83
+ }
84
+ function extractApiKeyFormat(rawValue) {
85
+ if (!rawValue) return void 0;
86
+ let value = rawValue.trim();
87
+ const spaceIdx = value.indexOf(" ");
88
+ if (spaceIdx > 0) {
89
+ const scheme = value.slice(0, spaceIdx).toLowerCase();
90
+ if (scheme === "bearer" || scheme === "basic" || scheme === "token") {
91
+ value = value.slice(spaceIdx + 1).trim();
92
+ }
93
+ }
94
+ const lower = value.toLowerCase();
95
+ for (const prefix of KEY_FORMAT_PREFIXES) {
96
+ if (lower.startsWith(prefix)) {
97
+ return prefix;
98
+ }
99
+ }
100
+ return void 0;
101
+ }
102
+ function isSecretHeader(name) {
103
+ if (SECRET_HEADER_NAMES.has(name)) return true;
104
+ if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;
105
+ if (isSignatureHeader(name)) return true;
106
+ return false;
107
+ }
108
+ function isPlatformHeader(name) {
109
+ if (PLATFORM_HEADER_NAMES.has(name)) return true;
110
+ return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));
111
+ }
112
+ function sanitizeHeaders(raw) {
113
+ const headers = {};
114
+ const platformHeaders = {};
115
+ let apiKeyFormat;
116
+ let cookieCount;
117
+ let totalBytes = 0;
118
+ let count = 0;
119
+ if (!raw) return { headers };
120
+ for (const rawName of Object.keys(raw)) {
121
+ if (count >= MAX_HEADERS) break;
122
+ const name = rawName.toLowerCase();
123
+ const rawValue = raw[rawName];
124
+ if (rawValue === void 0) continue;
125
+ const joined = Array.isArray(rawValue) ? rawValue.join(", ") : String(rawValue);
126
+ if (CREDENTIAL_HEADER_NAMES.has(name)) {
127
+ const fmt = extractApiKeyFormat(joined);
128
+ if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
129
+ continue;
130
+ }
131
+ if (name === "cookie") {
132
+ cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
133
+ }
134
+ if (isSecretHeader(name)) continue;
135
+ let value = joined;
136
+ if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
137
+ value = value.slice(0, MAX_HEADER_VALUE_BYTES);
138
+ }
139
+ const entryBytes = byteLength(name) + byteLength(value);
140
+ if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;
141
+ totalBytes += entryBytes;
142
+ count++;
143
+ headers[name] = value;
144
+ if (isPlatformHeader(name)) platformHeaders[name] = value;
145
+ }
146
+ const result = { headers };
147
+ if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
148
+ if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
149
+ if (cookieCount !== void 0) result.cookieCount = cookieCount;
150
+ return result;
151
+ }
152
+ var CONNECTION_HEADER_SOURCES = [
153
+ ["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
154
+ [
155
+ "country",
156
+ ["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
157
+ ],
158
+ ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
159
+ ["countryRegionName", ["cloudfront-viewer-country-region-name"]],
160
+ ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
161
+ ["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
162
+ ["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
163
+ ["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
164
+ ["asn", ["cloudfront-viewer-asn"]],
165
+ ["tlsVersion", ["cloudfront-viewer-tls"]],
166
+ ["httpVersion", ["cloudfront-viewer-http-version"]],
167
+ ["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
168
+ ["metroCode", ["cloudfront-viewer-metro-code"]],
169
+ // TLS fingerprints can only be computed where TLS terminates. When a CDN
170
+ // terminates TLS in front of the merchant, its fingerprint headers ARE the
171
+ // connection-layer truth — normalising them here is the permanent design.
172
+ // CloudFront delivers JA3/JA4 only via an origin request policy and only
173
+ // for HTTPS viewer connections.
174
+ ["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
175
+ ["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
176
+ // Header-structure fingerprint: browser/SDK-distinctive header ordering.
177
+ ["headerOrder", ["cloudfront-viewer-header-order"]],
178
+ ["headerCount", ["cloudfront-viewer-header-count"]]
179
+ ];
180
+ var MAX_CONNECTION_VALUE_CHARS = 256;
181
+ function deriveConnectionFromHeaders(headers) {
182
+ if (!headers) return void 0;
183
+ const lower = {};
184
+ for (const name of Object.keys(headers)) {
185
+ const value = headers[name];
186
+ if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
187
+ }
188
+ const connection = {};
189
+ for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
190
+ for (const source of sources) {
191
+ const value = lower[source]?.trim();
192
+ if (value) {
193
+ connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
194
+ break;
195
+ }
196
+ }
197
+ }
198
+ {
199
+ const addr = lower["cloudfront-viewer-address"]?.trim();
200
+ const portMatch = addr?.match(/:(\d+)$/);
201
+ if (portMatch) connection.sourcePort = portMatch[1];
202
+ if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
203
+ }
204
+ if (!connection.ip) {
205
+ const xff = lower["x-forwarded-for"];
206
+ const client = xff?.split(",")[0]?.trim();
207
+ if (client) connection.ip = client;
208
+ }
209
+ if (!connection.tlsCipher) {
210
+ const cipher = connection.tlsVersion?.split(":")[1];
211
+ if (cipher) connection.tlsCipher = cipher;
212
+ }
213
+ return Object.keys(connection).length > 0 ? connection : void 0;
214
+ }
215
+ function buildSdkObservedMetadata(rawHeaders) {
216
+ const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
217
+ const flat = {};
218
+ if (rawHeaders) {
219
+ for (const name of Object.keys(rawHeaders)) {
220
+ const value = rawHeaders[name];
221
+ if (value === void 0) continue;
222
+ flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
223
+ }
224
+ }
225
+ const connection = deriveConnectionFromHeaders(flat);
226
+ return {
227
+ headers,
228
+ ...apiKeyFormat && { apiKeyFormat },
229
+ ...platformHeaders && { platformHeaders },
230
+ ...connection && { connection },
231
+ ...cookieCount !== void 0 && { cookieCount },
232
+ schemaVersion: CAPTURE_SCHEMA_VERSION
233
+ };
234
+ }
235
+
236
+ // src/edge-core/request.ts
237
+ function headerValue(req, name) {
238
+ return req.headers[name.toLowerCase()];
239
+ }
240
+ function requestUrl(req, host) {
241
+ const qs = req.querystring ? `?${req.querystring}` : "";
242
+ return `https://${host}${req.uri}${qs}`;
243
+ }
244
+
245
+ // src/edge-core/detect.ts
246
+ var SD_JWT_PATTERN = /^eyJ[\w-]+\.[\w-]*\.[\w-]+~/;
247
+ function decodeBase64Url(seg) {
248
+ const b64 = seg.replace(/-/g, "+").replace(/_/g, "/");
249
+ const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
250
+ const binary = atob(padded);
251
+ const bytes = new Uint8Array(binary.length);
252
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
253
+ return new TextDecoder().decode(bytes);
254
+ }
255
+ function sniffJwtHeader(compact) {
256
+ try {
257
+ const seg = compact.split(".")[0];
258
+ return JSON.parse(decodeBase64Url(seg));
259
+ } catch {
260
+ return void 0;
261
+ }
262
+ }
263
+ function parseJsonBody(bodyText) {
264
+ if (!bodyText) return void 0;
265
+ try {
266
+ const parsed = JSON.parse(bodyText);
267
+ return typeof parsed === "object" && parsed !== null ? parsed : void 0;
268
+ } catch {
269
+ return void 0;
270
+ }
271
+ }
272
+ function detectCommerce(req, host) {
273
+ const url = requestUrl(req, host);
274
+ const method = req.method;
275
+ const headers = req.headers;
276
+ const jsonBody = parseJsonBody(req.bodyText);
277
+ const truncated = req.bodyTruncated ? { bodyTruncated: true } : {};
278
+ const authHeader = headerValue(req, "authorization");
279
+ const bearer = authHeader?.replace(/^Bearer\s+/i, "");
280
+ const mandateHeader = headerValue(req, "x-payment-mandate") ?? headerValue(req, "payment-mandate");
281
+ const sdJwtCandidate = [mandateHeader, bearer].find((v) => v && SD_JWT_PATTERN.test(v));
282
+ if (sdJwtCandidate) {
283
+ const typ = sniffJwtHeader(sdJwtCandidate)?.typ;
284
+ return {
285
+ protocol: "vi-sd-jwt",
286
+ artifacts: { viSdJwt: sdJwtCandidate },
287
+ evidence: { typ, ...truncated }
288
+ };
289
+ }
290
+ const signature = headerValue(req, "signature");
291
+ const signatureInput = headerValue(req, "signature-input");
292
+ if (signature && signatureInput) {
293
+ const signatureAgent = headerValue(req, "signature-agent");
294
+ const registryHint = headerValue(req, "x-agent-registry");
295
+ const lowerInput = signatureInput.toLowerCase();
296
+ const protocol = signatureAgent ? "rfc9421-web-bot-auth" : registryHint?.toLowerCase().includes("visa") || lowerInput.includes("visa") ? "rfc9421-tap" : registryHint?.toLowerCase().includes("mastercard") || lowerInput.includes("mastercard") ? "rfc9421-agent-pay" : "rfc9421";
297
+ return {
298
+ protocol,
299
+ artifacts: {
300
+ rfc9421: { headers, method, url, ...req.bodyText && { body: req.bodyText } }
301
+ },
302
+ evidence: {
303
+ ...signatureAgent && { signatureAgent },
304
+ ...registryHint && { registryHint },
305
+ keyid: signatureInput.match(/keyid="([^"]+)"/)?.[1],
306
+ ...truncated
307
+ }
308
+ };
309
+ }
310
+ const acpTimestamp = headerValue(req, "timestamp");
311
+ if (signature && !signatureInput && (acpTimestamp || headerValue(req, "idempotency-key"))) {
312
+ return {
313
+ protocol: "acp",
314
+ artifacts: {
315
+ acpRequest: {
316
+ method,
317
+ url,
318
+ headers,
319
+ ...req.bodyText && { rawBody: req.bodyText },
320
+ ...jsonBody && { body: jsonBody }
321
+ }
322
+ },
323
+ evidence: { hasTimestamp: Boolean(acpTimestamp), ...truncated }
324
+ };
325
+ }
326
+ if (/\/checkout[-_]sessions(\/|$)/.test(req.uri)) {
327
+ return {
328
+ protocol: "ucp",
329
+ artifacts: { ucpRequest: { method, url, ...jsonBody && { body: jsonBody } } },
330
+ evidence: { path: req.uri, ...truncated }
331
+ };
332
+ }
333
+ if (jsonBody) {
334
+ const intent = jsonBody.intent_mandate ?? jsonBody.intentMandate;
335
+ const cart = jsonBody.cart_mandate ?? jsonBody.cartMandate;
336
+ const payment = jsonBody.payment_mandate ?? jsonBody.paymentMandate;
337
+ if (typeof intent === "string" || typeof cart === "string" || typeof payment === "string") {
338
+ return {
339
+ protocol: "ap2",
340
+ artifacts: {
341
+ ap2Mandates: {
342
+ ...typeof intent === "string" && { intent },
343
+ ...typeof cart === "string" && { cart },
344
+ ...typeof payment === "string" && { payment }
345
+ }
346
+ },
347
+ evidence: {
348
+ mandatesPresent: [
349
+ typeof intent === "string" && "intent",
350
+ typeof cart === "string" && "cart",
351
+ typeof payment === "string" && "payment"
352
+ ].filter(Boolean),
353
+ ...truncated
354
+ }
355
+ };
356
+ }
357
+ }
358
+ if (authHeader && /^Payment\s+/i.test(authHeader) || headerValue(req, "payment-authorization")) {
359
+ return {
360
+ protocol: "mpp",
361
+ artifacts: {
362
+ mppRequest: {
363
+ method,
364
+ url,
365
+ headers,
366
+ ...req.bodyText && { rawBody: req.bodyText },
367
+ ...jsonBody && { body: jsonBody }
368
+ }
369
+ },
370
+ evidence: truncated
371
+ };
372
+ }
373
+ if (headerValue(req, "payment-signature") || headerValue(req, "x-payment")) {
374
+ return {
375
+ protocol: "x402",
376
+ artifacts: {
377
+ x402Request: { method, url, headers, ...jsonBody && { body: jsonBody } }
378
+ },
379
+ evidence: truncated
380
+ };
381
+ }
382
+ return void 0;
383
+ }
384
+
385
+ // src/adapters/commerce-detect.ts
386
+ var MAX_BODY_BYTES = 64 * 1024;
387
+ function detect(req, host) {
388
+ try {
389
+ return detectCommerce(req, host)?.artifacts;
390
+ } catch {
391
+ return void 0;
392
+ }
393
+ }
394
+ async function detectFetchCommerce(request) {
395
+ const url = new URL(request.url);
396
+ const headers = {};
397
+ request.headers.forEach((v, k) => headers[k.toLowerCase()] = v);
398
+ let bodyText;
399
+ const length = Number(headers["content-length"] ?? 0);
400
+ if (request.method !== "GET" && request.method !== "HEAD" && length <= MAX_BODY_BYTES) {
401
+ bodyText = await request.clone().text().catch(() => void 0);
402
+ }
403
+ return detect(
404
+ {
405
+ method: request.method,
406
+ uri: url.pathname,
407
+ querystring: url.search.replace(/^\?/, ""),
408
+ headers,
409
+ ...bodyText ? { bodyText } : {}
410
+ },
411
+ headers["x-forwarded-host"] ?? url.host
412
+ );
413
+ }
414
+
1
415
  // src/version.ts
2
- var SDK_VERSION = "5.14.0";
416
+ var SDK_VERSION = "5.15.0";
3
417
 
4
418
  // src/http.ts
5
419
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -463,6 +877,7 @@ async function callVerifyAccessAPI(config, request) {
463
877
  if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
464
878
  if (requestData.commercePhase) body.commercePhase = requestData.commercePhase;
465
879
  if (requestData.checkoutSessionId) body.checkoutSessionId = requestData.checkoutSessionId;
880
+ if (requestData.checkoutJwt) body.checkoutJwt = requestData.checkoutJwt;
466
881
  if (requestData.checkoutItems) body.checkoutItems = requestData.checkoutItems;
467
882
  if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
468
883
  if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
@@ -613,7 +1028,8 @@ async function verify(config, request, options) {
613
1028
  "[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access decisions (verified ID + runtime challenge + PDLSS + trust score). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side."
614
1029
  );
615
1030
  }
616
- if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache) {
1031
+ const uncacheable = Boolean(request.commerceArtifacts);
1032
+ if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
617
1033
  const cached = getCachedResult(request, mergedConfig.counterpartyId);
618
1034
  if (cached) {
619
1035
  if (mergedConfig.debug) {
@@ -694,7 +1110,10 @@ async function verify(config, request, options) {
694
1110
  // MERCHANT caller only (bridge callers strip it before the agent plane).
695
1111
  settlementToken: apiResponse.settlementToken,
696
1112
  // 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
697
- fulfilment: apiResponse.fulfilment
1113
+ fulfilment: apiResponse.fulfilment,
1114
+ mandates: apiResponse.mandates,
1115
+ kyaToken: apiResponse.kyaToken,
1116
+ aep: apiResponse.aep
698
1117
  };
699
1118
  return result2;
700
1119
  }
@@ -704,7 +1123,10 @@ async function verify(config, request, options) {
704
1123
  trustScore: apiResponse.agent.trustScore,
705
1124
  trustLevel: getTrustLevel(apiResponse.agent.trustScore),
706
1125
  blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
707
- status: apiResponse.agent.agentStatus
1126
+ status: apiResponse.agent.agentStatus,
1127
+ ...apiResponse.agent.protocolIdentities && {
1128
+ protocolIdentities: apiResponse.agent.protocolIdentities
1129
+ }
708
1130
  } : void 0;
709
1131
  const developer = apiResponse.developer ? {
710
1132
  astradId: apiResponse.developer.kyaOwnerId,
@@ -755,7 +1177,11 @@ async function verify(config, request, options) {
755
1177
  settlementOutcome: apiResponse.settlementOutcome,
756
1178
  settlementToken: apiResponse.settlementToken,
757
1179
  // 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
758
- fulfilment: apiResponse.fulfilment
1180
+ fulfilment: apiResponse.fulfilment,
1181
+ // 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
1182
+ mandates: apiResponse.mandates,
1183
+ kyaToken: apiResponse.kyaToken,
1184
+ aep: apiResponse.aep
759
1185
  };
760
1186
  if (result.recommendation === "deny") {
761
1187
  result.policyAllowed = false;
@@ -775,7 +1201,9 @@ async function verify(config, request, options) {
775
1201
  }
776
1202
  const escalates = result.requiresStepUp === true || result.requiresApproval === true || result.recommendation === "step_up_required";
777
1203
  if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny" && !escalates) {
778
- cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
1204
+ if (!uncacheable) {
1205
+ cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
1206
+ }
779
1207
  }
780
1208
  return result;
781
1209
  }
@@ -929,239 +1357,30 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
929
1357
  return failures;
930
1358
  }
931
1359
 
932
- // src/metadata-capture.ts
933
- var CAPTURE_SCHEMA_VERSION = 1;
934
- var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
935
- "cookie",
936
- "set-cookie",
937
- "x-csrf-token",
938
- "proxy-authorization",
939
- "x-astrasync-signature",
940
- "x-astrasync-secret",
941
- "x-hub-signature",
942
- "x-hub-signature-256",
943
- // Short-lived verify dedupe token — must never persist in stored metadata.
944
- "x-astra-verified-hop"
945
- ]);
946
- var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
947
- var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
948
- "authorization",
949
- "x-api-key",
950
- "x-goog-api-key",
951
- "api-key"
952
- ]);
953
- function isSignatureHeader(name) {
954
- return name === "signature" || name.endsWith("-signature") || name.endsWith("-signature-256");
955
- }
956
- var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
957
- "openai-organization",
958
- "openai-project",
959
- "openai-version",
960
- "openai-processing-ms",
961
- "anthropic-version",
962
- "anthropic-beta",
963
- "x-goog-user-project",
964
- "x-goog-api-client",
965
- "user-agent",
966
- "x-agent-card-url",
967
- "x-agent-provider"
968
- ]);
969
- var PLATFORM_HEADER_PREFIXES = [
970
- "x-goog-",
971
- "x-stainless-",
972
- "x-anthropic-",
973
- "x-openai-",
974
- "sec-ch-"
975
- ];
976
- var KEY_FORMAT_PREFIXES = [
977
- "sk-ant-api03",
978
- "sk-ant-api",
979
- "sk-ant",
980
- "sk-proj",
981
- "sk-svcacct",
982
- "sk-or-v1",
983
- "sk-or",
984
- "sk-lf",
985
- "sk-",
986
- "gsk_",
987
- "aiza",
988
- "ya29",
989
- "ghp_",
990
- "gho_",
991
- "github_pat_",
992
- "xai-",
993
- "pplx-",
994
- "r8_",
995
- "hf_",
996
- "astra-",
997
- "astrae-"
998
- ];
999
- var MAX_HEADERS = 64;
1000
- var MAX_HEADER_VALUE_BYTES = 1024;
1001
- var MAX_TOTAL_BYTES = 16 * 1024;
1002
- function byteLength(s) {
1003
- let bytes = 0;
1004
- for (let i = 0; i < s.length; i++) {
1005
- const code = s.charCodeAt(i);
1006
- if (code < 128) bytes += 1;
1007
- else if (code < 2048) bytes += 2;
1008
- else if (code >= 55296 && code <= 56319) {
1009
- bytes += 4;
1010
- i++;
1011
- } else bytes += 3;
1012
- }
1013
- return bytes;
1014
- }
1015
- function extractApiKeyFormat(rawValue) {
1016
- if (!rawValue) return void 0;
1017
- let value = rawValue.trim();
1018
- const spaceIdx = value.indexOf(" ");
1019
- if (spaceIdx > 0) {
1020
- const scheme = value.slice(0, spaceIdx).toLowerCase();
1021
- if (scheme === "bearer" || scheme === "basic" || scheme === "token") {
1022
- value = value.slice(spaceIdx + 1).trim();
1023
- }
1024
- }
1025
- const lower = value.toLowerCase();
1026
- for (const prefix of KEY_FORMAT_PREFIXES) {
1027
- if (lower.startsWith(prefix)) {
1028
- return prefix;
1029
- }
1030
- }
1031
- return void 0;
1032
- }
1033
- function isSecretHeader(name) {
1034
- if (SECRET_HEADER_NAMES.has(name)) return true;
1035
- if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;
1036
- if (isSignatureHeader(name)) return true;
1037
- return false;
1038
- }
1039
- function isPlatformHeader(name) {
1040
- if (PLATFORM_HEADER_NAMES.has(name)) return true;
1041
- return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));
1042
- }
1043
- function sanitizeHeaders(raw) {
1044
- const headers = {};
1045
- const platformHeaders = {};
1046
- let apiKeyFormat;
1047
- let cookieCount;
1048
- let totalBytes = 0;
1049
- let count = 0;
1050
- if (!raw) return { headers };
1051
- for (const rawName of Object.keys(raw)) {
1052
- if (count >= MAX_HEADERS) break;
1053
- const name = rawName.toLowerCase();
1054
- const rawValue = raw[rawName];
1055
- if (rawValue === void 0) continue;
1056
- const joined = Array.isArray(rawValue) ? rawValue.join(", ") : String(rawValue);
1057
- if (CREDENTIAL_HEADER_NAMES.has(name)) {
1058
- const fmt = extractApiKeyFormat(joined);
1059
- if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
1060
- continue;
1061
- }
1062
- if (name === "cookie") {
1063
- cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
1064
- }
1065
- if (isSecretHeader(name)) continue;
1066
- let value = joined;
1067
- if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
1068
- value = value.slice(0, MAX_HEADER_VALUE_BYTES);
1069
- }
1070
- const entryBytes = byteLength(name) + byteLength(value);
1071
- if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;
1072
- totalBytes += entryBytes;
1073
- count++;
1074
- headers[name] = value;
1075
- if (isPlatformHeader(name)) platformHeaders[name] = value;
1076
- }
1077
- const result = { headers };
1078
- if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
1079
- if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
1080
- if (cookieCount !== void 0) result.cookieCount = cookieCount;
1081
- return result;
1082
- }
1083
- var CONNECTION_HEADER_SOURCES = [
1084
- ["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
1085
- [
1086
- "country",
1087
- ["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
1088
- ],
1089
- ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
1090
- ["countryRegionName", ["cloudfront-viewer-country-region-name"]],
1091
- ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
1092
- ["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
1093
- ["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
1094
- ["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
1095
- ["asn", ["cloudfront-viewer-asn"]],
1096
- ["tlsVersion", ["cloudfront-viewer-tls"]],
1097
- ["httpVersion", ["cloudfront-viewer-http-version"]],
1098
- ["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
1099
- ["metroCode", ["cloudfront-viewer-metro-code"]],
1100
- // TLS fingerprints can only be computed where TLS terminates. When a CDN
1101
- // terminates TLS in front of the merchant, its fingerprint headers ARE the
1102
- // connection-layer truth — normalising them here is the permanent design.
1103
- // CloudFront delivers JA3/JA4 only via an origin request policy and only
1104
- // for HTTPS viewer connections.
1105
- ["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
1106
- ["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
1107
- // Header-structure fingerprint: browser/SDK-distinctive header ordering.
1108
- ["headerOrder", ["cloudfront-viewer-header-order"]],
1109
- ["headerCount", ["cloudfront-viewer-header-count"]]
1110
- ];
1111
- var MAX_CONNECTION_VALUE_CHARS = 256;
1112
- function deriveConnectionFromHeaders(headers) {
1113
- if (!headers) return void 0;
1114
- const lower = {};
1115
- for (const name of Object.keys(headers)) {
1116
- const value = headers[name];
1117
- if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
1118
- }
1119
- const connection = {};
1120
- for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
1121
- for (const source of sources) {
1122
- const value = lower[source]?.trim();
1123
- if (value) {
1124
- connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
1125
- break;
1126
- }
1360
+ // src/route-pattern.ts
1361
+ function routePatternToRegExp(pattern, opts = {}) {
1362
+ let source = "";
1363
+ for (let i = 0; i < pattern.length; i++) {
1364
+ const ch = pattern[i];
1365
+ if (ch === "*") {
1366
+ source += ".*";
1367
+ } else if (ch === ":" && /[A-Za-z_]/.test(pattern[i + 1] ?? "") && (i === 0 || pattern[i - 1] === "/")) {
1368
+ let j = i + 1;
1369
+ while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) j++;
1370
+ source += "[^/]+";
1371
+ i = j - 1;
1372
+ } else {
1373
+ source += ch.replace(/[.+?^${}()|[\]\\/]/g, "\\$&");
1127
1374
  }
1128
1375
  }
1129
- {
1130
- const addr = lower["cloudfront-viewer-address"]?.trim();
1131
- const portMatch = addr?.match(/:(\d+)$/);
1132
- if (portMatch) connection.sourcePort = portMatch[1];
1133
- if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
1134
- }
1135
- if (!connection.ip) {
1136
- const xff = lower["x-forwarded-for"];
1137
- const client = xff?.split(",")[0]?.trim();
1138
- if (client) connection.ip = client;
1139
- }
1140
- if (!connection.tlsCipher) {
1141
- const cipher = connection.tlsVersion?.split(":")[1];
1142
- if (cipher) connection.tlsCipher = cipher;
1376
+ try {
1377
+ return new RegExp(`^${source}$`, opts.caseInsensitive ? "i" : "");
1378
+ } catch {
1379
+ return null;
1143
1380
  }
1144
- return Object.keys(connection).length > 0 ? connection : void 0;
1145
1381
  }
1146
- function buildSdkObservedMetadata(rawHeaders) {
1147
- const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
1148
- const flat = {};
1149
- if (rawHeaders) {
1150
- for (const name of Object.keys(rawHeaders)) {
1151
- const value = rawHeaders[name];
1152
- if (value === void 0) continue;
1153
- flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
1154
- }
1155
- }
1156
- const connection = deriveConnectionFromHeaders(flat);
1157
- return {
1158
- headers,
1159
- ...apiKeyFormat && { apiKeyFormat },
1160
- ...platformHeaders && { platformHeaders },
1161
- ...connection && { connection },
1162
- ...cookieCount !== void 0 && { cookieCount },
1163
- schemaVersion: CAPTURE_SCHEMA_VERSION
1164
- };
1382
+ function matchRoutePattern(pattern, path, opts = {}) {
1383
+ return routePatternToRegExp(pattern, opts)?.test(path) ?? false;
1165
1384
  }
1166
1385
 
1167
1386
  // src/edge-config.ts
@@ -1196,6 +1415,7 @@ function isEdgeConfig(value) {
1196
1415
  if (r.sampling !== void 0 && !isSamplingShape(r.sampling)) return false;
1197
1416
  }
1198
1417
  if (!isSamplingShape(v.sampling)) return false;
1418
+ if (v.minTls !== void 0 && v.minTls !== "1.2" && v.minTls !== "1.3") return false;
1199
1419
  if (v.queryValueAllowlist !== void 0) {
1200
1420
  if (!Array.isArray(v.queryValueAllowlist) || v.queryValueAllowlist.length > 16 || !v.queryValueAllowlist.every((e) => typeof e === "string" && e.length > 0 && e.length <= 64)) {
1201
1421
  return false;
@@ -1911,9 +2131,7 @@ function extractCredentialsFromNextRequest(request) {
1911
2131
  return credentials;
1912
2132
  }
1913
2133
  function matchRoute(pattern, path) {
1914
- const regexPattern = pattern.replace(/\*/g, ".*").replace(/\//g, "\\/");
1915
- const regex = new RegExp(`^${regexPattern}$`);
1916
- return regex.test(path);
2134
+ return matchRoutePattern(pattern, path);
1917
2135
  }
1918
2136
  function findRouteConfig(routes, path, method) {
1919
2137
  return routes.find((route) => {
@@ -2104,7 +2322,8 @@ function createMiddleware(options) {
2104
2322
  skipPaths = [],
2105
2323
  showInterstitial,
2106
2324
  showCommerceShield,
2107
- enableRuntimeChallenge = true,
2325
+ // Round 27.8: opt-in only (the merchant turns it on); was default-on.
2326
+ enableRuntimeChallenge = false,
2108
2327
  routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
2109
2328
  anonymousBeacon = true,
2110
2329
  trustVerifiedHop = false,
@@ -2241,8 +2460,10 @@ function createMiddleware(options) {
2241
2460
  const originalClientIp = forwardedFor?.split(",")[0]?.trim();
2242
2461
  const attemptHeader = request.headers.get("x-astra-attempt-id");
2243
2462
  const inboundAttemptId = attemptHeader && /^att_[0-9a-f]{32}$/.test(attemptHeader) ? attemptHeader : void 0;
2463
+ const commerceArtifacts = await detectFetchCommerce(request);
2244
2464
  const verificationRequest = {
2245
2465
  credentials,
2466
+ ...commerceArtifacts && { commerceArtifacts },
2246
2467
  purpose,
2247
2468
  action: pdlssPair.action,
2248
2469
  resource: pathname,