@astrasyncai/verification-gateway 5.7.0 → 5.9.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 (106) hide show
  1. package/README.md +37 -1
  2. package/dist/adapters/express.d.mts +1 -1
  3. package/dist/adapters/express.d.ts +1 -1
  4. package/dist/adapters/express.js +41 -7
  5. package/dist/adapters/express.js.map +1 -1
  6. package/dist/adapters/express.mjs +41 -7
  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 +2 -2
  11. package/dist/adapters/mcp.js.map +1 -1
  12. package/dist/adapters/mcp.mjs +2 -2
  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 +41 -7
  17. package/dist/adapters/nextjs.js.map +1 -1
  18. package/dist/adapters/nextjs.mjs +41 -7
  19. package/dist/adapters/nextjs.mjs.map +1 -1
  20. package/dist/adapters/sdk.d.mts +1 -1
  21. package/dist/adapters/sdk.d.ts +1 -1
  22. package/dist/adapters/sdk.js +2 -2
  23. package/dist/adapters/sdk.js.map +1 -1
  24. package/dist/adapters/sdk.mjs +2 -2
  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 +14 -6
  31. package/dist/bin/astrasync-codex-hook.js +14 -6
  32. package/dist/bin/astrasync-guard.js +14 -6
  33. package/dist/bin/astrasync.js +15 -6
  34. package/dist/browser/background.js +14 -6
  35. package/dist/browser/background.js.map +1 -1
  36. package/dist/browser/background.mjs +14 -6
  37. package/dist/browser/background.mjs.map +1 -1
  38. package/dist/cli/index.js +12 -4
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/cli/index.mjs +12 -4
  41. package/dist/cli/index.mjs.map +1 -1
  42. package/dist/codex/index.js +14 -6
  43. package/dist/codex/index.js.map +1 -1
  44. package/dist/codex/index.mjs +14 -6
  45. package/dist/codex/index.mjs.map +1 -1
  46. package/dist/cursor/extension.js +14 -6
  47. package/dist/cursor/extension.js.map +1 -1
  48. package/dist/cursor/extension.mjs +14 -6
  49. package/dist/cursor/extension.mjs.map +1 -1
  50. package/dist/edge-config.d.mts +24 -1
  51. package/dist/edge-config.d.ts +24 -1
  52. package/dist/edge-config.js +13 -5
  53. package/dist/edge-config.js.map +1 -1
  54. package/dist/edge-config.mjs +13 -5
  55. package/dist/edge-config.mjs.map +1 -1
  56. package/dist/edge-core/index.d.mts +14 -6
  57. package/dist/edge-core/index.d.ts +14 -6
  58. package/dist/edge-core/index.js +110 -16
  59. package/dist/edge-core/index.js.map +1 -1
  60. package/dist/edge-core/index.mjs +110 -16
  61. package/dist/edge-core/index.mjs.map +1 -1
  62. package/dist/gateway/gateway.js +14 -6
  63. package/dist/gateway/gateway.js.map +1 -1
  64. package/dist/gateway/gateway.mjs +14 -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 +80 -6
  69. package/dist/index.d.ts +80 -6
  70. package/dist/index.js +54 -7
  71. package/dist/index.js.map +1 -1
  72. package/dist/index.mjs +52 -7
  73. package/dist/index.mjs.map +1 -1
  74. package/dist/metadata-capture.d.mts +18 -1
  75. package/dist/metadata-capture.d.ts +18 -1
  76. package/dist/metadata-capture.js +10 -0
  77. package/dist/metadata-capture.js.map +1 -1
  78. package/dist/metadata-capture.mjs +8 -0
  79. package/dist/metadata-capture.mjs.map +1 -1
  80. package/dist/platform-signatures.d.mts +1 -1
  81. package/dist/platform-signatures.d.ts +1 -1
  82. package/dist/platform-signatures.js +24 -1
  83. package/dist/platform-signatures.js.map +1 -1
  84. package/dist/platform-signatures.mjs +24 -1
  85. package/dist/platform-signatures.mjs.map +1 -1
  86. package/dist/registration/index.js +1 -1
  87. package/dist/registration/index.js.map +1 -1
  88. package/dist/registration/index.mjs +1 -1
  89. package/dist/registration/index.mjs.map +1 -1
  90. package/dist/transport/index.js +1 -1
  91. package/dist/transport/index.js.map +1 -1
  92. package/dist/transport/index.mjs +1 -1
  93. package/dist/transport/index.mjs.map +1 -1
  94. package/dist/{types-BK_pRNSs.d.mts → types-CTmUpNpS.d.mts} +25 -2
  95. package/dist/{types-BK_pRNSs.d.ts → types-CTmUpNpS.d.ts} +25 -2
  96. package/dist/{types-CwY5IY-0.d.ts → types-CtFXmDzm.d.ts} +17 -2
  97. package/dist/{types-BCmHFdkJ.d.mts → types-DQrn_kei.d.mts} +17 -2
  98. package/dist/ui/index.d.mts +1 -1
  99. package/dist/ui/index.d.ts +1 -1
  100. package/dist/verify.d.mts +13 -1
  101. package/dist/verify.d.ts +13 -1
  102. package/dist/verify.js +2 -2
  103. package/dist/verify.js.map +1 -1
  104. package/dist/verify.mjs +2 -2
  105. package/dist/verify.mjs.map +1 -1
  106. package/package.json +3 -3
@@ -43,7 +43,7 @@ __export(edge_core_exports, {
43
43
  module.exports = __toCommonJS(edge_core_exports);
44
44
 
45
45
  // src/version.ts
46
- var SDK_VERSION = "5.7.0";
46
+ var SDK_VERSION = "5.9.0";
47
47
 
48
48
  // src/http.ts
49
49
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -69,7 +69,7 @@ var DEFAULT_EDGE_CONFIG = Object.freeze({
69
69
  mode: "observe",
70
70
  depth: "classify",
71
71
  pathRules: [],
72
- sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
72
+ sampling: Object.freeze({ anonymousBeaconRate: 1 }),
73
73
  failurePosture: "open"
74
74
  });
75
75
  var DEFAULT_TTL_MS = 60 * 1e3;
@@ -155,6 +155,12 @@ var KEY_FORMAT_PREFIXES = [
155
155
  var MAX_HEADERS = 64;
156
156
  var MAX_HEADER_VALUE_BYTES = 1024;
157
157
  var MAX_TOTAL_BYTES = 16 * 1024;
158
+ var DECLARED_SOURCE_MAX = 64;
159
+ var DECLARED_SOURCE_PATTERN = /^[a-z0-9][a-z0-9 ._/-]{0,63}$/;
160
+ function normalizeDeclaredSource(value) {
161
+ const trimmed = value?.trim().slice(0, DECLARED_SOURCE_MAX).toLowerCase();
162
+ return trimmed && DECLARED_SOURCE_PATTERN.test(trimmed) ? trimmed : void 0;
163
+ }
158
164
  function byteLength(s) {
159
165
  let bytes = 0;
160
166
  for (let i = 0; i < s.length; i++) {
@@ -258,7 +264,20 @@ var PLATFORM_AGENT_SIGNATURES = [
258
264
  {
259
265
  vendor: "gemini",
260
266
  displayName: "Google Gemini",
261
- uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
267
+ uaPatterns: [
268
+ /gemini/i,
269
+ /google-gemini/i,
270
+ /bard/i,
271
+ // Google's AI/agent fetcher tokens (VI uplift 1.3). These are the
272
+ // AI-training/agent crawlers, NOT the Search crawler — googlebot IP
273
+ // ranges attribute Search and are deliberately absent from
274
+ // vendor-ip-ranges. Anchored tokens: none appears in stock browser
275
+ // UAs, and `-` counts as a \b boundary so GoogleOther-Image/-Video
276
+ // match too.
277
+ /\bGoogle-Extended\b/i,
278
+ /\bGoogleOther\b/i,
279
+ /\bGoogle-CloudVertexBot\b/i
280
+ ],
262
281
  agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
263
282
  apiKeyFormatPatterns: [/^aiza/i],
264
283
  headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
@@ -304,6 +323,16 @@ var PLATFORM_AGENT_SIGNATURES = [
304
323
  uaPatterns: [/\bcomet\/\d/i],
305
324
  headerPatterns: [/^sec-ch-ua: .*comet/i]
306
325
  },
326
+ // The MCP bridge's own catalog fetches (VI uplift 1.5). Deliberately a
327
+ // DISTINCT UA from `astrasync-sdk/`: bridge fetches are buyer-agent
328
+ // traffic merchants should see (identified · unregistered), so this
329
+ // vendor is kept OUT of the self-traffic filter and the edge's SELF
330
+ // short-circuit.
331
+ {
332
+ vendor: "astrasync-bridge",
333
+ displayName: "AstraSync MCP bridge (buyer-agent catalog fetch)",
334
+ uaPatterns: [/^astrasync-bridge\//i]
335
+ },
307
336
  // Our own SDK self-identifies (sdkFetch stamps this UA) — first-party
308
337
  // traffic must never pollute the unknown/anonymous pool it exists to audit.
309
338
  {
@@ -834,7 +863,7 @@ async function verify(config, request, options) {
834
863
  name: apiResponse.agent.name,
835
864
  trustScore: apiResponse.agent.trustScore,
836
865
  trustLevel: getTrustLevel(apiResponse.agent.trustScore),
837
- blockchainVerified: apiResponse.agent.blockchainStatus === "verified",
866
+ blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
838
867
  status: apiResponse.agent.agentStatus
839
868
  } : void 0;
840
869
  const developer = apiResponse.developer ? {
@@ -934,10 +963,24 @@ function requestUrl(req, host) {
934
963
  const qs = req.querystring ? `?${req.querystring}` : "";
935
964
  return `https://${host}${req.uri}${qs}`;
936
965
  }
937
- function buildObservedMetadata(req) {
966
+ var ATTEMPT_ID_RE = /^att_[0-9a-f]{32}$/;
967
+ function extractAttemptId(req) {
968
+ const header = headerValue(req, "x-astra-attempt-id");
969
+ if (header && ATTEMPT_ID_RE.test(header)) return header;
970
+ if (req.querystring) {
971
+ try {
972
+ const fromQuery = new URLSearchParams(req.querystring).get("astra_attempt");
973
+ if (fromQuery && ATTEMPT_ID_RE.test(fromQuery)) return fromQuery;
974
+ } catch {
975
+ }
976
+ }
977
+ return void 0;
978
+ }
979
+ function buildObservedMetadata(req, queryValueAllowlist) {
938
980
  const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(req.headers);
939
981
  const connection = req.connection ?? {};
940
982
  const queryKeys = extractQueryKeys(req.querystring);
983
+ const queryParams = extractAllowlistedQueryParams(req.querystring, queryValueAllowlist);
941
984
  return {
942
985
  headers,
943
986
  ...apiKeyFormat && { apiKeyFormat },
@@ -945,6 +988,7 @@ function buildObservedMetadata(req) {
945
988
  ...Object.keys(connection).length > 0 && { connection },
946
989
  ...cookieCount !== void 0 && { cookieCount },
947
990
  ...queryKeys && { queryKeys },
991
+ ...queryParams && { queryParams },
948
992
  schemaVersion: CAPTURE_SCHEMA_VERSION
949
993
  };
950
994
  }
@@ -968,6 +1012,29 @@ function extractQueryKeys(querystring) {
968
1012
  }
969
1013
  return keys.length > 0 ? keys : void 0;
970
1014
  }
1015
+ var MAX_QUERY_PARAMS = 16;
1016
+ var MAX_QUERY_VALUE_CHARS = 256;
1017
+ function extractAllowlistedQueryParams(querystring, allowlist) {
1018
+ if (!querystring || !allowlist || allowlist.length === 0) return void 0;
1019
+ let params;
1020
+ try {
1021
+ params = new URLSearchParams(querystring);
1022
+ } catch {
1023
+ return void 0;
1024
+ }
1025
+ const matches = (name) => allowlist.some(
1026
+ (entry) => entry.endsWith("*") ? name.startsWith(entry.slice(0, -1)) : name === entry
1027
+ );
1028
+ const out = {};
1029
+ let count = 0;
1030
+ for (const [key, value] of params.entries()) {
1031
+ const name = key.toLowerCase().slice(0, MAX_QUERY_KEY_CHARS);
1032
+ if (!name || out[name] !== void 0 || !matches(name)) continue;
1033
+ out[name] = value.slice(0, MAX_QUERY_VALUE_CHARS);
1034
+ if (++count >= MAX_QUERY_PARAMS) break;
1035
+ }
1036
+ return count > 0 ? out : void 0;
1037
+ }
971
1038
 
972
1039
  // src/edge-core/detect.ts
973
1040
  var SD_JWT_PATTERN = /^eyJ[\w-]+\.[\w-]*\.[\w-]+~/;
@@ -1127,7 +1194,8 @@ function resolvePolicy(config, path) {
1127
1194
  return {
1128
1195
  mode: rule.mode ?? config.mode,
1129
1196
  depth: rule.depth ?? config.depth,
1130
- skip: rule.skip === true
1197
+ skip: rule.skip === true,
1198
+ ...rule.sampling && { sampling: rule.sampling }
1131
1199
  };
1132
1200
  }
1133
1201
  function classify(req, host, depth) {
@@ -1421,7 +1489,9 @@ async function withBudget(promise, ms) {
1421
1489
  if (timer) clearTimeout(timer);
1422
1490
  }
1423
1491
  }
1424
- async function emitBeacon(options, req, classification, budgetMs) {
1492
+ async function emitBeacon(options, req, classification, budgetMs, queryValueAllowlist) {
1493
+ const attemptId = extractAttemptId(req);
1494
+ const declaredSource = normalizeDeclaredSource(headerValue(req, "x-astra-source"));
1425
1495
  const budgeted = withBudget(
1426
1496
  reportUnregisteredAttempt(
1427
1497
  { apiBaseUrl: options.apiBaseUrl, counterpartyId: options.counterpartyId },
@@ -1432,12 +1502,20 @@ async function emitBeacon(options, req, classification, budgetMs) {
1432
1502
  userAgent: headerValue(req, "user-agent"),
1433
1503
  requestPath: req.uri,
1434
1504
  requestMethod: req.method,
1505
+ // Attempt-chain handle (header or ?astra_attempt= deep link) — joins
1506
+ // this beacon into the agent's research chain via pe_attempt_idx.
1507
+ ...attemptId && { attemptId },
1508
+ // First-class referer + accept: traffic-source and surface-classifier
1509
+ // inputs (previously buried inside observedMetadata.headers).
1510
+ referer: headerValue(req, "referer"),
1511
+ accept: headerValue(req, "accept"),
1512
+ ...declaredSource && { declaredSource },
1435
1513
  // Evidence fields the backend persists into the event record.
1436
1514
  protocol: classification.protocol,
1437
1515
  evidence: classification.evidence,
1438
1516
  // The full sanitized header + connection capture for the
1439
1517
  // unregistered caller (fire-and-forget, so free).
1440
- observedMetadata: buildObservedMetadata(req)
1518
+ observedMetadata: buildObservedMetadata(req, queryValueAllowlist)
1441
1519
  }
1442
1520
  ),
1443
1521
  budgetMs
@@ -1463,13 +1541,14 @@ function baseOutcome(classification) {
1463
1541
  protocol: classification.protocol
1464
1542
  };
1465
1543
  }
1466
- function buildVerificationRequest(options, req, classification, includeArtifacts) {
1544
+ function buildVerificationRequest(options, req, classification, includeArtifacts, queryValueAllowlist) {
1467
1545
  const pdlss = resolveHttpPdlss({
1468
1546
  method: req.method,
1469
1547
  astraPurpose: headerValue(req, "x-astra-purpose"),
1470
1548
  astraAction: headerValue(req, "x-astra-action")
1471
1549
  });
1472
1550
  const attemptId = headerValue(req, "x-astra-attempt-id");
1551
+ const declaredSource = normalizeDeclaredSource(headerValue(req, "x-astra-source"));
1473
1552
  return {
1474
1553
  ...attemptId && /^att_[0-9a-f]{32}$/.test(attemptId) && { attemptId },
1475
1554
  credentials: extractCredentials(req.headers, {}),
@@ -1484,10 +1563,11 @@ function buildVerificationRequest(options, req, classification, includeArtifacts
1484
1563
  userAgent: headerValue(req, "user-agent"),
1485
1564
  referer: headerValue(req, "referer"),
1486
1565
  host: headerValue(req, "host"),
1566
+ ...declaredSource && { declaredSource },
1487
1567
  // The full sanitized header + connection capture. The backend stores
1488
1568
  // it fire-and-forget (zero decision latency) and uses the key-format
1489
1569
  // / platform headers for attribution.
1490
- observedMetadata: buildObservedMetadata(req)
1570
+ observedMetadata: buildObservedMetadata(req, queryValueAllowlist)
1491
1571
  },
1492
1572
  ...includeArtifacts && classification.artifacts && { commerceArtifacts: classification.artifacts }
1493
1573
  };
@@ -1534,7 +1614,8 @@ function unavailableOutcome(classification, policy, reason, correlationId) {
1534
1614
  function isApiErrorResult(result) {
1535
1615
  return (result.failures ?? []).some((f) => f.dimension === "verify_access.api_error") === true && !result.misconfigured;
1536
1616
  }
1537
- async function runTier(options, req, classification, policy, apiKey, sampling) {
1617
+ async function runTier(options, req, classification, policy, apiKey, capture) {
1618
+ const { sampling, queryValueAllowlist } = capture;
1538
1619
  const budgets = options.budgets ?? {};
1539
1620
  const beaconMs = budgets.beaconMs ?? 300;
1540
1621
  const verifyMs = policy.mode === "enforce" ? budgets.verifyEnforceMs ?? 3e3 : budgets.verifyObserveMs ?? 1500;
@@ -1555,7 +1636,13 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1555
1636
  const result = await withBudget(
1556
1637
  verify(
1557
1638
  gatewayConfig,
1558
- buildVerificationRequest(options, req, classification, policy.depth === "authorize")
1639
+ buildVerificationRequest(
1640
+ options,
1641
+ req,
1642
+ classification,
1643
+ policy.depth === "authorize",
1644
+ queryValueAllowlist
1645
+ )
1559
1646
  ),
1560
1647
  verifyMs
1561
1648
  );
@@ -1579,7 +1666,10 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1579
1666
  case "identified": {
1580
1667
  if (policy.depth === "authorize" && classification.artifacts) {
1581
1668
  const result = await withBudget(
1582
- verify(gatewayConfig, buildVerificationRequest(options, req, classification, true)),
1669
+ verify(
1670
+ gatewayConfig,
1671
+ buildVerificationRequest(options, req, classification, true, queryValueAllowlist)
1672
+ ),
1583
1673
  verifyMs
1584
1674
  );
1585
1675
  if (!result) {
@@ -1599,7 +1689,7 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1599
1689
  }
1600
1690
  return outcomeFromVerifyResult(classification, result);
1601
1691
  }
1602
- await emitBeacon(options, req, classification, beaconMs);
1692
+ await emitBeacon(options, req, classification, beaconMs, queryValueAllowlist);
1603
1693
  const outcome = baseOutcome(classification);
1604
1694
  if (policy.mode === "enforce" && policy.depth !== "classify") {
1605
1695
  outcome.decision = "deny";
@@ -1613,7 +1703,8 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1613
1703
  options,
1614
1704
  req,
1615
1705
  { ...classification, protocol: classification.protocol ?? "ua-heuristic" },
1616
- beaconMs
1706
+ beaconMs,
1707
+ queryValueAllowlist
1617
1708
  );
1618
1709
  }
1619
1710
  return baseOutcome(classification);
@@ -1640,7 +1731,10 @@ async function evaluateEdgeRequest(options, req, config, apiKey) {
1640
1731
  if (classification.tier === "human" || classification.tier === "self") {
1641
1732
  return { policy, classification, application: passUntouched() };
1642
1733
  }
1643
- const outcome = await runTier(options, req, classification, policy, apiKey, config.sampling);
1734
+ const outcome = await runTier(options, req, classification, policy, apiKey, {
1735
+ sampling: policy.sampling ?? config.sampling,
1736
+ queryValueAllowlist: config.queryValueAllowlist
1737
+ });
1644
1738
  if (outcome.decision !== "allow") {
1645
1739
  options.log?.(
1646
1740
  "info",