@astrasyncai/verification-gateway 3.12.0 → 4.1.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 (134) hide show
  1. package/README.md +106 -29
  2. package/dist/adapter-interface/interface.d.mts +2 -2
  3. package/dist/adapter-interface/interface.d.ts +2 -2
  4. package/dist/adapters/express.d.mts +2 -2
  5. package/dist/adapters/express.d.ts +2 -2
  6. package/dist/adapters/express.js +482 -22
  7. package/dist/adapters/express.js.map +1 -1
  8. package/dist/adapters/express.mjs +482 -22
  9. package/dist/adapters/express.mjs.map +1 -1
  10. package/dist/adapters/http-pdlss.d.mts +3 -3
  11. package/dist/adapters/http-pdlss.d.ts +3 -3
  12. package/dist/adapters/http-pdlss.js.map +1 -1
  13. package/dist/adapters/http-pdlss.mjs.map +1 -1
  14. package/dist/adapters/mcp.d.mts +56 -36
  15. package/dist/adapters/mcp.d.ts +56 -36
  16. package/dist/adapters/mcp.js +309 -10
  17. package/dist/adapters/mcp.js.map +1 -1
  18. package/dist/adapters/mcp.mjs +309 -10
  19. package/dist/adapters/mcp.mjs.map +1 -1
  20. package/dist/adapters/nextjs.d.mts +2 -2
  21. package/dist/adapters/nextjs.d.ts +2 -2
  22. package/dist/adapters/nextjs.js +518 -25
  23. package/dist/adapters/nextjs.js.map +1 -1
  24. package/dist/adapters/nextjs.mjs +518 -25
  25. package/dist/adapters/nextjs.mjs.map +1 -1
  26. package/dist/adapters/sdk.d.mts +2 -2
  27. package/dist/adapters/sdk.d.ts +2 -2
  28. package/dist/adapters/sdk.js +72 -9
  29. package/dist/adapters/sdk.js.map +1 -1
  30. package/dist/adapters/sdk.mjs +72 -9
  31. package/dist/adapters/sdk.mjs.map +1 -1
  32. package/dist/agent/index.d.mts +2 -2
  33. package/dist/agent/index.d.ts +2 -2
  34. package/dist/agent/index.js.map +1 -1
  35. package/dist/agent/index.mjs.map +1 -1
  36. package/dist/bin/astrasync-claude-hook.js +83 -20
  37. package/dist/bin/astrasync-codex-hook.js +83 -20
  38. package/dist/bin/astrasync-guard.js +83 -20
  39. package/dist/bin/astrasync.js +150 -33
  40. package/dist/browser/background.js +83 -20
  41. package/dist/browser/background.js.map +1 -1
  42. package/dist/browser/background.mjs +83 -20
  43. package/dist/browser/background.mjs.map +1 -1
  44. package/dist/browser/browser-adapter.d.mts +2 -2
  45. package/dist/browser/browser-adapter.d.ts +2 -2
  46. package/dist/claude-code/claude-code-adapter.d.mts +2 -2
  47. package/dist/claude-code/claude-code-adapter.d.ts +2 -2
  48. package/dist/cli/index.d.mts +2 -2
  49. package/dist/cli/index.d.ts +2 -2
  50. package/dist/codex/index.d.mts +3 -3
  51. package/dist/codex/index.d.ts +3 -3
  52. package/dist/codex/index.js +83 -20
  53. package/dist/codex/index.js.map +1 -1
  54. package/dist/codex/index.mjs +83 -20
  55. package/dist/codex/index.mjs.map +1 -1
  56. package/dist/cursor/cursor-adapter.d.mts +2 -2
  57. package/dist/cursor/cursor-adapter.d.ts +2 -2
  58. package/dist/cursor/extension.d.mts +2 -2
  59. package/dist/cursor/extension.d.ts +2 -2
  60. package/dist/cursor/extension.js +83 -20
  61. package/dist/cursor/extension.js.map +1 -1
  62. package/dist/cursor/extension.mjs +83 -20
  63. package/dist/cursor/extension.mjs.map +1 -1
  64. package/dist/edge-config.d.mts +22 -7
  65. package/dist/edge-config.d.ts +22 -7
  66. package/dist/edge-config.js.map +1 -1
  67. package/dist/edge-config.mjs.map +1 -1
  68. package/dist/edge-core/index.d.mts +425 -0
  69. package/dist/edge-core/index.d.ts +425 -0
  70. package/dist/edge-core/index.js +1482 -0
  71. package/dist/edge-core/index.js.map +1 -0
  72. package/dist/edge-core/index.mjs +1437 -0
  73. package/dist/edge-core/index.mjs.map +1 -0
  74. package/dist/{express-B39o89gf.d.mts → express-BVd1_3FE.d.ts} +9 -7
  75. package/dist/{express-BuxKNO_q.d.ts → express-D_4hTn5Z.d.mts} +9 -7
  76. package/dist/gateway/gateway.d.mts +2 -2
  77. package/dist/gateway/gateway.d.ts +2 -2
  78. package/dist/gateway/gateway.js +83 -20
  79. package/dist/gateway/gateway.js.map +1 -1
  80. package/dist/gateway/gateway.mjs +83 -20
  81. package/dist/gateway/gateway.mjs.map +1 -1
  82. package/dist/git-trigger/git-hooks.d.mts +2 -2
  83. package/dist/git-trigger/git-hooks.d.ts +2 -2
  84. package/dist/{index-CLHdqs2M.d.ts → index-B0YHu_SP.d.ts} +30 -27
  85. package/dist/{index-DME3w3lf.d.mts → index-BPEBlOsE.d.mts} +30 -27
  86. package/dist/{index-CqydB4ks.d.mts → index-DQb5-_1X.d.mts} +1 -1
  87. package/dist/{index-BG62SXso.d.ts → index-T1aBoUcc.d.ts} +1 -1
  88. package/dist/index.d.mts +11 -11
  89. package/dist/index.d.ts +11 -11
  90. package/dist/index.js +595 -272
  91. package/dist/index.js.map +1 -1
  92. package/dist/index.mjs +592 -272
  93. package/dist/index.mjs.map +1 -1
  94. package/dist/local-evaluator/evaluator.d.mts +2 -2
  95. package/dist/local-evaluator/evaluator.d.ts +2 -2
  96. package/dist/metadata-capture.d.mts +63 -4
  97. package/dist/metadata-capture.d.ts +63 -4
  98. package/dist/metadata-capture.js +67 -0
  99. package/dist/metadata-capture.js.map +1 -1
  100. package/dist/metadata-capture.mjs +64 -0
  101. package/dist/metadata-capture.mjs.map +1 -1
  102. package/dist/{nextjs-D74W7wt-.d.mts → nextjs-WyeVr2Kp.d.mts} +3 -3
  103. package/dist/{nextjs-Ddlw_J1J.d.ts → nextjs-w7RTbP1P.d.ts} +3 -3
  104. package/dist/platform-signatures.d.mts +5 -6
  105. package/dist/platform-signatures.d.ts +5 -6
  106. package/dist/platform-signatures.js.map +1 -1
  107. package/dist/platform-signatures.mjs.map +1 -1
  108. package/dist/registration/index.d.mts +10 -11
  109. package/dist/registration/index.d.ts +10 -11
  110. package/dist/registration/index.js.map +1 -1
  111. package/dist/registration/index.mjs.map +1 -1
  112. package/dist/{sdk-CT7gdkfR.d.ts → sdk-CbTNIkAa.d.mts} +4 -4
  113. package/dist/{sdk-Bn6bj7kt.d.mts → sdk-QeX0Z8Ho.d.ts} +4 -4
  114. package/dist/transport/index.d.mts +2 -2
  115. package/dist/transport/index.d.ts +2 -2
  116. package/dist/transport/index.js.map +1 -1
  117. package/dist/transport/index.mjs.map +1 -1
  118. package/dist/{types-DHu7m9HI.d.ts → types-BLUx92FJ.d.ts} +1 -1
  119. package/dist/{types-Djw4GLtz.d.mts → types-DqfPU5Bl.d.mts} +1 -1
  120. package/dist/{types-BntuzEEn.d.mts → types-r850cOt0.d.mts} +121 -88
  121. package/dist/{types-SDu4Llbe.d.ts → types-sMxBT-nM.d.ts} +121 -88
  122. package/dist/ui/index.d.mts +11 -7
  123. package/dist/ui/index.d.ts +11 -7
  124. package/dist/ui/index.js +13 -9
  125. package/dist/ui/index.js.map +1 -1
  126. package/dist/ui/index.mjs +10 -8
  127. package/dist/ui/index.mjs.map +1 -1
  128. package/dist/verify.d.mts +11 -8
  129. package/dist/verify.d.ts +11 -8
  130. package/dist/verify.js +76 -8
  131. package/dist/verify.js.map +1 -1
  132. package/dist/verify.mjs +75 -8
  133. package/dist/verify.mjs.map +1 -1
  134. package/package.json +8 -2
package/dist/index.js CHANGED
@@ -36,6 +36,7 @@ __export(src_exports, {
36
36
  AstraSync: () => AstraSync,
37
37
  AstraSyncError: () => AstraSyncError,
38
38
  AuthenticationError: () => AuthenticationError,
39
+ CAPTURE_SCHEMA_VERSION: () => CAPTURE_SCHEMA_VERSION,
39
40
  ChallengeHandler: () => ChallengeHandler,
40
41
  DEFAULT_EDGE_CONFIG: () => DEFAULT_EDGE_CONFIG,
41
42
  DEFAULT_TRUST_THRESHOLDS: () => DEFAULT_TRUST_THRESHOLDS,
@@ -54,9 +55,11 @@ __export(src_exports, {
54
55
  authorizeSettlement: () => authorizeSettlement,
55
56
  awaitStepUpApproval: () => awaitStepUpApproval,
56
57
  buildGuidance: () => buildGuidance,
58
+ buildSdkObservedMetadata: () => buildSdkObservedMetadata,
57
59
  clearCache: () => clearCache,
58
60
  createMcpMiddleware: () => createMcpMiddleware,
59
61
  degradeToObserve: () => degradeToObserve,
62
+ deriveConnectionFromHeaders: () => deriveConnectionFromHeaders,
60
63
  detectPlatformFingerprint: () => detectPlatformFingerprint,
61
64
  determineAccessLevel: () => determineAccessLevel,
62
65
  express: () => express_exports,
@@ -214,7 +217,7 @@ function getCapabilities(accessLevel) {
214
217
  }
215
218
 
216
219
  // src/version.ts
217
- var SDK_VERSION = "3.12.0";
220
+ var SDK_VERSION = "4.1.0";
218
221
 
219
222
  // src/well-known.ts
220
223
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -292,7 +295,7 @@ var DEFAULT_CONFIG = {
292
295
  };
293
296
  var initCheckPerformed = false;
294
297
  var deprecationWarningShown = false;
295
- async function performInitCheck(apiBaseUrl, debug, strictInit) {
298
+ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
296
299
  initCheckPerformed = true;
297
300
  try {
298
301
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
@@ -309,6 +312,28 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
309
312
  `[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
310
313
  );
311
314
  }
315
+ if (apiKey) {
316
+ const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
317
+ headers: { Authorization: `Bearer ${apiKey}` }
318
+ });
319
+ if (selfCheck.status === 401) {
320
+ const body = await selfCheck.json().catch(() => ({}));
321
+ const message = `[VerificationGateway] the configured AstraSync API key was REJECTED at startup (${body.code ?? "api_key_invalid"}: ${body.message ?? "invalid key"}). Every inbound agent will be turned away until the key is rotated` + (body.remediation?.manageUrl ? ` at ${body.remediation.manageUrl}` : "") + `.`;
322
+ if (strictInit) {
323
+ throw new Error(`${message} (strictInit=true)`);
324
+ }
325
+ console.error(message);
326
+ } else if (selfCheck.ok) {
327
+ const body = await selfCheck.json().catch(() => ({}));
328
+ if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
329
+ console.warn(
330
+ `[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
331
+ );
332
+ } else if (debug) {
333
+ console.log("[VerificationGateway] API key self-check passed");
334
+ }
335
+ }
336
+ }
312
337
  } catch (err) {
313
338
  if (strictInit) {
314
339
  throw err;
@@ -426,8 +451,17 @@ function hasCredentials(credentials) {
426
451
  function createGuidanceResponse(_config, reason, options = {}) {
427
452
  const source = options.source ?? "no_credentials";
428
453
  const isApiError = source === "api_error";
454
+ const isMisconfig = source === "merchant_misconfig";
429
455
  const urls = options.urls;
430
- const guidance = isApiError ? {
456
+ const guidance = isMisconfig ? {
457
+ message: "This site's AstraSync integration is misconfigured (its API key was revoked, expired, or rotated). Your identity and the AstraSync platform are fine \u2014 contact the site operator. Retrying will not help.",
458
+ registrationUrl: urls?.registrationUrl ?? "",
459
+ documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
460
+ steps: [
461
+ "Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
462
+ "Do not retry: the failure is deterministic until the operator updates their key"
463
+ ]
464
+ } : isApiError ? {
431
465
  message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
432
466
  registrationUrl: urls?.registrationUrl ?? "",
433
467
  documentationUrl: urls?.documentationUrl ?? "",
@@ -465,13 +499,22 @@ function createGuidanceResponse(_config, reason, options = {}) {
465
499
  // partners (and their custom onDenied handlers) can branch on
466
500
  // dimension. Without this, the synthesised stub was indistinguishable
467
501
  // from a real policy deny.
468
- failures: isApiError ? [
502
+ failures: isMisconfig ? [
503
+ {
504
+ dimension: "verify_access.merchant_misconfigured",
505
+ message: reason ?? "The integration API key was rejected by AstraSync",
506
+ guidance: guidance.message
507
+ }
508
+ ] : isApiError ? [
469
509
  {
470
510
  dimension: "verify_access.api_error",
471
511
  message: reason ?? "Verification temporarily unavailable",
472
512
  guidance: guidance.message
473
513
  }
474
514
  ] : void 0,
515
+ // 4.0.0: typed marker so adapters render the misconfig envelope (503 +
516
+ // MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
517
+ ...isMisconfig && { misconfigured: true },
475
518
  correlationId: options.correlationId,
476
519
  attemptId: options.attemptId,
477
520
  verifiedAt: /* @__PURE__ */ new Date()
@@ -526,7 +569,8 @@ async function callVerifyAccessAPI(config, request) {
526
569
  const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
527
570
  method: "POST",
528
571
  headers,
529
- body: JSON.stringify(body)
572
+ body: JSON.stringify(body),
573
+ signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
530
574
  });
531
575
  const data = await response.json();
532
576
  if (response.status === 410) {
@@ -550,6 +594,17 @@ async function callVerifyAccessAPI(config, request) {
550
594
  };
551
595
  }
552
596
  if (!response.ok) {
597
+ if (response.status === 401) {
598
+ return {
599
+ success: false,
600
+ error: data.message || data.error || "Integration API key rejected",
601
+ misconfig: true,
602
+ misconfigCode: typeof data?.code === "string" ? data.code : void 0,
603
+ remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
604
+ correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
605
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
606
+ };
607
+ }
553
608
  return {
554
609
  success: false,
555
610
  error: data.message || data.error || `API returned ${response.status}`,
@@ -571,9 +626,19 @@ async function verify(config, request, options) {
571
626
  const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
572
627
  if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
573
628
  if (mergedConfig.strictInit) {
574
- await performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, true);
629
+ await performInitCheck(
630
+ mergedConfig.apiBaseUrl,
631
+ mergedConfig.debug,
632
+ true,
633
+ mergedConfig.apiKey
634
+ );
575
635
  } else {
576
- void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, false);
636
+ void performInitCheck(
637
+ mergedConfig.apiBaseUrl,
638
+ mergedConfig.debug,
639
+ false,
640
+ mergedConfig.apiKey
641
+ );
577
642
  }
578
643
  }
579
644
  if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
@@ -612,9 +677,10 @@ async function verify(config, request, options) {
612
677
  const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
613
678
  if (!apiResponse.success) {
614
679
  return createGuidanceResponse(mergedConfig, apiResponse.error, {
615
- source: "api_error",
680
+ source: apiResponse.misconfig ? "merchant_misconfig" : "api_error",
616
681
  correlationId: apiResponse.correlationId,
617
682
  attemptId: apiResponse.attemptId,
683
+ remediation: apiResponse.remediation,
618
684
  urls
619
685
  });
620
686
  }
@@ -1149,6 +1215,7 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
1149
1215
  }
1150
1216
 
1151
1217
  // src/metadata-capture.ts
1218
+ var CAPTURE_SCHEMA_VERSION = 1;
1152
1219
  var SECRET_HEADER_NAMES = /* @__PURE__ */ new Set([
1153
1220
  "cookie",
1154
1221
  "set-cookie",
@@ -1293,6 +1360,373 @@ function extractPlatformHeaders(sanitized) {
1293
1360
  }
1294
1361
  return out;
1295
1362
  }
1363
+ var CONNECTION_HEADER_SOURCES = [
1364
+ ["ip", ["cf-connecting-ip", "fastly-client-ip", "true-client-ip", "x-real-ip"]],
1365
+ [
1366
+ "country",
1367
+ ["cf-ipcountry", "x-vercel-ip-country", "cloudfront-viewer-country", "fastly-geo-country"]
1368
+ ],
1369
+ ["region", ["x-vercel-ip-country-region", "cloudfront-viewer-country-region"]],
1370
+ ["city", ["x-vercel-ip-city", "cloudfront-viewer-city"]],
1371
+ ["asn", ["cloudfront-viewer-asn"]],
1372
+ ["tlsVersion", ["cloudfront-viewer-tls"]],
1373
+ ["httpVersion", ["cloudfront-viewer-http-version"]],
1374
+ // TLS fingerprints can only be computed where TLS terminates. When a CDN
1375
+ // terminates TLS in front of the merchant, its fingerprint headers ARE the
1376
+ // connection-layer truth — normalising them here is the permanent design.
1377
+ ["tlsFingerprint", ["cf-ja3-hash"]],
1378
+ ["ja4", ["cf-ja4"]]
1379
+ ];
1380
+ function deriveConnectionFromHeaders(headers) {
1381
+ if (!headers) return void 0;
1382
+ const lower = {};
1383
+ for (const name of Object.keys(headers)) {
1384
+ const value = headers[name];
1385
+ if (typeof value === "string" && value.length > 0) lower[name.toLowerCase()] = value;
1386
+ }
1387
+ const connection = {};
1388
+ for (const [key, sources] of CONNECTION_HEADER_SOURCES) {
1389
+ for (const source of sources) {
1390
+ const value = lower[source]?.trim();
1391
+ if (value) {
1392
+ connection[key] = value;
1393
+ break;
1394
+ }
1395
+ }
1396
+ }
1397
+ if (!connection.ip) {
1398
+ const xff = lower["x-forwarded-for"];
1399
+ const client = xff?.split(",")[0]?.trim();
1400
+ if (client) connection.ip = client;
1401
+ }
1402
+ return Object.keys(connection).length > 0 ? connection : void 0;
1403
+ }
1404
+ function buildSdkObservedMetadata(rawHeaders) {
1405
+ const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
1406
+ const flat = {};
1407
+ if (rawHeaders) {
1408
+ for (const name of Object.keys(rawHeaders)) {
1409
+ const value = rawHeaders[name];
1410
+ if (value === void 0) continue;
1411
+ flat[name.toLowerCase()] = Array.isArray(value) ? value.join(", ") : String(value);
1412
+ }
1413
+ }
1414
+ const connection = deriveConnectionFromHeaders(flat);
1415
+ return {
1416
+ headers,
1417
+ ...apiKeyFormat && { apiKeyFormat },
1418
+ ...platformHeaders && { platformHeaders },
1419
+ ...connection && { connection },
1420
+ schemaVersion: CAPTURE_SCHEMA_VERSION
1421
+ };
1422
+ }
1423
+
1424
+ // src/edge-config.ts
1425
+ var DEFAULT_EDGE_CONFIG = Object.freeze({
1426
+ version: 1,
1427
+ mode: "observe",
1428
+ depth: "classify",
1429
+ pathRules: [],
1430
+ sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
1431
+ failurePosture: "open"
1432
+ });
1433
+ var EDGE_MODES = ["observe", "enforce"];
1434
+ var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
1435
+ function isEdgeConfig(value) {
1436
+ if (typeof value !== "object" || value === null) return false;
1437
+ const v = value;
1438
+ if (v.version !== 1) return false;
1439
+ if (!EDGE_MODES.includes(v.mode)) return false;
1440
+ if (!EDGE_DEPTHS.includes(v.depth)) return false;
1441
+ if (!Array.isArray(v.pathRules)) return false;
1442
+ for (const rule of v.pathRules) {
1443
+ if (typeof rule !== "object" || rule === null) return false;
1444
+ const r = rule;
1445
+ if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
1446
+ if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
1447
+ if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
1448
+ }
1449
+ const sampling = v.sampling;
1450
+ if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
1451
+ return false;
1452
+ }
1453
+ return v.failurePosture === "open";
1454
+ }
1455
+ async function fetchEdgeConfig(config, counterpartyId, opts) {
1456
+ if (!counterpartyId) return null;
1457
+ const headers = { Accept: "application/json" };
1458
+ if (config.apiKey) {
1459
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
1460
+ headers["X-API-Key"] = config.apiKey;
1461
+ }
1462
+ if (opts?.etag) headers["If-None-Match"] = opts.etag;
1463
+ try {
1464
+ const response = await fetch(
1465
+ `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
1466
+ { method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
1467
+ );
1468
+ if (response.status === 304) return { notModified: true };
1469
+ if (!response.ok) return null;
1470
+ const body = await response.json();
1471
+ const edgeConfig = body.data?.edgeConfig;
1472
+ if (!isEdgeConfig(edgeConfig)) return null;
1473
+ return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
1474
+ } catch {
1475
+ return null;
1476
+ }
1477
+ }
1478
+ var DEFAULT_TTL_MS = 60 * 1e3;
1479
+ var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
1480
+ var cache2 = /* @__PURE__ */ new Map();
1481
+ var inflight2 = /* @__PURE__ */ new Map();
1482
+ function cacheKey(apiBaseUrl, counterpartyId) {
1483
+ return `${apiBaseUrl}|${counterpartyId}`;
1484
+ }
1485
+ function degradeToObserve(config) {
1486
+ if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
1487
+ return config;
1488
+ }
1489
+ return {
1490
+ ...config,
1491
+ mode: "observe",
1492
+ pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
1493
+ };
1494
+ }
1495
+ async function revalidate(config, counterpartyId) {
1496
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
1497
+ const existing = inflight2.get(key);
1498
+ if (existing) return existing;
1499
+ const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache2.get(key)?.etag }).then((result) => {
1500
+ if (result === null) return;
1501
+ const now = Date.now();
1502
+ if ("notModified" in result) {
1503
+ const entry = cache2.get(key);
1504
+ if (entry) entry.lastSuccessAt = now;
1505
+ return;
1506
+ }
1507
+ cache2.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
1508
+ }).finally(() => {
1509
+ inflight2.delete(key);
1510
+ });
1511
+ inflight2.set(key, promise);
1512
+ return promise;
1513
+ }
1514
+ async function getEdgeConfig(config, counterpartyId, opts) {
1515
+ const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
1516
+ const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
1517
+ const key = cacheKey(config.apiBaseUrl, counterpartyId);
1518
+ const entry = cache2.get(key);
1519
+ if (entry) {
1520
+ const age = Date.now() - entry.lastSuccessAt;
1521
+ if (age > ttlMs) {
1522
+ revalidate(config, counterpartyId).catch(() => {
1523
+ });
1524
+ }
1525
+ return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
1526
+ }
1527
+ await revalidate(config, counterpartyId).catch(() => {
1528
+ });
1529
+ return cache2.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
1530
+ }
1531
+ function matchEdgePathRule(rules, path) {
1532
+ for (const rule of rules) {
1533
+ if (globToRegExp(rule.pattern).test(path)) return rule;
1534
+ }
1535
+ return void 0;
1536
+ }
1537
+ function globToRegExp(pattern) {
1538
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
1539
+ return new RegExp(`^${escaped}$`, "i");
1540
+ }
1541
+ function _resetEdgeConfigCache() {
1542
+ cache2.clear();
1543
+ inflight2.clear();
1544
+ }
1545
+
1546
+ // src/platform-signatures.ts
1547
+ var PLATFORM_AGENT_SIGNATURES = [
1548
+ {
1549
+ vendor: "claude",
1550
+ displayName: "Anthropic Claude",
1551
+ uaPatterns: [/claude/i, /anthropic/i],
1552
+ agentCardPatterns: [/anthropic\.com/i, /claude\.ai/i],
1553
+ apiKeyFormatPatterns: [/^sk-ant/i],
1554
+ headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i]
1555
+ },
1556
+ {
1557
+ vendor: "chatgpt",
1558
+ displayName: "OpenAI ChatGPT",
1559
+ uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\d/i],
1560
+ agentCardPatterns: [/openai\.com/i, /chatgpt\.com/i],
1561
+ apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],
1562
+ headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i]
1563
+ },
1564
+ {
1565
+ vendor: "gemini",
1566
+ displayName: "Google Gemini",
1567
+ uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
1568
+ agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
1569
+ apiKeyFormatPatterns: [/^aiza/i],
1570
+ headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
1571
+ },
1572
+ {
1573
+ vendor: "cursor",
1574
+ displayName: "Cursor",
1575
+ uaPatterns: [/cursor/i],
1576
+ agentCardPatterns: [/cursor\.sh/i, /cursor\.com/i]
1577
+ },
1578
+ {
1579
+ vendor: "goose",
1580
+ displayName: "Block Goose",
1581
+ uaPatterns: [/goose/i, /block-goose/i],
1582
+ agentCardPatterns: [/block\.xyz\/goose/i, /goose\.tools/i]
1583
+ },
1584
+ {
1585
+ vendor: "perplexity",
1586
+ displayName: "Perplexity",
1587
+ uaPatterns: [/perplexity/i],
1588
+ agentCardPatterns: [/perplexity\.ai/i],
1589
+ apiKeyFormatPatterns: [/^pplx-/i]
1590
+ }
1591
+ ];
1592
+ function matchPlatformSignature(signatures, input) {
1593
+ const ua = input.userAgent ?? "";
1594
+ const cardUrl = input.agentCardUrl ?? "";
1595
+ const apiKeyFormat = input.apiKeyFormat ?? "";
1596
+ const headerLines = [];
1597
+ if (input.platformHeaders) {
1598
+ for (const [name, value] of Object.entries(input.platformHeaders)) {
1599
+ headerLines.push(name, `${name}: ${value}`);
1600
+ }
1601
+ }
1602
+ for (const sig of signatures) {
1603
+ const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));
1604
+ const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
1605
+ const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
1606
+ const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
1607
+ if (uaMatch || cardMatch || keyMatch || headerMatch) {
1608
+ const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
1609
+ const cardHost = (() => {
1610
+ try {
1611
+ return cardUrl ? new URL(cardUrl).host : "";
1612
+ } catch {
1613
+ return "";
1614
+ }
1615
+ })();
1616
+ const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
1617
+ return {
1618
+ vendor: sig.vendor,
1619
+ fingerprintKey: `${sig.vendor}:${keyBasis}`,
1620
+ displayName: sig.displayName
1621
+ };
1622
+ }
1623
+ }
1624
+ return void 0;
1625
+ }
1626
+ function detectPlatformFingerprint(input) {
1627
+ return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input);
1628
+ }
1629
+
1630
+ // src/edge-core/classify.ts
1631
+ var STATIC_EXTENSIONS = /\.(css|js|mjs|map|png|jpe?g|gif|webp|avif|svg|ico|woff2?|ttf|otf|eot|mp4|webm|pdf|txt|xml)$/i;
1632
+ var BOT_UA_PATTERN = /curl|wget|python-requests|python-urllib|node-fetch|axios|got|okhttp|go-http-client|libwww|httpie|java\/|ruby|php|scrapy|headless|phantomjs|selenium|playwright|puppeteer|bot|crawler|spider|slurp/i;
1633
+ var BROWSER_UA_PATTERN = /mozilla\/\d/i;
1634
+ var _patterns = { STATIC_EXTENSIONS, BOT_UA_PATTERN, BROWSER_UA_PATTERN };
1635
+
1636
+ // src/edge-core/events.ts
1637
+ function sampled(rate, random = Math.random) {
1638
+ if (rate <= 0) return false;
1639
+ if (rate >= 1) return true;
1640
+ return random() < rate;
1641
+ }
1642
+
1643
+ // src/adapters/anonymous-beacon.ts
1644
+ function readHeader(raw, name) {
1645
+ const value = raw[name];
1646
+ if (typeof value === "string") return value;
1647
+ if (Array.isArray(value)) return value[0];
1648
+ return void 0;
1649
+ }
1650
+ function classifyPassThroughTraffic(path, rawHeaders) {
1651
+ if (_patterns.STATIC_EXTENSIONS.test(path)) return { kind: "never" };
1652
+ const credentials = extractCredentials(rawHeaders, {});
1653
+ if (credentials.astraId || credentials.apiKey || credentials.jwt) {
1654
+ return { kind: "never" };
1655
+ }
1656
+ const userAgent = readHeader(rawHeaders, "user-agent") ?? "";
1657
+ const { apiKeyFormat, platformHeaders } = sanitizeHeaders(rawHeaders);
1658
+ const fingerprint = detectPlatformFingerprint({ userAgent, apiKeyFormat, platformHeaders });
1659
+ if (fingerprint) {
1660
+ return {
1661
+ kind: "platform",
1662
+ protocol: "platform-ua",
1663
+ evidence: { vendor: fingerprint.vendor, userAgent: userAgent || "(none)" }
1664
+ };
1665
+ }
1666
+ if (!userAgent || _patterns.BOT_UA_PATTERN.test(userAgent) || !_patterns.BROWSER_UA_PATTERN.test(userAgent)) {
1667
+ return {
1668
+ kind: "anonymous-bot",
1669
+ protocol: "ua-heuristic",
1670
+ evidence: { userAgent: userAgent || "(none)" }
1671
+ };
1672
+ }
1673
+ if (!readHeader(rawHeaders, "sec-fetch-mode") && !readHeader(rawHeaders, "accept-language")) {
1674
+ return {
1675
+ kind: "anonymous-bot",
1676
+ protocol: "ua-heuristic",
1677
+ evidence: { userAgent, spoofedBrowser: true }
1678
+ };
1679
+ }
1680
+ return { kind: "never" };
1681
+ }
1682
+ function createAnonymousBeacon(config, options) {
1683
+ const counterpartyId = config.counterpartyId;
1684
+ if (!counterpartyId) return () => {
1685
+ };
1686
+ const random = options?.random ?? Math.random;
1687
+ let edgeConfig;
1688
+ let refreshing = false;
1689
+ const refreshConfig = () => {
1690
+ if (refreshing) return;
1691
+ refreshing = true;
1692
+ getEdgeConfig(config, counterpartyId).then((cfg) => {
1693
+ edgeConfig = cfg;
1694
+ }).catch(() => {
1695
+ }).finally(() => {
1696
+ refreshing = false;
1697
+ });
1698
+ };
1699
+ refreshConfig();
1700
+ return (input) => {
1701
+ try {
1702
+ refreshConfig();
1703
+ const cfg = edgeConfig;
1704
+ if (!cfg) return;
1705
+ const traffic = classifyPassThroughTraffic(input.requestPath, input.rawHeaders);
1706
+ if (traffic.kind === "never") return;
1707
+ if (traffic.kind === "anonymous-bot" && !sampled(cfg.sampling.anonymousBeaconRate, random)) {
1708
+ return;
1709
+ }
1710
+ const userAgent = readHeader(input.rawHeaders, "user-agent");
1711
+ const xff = input.rawHeaders["x-forwarded-for"];
1712
+ const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
1713
+ const sourceIp = input.sourceIp ?? xffStr?.split(",")[0]?.trim();
1714
+ reportUnregisteredAttempt(config, {
1715
+ ...input.counterpartyUrl && { counterpartyUrl: input.counterpartyUrl },
1716
+ counterpartyType: options?.counterpartyType ?? config.counterpartyType ?? "api",
1717
+ ...sourceIp && { sourceIp },
1718
+ ...userAgent && { userAgent },
1719
+ requestPath: input.requestPath,
1720
+ requestMethod: input.requestMethod,
1721
+ ...traffic.protocol && { protocol: traffic.protocol },
1722
+ ...traffic.evidence && { evidence: traffic.evidence },
1723
+ observedMetadata: buildSdkObservedMetadata(input.rawHeaders)
1724
+ }).catch(() => {
1725
+ });
1726
+ } catch {
1727
+ }
1728
+ };
1729
+ }
1296
1730
 
1297
1731
  // src/adapters/express.ts
1298
1732
  function defaultExtractCredentials(req) {
@@ -1304,7 +1738,7 @@ function defaultExtractCredentials(req) {
1304
1738
  function extractAstraSyncCredentials(req) {
1305
1739
  return extractHttpCredentials(req.headers);
1306
1740
  }
1307
- function headerValue(value) {
1741
+ function headerValue2(value) {
1308
1742
  if (typeof value === "string") return value;
1309
1743
  if (Array.isArray(value)) return value[0];
1310
1744
  return void 0;
@@ -1312,9 +1746,9 @@ function headerValue(value) {
1312
1746
  function resolveRequestPdlss(req, routeConfig, customExtractPurpose, customExtractAction) {
1313
1747
  return resolveHttpPdlss({
1314
1748
  method: req.method,
1315
- astraPurpose: headerValue(req.headers["x-astra-purpose"]),
1316
- astraAction: headerValue(req.headers["x-astra-action"]),
1317
- legacyPurpose: headerValue(req.headers["x-purpose"] ?? req.headers["X-Purpose"]),
1749
+ astraPurpose: headerValue2(req.headers["x-astra-purpose"]),
1750
+ astraAction: headerValue2(req.headers["x-astra-action"]),
1751
+ legacyPurpose: headerValue2(req.headers["x-purpose"] ?? req.headers["X-Purpose"]),
1318
1752
  queryPurpose: typeof req.query.purpose === "string" ? req.query.purpose : void 0,
1319
1753
  routePurpose: routeConfig?.purpose,
1320
1754
  routeAction: routeConfig?.action,
@@ -1362,6 +1796,20 @@ function dedupeFailures(result) {
1362
1796
  }
1363
1797
  }
1364
1798
  function defaultOnDenied(result, _req, res) {
1799
+ if (result.misconfigured) {
1800
+ res.setHeader("X-Astra-Gateway-Mode", "enforced");
1801
+ res.status(503).json({
1802
+ success: false,
1803
+ error: {
1804
+ code: "MERCHANT_VERIFICATION_MISCONFIGURED",
1805
+ message: result.denialReasons?.[0] || "This site's AstraSync integration is misconfigured",
1806
+ guidance: result.guidance,
1807
+ failures: result.failures,
1808
+ correlationId: result.correlationId
1809
+ }
1810
+ });
1811
+ return;
1812
+ }
1365
1813
  const statusCode = !result.identityVerified ? 401 : 403;
1366
1814
  res.setHeader("X-Astra-Gateway-Mode", "enforced");
1367
1815
  res.status(statusCode).json({
@@ -1383,6 +1831,11 @@ function defaultOnDenied(result, _req, res) {
1383
1831
  }
1384
1832
  var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
1385
1833
  function createMiddleware(options) {
1834
+ if ("routes" in options) {
1835
+ console.warn(
1836
+ "[VerificationGateway] `routes` is dashboard-managed since v2.9.7; this option is ignored \u2014 configure route policy in your AstraSync dashboard."
1837
+ );
1838
+ }
1386
1839
  const {
1387
1840
  extractCredentials: customExtractCredentials,
1388
1841
  extractPurpose: customExtractPurpose,
@@ -1394,12 +1847,25 @@ function createMiddleware(options) {
1394
1847
  routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
1395
1848
  failOnError = "open",
1396
1849
  caseInsensitiveRouteMatch = false,
1850
+ anonymousBeacon = true,
1397
1851
  ...config
1398
1852
  } = options;
1399
1853
  if (config.apiBaseUrl) {
1400
1854
  prefetchWellKnown(config.apiBaseUrl).catch(() => {
1401
1855
  });
1402
1856
  }
1857
+ const emitAnonymousBeacon = anonymousBeacon ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? "api" }) : void 0;
1858
+ const beaconPassThrough = emitAnonymousBeacon ? (req) => {
1859
+ const xff = req.headers["x-forwarded-for"];
1860
+ const xffStr = Array.isArray(xff) ? xff.join(", ") : xff;
1861
+ emitAnonymousBeacon({
1862
+ requestPath: req.path,
1863
+ requestMethod: req.method,
1864
+ counterpartyUrl: config.counterpartyUrl || `${req.protocol}://${req.get("host")}`,
1865
+ sourceIp: req.ip ?? (xffStr ? xffStr.split(",")[0].trim() : void 0),
1866
+ rawHeaders: req.headers
1867
+ });
1868
+ } : void 0;
1403
1869
  let cachedRoutes = [];
1404
1870
  let lastFetchAt = 0;
1405
1871
  let refreshing = null;
@@ -1460,6 +1926,7 @@ function createMiddleware(options) {
1460
1926
  cachedRoutes.length === 0 ? "no-policy" : "no-match"
1461
1927
  );
1462
1928
  }
1929
+ beaconPassThrough?.(req);
1463
1930
  return next();
1464
1931
  }
1465
1932
  const wellKnownUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
@@ -1470,6 +1937,7 @@ function createMiddleware(options) {
1470
1937
  res.setHeader("X-Astra-Gateway-Mode", "unenforced");
1471
1938
  res.setHeader("X-Astra-Gateway-Reason", "route-none");
1472
1939
  }
1940
+ beaconPassThrough?.(req);
1473
1941
  return next();
1474
1942
  }
1475
1943
  const pdlssPair = resolveRequestPdlss(
@@ -1562,16 +2030,10 @@ function createMiddleware(options) {
1562
2030
  forwardedFor: forwardedForStr,
1563
2031
  agentCardUrl,
1564
2032
  // Workstream D — capture EVERY inbound header (SDK-only merchants
1565
- // have no edge to do it upstream). Local string work, secrets
1566
- // stripped; out of the verify cache key so it doesn't defeat caching.
1567
- observedMetadata: (() => {
1568
- const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(req.headers);
1569
- return {
1570
- headers,
1571
- ...apiKeyFormat && { apiKeyFormat },
1572
- ...platformHeaders && { platformHeaders }
1573
- };
1574
- })()
2033
+ // have no edge to do it upstream) plus the CDN-derived connection
2034
+ // block. Local string work, secrets stripped; out of the verify
2035
+ // cache key so it doesn't defeat caching.
2036
+ observedMetadata: buildSdkObservedMetadata(req.headers)
1575
2037
  }
1576
2038
  };
1577
2039
  let result = await verify(config, verificationRequest);
@@ -1765,7 +2227,7 @@ function resolveNextPdlss(request, routeConfig) {
1765
2227
  routeAction: routeConfig?.action
1766
2228
  });
1767
2229
  }
1768
- function generateCommerceShieldHtml(result, options) {
2230
+ function generateInterstitialHtml(result, options) {
1769
2231
  const title = escapeHtml(options.commerceShield?.title || "AstraSync Agent Verification");
1770
2232
  const message = escapeHtml(
1771
2233
  options.commerceShield?.message || result.guidance?.message || "This site verifies AI agents before granting access. We noticed you're visiting without AstraSync credentials."
@@ -1921,13 +2383,31 @@ function generateCommerceShieldHtml(result, options) {
1921
2383
  }
1922
2384
  var DEFAULT_ROUTES_REFRESH_MS2 = 5 * 60 * 1e3;
1923
2385
  function createMiddleware2(options) {
2386
+ if ("routes" in options) {
2387
+ console.warn(
2388
+ "[VerificationGateway/Next.js] `routes` is dashboard-managed since v2.9.7; this option is ignored \u2014 configure route policy in your AstraSync dashboard."
2389
+ );
2390
+ }
1924
2391
  const {
1925
2392
  skipPaths = [],
1926
- showCommerceShield = true,
2393
+ showInterstitial,
2394
+ showCommerceShield,
1927
2395
  enableRuntimeChallenge = true,
1928
2396
  routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS2,
2397
+ anonymousBeacon = true,
1929
2398
  ...config
1930
2399
  } = options;
2400
+ const interstitialEnabled = showInterstitial ?? showCommerceShield ?? true;
2401
+ const emitAnonymousBeacon = anonymousBeacon ? createAnonymousBeacon(config, { counterpartyType: config.counterpartyType ?? "website" }) : void 0;
2402
+ const beaconPassThrough = emitAnonymousBeacon ? (request, pathname) => {
2403
+ emitAnonymousBeacon({
2404
+ requestPath: pathname,
2405
+ requestMethod: request.method,
2406
+ counterpartyUrl: config.counterpartyUrl || request.nextUrl.origin,
2407
+ sourceIp: request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || void 0,
2408
+ rawHeaders: Object.fromEntries(request.headers.entries())
2409
+ });
2410
+ } : void 0;
1931
2411
  let cachedRoutes = [];
1932
2412
  let lastFetchAt = 0;
1933
2413
  let refreshing = null;
@@ -1969,9 +2449,11 @@ function createMiddleware2(options) {
1969
2449
  }
1970
2450
  const routeConfig = findRouteConfig2(cachedRoutes, pathname, request.method);
1971
2451
  if (!routeConfig) {
2452
+ beaconPassThrough?.(request, pathname);
1972
2453
  return NextResponse.next();
1973
2454
  }
1974
2455
  if (routeConfig.minAccessLevel === "none") {
2456
+ beaconPassThrough?.(request, pathname);
1975
2457
  return NextResponse.next();
1976
2458
  }
1977
2459
  const credentials = extractCredentialsFromNextRequest(request);
@@ -2023,8 +2505,8 @@ function createMiddleware2(options) {
2023
2505
  { status: 403 }
2024
2506
  );
2025
2507
  }
2026
- if (showCommerceShield) {
2027
- return new NextResponse(generateCommerceShieldHtml(preCheckResult, options), {
2508
+ if (interstitialEnabled) {
2509
+ return new NextResponse(generateInterstitialHtml(preCheckResult, options), {
2028
2510
  status: 200,
2029
2511
  headers: {
2030
2512
  "Content-Type": "text/html",
@@ -2052,17 +2534,9 @@ function createMiddleware2(options) {
2052
2534
  host: request.headers.get("host") || void 0,
2053
2535
  forwardedFor,
2054
2536
  agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0,
2055
- // Workstream D — full sanitised header capture (Web Headers → plain map).
2056
- observedMetadata: (() => {
2057
- const { headers, apiKeyFormat, platformHeaders } = sanitizeHeaders(
2058
- Object.fromEntries(request.headers.entries())
2059
- );
2060
- return {
2061
- headers,
2062
- ...apiKeyFormat && { apiKeyFormat },
2063
- ...platformHeaders && { platformHeaders }
2064
- };
2065
- })()
2537
+ // Workstream D — full sanitised header capture + CDN-derived
2538
+ // connection block (Web Headers → plain map).
2539
+ observedMetadata: buildSdkObservedMetadata(Object.fromEntries(request.headers.entries()))
2066
2540
  }
2067
2541
  };
2068
2542
  let result = await verify(config, verificationRequest);
@@ -2078,6 +2552,21 @@ function createMiddleware2(options) {
2078
2552
  const approvalRequired = result.identityVerified && result.policyAllowed && requiresHumanApproval(result);
2079
2553
  if (approvalRequired) annotateApprovalRequired(result);
2080
2554
  if (!result.identityVerified || !result.policyAllowed || approvalRequired) {
2555
+ if (result.misconfigured && pathname.startsWith("/api/")) {
2556
+ return NextResponse.json(
2557
+ {
2558
+ success: false,
2559
+ error: {
2560
+ code: "MERCHANT_VERIFICATION_MISCONFIGURED",
2561
+ message: result.denialReasons?.[0] || "This site's AstraSync integration is misconfigured",
2562
+ guidance: result.guidance,
2563
+ failures: result.failures,
2564
+ correlationId: result.correlationId
2565
+ }
2566
+ },
2567
+ { status: 503 }
2568
+ );
2569
+ }
2081
2570
  if (pathname.startsWith("/api/")) {
2082
2571
  return NextResponse.json(
2083
2572
  {
@@ -2102,8 +2591,8 @@ function createMiddleware2(options) {
2102
2591
  }
2103
2592
  );
2104
2593
  }
2105
- if (showCommerceShield) {
2106
- return new NextResponse(generateCommerceShieldHtml(result, options), {
2594
+ if (interstitialEnabled) {
2595
+ return new NextResponse(generateInterstitialHtml(result, options), {
2107
2596
  status: 200,
2108
2597
  headers: {
2109
2598
  "Content-Type": "text/html",
@@ -2191,7 +2680,7 @@ var VerificationGatewayClient = class {
2191
2680
  /**
2192
2681
  * Quick verification — checks credentials and policy in one call.
2193
2682
  *
2194
- * Round-18 G4: return shape mirrors `VerificationResult`'s identity/policy
2683
+ * The return shape mirrors `VerificationResult`'s identity/policy
2195
2684
  * split. Map to HTTP status the same way: `!identityVerified` → 401,
2196
2685
  * `identityVerified && !policyAllowed` → 403.
2197
2686
  */
@@ -2621,8 +3110,8 @@ function extractX402TransactionValue(req) {
2621
3110
  // src/transport/rfc9421.ts
2622
3111
  var import_structured_headers = require("structured-headers");
2623
3112
  function parseRFC9421(headers) {
2624
- const sigInput = readHeader(headers, "signature-input");
2625
- const sig = readHeader(headers, "signature");
3113
+ const sigInput = readHeader2(headers, "signature-input");
3114
+ const sig = readHeader2(headers, "signature");
2626
3115
  if (!sigInput || !sig) return null;
2627
3116
  let inputDict;
2628
3117
  let sigDict;
@@ -2666,7 +3155,7 @@ function parseRFC9421(headers) {
2666
3155
  if (signatures.length === 0) return null;
2667
3156
  return { signatures };
2668
3157
  }
2669
- function readHeader(headers, name) {
3158
+ function readHeader2(headers, name) {
2670
3159
  for (const key of Object.keys(headers)) {
2671
3160
  if (key.toLowerCase() === name) {
2672
3161
  const raw = headers[key];
@@ -2984,11 +3473,11 @@ function extractACPContext(request) {
2984
3473
  const purpose = mapACPRequestToPurpose(method, path);
2985
3474
  const sessionId = extractSessionId2(path);
2986
3475
  const headers = request.headers ?? {};
2987
- const signatureHeader = readHeader2(headers, "signature");
2988
- const timestampHeader = readHeader2(headers, "timestamp");
2989
- const idempotencyKey = readHeader2(headers, "idempotency-key");
2990
- const apiVersion = readHeader2(headers, "api-version");
2991
- const bearer = extractBearer(readHeader2(headers, "authorization"));
3476
+ const signatureHeader = readHeader3(headers, "signature");
3477
+ const timestampHeader = readHeader3(headers, "timestamp");
3478
+ const idempotencyKey = readHeader3(headers, "idempotency-key");
3479
+ const apiVersion = readHeader3(headers, "api-version");
3480
+ const bearer = extractBearer(readHeader3(headers, "authorization"));
2992
3481
  const body = request.body ?? {};
2993
3482
  const merchantId = coerceString3(body.merchant_id ?? body.merchantId);
2994
3483
  const totals = Array.isArray(body.totals) ? body.totals : void 0;
@@ -3056,7 +3545,7 @@ function extractFulfillmentOption(body) {
3056
3545
  }
3057
3546
  return void 0;
3058
3547
  }
3059
- function readHeader2(headers, name) {
3548
+ function readHeader3(headers, name) {
3060
3549
  for (const key of Object.keys(headers)) {
3061
3550
  if (key.toLowerCase() === name) {
3062
3551
  const raw = headers[key];
@@ -3850,9 +4339,9 @@ function toBuf(bytes) {
3850
4339
  new Uint8Array(out).set(bytes);
3851
4340
  return out;
3852
4341
  }
3853
- function checkTimestamp(headerValue2, toleranceSec, nowFn) {
3854
- if (!headerValue2) return { ok: false, error: "missing Timestamp header" };
3855
- const ts = parseTimestamp(headerValue2);
4342
+ function checkTimestamp(headerValue3, toleranceSec, nowFn) {
4343
+ if (!headerValue3) return { ok: false, error: "missing Timestamp header" };
4344
+ const ts = parseTimestamp(headerValue3);
3856
4345
  if (ts === null) return { ok: false, error: "unparseable Timestamp header" };
3857
4346
  const now = nowFn ? nowFn() : Math.floor(Date.now() / 1e3);
3858
4347
  if (Math.abs(now - ts) > toleranceSec) {
@@ -3896,7 +4385,7 @@ async function getSubtle() {
3896
4385
  // src/transport/mpp.ts
3897
4386
  var import_mppx = require("mppx");
3898
4387
  function extractMPPFromRequest(request) {
3899
- const auth = readHeader3(request.headers, "authorization");
4388
+ const auth = readHeader4(request.headers, "authorization");
3900
4389
  if (!auth || !/^\s*Payment\s+/i.test(auth)) return null;
3901
4390
  try {
3902
4391
  const credential = import_mppx.Credential.deserialize(auth);
@@ -3924,7 +4413,7 @@ function extractMPPFromResponse(response) {
3924
4413
  offeredMethods: methods
3925
4414
  };
3926
4415
  }
3927
- const receiptHeader = readHeader3(response.headers, "payment-receipt");
4416
+ const receiptHeader = readHeader4(response.headers, "payment-receipt");
3928
4417
  if (receiptHeader) {
3929
4418
  try {
3930
4419
  const parsed = import_mppx.Receipt.deserialize(receiptHeader);
@@ -3944,7 +4433,7 @@ function extractMPPFromResponse(response) {
3944
4433
  return { kind: "error", error: { type: "invalid-receipt-encoding" } };
3945
4434
  }
3946
4435
  }
3947
- const contentType = readHeader3(response.headers, "content-type");
4436
+ const contentType = readHeader4(response.headers, "content-type");
3948
4437
  if (contentType && /application\/problem\+json/i.test(contentType)) {
3949
4438
  const body = typeof response.body === "object" && response.body !== null ? response.body : {};
3950
4439
  return {
@@ -3967,7 +4456,7 @@ function extractMPPContext(message) {
3967
4456
  return extractMPPFromRequest(message);
3968
4457
  }
3969
4458
  function collectChallenges(response) {
3970
- const wwwAuth = readHeader3(response.headers, "www-authenticate");
4459
+ const wwwAuth = readHeader4(response.headers, "www-authenticate");
3971
4460
  if (!wwwAuth) return [];
3972
4461
  const headers = new Headers();
3973
4462
  headers.set("www-authenticate", wwwAuth);
@@ -3995,7 +4484,7 @@ function summarizeChallenge(ch) {
3995
4484
  opaque: raw.opaque
3996
4485
  };
3997
4486
  }
3998
- function readHeader3(headers, name) {
4487
+ function readHeader4(headers, name) {
3999
4488
  for (const key of Object.keys(headers)) {
4000
4489
  if (key.toLowerCase() === name) {
4001
4490
  const raw = headers[key];
@@ -4084,14 +4573,14 @@ function verifyMPP(input) {
4084
4573
  var import_schemas = require("@x402/core/schemas");
4085
4574
  var import_utils = require("@x402/core/utils");
4086
4575
  function extractX402FromRequest(request) {
4087
- const headerValue2 = readHeader4(request.headers, "x-payment");
4576
+ const headerValue3 = readHeader5(request.headers, "x-payment");
4088
4577
  if (request.body && typeof request.body === "object") {
4089
4578
  const parsed = tryParsePayload(request.body);
4090
4579
  if (parsed) return buildPayloadContext(parsed, "body");
4091
4580
  }
4092
- if (headerValue2) {
4581
+ if (headerValue3) {
4093
4582
  try {
4094
- const decoded = (0, import_utils.safeBase64Decode)(headerValue2);
4583
+ const decoded = (0, import_utils.safeBase64Decode)(headerValue3);
4095
4584
  if (decoded) {
4096
4585
  const json = JSON.parse(decoded);
4097
4586
  const parsed = tryParsePayload(json);
@@ -4114,10 +4603,10 @@ function extractX402FromResponse(response) {
4114
4603
  const parsed = tryParseRequired(response.body);
4115
4604
  if (parsed) return buildRequiredContext(parsed, "body");
4116
4605
  }
4117
- const headerValue2 = readHeader4(response.headers, "x-payment-required");
4118
- if (headerValue2) {
4606
+ const headerValue3 = readHeader5(response.headers, "x-payment-required");
4607
+ if (headerValue3) {
4119
4608
  try {
4120
- const decoded = (0, import_utils.safeBase64Decode)(headerValue2);
4609
+ const decoded = (0, import_utils.safeBase64Decode)(headerValue3);
4121
4610
  if (decoded) {
4122
4611
  const json = JSON.parse(decoded);
4123
4612
  const parsed = tryParseRequired(json);
@@ -4214,7 +4703,7 @@ function coerceVersion(v) {
4214
4703
  if (v === 1 || v === 2) return v;
4215
4704
  return null;
4216
4705
  }
4217
- function readHeader4(headers, name) {
4706
+ function readHeader5(headers, name) {
4218
4707
  if (!headers) return void 0;
4219
4708
  for (const key of Object.keys(headers)) {
4220
4709
  if (key.toLowerCase() === name) {
@@ -4962,8 +5451,11 @@ function mcpToPdlss(parsed, requestPath, headerPurpose, headerAction, toolGate)
4962
5451
  } else if (parsed.actionFromBody && parsed.actionSourceFromBody) {
4963
5452
  action = parsed.actionFromBody;
4964
5453
  actionSource = parsed.actionSourceFromBody;
5454
+ } else if (parsed.method === "tools/call") {
5455
+ action = void 0;
5456
+ actionSource = void 0;
4965
5457
  } else {
4966
- action = parsed.toolName ? parsed.method === "tools/call" ? parsed.toolName : `${parsed.method}:${parsed.toolName}` : parsed.method;
5458
+ action = parsed.toolName ? `${parsed.method}:${parsed.toolName}` : parsed.method;
4967
5459
  actionSource = "transport_layer";
4968
5460
  }
4969
5461
  return { purpose, action, resource, purposeSource, actionSource };
@@ -5001,6 +5493,24 @@ function dedupeFailures2(result) {
5001
5493
  }
5002
5494
  function defaultMcpDenied(result, req, res) {
5003
5495
  const id = req.body?.id ?? null;
5496
+ if (result.misconfigured) {
5497
+ res.setHeader("X-Astra-Gateway-Mode", "enforced");
5498
+ res.status(503).json({
5499
+ jsonrpc: "2.0",
5500
+ id,
5501
+ error: {
5502
+ // -32002 → merchant verification misconfigured (see -32000/-32001 below)
5503
+ code: -32002,
5504
+ message: result.denialReasons?.[0] ?? "This server's AstraSync integration is misconfigured",
5505
+ data: {
5506
+ guidance: result.guidance,
5507
+ failures: result.failures,
5508
+ correlationId: result.correlationId
5509
+ }
5510
+ }
5511
+ });
5512
+ return;
5513
+ }
5004
5514
  const status = !result.identityVerified ? 401 : 403;
5005
5515
  res.setHeader("X-Astra-Gateway-Mode", "enforced");
5006
5516
  res.status(status).json({
@@ -5010,6 +5520,7 @@ function defaultMcpDenied(result, req, res) {
5010
5520
  // JSON-RPC error codes:
5011
5521
  // -32000 → unauthorized (no identity resolved)
5012
5522
  // -32001 → insufficient access (identity OK, policy denied)
5523
+ // -32002 → merchant verification misconfigured (handled above)
5013
5524
  code: !result.identityVerified ? -32e3 : -32001,
5014
5525
  message: result.denialReasons?.[0] ?? "Access denied",
5015
5526
  data: {
@@ -5059,6 +5570,15 @@ function createMcpMiddleware(options) {
5059
5570
  prefetchWellKnown(config.apiBaseUrl).catch(() => {
5060
5571
  });
5061
5572
  }
5573
+ if (toolGates) {
5574
+ for (const [toolName, gate] of Object.entries(toolGates)) {
5575
+ if (typeof gate === "string") {
5576
+ console.warn(
5577
+ `[VerificationGateway/MCP] toolGates['${toolName}'] uses the bare-string shorthand ('${gate}'). Gated tools need a PDLSS purpose (else PDLSS_PURPOSE_REQUIRED 400) and evaluate purpose-only without a declared action. Use the object form instead: { minAccessLevel: '${gate}', purpose: '...', action: '...' }.`
5578
+ );
5579
+ }
5580
+ }
5581
+ }
5062
5582
  return async (req, res, next) => {
5063
5583
  try {
5064
5584
  if (skip) return next();
@@ -5178,7 +5698,13 @@ function createMcpMiddleware(options) {
5178
5698
  callerMetadata: {
5179
5699
  sourceIp: req.ip,
5180
5700
  userAgent: req.headers["user-agent"],
5181
- host: req.headers.host
5701
+ host: req.headers.host,
5702
+ // Capture EVERY inbound header (parity with the express adapter —
5703
+ // MCP-only merchants have no edge to do it upstream) plus the
5704
+ // CDN-derived connection block. Local string work, secrets
5705
+ // stripped; out of the verify cache key so it doesn't defeat
5706
+ // caching.
5707
+ observedMetadata: buildSdkObservedMetadata(req.headers)
5182
5708
  }
5183
5709
  };
5184
5710
  let result = await verify(config, verificationRequest);
@@ -5963,212 +6489,6 @@ async function recordDecision2(config, params) {
5963
6489
  blockchainTxHash: result.blockchainTxHash
5964
6490
  };
5965
6491
  }
5966
-
5967
- // src/edge-config.ts
5968
- var DEFAULT_EDGE_CONFIG = Object.freeze({
5969
- version: 1,
5970
- mode: "observe",
5971
- depth: "classify",
5972
- pathRules: [],
5973
- sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
5974
- failurePosture: "open"
5975
- });
5976
- var EDGE_MODES = ["observe", "enforce"];
5977
- var EDGE_DEPTHS = ["classify", "authenticate", "authorize"];
5978
- function isEdgeConfig(value) {
5979
- if (typeof value !== "object" || value === null) return false;
5980
- const v = value;
5981
- if (v.version !== 1) return false;
5982
- if (!EDGE_MODES.includes(v.mode)) return false;
5983
- if (!EDGE_DEPTHS.includes(v.depth)) return false;
5984
- if (!Array.isArray(v.pathRules)) return false;
5985
- for (const rule of v.pathRules) {
5986
- if (typeof rule !== "object" || rule === null) return false;
5987
- const r = rule;
5988
- if (typeof r.pattern !== "string" || r.pattern.length === 0) return false;
5989
- if (r.mode !== void 0 && !EDGE_MODES.includes(r.mode)) return false;
5990
- if (r.depth !== void 0 && !EDGE_DEPTHS.includes(r.depth)) return false;
5991
- }
5992
- const sampling = v.sampling;
5993
- if (typeof sampling !== "object" || sampling === null || typeof sampling.anonymousBeaconRate !== "number" || sampling.anonymousBeaconRate < 0 || sampling.anonymousBeaconRate > 1) {
5994
- return false;
5995
- }
5996
- return v.failurePosture === "open";
5997
- }
5998
- async function fetchEdgeConfig(config, counterpartyId, opts) {
5999
- if (!counterpartyId) return null;
6000
- const headers = { Accept: "application/json" };
6001
- if (config.apiKey) {
6002
- headers["Authorization"] = `Bearer ${config.apiKey}`;
6003
- headers["X-API-Key"] = config.apiKey;
6004
- }
6005
- if (opts?.etag) headers["If-None-Match"] = opts.etag;
6006
- try {
6007
- const response = await fetch(
6008
- `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/edge-config`,
6009
- { method: "GET", headers, signal: AbortSignal.timeout(opts?.timeoutMs ?? 5e3) }
6010
- );
6011
- if (response.status === 304) return { notModified: true };
6012
- if (!response.ok) return null;
6013
- const body = await response.json();
6014
- const edgeConfig = body.data?.edgeConfig;
6015
- if (!isEdgeConfig(edgeConfig)) return null;
6016
- return { edgeConfig, etag: response.headers.get("etag") ?? void 0 };
6017
- } catch {
6018
- return null;
6019
- }
6020
- }
6021
- var DEFAULT_TTL_MS = 60 * 1e3;
6022
- var DEFAULT_MAX_STALE_MS = 24 * 60 * 60 * 1e3;
6023
- var cache2 = /* @__PURE__ */ new Map();
6024
- var inflight2 = /* @__PURE__ */ new Map();
6025
- function cacheKey(apiBaseUrl, counterpartyId) {
6026
- return `${apiBaseUrl}|${counterpartyId}`;
6027
- }
6028
- function degradeToObserve(config) {
6029
- if (config.mode !== "enforce" && !config.pathRules.some((r) => r.mode === "enforce")) {
6030
- return config;
6031
- }
6032
- return {
6033
- ...config,
6034
- mode: "observe",
6035
- pathRules: config.pathRules.map((r) => r.mode === "enforce" ? { ...r, mode: "observe" } : r)
6036
- };
6037
- }
6038
- async function revalidate(config, counterpartyId) {
6039
- const key = cacheKey(config.apiBaseUrl, counterpartyId);
6040
- const existing = inflight2.get(key);
6041
- if (existing) return existing;
6042
- const promise = fetchEdgeConfig(config, counterpartyId, { etag: cache2.get(key)?.etag }).then((result) => {
6043
- if (result === null) return;
6044
- const now = Date.now();
6045
- if ("notModified" in result) {
6046
- const entry = cache2.get(key);
6047
- if (entry) entry.lastSuccessAt = now;
6048
- return;
6049
- }
6050
- cache2.set(key, { config: result.edgeConfig, etag: result.etag, lastSuccessAt: now });
6051
- }).finally(() => {
6052
- inflight2.delete(key);
6053
- });
6054
- inflight2.set(key, promise);
6055
- return promise;
6056
- }
6057
- async function getEdgeConfig(config, counterpartyId, opts) {
6058
- const ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
6059
- const maxStaleMs = opts?.maxStaleMs ?? DEFAULT_MAX_STALE_MS;
6060
- const key = cacheKey(config.apiBaseUrl, counterpartyId);
6061
- const entry = cache2.get(key);
6062
- if (entry) {
6063
- const age = Date.now() - entry.lastSuccessAt;
6064
- if (age > ttlMs) {
6065
- revalidate(config, counterpartyId).catch(() => {
6066
- });
6067
- }
6068
- return age > maxStaleMs ? degradeToObserve(entry.config) : entry.config;
6069
- }
6070
- await revalidate(config, counterpartyId).catch(() => {
6071
- });
6072
- return cache2.get(key)?.config ?? DEFAULT_EDGE_CONFIG;
6073
- }
6074
- function matchEdgePathRule(rules, path) {
6075
- for (const rule of rules) {
6076
- if (globToRegExp(rule.pattern).test(path)) return rule;
6077
- }
6078
- return void 0;
6079
- }
6080
- function globToRegExp(pattern) {
6081
- const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
6082
- return new RegExp(`^${escaped}$`, "i");
6083
- }
6084
- function _resetEdgeConfigCache() {
6085
- cache2.clear();
6086
- inflight2.clear();
6087
- }
6088
-
6089
- // src/platform-signatures.ts
6090
- var PLATFORM_AGENT_SIGNATURES = [
6091
- {
6092
- vendor: "claude",
6093
- displayName: "Anthropic Claude",
6094
- uaPatterns: [/claude/i, /anthropic/i],
6095
- agentCardPatterns: [/anthropic\.com/i, /claude\.ai/i],
6096
- apiKeyFormatPatterns: [/^sk-ant/i],
6097
- headerPatterns: [/^anthropic-version/i, /^anthropic-beta/i, /^x-anthropic-/i]
6098
- },
6099
- {
6100
- vendor: "chatgpt",
6101
- displayName: "OpenAI ChatGPT",
6102
- uaPatterns: [/chatgpt/i, /openai/i, /gpt-?\d/i],
6103
- agentCardPatterns: [/openai\.com/i, /chatgpt\.com/i],
6104
- apiKeyFormatPatterns: [/^sk-proj/i, /^sk-svcacct/i],
6105
- headerPatterns: [/^openai-organization/i, /^openai-project/i, /^openai-version/i]
6106
- },
6107
- {
6108
- vendor: "gemini",
6109
- displayName: "Google Gemini",
6110
- uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
6111
- agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
6112
- apiKeyFormatPatterns: [/^aiza/i],
6113
- headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
6114
- },
6115
- {
6116
- vendor: "cursor",
6117
- displayName: "Cursor",
6118
- uaPatterns: [/cursor/i],
6119
- agentCardPatterns: [/cursor\.sh/i, /cursor\.com/i]
6120
- },
6121
- {
6122
- vendor: "goose",
6123
- displayName: "Block Goose",
6124
- uaPatterns: [/goose/i, /block-goose/i],
6125
- agentCardPatterns: [/block\.xyz\/goose/i, /goose\.tools/i]
6126
- },
6127
- {
6128
- vendor: "perplexity",
6129
- displayName: "Perplexity",
6130
- uaPatterns: [/perplexity/i],
6131
- agentCardPatterns: [/perplexity\.ai/i],
6132
- apiKeyFormatPatterns: [/^pplx-/i]
6133
- }
6134
- ];
6135
- function matchPlatformSignature(signatures, input) {
6136
- const ua = input.userAgent ?? "";
6137
- const cardUrl = input.agentCardUrl ?? "";
6138
- const apiKeyFormat = input.apiKeyFormat ?? "";
6139
- const headerLines = [];
6140
- if (input.platformHeaders) {
6141
- for (const [name, value] of Object.entries(input.platformHeaders)) {
6142
- headerLines.push(name, `${name}: ${value}`);
6143
- }
6144
- }
6145
- for (const sig of signatures) {
6146
- const uaMatch = sig.uaPatterns?.some((p) => p.test(ua));
6147
- const cardMatch = sig.agentCardPatterns?.some((p) => p.test(cardUrl));
6148
- const keyMatch = apiKeyFormat.length > 0 && sig.apiKeyFormatPatterns?.some((p) => p.test(apiKeyFormat));
6149
- const headerMatch = headerLines.length > 0 && sig.headerPatterns?.some((p) => headerLines.some((line) => p.test(line)));
6150
- if (uaMatch || cardMatch || keyMatch || headerMatch) {
6151
- const uaBase = ua.split(/[\s/]/)[0]?.toLowerCase() ?? "";
6152
- const cardHost = (() => {
6153
- try {
6154
- return cardUrl ? new URL(cardUrl).host : "";
6155
- } catch {
6156
- return "";
6157
- }
6158
- })();
6159
- const keyBasis = uaBase || cardHost || apiKeyFormat || "unknown";
6160
- return {
6161
- vendor: sig.vendor,
6162
- fingerprintKey: `${sig.vendor}:${keyBasis}`,
6163
- displayName: sig.displayName
6164
- };
6165
- }
6166
- }
6167
- return void 0;
6168
- }
6169
- function detectPlatformFingerprint(input) {
6170
- return matchPlatformSignature(PLATFORM_AGENT_SIGNATURES, input);
6171
- }
6172
6492
  // Annotate the CommonJS export names for ESM import in node:
6173
6493
  0 && (module.exports = {
6174
6494
  ACCESS_LEVEL_DESCRIPTIONS,
@@ -6177,6 +6497,7 @@ function detectPlatformFingerprint(input) {
6177
6497
  AstraSync,
6178
6498
  AstraSyncError,
6179
6499
  AuthenticationError,
6500
+ CAPTURE_SCHEMA_VERSION,
6180
6501
  ChallengeHandler,
6181
6502
  DEFAULT_EDGE_CONFIG,
6182
6503
  DEFAULT_TRUST_THRESHOLDS,
@@ -6195,9 +6516,11 @@ function detectPlatformFingerprint(input) {
6195
6516
  authorizeSettlement,
6196
6517
  awaitStepUpApproval,
6197
6518
  buildGuidance,
6519
+ buildSdkObservedMetadata,
6198
6520
  clearCache,
6199
6521
  createMcpMiddleware,
6200
6522
  degradeToObserve,
6523
+ deriveConnectionFromHeaders,
6201
6524
  detectPlatformFingerprint,
6202
6525
  determineAccessLevel,
6203
6526
  express,