@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
@@ -25,8 +25,440 @@ __export(express_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(express_exports);
27
27
 
28
+ // src/metadata-capture.ts
29
+ var CAPTURE_SCHEMA_VERSION = 1;
30
+ var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
31
+ "cookie",
32
+ "set-cookie",
33
+ "x-csrf-token",
34
+ "proxy-authorization",
35
+ "x-astrasync-signature",
36
+ "x-astrasync-secret",
37
+ "x-hub-signature",
38
+ "x-hub-signature-256",
39
+ // Short-lived verify dedupe token — must never persist in stored metadata.
40
+ "x-astra-verified-hop"
41
+ ]);
42
+ var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
43
+ var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
44
+ "authorization",
45
+ "x-api-key",
46
+ "x-goog-api-key",
47
+ "api-key"
48
+ ]);
49
+ function isSignatureHeader(name) {
50
+ return name === "signature" || name.endsWith("-signature") || name.endsWith("-signature-256");
51
+ }
52
+ var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
53
+ "openai-organization",
54
+ "openai-project",
55
+ "openai-version",
56
+ "openai-processing-ms",
57
+ "anthropic-version",
58
+ "anthropic-beta",
59
+ "x-goog-user-project",
60
+ "x-goog-api-client",
61
+ "user-agent",
62
+ "x-agent-card-url",
63
+ "x-agent-provider"
64
+ ]);
65
+ var PLATFORM_HEADER_PREFIXES = [
66
+ "x-goog-",
67
+ "x-stainless-",
68
+ "x-anthropic-",
69
+ "x-openai-",
70
+ "sec-ch-"
71
+ ];
72
+ var KEY_FORMAT_PREFIXES = [
73
+ "sk-ant-api03",
74
+ "sk-ant-api",
75
+ "sk-ant",
76
+ "sk-proj",
77
+ "sk-svcacct",
78
+ "sk-or-v1",
79
+ "sk-or",
80
+ "sk-lf",
81
+ "sk-",
82
+ "gsk_",
83
+ "aiza",
84
+ "ya29",
85
+ "ghp_",
86
+ "gho_",
87
+ "github_pat_",
88
+ "xai-",
89
+ "pplx-",
90
+ "r8_",
91
+ "hf_",
92
+ "astra-",
93
+ "astrae-"
94
+ ];
95
+ var MAX_HEADERS = 64;
96
+ var MAX_HEADER_VALUE_BYTES = 1024;
97
+ var MAX_TOTAL_BYTES = 16 * 1024;
98
+ function byteLength(s) {
99
+ let bytes = 0;
100
+ for (let i = 0; i < s.length; i++) {
101
+ const code = s.charCodeAt(i);
102
+ if (code < 128) bytes += 1;
103
+ else if (code < 2048) bytes += 2;
104
+ else if (code >= 55296 && code <= 56319) {
105
+ bytes += 4;
106
+ i++;
107
+ } else bytes += 3;
108
+ }
109
+ return bytes;
110
+ }
111
+ function extractApiKeyFormat(rawValue) {
112
+ if (!rawValue) return void 0;
113
+ let value = rawValue.trim();
114
+ const spaceIdx = value.indexOf(" ");
115
+ if (spaceIdx > 0) {
116
+ const scheme = value.slice(0, spaceIdx).toLowerCase();
117
+ if (scheme === "bearer" || scheme === "basic" || scheme === "token") {
118
+ value = value.slice(spaceIdx + 1).trim();
119
+ }
120
+ }
121
+ const lower = value.toLowerCase();
122
+ for (const prefix of KEY_FORMAT_PREFIXES) {
123
+ if (lower.startsWith(prefix)) {
124
+ return prefix;
125
+ }
126
+ }
127
+ return void 0;
128
+ }
129
+ function isSecretHeader(name) {
130
+ if (SECRET_HEADER_NAMES.has(name)) return true;
131
+ if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;
132
+ if (isSignatureHeader(name)) return true;
133
+ return false;
134
+ }
135
+ function isPlatformHeader(name) {
136
+ if (PLATFORM_HEADER_NAMES.has(name)) return true;
137
+ return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));
138
+ }
139
+ function sanitizeHeaders(raw) {
140
+ const headers = {};
141
+ const platformHeaders = {};
142
+ let apiKeyFormat;
143
+ let cookieCount;
144
+ let totalBytes = 0;
145
+ let count = 0;
146
+ if (!raw) return { headers };
147
+ for (const rawName of Object.keys(raw)) {
148
+ if (count >= MAX_HEADERS) break;
149
+ const name = rawName.toLowerCase();
150
+ const rawValue = raw[rawName];
151
+ if (rawValue === void 0) continue;
152
+ const joined = Array.isArray(rawValue) ? rawValue.join(", ") : String(rawValue);
153
+ if (CREDENTIAL_HEADER_NAMES.has(name)) {
154
+ const fmt = extractApiKeyFormat(joined);
155
+ if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
156
+ continue;
157
+ }
158
+ if (name === "cookie") {
159
+ cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
160
+ }
161
+ if (isSecretHeader(name)) continue;
162
+ let value = joined;
163
+ if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
164
+ value = value.slice(0, MAX_HEADER_VALUE_BYTES);
165
+ }
166
+ const entryBytes = byteLength(name) + byteLength(value);
167
+ if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;
168
+ totalBytes += entryBytes;
169
+ count++;
170
+ headers[name] = value;
171
+ if (isPlatformHeader(name)) platformHeaders[name] = value;
172
+ }
173
+ const result = { headers };
174
+ if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
175
+ if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
176
+ if (cookieCount !== void 0) result.cookieCount = cookieCount;
177
+ return result;
178
+ }
179
+ var CONNECTION_HEADER_SOURCES = [
180
+ ["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
181
+ [
182
+ "country",
183
+ ["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
184
+ ],
185
+ ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
186
+ ["countryRegionName", ["cloudfront-viewer-country-region-name"]],
187
+ ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
188
+ ["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
189
+ ["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
190
+ ["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
191
+ ["asn", ["cloudfront-viewer-asn"]],
192
+ ["tlsVersion", ["cloudfront-viewer-tls"]],
193
+ ["httpVersion", ["cloudfront-viewer-http-version"]],
194
+ ["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
195
+ ["metroCode", ["cloudfront-viewer-metro-code"]],
196
+ // TLS fingerprints can only be computed where TLS terminates. When a CDN
197
+ // terminates TLS in front of the merchant, its fingerprint headers ARE the
198
+ // connection-layer truth — normalising them here is the permanent design.
199
+ // CloudFront delivers JA3/JA4 only via an origin request policy and only
200
+ // for HTTPS viewer connections.
201
+ ["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
202
+ ["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
203
+ // Header-structure fingerprint: browser/SDK-distinctive header ordering.
204
+ ["headerOrder", ["cloudfront-viewer-header-order"]],
205
+ ["headerCount", ["cloudfront-viewer-header-count"]]
206
+ ];
207
+ var MAX_CONNECTION_VALUE_CHARS = 256;
208
+ function deriveConnectionFromHeaders(headers) {
209
+ if (!headers) return void 0;
210
+ const lower = {};
211
+ for (const name of Object.keys(headers)) {
212
+ const value = headers[name];
213
+ if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
214
+ }
215
+ const connection = {};
216
+ for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
217
+ for (const source of sources) {
218
+ const value = lower[source]?.trim();
219
+ if (value) {
220
+ connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
221
+ break;
222
+ }
223
+ }
224
+ }
225
+ {
226
+ const addr = lower["cloudfront-viewer-address"]?.trim();
227
+ const portMatch = addr?.match(/:(\d+)$/);
228
+ if (portMatch) connection.sourcePort = portMatch[1];
229
+ if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
230
+ }
231
+ if (!connection.ip) {
232
+ const xff = lower["x-forwarded-for"];
233
+ const client = xff?.split(",")[0]?.trim();
234
+ if (client) connection.ip = client;
235
+ }
236
+ if (!connection.tlsCipher) {
237
+ const cipher = connection.tlsVersion?.split(":")[1];
238
+ if (cipher) connection.tlsCipher = cipher;
239
+ }
240
+ return Object.keys(connection).length > 0 ? connection : void 0;
241
+ }
242
+ function buildSdkObservedMetadata(rawHeaders) {
243
+ const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
244
+ const flat = {};
245
+ if (rawHeaders) {
246
+ for (const name of Object.keys(rawHeaders)) {
247
+ const value = rawHeaders[name];
248
+ if (value === void 0) continue;
249
+ flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
250
+ }
251
+ }
252
+ const connection = deriveConnectionFromHeaders(flat);
253
+ return {
254
+ headers,
255
+ ...apiKeyFormat && { apiKeyFormat },
256
+ ...platformHeaders && { platformHeaders },
257
+ ...connection && { connection },
258
+ ...cookieCount !== void 0 && { cookieCount },
259
+ schemaVersion: CAPTURE_SCHEMA_VERSION
260
+ };
261
+ }
262
+
263
+ // src/edge-core/request.ts
264
+ function headerValue(req, name) {
265
+ return req.headers[name.toLowerCase()];
266
+ }
267
+ function requestUrl(req, host) {
268
+ const qs = req.querystring ? `?${req.querystring}` : "";
269
+ return `https://${host}${req.uri}${qs}`;
270
+ }
271
+
272
+ // src/edge-core/detect.ts
273
+ var SD_JWT_PATTERN = /^eyJ[\w-]+\.[\w-]*\.[\w-]+~/;
274
+ function decodeBase64Url(seg) {
275
+ const b64 = seg.replace(/-/g, "+").replace(/_/g, "/");
276
+ const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
277
+ const binary = atob(padded);
278
+ const bytes = new Uint8Array(binary.length);
279
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
280
+ return new TextDecoder().decode(bytes);
281
+ }
282
+ function sniffJwtHeader(compact) {
283
+ try {
284
+ const seg = compact.split(".")[0];
285
+ return JSON.parse(decodeBase64Url(seg));
286
+ } catch {
287
+ return void 0;
288
+ }
289
+ }
290
+ function parseJsonBody(bodyText) {
291
+ if (!bodyText) return void 0;
292
+ try {
293
+ const parsed = JSON.parse(bodyText);
294
+ return typeof parsed === "object" && parsed !== null ? parsed : void 0;
295
+ } catch {
296
+ return void 0;
297
+ }
298
+ }
299
+ function detectCommerce(req, host) {
300
+ const url = requestUrl(req, host);
301
+ const method = req.method;
302
+ const headers = req.headers;
303
+ const jsonBody = parseJsonBody(req.bodyText);
304
+ const truncated = req.bodyTruncated ? { bodyTruncated: true } : {};
305
+ const authHeader = headerValue(req, "authorization");
306
+ const bearer = authHeader?.replace(/^Bearer\s+/i, "");
307
+ const mandateHeader = headerValue(req, "x-payment-mandate") ?? headerValue(req, "payment-mandate");
308
+ const sdJwtCandidate = [mandateHeader, bearer].find((v) => v && SD_JWT_PATTERN.test(v));
309
+ if (sdJwtCandidate) {
310
+ const typ = sniffJwtHeader(sdJwtCandidate)?.typ;
311
+ return {
312
+ protocol: "vi-sd-jwt",
313
+ artifacts: { viSdJwt: sdJwtCandidate },
314
+ evidence: { typ, ...truncated }
315
+ };
316
+ }
317
+ const signature = headerValue(req, "signature");
318
+ const signatureInput = headerValue(req, "signature-input");
319
+ if (signature && signatureInput) {
320
+ const signatureAgent = headerValue(req, "signature-agent");
321
+ const registryHint = headerValue(req, "x-agent-registry");
322
+ const lowerInput = signatureInput.toLowerCase();
323
+ 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";
324
+ return {
325
+ protocol,
326
+ artifacts: {
327
+ rfc9421: { headers, method, url, ...req.bodyText && { body: req.bodyText } }
328
+ },
329
+ evidence: {
330
+ ...signatureAgent && { signatureAgent },
331
+ ...registryHint && { registryHint },
332
+ keyid: signatureInput.match(/keyid="([^"]+)"/)?.[1],
333
+ ...truncated
334
+ }
335
+ };
336
+ }
337
+ const acpTimestamp = headerValue(req, "timestamp");
338
+ if (signature && !signatureInput && (acpTimestamp || headerValue(req, "idempotency-key"))) {
339
+ return {
340
+ protocol: "acp",
341
+ artifacts: {
342
+ acpRequest: {
343
+ method,
344
+ url,
345
+ headers,
346
+ ...req.bodyText && { rawBody: req.bodyText },
347
+ ...jsonBody && { body: jsonBody }
348
+ }
349
+ },
350
+ evidence: { hasTimestamp: Boolean(acpTimestamp), ...truncated }
351
+ };
352
+ }
353
+ if (/\/checkout[-_]sessions(\/|$)/.test(req.uri)) {
354
+ return {
355
+ protocol: "ucp",
356
+ artifacts: { ucpRequest: { method, url, ...jsonBody && { body: jsonBody } } },
357
+ evidence: { path: req.uri, ...truncated }
358
+ };
359
+ }
360
+ if (jsonBody) {
361
+ const intent = jsonBody.intent_mandate ?? jsonBody.intentMandate;
362
+ const cart = jsonBody.cart_mandate ?? jsonBody.cartMandate;
363
+ const payment = jsonBody.payment_mandate ?? jsonBody.paymentMandate;
364
+ if (typeof intent === "string" || typeof cart === "string" || typeof payment === "string") {
365
+ return {
366
+ protocol: "ap2",
367
+ artifacts: {
368
+ ap2Mandates: {
369
+ ...typeof intent === "string" && { intent },
370
+ ...typeof cart === "string" && { cart },
371
+ ...typeof payment === "string" && { payment }
372
+ }
373
+ },
374
+ evidence: {
375
+ mandatesPresent: [
376
+ typeof intent === "string" && "intent",
377
+ typeof cart === "string" && "cart",
378
+ typeof payment === "string" && "payment"
379
+ ].filter(Boolean),
380
+ ...truncated
381
+ }
382
+ };
383
+ }
384
+ }
385
+ if (authHeader && /^Payment\s+/i.test(authHeader) || headerValue(req, "payment-authorization")) {
386
+ return {
387
+ protocol: "mpp",
388
+ artifacts: {
389
+ mppRequest: {
390
+ method,
391
+ url,
392
+ headers,
393
+ ...req.bodyText && { rawBody: req.bodyText },
394
+ ...jsonBody && { body: jsonBody }
395
+ }
396
+ },
397
+ evidence: truncated
398
+ };
399
+ }
400
+ if (headerValue(req, "payment-signature") || headerValue(req, "x-payment")) {
401
+ return {
402
+ protocol: "x402",
403
+ artifacts: {
404
+ x402Request: { method, url, headers, ...jsonBody && { body: jsonBody } }
405
+ },
406
+ evidence: truncated
407
+ };
408
+ }
409
+ return void 0;
410
+ }
411
+
412
+ // src/adapters/commerce-detect.ts
413
+ var MAX_BODY_BYTES = 64 * 1024;
414
+ function lowerHeaders(headers) {
415
+ const out = {};
416
+ if (typeof Headers !== "undefined" && headers instanceof Headers) {
417
+ headers.forEach((v, k) => out[k.toLowerCase()] = v);
418
+ return out;
419
+ }
420
+ for (const [k, v] of Object.entries(headers)) {
421
+ if (v === void 0) continue;
422
+ out[k.toLowerCase()] = Array.isArray(v) ? v.join(", ") : v;
423
+ }
424
+ return out;
425
+ }
426
+ function detect(req, host) {
427
+ try {
428
+ return detectCommerce(req, host)?.artifacts;
429
+ } catch {
430
+ return void 0;
431
+ }
432
+ }
433
+ function detectExpressCommerce(req) {
434
+ const headers = lowerHeaders(req.headers);
435
+ const [uri, query = ""] = (req.originalUrl ?? req.url).split("?");
436
+ let bodyText;
437
+ if (req.rawBody !== void 0) {
438
+ bodyText = typeof req.rawBody === "string" ? req.rawBody : req.rawBody.toString("utf8");
439
+ } else if (typeof req.body === "string") {
440
+ bodyText = req.body;
441
+ } else if (req.body && typeof req.body === "object" && Object.keys(req.body).length > 0) {
442
+ bodyText = JSON.stringify(req.body);
443
+ }
444
+ const truncated = bodyText !== void 0 && bodyText.length > MAX_BODY_BYTES;
445
+ return detect(
446
+ {
447
+ method: req.method,
448
+ uri,
449
+ querystring: query,
450
+ headers,
451
+ ...bodyText !== void 0 && {
452
+ bodyText: truncated ? bodyText.slice(0, MAX_BODY_BYTES) : bodyText,
453
+ bodyTruncated: truncated
454
+ }
455
+ },
456
+ headers["x-forwarded-host"] ?? headers.host ?? "localhost"
457
+ );
458
+ }
459
+
28
460
  // src/version.ts
29
- var SDK_VERSION = "5.14.0";
461
+ var SDK_VERSION = "5.15.0";
30
462
 
31
463
  // src/http.ts
32
464
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -542,6 +974,7 @@ async function callVerifyAccessAPI(config, request) {
542
974
  if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
543
975
  if (requestData.commercePhase) body.commercePhase = requestData.commercePhase;
544
976
  if (requestData.checkoutSessionId) body.checkoutSessionId = requestData.checkoutSessionId;
977
+ if (requestData.checkoutJwt) body.checkoutJwt = requestData.checkoutJwt;
545
978
  if (requestData.checkoutItems) body.checkoutItems = requestData.checkoutItems;
546
979
  if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
547
980
  if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
@@ -692,7 +1125,8 @@ async function verify(config, request, options) {
692
1125
  "[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."
693
1126
  );
694
1127
  }
695
- if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache) {
1128
+ const uncacheable = Boolean(request.commerceArtifacts);
1129
+ if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
696
1130
  const cached = getCachedResult(request, mergedConfig.counterpartyId);
697
1131
  if (cached) {
698
1132
  if (mergedConfig.debug) {
@@ -773,7 +1207,10 @@ async function verify(config, request, options) {
773
1207
  // MERCHANT caller only (bridge callers strip it before the agent plane).
774
1208
  settlementToken: apiResponse.settlementToken,
775
1209
  // 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
776
- fulfilment: apiResponse.fulfilment
1210
+ fulfilment: apiResponse.fulfilment,
1211
+ mandates: apiResponse.mandates,
1212
+ kyaToken: apiResponse.kyaToken,
1213
+ aep: apiResponse.aep
777
1214
  };
778
1215
  return result2;
779
1216
  }
@@ -783,7 +1220,10 @@ async function verify(config, request, options) {
783
1220
  trustScore: apiResponse.agent.trustScore,
784
1221
  trustLevel: getTrustLevel(apiResponse.agent.trustScore),
785
1222
  blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
786
- status: apiResponse.agent.agentStatus
1223
+ status: apiResponse.agent.agentStatus,
1224
+ ...apiResponse.agent.protocolIdentities && {
1225
+ protocolIdentities: apiResponse.agent.protocolIdentities
1226
+ }
787
1227
  } : void 0;
788
1228
  const developer = apiResponse.developer ? {
789
1229
  astradId: apiResponse.developer.kyaOwnerId,
@@ -834,7 +1274,11 @@ async function verify(config, request, options) {
834
1274
  settlementOutcome: apiResponse.settlementOutcome,
835
1275
  settlementToken: apiResponse.settlementToken,
836
1276
  // 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
837
- fulfilment: apiResponse.fulfilment
1277
+ fulfilment: apiResponse.fulfilment,
1278
+ // 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
1279
+ mandates: apiResponse.mandates,
1280
+ kyaToken: apiResponse.kyaToken,
1281
+ aep: apiResponse.aep
838
1282
  };
839
1283
  if (result.recommendation === "deny") {
840
1284
  result.policyAllowed = false;
@@ -854,7 +1298,9 @@ async function verify(config, request, options) {
854
1298
  }
855
1299
  const escalates = result.requiresStepUp === true || result.requiresApproval === true || result.recommendation === "step_up_required";
856
1300
  if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny" && !escalates) {
857
- cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
1301
+ if (!uncacheable) {
1302
+ cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
1303
+ }
858
1304
  }
859
1305
  return result;
860
1306
  }
@@ -1138,239 +1584,30 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
1138
1584
  return failures;
1139
1585
  }
1140
1586
 
1141
- // src/metadata-capture.ts
1142
- var CAPTURE_SCHEMA_VERSION = 1;
1143
- var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
1144
- "cookie",
1145
- "set-cookie",
1146
- "x-csrf-token",
1147
- "proxy-authorization",
1148
- "x-astrasync-signature",
1149
- "x-astrasync-secret",
1150
- "x-hub-signature",
1151
- "x-hub-signature-256",
1152
- // Short-lived verify dedupe token — must never persist in stored metadata.
1153
- "x-astra-verified-hop"
1154
- ]);
1155
- var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
1156
- var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
1157
- "authorization",
1158
- "x-api-key",
1159
- "x-goog-api-key",
1160
- "api-key"
1161
- ]);
1162
- function isSignatureHeader(name) {
1163
- return name === "signature" || name.endsWith("-signature") || name.endsWith("-signature-256");
1164
- }
1165
- var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
1166
- "openai-organization",
1167
- "openai-project",
1168
- "openai-version",
1169
- "openai-processing-ms",
1170
- "anthropic-version",
1171
- "anthropic-beta",
1172
- "x-goog-user-project",
1173
- "x-goog-api-client",
1174
- "user-agent",
1175
- "x-agent-card-url",
1176
- "x-agent-provider"
1177
- ]);
1178
- var PLATFORM_HEADER_PREFIXES = [
1179
- "x-goog-",
1180
- "x-stainless-",
1181
- "x-anthropic-",
1182
- "x-openai-",
1183
- "sec-ch-"
1184
- ];
1185
- var KEY_FORMAT_PREFIXES = [
1186
- "sk-ant-api03",
1187
- "sk-ant-api",
1188
- "sk-ant",
1189
- "sk-proj",
1190
- "sk-svcacct",
1191
- "sk-or-v1",
1192
- "sk-or",
1193
- "sk-lf",
1194
- "sk-",
1195
- "gsk_",
1196
- "aiza",
1197
- "ya29",
1198
- "ghp_",
1199
- "gho_",
1200
- "github_pat_",
1201
- "xai-",
1202
- "pplx-",
1203
- "r8_",
1204
- "hf_",
1205
- "astra-",
1206
- "astrae-"
1207
- ];
1208
- var MAX_HEADERS = 64;
1209
- var MAX_HEADER_VALUE_BYTES = 1024;
1210
- var MAX_TOTAL_BYTES = 16 * 1024;
1211
- function byteLength(s) {
1212
- let bytes = 0;
1213
- for (let i = 0; i < s.length; i++) {
1214
- const code = s.charCodeAt(i);
1215
- if (code < 128) bytes += 1;
1216
- else if (code < 2048) bytes += 2;
1217
- else if (code >= 55296 && code <= 56319) {
1218
- bytes += 4;
1219
- i++;
1220
- } else bytes += 3;
1221
- }
1222
- return bytes;
1223
- }
1224
- function extractApiKeyFormat(rawValue) {
1225
- if (!rawValue) return void 0;
1226
- let value = rawValue.trim();
1227
- const spaceIdx = value.indexOf(" ");
1228
- if (spaceIdx > 0) {
1229
- const scheme = value.slice(0, spaceIdx).toLowerCase();
1230
- if (scheme === "bearer" || scheme === "basic" || scheme === "token") {
1231
- value = value.slice(spaceIdx + 1).trim();
1232
- }
1233
- }
1234
- const lower = value.toLowerCase();
1235
- for (const prefix of KEY_FORMAT_PREFIXES) {
1236
- if (lower.startsWith(prefix)) {
1237
- return prefix;
1238
- }
1239
- }
1240
- return void 0;
1241
- }
1242
- function isSecretHeader(name) {
1243
- if (SECRET_HEADER_NAMES.has(name)) return true;
1244
- if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;
1245
- if (isSignatureHeader(name)) return true;
1246
- return false;
1247
- }
1248
- function isPlatformHeader(name) {
1249
- if (PLATFORM_HEADER_NAMES.has(name)) return true;
1250
- return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));
1251
- }
1252
- function sanitizeHeaders(raw) {
1253
- const headers = {};
1254
- const platformHeaders = {};
1255
- let apiKeyFormat;
1256
- let cookieCount;
1257
- let totalBytes = 0;
1258
- let count = 0;
1259
- if (!raw) return { headers };
1260
- for (const rawName of Object.keys(raw)) {
1261
- if (count >= MAX_HEADERS) break;
1262
- const name = rawName.toLowerCase();
1263
- const rawValue = raw[rawName];
1264
- if (rawValue === void 0) continue;
1265
- const joined = Array.isArray(rawValue) ? rawValue.join(", ") : String(rawValue);
1266
- if (CREDENTIAL_HEADER_NAMES.has(name)) {
1267
- const fmt = extractApiKeyFormat(joined);
1268
- if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
1269
- continue;
1270
- }
1271
- if (name === "cookie") {
1272
- cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
1273
- }
1274
- if (isSecretHeader(name)) continue;
1275
- let value = joined;
1276
- if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
1277
- value = value.slice(0, MAX_HEADER_VALUE_BYTES);
1278
- }
1279
- const entryBytes = byteLength(name) + byteLength(value);
1280
- if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;
1281
- totalBytes += entryBytes;
1282
- count++;
1283
- headers[name] = value;
1284
- if (isPlatformHeader(name)) platformHeaders[name] = value;
1285
- }
1286
- const result = { headers };
1287
- if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
1288
- if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
1289
- if (cookieCount !== void 0) result.cookieCount = cookieCount;
1290
- return result;
1291
- }
1292
- var CONNECTION_HEADER_SOURCES = [
1293
- ["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
1294
- [
1295
- "country",
1296
- ["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
1297
- ],
1298
- ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
1299
- ["countryRegionName", ["cloudfront-viewer-country-region-name"]],
1300
- ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
1301
- ["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
1302
- ["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
1303
- ["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
1304
- ["asn", ["cloudfront-viewer-asn"]],
1305
- ["tlsVersion", ["cloudfront-viewer-tls"]],
1306
- ["httpVersion", ["cloudfront-viewer-http-version"]],
1307
- ["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
1308
- ["metroCode", ["cloudfront-viewer-metro-code"]],
1309
- // TLS fingerprints can only be computed where TLS terminates. When a CDN
1310
- // terminates TLS in front of the merchant, its fingerprint headers ARE the
1311
- // connection-layer truth — normalising them here is the permanent design.
1312
- // CloudFront delivers JA3/JA4 only via an origin request policy and only
1313
- // for HTTPS viewer connections.
1314
- ["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
1315
- ["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
1316
- // Header-structure fingerprint: browser/SDK-distinctive header ordering.
1317
- ["headerOrder", ["cloudfront-viewer-header-order"]],
1318
- ["headerCount", ["cloudfront-viewer-header-count"]]
1319
- ];
1320
- var MAX_CONNECTION_VALUE_CHARS = 256;
1321
- function deriveConnectionFromHeaders(headers) {
1322
- if (!headers) return void 0;
1323
- const lower = {};
1324
- for (const name of Object.keys(headers)) {
1325
- const value = headers[name];
1326
- if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
1327
- }
1328
- const connection = {};
1329
- for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
1330
- for (const source of sources) {
1331
- const value = lower[source]?.trim();
1332
- if (value) {
1333
- connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
1334
- break;
1335
- }
1587
+ // src/route-pattern.ts
1588
+ function routePatternToRegExp(pattern, opts = {}) {
1589
+ let source = "";
1590
+ for (let i = 0; i < pattern.length; i++) {
1591
+ const ch = pattern[i];
1592
+ if (ch === "*") {
1593
+ source += ".*";
1594
+ } else if (ch === ":" && /[A-Za-z_]/.test(pattern[i + 1] ?? "") && (i === 0 || pattern[i - 1] === "/")) {
1595
+ let j = i + 1;
1596
+ while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) j++;
1597
+ source += "[^/]+";
1598
+ i = j - 1;
1599
+ } else {
1600
+ source += ch.replace(/[.+?^${}()|[\]\\/]/g, "\\$&");
1336
1601
  }
1337
1602
  }
1338
- {
1339
- const addr = lower["cloudfront-viewer-address"]?.trim();
1340
- const portMatch = addr?.match(/:(\d+)$/);
1341
- if (portMatch) connection.sourcePort = portMatch[1];
1342
- if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
1343
- }
1344
- if (!connection.ip) {
1345
- const xff = lower["x-forwarded-for"];
1346
- const client = xff?.split(",")[0]?.trim();
1347
- if (client) connection.ip = client;
1348
- }
1349
- if (!connection.tlsCipher) {
1350
- const cipher = connection.tlsVersion?.split(":")[1];
1351
- if (cipher) connection.tlsCipher = cipher;
1603
+ try {
1604
+ return new RegExp(`^${source}$`, opts.caseInsensitive ? "i" : "");
1605
+ } catch {
1606
+ return null;
1352
1607
  }
1353
- return Object.keys(connection).length > 0 ? connection : void 0;
1354
1608
  }
1355
- function buildSdkObservedMetadata(rawHeaders) {
1356
- const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
1357
- const flat = {};
1358
- if (rawHeaders) {
1359
- for (const name of Object.keys(rawHeaders)) {
1360
- const value = rawHeaders[name];
1361
- if (value === void 0) continue;
1362
- flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
1363
- }
1364
- }
1365
- const connection = deriveConnectionFromHeaders(flat);
1366
- return {
1367
- headers,
1368
- ...apiKeyFormat && { apiKeyFormat },
1369
- ...platformHeaders && { platformHeaders },
1370
- ...connection && { connection },
1371
- ...cookieCount !== void 0 && { cookieCount },
1372
- schemaVersion: CAPTURE_SCHEMA_VERSION
1373
- };
1609
+ function matchRoutePattern(pattern, path, opts = {}) {
1610
+ return routePatternToRegExp(pattern, opts)?.test(path) ?? false;
1374
1611
  }
1375
1612
 
1376
1613
  // src/edge-config.ts
@@ -1405,6 +1642,7 @@ function isEdgeConfig(value) {
1405
1642
  if (r.sampling !== void 0 && !isSamplingShape(r.sampling)) return false;
1406
1643
  }
1407
1644
  if (!isSamplingShape(v.sampling)) return false;
1645
+ if (v.minTls !== void 0 && v.minTls !== "1.2" && v.minTls !== "1.3") return false;
1408
1646
  if (v.queryValueAllowlist !== void 0) {
1409
1647
  if (!Array.isArray(v.queryValueAllowlist) || v.queryValueAllowlist.length > 16 || !v.queryValueAllowlist.every((e) => typeof e === "string" && e.length > 0 && e.length <= 64)) {
1410
1648
  return false;
@@ -1992,14 +2230,11 @@ function resolveRequestPdlss(req, routeConfig, customExtractPurpose, customExtra
1992
2230
  });
1993
2231
  }
1994
2232
  function matchRoute(pattern, path, opts) {
1995
- const regexPattern = pattern.replace(/\*/g, ".*").replace(/\//g, "\\/");
1996
- const caseSensitiveRegex = new RegExp(`^${regexPattern}$`);
1997
- const caseSensitiveResult = caseSensitiveRegex.test(path);
2233
+ const caseSensitiveResult = matchRoutePattern(pattern, path);
1998
2234
  if (!opts?.caseInsensitive && !opts?.logShadowDivergence) {
1999
2235
  return caseSensitiveResult;
2000
2236
  }
2001
- const caseInsensitiveRegex = new RegExp(`^${regexPattern}$`, "i");
2002
- const caseInsensitiveResult = caseInsensitiveRegex.test(path);
2237
+ const caseInsensitiveResult = matchRoutePattern(pattern, path, { caseInsensitive: true });
2003
2238
  if (opts?.logShadowDivergence && caseSensitiveResult !== caseInsensitiveResult) {
2004
2239
  console.warn(
2005
2240
  `[SHADOW] matchRoute case-insensitive would change result: pattern=${pattern} path=${path} caseSensitive=${caseSensitiveResult} caseInsensitive=${caseInsensitiveResult} correlationId=${opts.correlationId ?? "unknown"}`
@@ -2262,8 +2497,10 @@ function createMiddleware(options) {
2262
2497
  }
2263
2498
  const attemptHeader = req.headers["x-astra-attempt-id"];
2264
2499
  const inboundAttemptId = typeof attemptHeader === "string" && /^att_[0-9a-f]{32}$/.test(attemptHeader) ? attemptHeader : void 0;
2500
+ const commerceArtifacts = detectExpressCommerce(req);
2265
2501
  const verificationRequest = {
2266
2502
  credentials,
2503
+ ...commerceArtifacts && { commerceArtifacts },
2267
2504
  purpose,
2268
2505
  action: pdlssPair.action,
2269
2506
  resource: req.path,