@astrasyncai/verification-gateway 5.14.0 → 5.16.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 (100) hide show
  1. package/README.md +36 -18
  2. package/dist/adapters/express.d.mts +1 -1
  3. package/dist/adapters/express.d.ts +1 -1
  4. package/dist/adapters/express.js +492 -240
  5. package/dist/adapters/express.js.map +1 -1
  6. package/dist/adapters/express.mjs +492 -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 +23 -6
  11. package/dist/adapters/mcp.js.map +1 -1
  12. package/dist/adapters/mcp.mjs +23 -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 +475 -239
  17. package/dist/adapters/nextjs.js.map +1 -1
  18. package/dist/adapters/nextjs.mjs +475 -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 +83 -23
  23. package/dist/adapters/sdk.js.map +1 -1
  24. package/dist/adapters/sdk.mjs +83 -23
  25. package/dist/adapters/sdk.mjs.map +1 -1
  26. package/dist/agent/index.d.mts +69 -54
  27. package/dist/agent/index.d.ts +69 -54
  28. package/dist/agent/index.js +24 -14
  29. package/dist/agent/index.js.map +1 -1
  30. package/dist/agent/index.mjs +24 -14
  31. package/dist/agent/index.mjs.map +1 -1
  32. package/dist/bin/astrasync-claude-hook.js +58 -11
  33. package/dist/bin/astrasync-codex-hook.js +58 -11
  34. package/dist/bin/astrasync-guard.js +177 -11
  35. package/dist/bin/astrasync.js +433 -38
  36. package/dist/browser/background.js +53 -6
  37. package/dist/browser/background.js.map +1 -1
  38. package/dist/browser/background.mjs +63 -6
  39. package/dist/browser/background.mjs.map +1 -1
  40. package/dist/cli/index.js +1 -1
  41. package/dist/cli/index.js.map +1 -1
  42. package/dist/cli/index.mjs +1 -1
  43. package/dist/cli/index.mjs.map +1 -1
  44. package/dist/codex/index.js +58 -11
  45. package/dist/codex/index.js.map +1 -1
  46. package/dist/codex/index.mjs +68 -11
  47. package/dist/codex/index.mjs.map +1 -1
  48. package/dist/cursor/extension.js +58 -11
  49. package/dist/cursor/extension.js.map +1 -1
  50. package/dist/cursor/extension.mjs +68 -11
  51. package/dist/cursor/extension.mjs.map +1 -1
  52. package/dist/edge-config.d.mts +31 -2
  53. package/dist/edge-config.d.ts +31 -2
  54. package/dist/edge-config.js +35 -5
  55. package/dist/edge-config.js.map +1 -1
  56. package/dist/edge-config.mjs +32 -4
  57. package/dist/edge-config.mjs.map +1 -1
  58. package/dist/edge-core/index.d.mts +11 -2
  59. package/dist/edge-core/index.d.ts +11 -2
  60. package/dist/edge-core/index.js +97 -11
  61. package/dist/edge-core/index.js.map +1 -1
  62. package/dist/edge-core/index.mjs +95 -11
  63. package/dist/edge-core/index.mjs.map +1 -1
  64. package/dist/gateway/gateway.js +53 -6
  65. package/dist/gateway/gateway.js.map +1 -1
  66. package/dist/gateway/gateway.mjs +63 -6
  67. package/dist/gateway/gateway.mjs.map +1 -1
  68. package/dist/git-trigger/git-hooks.d.mts +1 -1
  69. package/dist/git-trigger/git-hooks.d.ts +1 -1
  70. package/dist/index.d.mts +1407 -88
  71. package/dist/index.d.ts +1407 -88
  72. package/dist/index.js +5148 -2616
  73. package/dist/index.js.map +1 -1
  74. package/dist/index.mjs +5094 -2618
  75. package/dist/index.mjs.map +1 -1
  76. package/dist/registration/index.d.mts +28 -2
  77. package/dist/registration/index.d.ts +28 -2
  78. package/dist/registration/index.js +18 -3
  79. package/dist/registration/index.js.map +1 -1
  80. package/dist/registration/index.mjs +15 -2
  81. package/dist/registration/index.mjs.map +1 -1
  82. package/dist/transport/index.d.mts +7 -5
  83. package/dist/transport/index.d.ts +7 -5
  84. package/dist/transport/index.js +61 -5
  85. package/dist/transport/index.js.map +1 -1
  86. package/dist/transport/index.mjs +67 -11
  87. package/dist/transport/index.mjs.map +1 -1
  88. package/dist/{types-BCkwBA84.d.mts → types-Blz520bR.d.mts} +116 -12
  89. package/dist/{types-BCkwBA84.d.ts → types-Blz520bR.d.ts} +116 -12
  90. package/dist/{types-C_b4QTyO.d.ts → types-Bm1QvGqI.d.ts} +114 -10
  91. package/dist/{types-DlshIIR-.d.mts → types-DBe4hgfT.d.mts} +114 -10
  92. package/dist/ui/index.d.mts +1 -1
  93. package/dist/ui/index.d.ts +1 -1
  94. package/dist/verify.d.mts +1 -1
  95. package/dist/verify.d.ts +1 -1
  96. package/dist/verify.js +23 -6
  97. package/dist/verify.js.map +1 -1
  98. package/dist/verify.mjs +23 -6
  99. package/dist/verify.mjs.map +1 -1
  100. package/package.json +1 -1
@@ -25,8 +25,451 @@ __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) && headerValue(req, "ucp-agent")) {
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
+
460
+ // src/types.ts
461
+ function routePolicyOf(route) {
462
+ if (!route) return void 0;
463
+ const owners = route.allowedOwners?.filter(Boolean) ?? [];
464
+ const policy = {
465
+ ...owners.length > 0 && { allowedOwners: owners },
466
+ ...route.requiresRuntimeChallenge === true && { requiresRuntimeChallenge: true }
467
+ };
468
+ return Object.keys(policy).length > 0 ? policy : void 0;
469
+ }
470
+
28
471
  // src/version.ts
29
- var SDK_VERSION = "5.14.0";
472
+ var SDK_VERSION = "5.16.0";
30
473
 
31
474
  // src/http.ts
32
475
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -326,6 +769,8 @@ function getCacheKey(request, counterpartyId) {
326
769
  request.durationRequired ?? "",
327
770
  request.invocationProtocol || "",
328
771
  request.enableRuntimeChallenge ? "1" : "0",
772
+ // 5.16.0: route policy changes the verdict (owners / challenge).
773
+ request.routePolicy ? JSON.stringify(request.routePolicy) : "",
329
774
  // callerMetadata fields contribute to risk model; include the ones
330
775
  // backend reads. sourceIp/userAgent/forwardedFor change per-request
331
776
  // so their inclusion effectively forces a re-check for any varying
@@ -532,6 +977,7 @@ async function callVerifyAccessAPI(config, request) {
532
977
  if (requestData.subAgentDepth !== void 0) body.subAgentDepth = requestData.subAgentDepth;
533
978
  if (requestData.enableRuntimeChallenge)
534
979
  body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
980
+ if (requestData.routePolicy) body.routePolicy = requestData.routePolicy;
535
981
  if (requestData.createSession) body.createSession = requestData.createSession;
536
982
  if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;
537
983
  if (requestData.counterpartyType) body.counterpartyType = requestData.counterpartyType;
@@ -542,6 +988,7 @@ async function callVerifyAccessAPI(config, request) {
542
988
  if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
543
989
  if (requestData.commercePhase) body.commercePhase = requestData.commercePhase;
544
990
  if (requestData.checkoutSessionId) body.checkoutSessionId = requestData.checkoutSessionId;
991
+ if (requestData.checkoutJwt) body.checkoutJwt = requestData.checkoutJwt;
545
992
  if (requestData.checkoutItems) body.checkoutItems = requestData.checkoutItems;
546
993
  if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
547
994
  if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
@@ -692,7 +1139,8 @@ async function verify(config, request, options) {
692
1139
  "[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
1140
  );
694
1141
  }
695
- if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache) {
1142
+ const uncacheable = Boolean(request.commerceArtifacts);
1143
+ if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
696
1144
  const cached = getCachedResult(request, mergedConfig.counterpartyId);
697
1145
  if (cached) {
698
1146
  if (mergedConfig.debug) {
@@ -773,7 +1221,10 @@ async function verify(config, request, options) {
773
1221
  // MERCHANT caller only (bridge callers strip it before the agent plane).
774
1222
  settlementToken: apiResponse.settlementToken,
775
1223
  // 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
776
- fulfilment: apiResponse.fulfilment
1224
+ fulfilment: apiResponse.fulfilment,
1225
+ mandates: apiResponse.mandates,
1226
+ kyaToken: apiResponse.kyaToken,
1227
+ aep: apiResponse.aep
777
1228
  };
778
1229
  return result2;
779
1230
  }
@@ -783,7 +1234,10 @@ async function verify(config, request, options) {
783
1234
  trustScore: apiResponse.agent.trustScore,
784
1235
  trustLevel: getTrustLevel(apiResponse.agent.trustScore),
785
1236
  blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
786
- status: apiResponse.agent.agentStatus
1237
+ status: apiResponse.agent.agentStatus,
1238
+ ...apiResponse.agent.protocolIdentities && {
1239
+ protocolIdentities: apiResponse.agent.protocolIdentities
1240
+ }
787
1241
  } : void 0;
788
1242
  const developer = apiResponse.developer ? {
789
1243
  astradId: apiResponse.developer.kyaOwnerId,
@@ -834,7 +1288,11 @@ async function verify(config, request, options) {
834
1288
  settlementOutcome: apiResponse.settlementOutcome,
835
1289
  settlementToken: apiResponse.settlementToken,
836
1290
  // 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
837
- fulfilment: apiResponse.fulfilment
1291
+ fulfilment: apiResponse.fulfilment,
1292
+ // 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
1293
+ mandates: apiResponse.mandates,
1294
+ kyaToken: apiResponse.kyaToken,
1295
+ aep: apiResponse.aep
838
1296
  };
839
1297
  if (result.recommendation === "deny") {
840
1298
  result.policyAllowed = false;
@@ -854,7 +1312,9 @@ async function verify(config, request, options) {
854
1312
  }
855
1313
  const escalates = result.requiresStepUp === true || result.requiresApproval === true || result.recommendation === "step_up_required";
856
1314
  if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny" && !escalates) {
857
- cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
1315
+ if (!uncacheable) {
1316
+ cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
1317
+ }
858
1318
  }
859
1319
  return result;
860
1320
  }
@@ -1138,239 +1598,30 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
1138
1598
  return failures;
1139
1599
  }
1140
1600
 
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
- }
1601
+ // src/route-pattern.ts
1602
+ function routePatternToRegExp(pattern, opts = {}) {
1603
+ let source = "";
1604
+ for (let i = 0; i < pattern.length; i++) {
1605
+ const ch = pattern[i];
1606
+ if (ch === "*") {
1607
+ source += ".*";
1608
+ } else if (ch === ":" && /[A-Za-z_]/.test(pattern[i + 1] ?? "") && (i === 0 || pattern[i - 1] === "/")) {
1609
+ let j = i + 1;
1610
+ while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) j++;
1611
+ source += "[^/]+";
1612
+ i = j - 1;
1613
+ } else {
1614
+ source += ch.replace(/[.+?^${}()|[\]\\/]/g, "\\$&");
1336
1615
  }
1337
1616
  }
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;
1617
+ try {
1618
+ return new RegExp(`^${source}$`, opts.caseInsensitive ? "i" : "");
1619
+ } catch {
1620
+ return null;
1352
1621
  }
1353
- return Object.keys(connection).length > 0 ? connection : void 0;
1354
1622
  }
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
- };
1623
+ function matchRoutePattern(pattern, path, opts = {}) {
1624
+ return routePatternToRegExp(pattern, opts)?.test(path) ?? false;
1374
1625
  }
1375
1626
 
1376
1627
  // src/edge-config.ts
@@ -1405,6 +1656,7 @@ function isEdgeConfig(value) {
1405
1656
  if (r.sampling !== void 0 && !isSamplingShape(r.sampling)) return false;
1406
1657
  }
1407
1658
  if (!isSamplingShape(v.sampling)) return false;
1659
+ if (v.minTls !== void 0 && v.minTls !== "1.2" && v.minTls !== "1.3") return false;
1408
1660
  if (v.queryValueAllowlist !== void 0) {
1409
1661
  if (!Array.isArray(v.queryValueAllowlist) || v.queryValueAllowlist.length > 16 || !v.queryValueAllowlist.every((e) => typeof e === "string" && e.length > 0 && e.length <= 64)) {
1410
1662
  return false;
@@ -1992,14 +2244,11 @@ function resolveRequestPdlss(req, routeConfig, customExtractPurpose, customExtra
1992
2244
  });
1993
2245
  }
1994
2246
  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);
2247
+ const caseSensitiveResult = matchRoutePattern(pattern, path);
1998
2248
  if (!opts?.caseInsensitive && !opts?.logShadowDivergence) {
1999
2249
  return caseSensitiveResult;
2000
2250
  }
2001
- const caseInsensitiveRegex = new RegExp(`^${regexPattern}$`, "i");
2002
- const caseInsensitiveResult = caseInsensitiveRegex.test(path);
2251
+ const caseInsensitiveResult = matchRoutePattern(pattern, path, { caseInsensitive: true });
2003
2252
  if (opts?.logShadowDivergence && caseSensitiveResult !== caseInsensitiveResult) {
2004
2253
  console.warn(
2005
2254
  `[SHADOW] matchRoute case-insensitive would change result: pattern=${pattern} path=${path} caseSensitive=${caseSensitiveResult} caseInsensitive=${caseInsensitiveResult} correlationId=${opts.correlationId ?? "unknown"}`
@@ -2262,8 +2511,10 @@ function createMiddleware(options) {
2262
2511
  }
2263
2512
  const attemptHeader = req.headers["x-astra-attempt-id"];
2264
2513
  const inboundAttemptId = typeof attemptHeader === "string" && /^att_[0-9a-f]{32}$/.test(attemptHeader) ? attemptHeader : void 0;
2514
+ const commerceArtifacts = detectExpressCommerce(req);
2265
2515
  const verificationRequest = {
2266
2516
  credentials,
2517
+ ...commerceArtifacts && { commerceArtifacts },
2267
2518
  purpose,
2268
2519
  action: pdlssPair.action,
2269
2520
  resource: req.path,
@@ -2271,6 +2522,7 @@ function createMiddleware(options) {
2271
2522
  counterpartyUrl,
2272
2523
  counterpartyType: config.counterpartyType || "api",
2273
2524
  enableRuntimeChallenge,
2525
+ ...routePolicyOf(routeConfig) && { routePolicy: routePolicyOf(routeConfig) },
2274
2526
  durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,
2275
2527
  ...txValue !== void 0 && { transactionValue: txValue },
2276
2528
  ...txCurrency && { currency: txCurrency },