@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,437 @@
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 lowerHeaders(headers) {
388
+ const out = {};
389
+ if (typeof Headers !== "undefined" && headers instanceof Headers) {
390
+ headers.forEach((v, k) => out[k.toLowerCase()] = v);
391
+ return out;
392
+ }
393
+ for (const [k, v] of Object.entries(headers)) {
394
+ if (v === void 0) continue;
395
+ out[k.toLowerCase()] = Array.isArray(v) ? v.join(", ") : v;
396
+ }
397
+ return out;
398
+ }
399
+ function detect(req, host) {
400
+ try {
401
+ return detectCommerce(req, host)?.artifacts;
402
+ } catch {
403
+ return void 0;
404
+ }
405
+ }
406
+ function detectExpressCommerce(req) {
407
+ const headers = lowerHeaders(req.headers);
408
+ const [uri, query = ""] = (req.originalUrl ?? req.url).split("?");
409
+ let bodyText;
410
+ if (req.rawBody !== void 0) {
411
+ bodyText = typeof req.rawBody === "string" ? req.rawBody : req.rawBody.toString("utf8");
412
+ } else if (typeof req.body === "string") {
413
+ bodyText = req.body;
414
+ } else if (req.body && typeof req.body === "object" && Object.keys(req.body).length > 0) {
415
+ bodyText = JSON.stringify(req.body);
416
+ }
417
+ const truncated = bodyText !== void 0 && bodyText.length > MAX_BODY_BYTES;
418
+ return detect(
419
+ {
420
+ method: req.method,
421
+ uri,
422
+ querystring: query,
423
+ headers,
424
+ ...bodyText !== void 0 && {
425
+ bodyText: truncated ? bodyText.slice(0, MAX_BODY_BYTES) : bodyText,
426
+ bodyTruncated: truncated
427
+ }
428
+ },
429
+ headers["x-forwarded-host"] ?? headers.host ?? "localhost"
430
+ );
431
+ }
432
+
1
433
  // src/version.ts
2
- var SDK_VERSION = "5.14.0";
434
+ var SDK_VERSION = "5.15.0";
3
435
 
4
436
  // src/http.ts
5
437
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -515,6 +947,7 @@ async function callVerifyAccessAPI(config, request) {
515
947
  if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
516
948
  if (requestData.commercePhase) body.commercePhase = requestData.commercePhase;
517
949
  if (requestData.checkoutSessionId) body.checkoutSessionId = requestData.checkoutSessionId;
950
+ if (requestData.checkoutJwt) body.checkoutJwt = requestData.checkoutJwt;
518
951
  if (requestData.checkoutItems) body.checkoutItems = requestData.checkoutItems;
519
952
  if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
520
953
  if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
@@ -665,7 +1098,8 @@ async function verify(config, request, options) {
665
1098
  "[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."
666
1099
  );
667
1100
  }
668
- if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache) {
1101
+ const uncacheable = Boolean(request.commerceArtifacts);
1102
+ if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
669
1103
  const cached = getCachedResult(request, mergedConfig.counterpartyId);
670
1104
  if (cached) {
671
1105
  if (mergedConfig.debug) {
@@ -746,7 +1180,10 @@ async function verify(config, request, options) {
746
1180
  // MERCHANT caller only (bridge callers strip it before the agent plane).
747
1181
  settlementToken: apiResponse.settlementToken,
748
1182
  // 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
749
- fulfilment: apiResponse.fulfilment
1183
+ fulfilment: apiResponse.fulfilment,
1184
+ mandates: apiResponse.mandates,
1185
+ kyaToken: apiResponse.kyaToken,
1186
+ aep: apiResponse.aep
750
1187
  };
751
1188
  return result2;
752
1189
  }
@@ -756,7 +1193,10 @@ async function verify(config, request, options) {
756
1193
  trustScore: apiResponse.agent.trustScore,
757
1194
  trustLevel: getTrustLevel(apiResponse.agent.trustScore),
758
1195
  blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
759
- status: apiResponse.agent.agentStatus
1196
+ status: apiResponse.agent.agentStatus,
1197
+ ...apiResponse.agent.protocolIdentities && {
1198
+ protocolIdentities: apiResponse.agent.protocolIdentities
1199
+ }
760
1200
  } : void 0;
761
1201
  const developer = apiResponse.developer ? {
762
1202
  astradId: apiResponse.developer.kyaOwnerId,
@@ -807,7 +1247,11 @@ async function verify(config, request, options) {
807
1247
  settlementOutcome: apiResponse.settlementOutcome,
808
1248
  settlementToken: apiResponse.settlementToken,
809
1249
  // 5.6.0: fulfilment contact — merchant-only lane, same strip rule.
810
- fulfilment: apiResponse.fulfilment
1250
+ fulfilment: apiResponse.fulfilment,
1251
+ // 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
1252
+ mandates: apiResponse.mandates,
1253
+ kyaToken: apiResponse.kyaToken,
1254
+ aep: apiResponse.aep
811
1255
  };
812
1256
  if (result.recommendation === "deny") {
813
1257
  result.policyAllowed = false;
@@ -827,7 +1271,9 @@ async function verify(config, request, options) {
827
1271
  }
828
1272
  const escalates = result.requiresStepUp === true || result.requiresApproval === true || result.recommendation === "step_up_required";
829
1273
  if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny" && !escalates) {
830
- cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
1274
+ if (!uncacheable) {
1275
+ cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
1276
+ }
831
1277
  }
832
1278
  return result;
833
1279
  }
@@ -1111,239 +1557,30 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
1111
1557
  return failures;
1112
1558
  }
1113
1559
 
1114
- // src/metadata-capture.ts
1115
- var CAPTURE_SCHEMA_VERSION = 1;
1116
- var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
1117
- "cookie",
1118
- "set-cookie",
1119
- "x-csrf-token",
1120
- "proxy-authorization",
1121
- "x-astrasync-signature",
1122
- "x-astrasync-secret",
1123
- "x-hub-signature",
1124
- "x-hub-signature-256",
1125
- // Short-lived verify dedupe token — must never persist in stored metadata.
1126
- "x-astra-verified-hop"
1127
- ]);
1128
- var SECRET_HEADER_PREFIXES = ["x-astrasync-", "kya-", "kya_"];
1129
- var CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
1130
- "authorization",
1131
- "x-api-key",
1132
- "x-goog-api-key",
1133
- "api-key"
1134
- ]);
1135
- function isSignatureHeader(name) {
1136
- return name === "signature" || name.endsWith("-signature") || name.endsWith("-signature-256");
1137
- }
1138
- var PLATFORM_HEADER_NAMES = /* @__PURE__ */ new Set([
1139
- "openai-organization",
1140
- "openai-project",
1141
- "openai-version",
1142
- "openai-processing-ms",
1143
- "anthropic-version",
1144
- "anthropic-beta",
1145
- "x-goog-user-project",
1146
- "x-goog-api-client",
1147
- "user-agent",
1148
- "x-agent-card-url",
1149
- "x-agent-provider"
1150
- ]);
1151
- var PLATFORM_HEADER_PREFIXES = [
1152
- "x-goog-",
1153
- "x-stainless-",
1154
- "x-anthropic-",
1155
- "x-openai-",
1156
- "sec-ch-"
1157
- ];
1158
- var KEY_FORMAT_PREFIXES = [
1159
- "sk-ant-api03",
1160
- "sk-ant-api",
1161
- "sk-ant",
1162
- "sk-proj",
1163
- "sk-svcacct",
1164
- "sk-or-v1",
1165
- "sk-or",
1166
- "sk-lf",
1167
- "sk-",
1168
- "gsk_",
1169
- "aiza",
1170
- "ya29",
1171
- "ghp_",
1172
- "gho_",
1173
- "github_pat_",
1174
- "xai-",
1175
- "pplx-",
1176
- "r8_",
1177
- "hf_",
1178
- "astra-",
1179
- "astrae-"
1180
- ];
1181
- var MAX_HEADERS = 64;
1182
- var MAX_HEADER_VALUE_BYTES = 1024;
1183
- var MAX_TOTAL_BYTES = 16 * 1024;
1184
- function byteLength(s) {
1185
- let bytes = 0;
1186
- for (let i = 0; i < s.length; i++) {
1187
- const code = s.charCodeAt(i);
1188
- if (code < 128) bytes += 1;
1189
- else if (code < 2048) bytes += 2;
1190
- else if (code >= 55296 && code <= 56319) {
1191
- bytes += 4;
1192
- i++;
1193
- } else bytes += 3;
1194
- }
1195
- return bytes;
1196
- }
1197
- function extractApiKeyFormat(rawValue) {
1198
- if (!rawValue) return void 0;
1199
- let value = rawValue.trim();
1200
- const spaceIdx = value.indexOf(" ");
1201
- if (spaceIdx > 0) {
1202
- const scheme = value.slice(0, spaceIdx).toLowerCase();
1203
- if (scheme === "bearer" || scheme === "basic" || scheme === "token") {
1204
- value = value.slice(spaceIdx + 1).trim();
1205
- }
1206
- }
1207
- const lower = value.toLowerCase();
1208
- for (const prefix of KEY_FORMAT_PREFIXES) {
1209
- if (lower.startsWith(prefix)) {
1210
- return prefix;
1211
- }
1212
- }
1213
- return void 0;
1214
- }
1215
- function isSecretHeader(name) {
1216
- if (SECRET_HEADER_NAMES.has(name)) return true;
1217
- if (SECRET_HEADER_PREFIXES.some((p) => name.startsWith(p))) return true;
1218
- if (isSignatureHeader(name)) return true;
1219
- return false;
1220
- }
1221
- function isPlatformHeader(name) {
1222
- if (PLATFORM_HEADER_NAMES.has(name)) return true;
1223
- return PLATFORM_HEADER_PREFIXES.some((p) => name.startsWith(p));
1224
- }
1225
- function sanitizeHeaders(raw) {
1226
- const headers = {};
1227
- const platformHeaders = {};
1228
- let apiKeyFormat;
1229
- let cookieCount;
1230
- let totalBytes = 0;
1231
- let count = 0;
1232
- if (!raw) return { headers };
1233
- for (const rawName of Object.keys(raw)) {
1234
- if (count >= MAX_HEADERS) break;
1235
- const name = rawName.toLowerCase();
1236
- const rawValue = raw[rawName];
1237
- if (rawValue === void 0) continue;
1238
- const joined = Array.isArray(rawValue) ? rawValue.join(", ") : String(rawValue);
1239
- if (CREDENTIAL_HEADER_NAMES.has(name)) {
1240
- const fmt = extractApiKeyFormat(joined);
1241
- if (fmt && !apiKeyFormat) apiKeyFormat = fmt;
1242
- continue;
1243
- }
1244
- if (name === "cookie") {
1245
- cookieCount = joined.split(";").filter((s) => s.trim().length > 0).length;
1246
- }
1247
- if (isSecretHeader(name)) continue;
1248
- let value = joined;
1249
- if (byteLength(value) > MAX_HEADER_VALUE_BYTES) {
1250
- value = value.slice(0, MAX_HEADER_VALUE_BYTES);
1251
- }
1252
- const entryBytes = byteLength(name) + byteLength(value);
1253
- if (totalBytes + entryBytes > MAX_TOTAL_BYTES) continue;
1254
- totalBytes += entryBytes;
1255
- count++;
1256
- headers[name] = value;
1257
- if (isPlatformHeader(name)) platformHeaders[name] = value;
1258
- }
1259
- const result = { headers };
1260
- if (apiKeyFormat) result.apiKeyFormat = apiKeyFormat;
1261
- if (Object.keys(platformHeaders).length > 0) result.platformHeaders = platformHeaders;
1262
- if (cookieCount !== void 0) result.cookieCount = cookieCount;
1263
- return result;
1264
- }
1265
- var CONNECTION_HEADER_SOURCES = [
1266
- ["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
1267
- [
1268
- "country",
1269
- ["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
1270
- ],
1271
- ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
1272
- ["countryRegionName", ["cloudfront-viewer-country-region-name"]],
1273
- ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
1274
- ["latitude", ["x-vercel-ip-latitude", "cloudfront-viewer-latitude"]],
1275
- ["longitude", ["x-vercel-ip-longitude", "cloudfront-viewer-longitude"]],
1276
- ["postalCode", ["x-vercel-ip-postal-code", "cloudfront-viewer-postal-code"]],
1277
- ["asn", ["cloudfront-viewer-asn"]],
1278
- ["tlsVersion", ["cloudfront-viewer-tls"]],
1279
- ["httpVersion", ["cloudfront-viewer-http-version"]],
1280
- ["timeZone", ["x-vercel-ip-timezone", "cloudfront-viewer-time-zone"]],
1281
- ["metroCode", ["cloudfront-viewer-metro-code"]],
1282
- // TLS fingerprints can only be computed where TLS terminates. When a CDN
1283
- // terminates TLS in front of the merchant, its fingerprint headers ARE the
1284
- // connection-layer truth — normalising them here is the permanent design.
1285
- // CloudFront delivers JA3/JA4 only via an origin request policy and only
1286
- // for HTTPS viewer connections.
1287
- ["tlsFingerprint", ["cf-ja3-hash", "cloudfront-viewer-ja3-fingerprint"]],
1288
- ["ja4", ["cf-ja4", "cloudfront-viewer-ja4-fingerprint"]],
1289
- // Header-structure fingerprint: browser/SDK-distinctive header ordering.
1290
- ["headerOrder", ["cloudfront-viewer-header-order"]],
1291
- ["headerCount", ["cloudfront-viewer-header-count"]]
1292
- ];
1293
- var MAX_CONNECTION_VALUE_CHARS = 256;
1294
- function deriveConnectionFromHeaders(headers) {
1295
- if (!headers) return void 0;
1296
- const lower = {};
1297
- for (const name of Object.keys(headers)) {
1298
- const value = headers[name];
1299
- if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
1300
- }
1301
- const connection = {};
1302
- for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
1303
- for (const source of sources) {
1304
- const value = lower[source]?.trim();
1305
- if (value) {
1306
- connection[key] = value.slice(0, MAX_CONNECTION_VALUE_CHARS);
1307
- break;
1308
- }
1560
+ // src/route-pattern.ts
1561
+ function routePatternToRegExp(pattern, opts = {}) {
1562
+ let source = "";
1563
+ for (let i = 0; i < pattern.length; i++) {
1564
+ const ch = pattern[i];
1565
+ if (ch === "*") {
1566
+ source += ".*";
1567
+ } else if (ch === ":" && /[A-Za-z_]/.test(pattern[i + 1] ?? "") && (i === 0 || pattern[i - 1] === "/")) {
1568
+ let j = i + 1;
1569
+ while (j < pattern.length && /[A-Za-z0-9_]/.test(pattern[j])) j++;
1570
+ source += "[^/]+";
1571
+ i = j - 1;
1572
+ } else {
1573
+ source += ch.replace(/[.+?^${}()|[\]\\/]/g, "\\$&");
1309
1574
  }
1310
1575
  }
1311
- {
1312
- const addr = lower["cloudfront-viewer-address"]?.trim();
1313
- const portMatch = addr?.match(/:(\d+)$/);
1314
- if (portMatch) connection.sourcePort = portMatch[1];
1315
- if (!connection.ip && addr) connection.ip = addr.replace(/:\d+$/, "");
1316
- }
1317
- if (!connection.ip) {
1318
- const xff = lower["x-forwarded-for"];
1319
- const client = xff?.split(",")[0]?.trim();
1320
- if (client) connection.ip = client;
1321
- }
1322
- if (!connection.tlsCipher) {
1323
- const cipher = connection.tlsVersion?.split(":")[1];
1324
- if (cipher) connection.tlsCipher = cipher;
1576
+ try {
1577
+ return new RegExp(`^${source}$`, opts.caseInsensitive ? "i" : "");
1578
+ } catch {
1579
+ return null;
1325
1580
  }
1326
- return Object.keys(connection).length > 0 ? connection : void 0;
1327
1581
  }
1328
- function buildSdkObservedMetadata(rawHeaders) {
1329
- const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(rawHeaders);
1330
- const flat = {};
1331
- if (rawHeaders) {
1332
- for (const name of Object.keys(rawHeaders)) {
1333
- const value = rawHeaders[name];
1334
- if (value === void 0) continue;
1335
- flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
1336
- }
1337
- }
1338
- const connection = deriveConnectionFromHeaders(flat);
1339
- return {
1340
- headers,
1341
- ...apiKeyFormat && { apiKeyFormat },
1342
- ...platformHeaders && { platformHeaders },
1343
- ...connection && { connection },
1344
- ...cookieCount !== void 0 && { cookieCount },
1345
- schemaVersion: CAPTURE_SCHEMA_VERSION
1346
- };
1582
+ function matchRoutePattern(pattern, path, opts = {}) {
1583
+ return routePatternToRegExp(pattern, opts)?.test(path) ?? false;
1347
1584
  }
1348
1585
 
1349
1586
  // src/edge-config.ts
@@ -1378,6 +1615,7 @@ function isEdgeConfig(value) {
1378
1615
  if (r.sampling !== void 0 && !isSamplingShape(r.sampling)) return false;
1379
1616
  }
1380
1617
  if (!isSamplingShape(v.sampling)) return false;
1618
+ if (v.minTls !== void 0 && v.minTls !== "1.2" && v.minTls !== "1.3") return false;
1381
1619
  if (v.queryValueAllowlist !== void 0) {
1382
1620
  if (!Array.isArray(v.queryValueAllowlist) || v.queryValueAllowlist.length > 16 || !v.queryValueAllowlist.every((e) => typeof e === "string" && e.length > 0 && e.length <= 64)) {
1383
1621
  return false;
@@ -1965,14 +2203,11 @@ function resolveRequestPdlss(req, routeConfig, customExtractPurpose, customExtra
1965
2203
  });
1966
2204
  }
1967
2205
  function matchRoute(pattern, path, opts) {
1968
- const regexPattern = pattern.replace(/\*/g, ".*").replace(/\//g, "\\/");
1969
- const caseSensitiveRegex = new RegExp(`^${regexPattern}$`);
1970
- const caseSensitiveResult = caseSensitiveRegex.test(path);
2206
+ const caseSensitiveResult = matchRoutePattern(pattern, path);
1971
2207
  if (!opts?.caseInsensitive && !opts?.logShadowDivergence) {
1972
2208
  return caseSensitiveResult;
1973
2209
  }
1974
- const caseInsensitiveRegex = new RegExp(`^${regexPattern}$`, "i");
1975
- const caseInsensitiveResult = caseInsensitiveRegex.test(path);
2210
+ const caseInsensitiveResult = matchRoutePattern(pattern, path, { caseInsensitive: true });
1976
2211
  if (opts?.logShadowDivergence && caseSensitiveResult !== caseInsensitiveResult) {
1977
2212
  console.warn(
1978
2213
  `[SHADOW] matchRoute case-insensitive would change result: pattern=${pattern} path=${path} caseSensitive=${caseSensitiveResult} caseInsensitive=${caseInsensitiveResult} correlationId=${opts.correlationId ?? "unknown"}`
@@ -2235,8 +2470,10 @@ function createMiddleware(options) {
2235
2470
  }
2236
2471
  const attemptHeader = req.headers["x-astra-attempt-id"];
2237
2472
  const inboundAttemptId = typeof attemptHeader === "string" && /^att_[0-9a-f]{32}$/.test(attemptHeader) ? attemptHeader : void 0;
2473
+ const commerceArtifacts = detectExpressCommerce(req);
2238
2474
  const verificationRequest = {
2239
2475
  credentials,
2476
+ ...commerceArtifacts && { commerceArtifacts },
2240
2477
  purpose,
2241
2478
  action: pdlssPair.action,
2242
2479
  resource: req.path,