@astrasyncai/verification-gateway 5.8.0 → 5.10.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 +1 -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 +56 -7
  5. package/dist/adapters/express.js.map +1 -1
  6. package/dist/adapters/express.mjs +56 -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 +20 -2
  11. package/dist/adapters/mcp.js.map +1 -1
  12. package/dist/adapters/mcp.mjs +20 -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 +56 -7
  17. package/dist/adapters/nextjs.js.map +1 -1
  18. package/dist/adapters/nextjs.mjs +56 -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 +20 -2
  23. package/dist/adapters/sdk.js.map +1 -1
  24. package/dist/adapters/sdk.mjs +20 -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 +32 -6
  31. package/dist/bin/astrasync-codex-hook.js +32 -6
  32. package/dist/bin/astrasync-guard.js +32 -6
  33. package/dist/bin/astrasync.js +33 -6
  34. package/dist/browser/background.js +32 -6
  35. package/dist/browser/background.js.map +1 -1
  36. package/dist/browser/background.mjs +32 -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 +32 -6
  43. package/dist/codex/index.js.map +1 -1
  44. package/dist/codex/index.mjs +32 -6
  45. package/dist/codex/index.mjs.map +1 -1
  46. package/dist/cursor/extension.js +32 -6
  47. package/dist/cursor/extension.js.map +1 -1
  48. package/dist/cursor/extension.mjs +32 -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 +129 -17
  59. package/dist/edge-core/index.js.map +1 -1
  60. package/dist/edge-core/index.mjs +129 -17
  61. package/dist/edge-core/index.mjs.map +1 -1
  62. package/dist/gateway/gateway.js +32 -6
  63. package/dist/gateway/gateway.js.map +1 -1
  64. package/dist/gateway/gateway.mjs +32 -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 +73 -6
  69. package/dist/index.d.ts +73 -6
  70. package/dist/index.js +66 -7
  71. package/dist/index.js.map +1 -1
  72. package/dist/index.mjs +64 -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 +20 -2
  103. package/dist/verify.js.map +1 -1
  104. package/dist/verify.mjs +20 -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.8.0";
46
+ var SDK_VERSION = "5.10.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
  {
@@ -695,6 +724,24 @@ async function callVerifyAccessAPI(config, request) {
695
724
  }
696
725
  };
697
726
  }
727
+ if (response.status === 400 && data?.error === "INVALID_AGENT_ID") {
728
+ const message = typeof data?.message === "string" ? data.message : "Agent identifier must be a canonical ASTRA-* id.";
729
+ return {
730
+ success: true,
731
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
732
+ access: {
733
+ allowed: false,
734
+ reason: "invalid_agent_id",
735
+ failures: [
736
+ {
737
+ dimension: "identity.invalid_agent_id",
738
+ message,
739
+ guidance: typeof data?.guidance === "string" ? data.guidance : "Present your canonical ASTRA-* id (discover it via GET /api/agents/request-registration/{requestId} after owner approval)."
740
+ }
741
+ ]
742
+ }
743
+ };
744
+ }
698
745
  if (!response.ok) {
699
746
  if (response.status === 401) {
700
747
  return {
@@ -834,7 +881,7 @@ async function verify(config, request, options) {
834
881
  name: apiResponse.agent.name,
835
882
  trustScore: apiResponse.agent.trustScore,
836
883
  trustLevel: getTrustLevel(apiResponse.agent.trustScore),
837
- blockchainVerified: apiResponse.agent.blockchainStatus === "verified",
884
+ blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
838
885
  status: apiResponse.agent.agentStatus
839
886
  } : void 0;
840
887
  const developer = apiResponse.developer ? {
@@ -934,10 +981,24 @@ function requestUrl(req, host) {
934
981
  const qs = req.querystring ? `?${req.querystring}` : "";
935
982
  return `https://${host}${req.uri}${qs}`;
936
983
  }
937
- function buildObservedMetadata(req) {
984
+ var ATTEMPT_ID_RE = /^att_[0-9a-f]{32}$/;
985
+ function extractAttemptId(req) {
986
+ const header = headerValue(req, "x-astra-attempt-id");
987
+ if (header && ATTEMPT_ID_RE.test(header)) return header;
988
+ if (req.querystring) {
989
+ try {
990
+ const fromQuery = new URLSearchParams(req.querystring).get("astra_attempt");
991
+ if (fromQuery && ATTEMPT_ID_RE.test(fromQuery)) return fromQuery;
992
+ } catch {
993
+ }
994
+ }
995
+ return void 0;
996
+ }
997
+ function buildObservedMetadata(req, queryValueAllowlist) {
938
998
  const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(req.headers);
939
999
  const connection = req.connection ?? {};
940
1000
  const queryKeys = extractQueryKeys(req.querystring);
1001
+ const queryParams = extractAllowlistedQueryParams(req.querystring, queryValueAllowlist);
941
1002
  return {
942
1003
  headers,
943
1004
  ...apiKeyFormat && { apiKeyFormat },
@@ -945,6 +1006,7 @@ function buildObservedMetadata(req) {
945
1006
  ...Object.keys(connection).length > 0 && { connection },
946
1007
  ...cookieCount !== void 0 && { cookieCount },
947
1008
  ...queryKeys && { queryKeys },
1009
+ ...queryParams && { queryParams },
948
1010
  schemaVersion: CAPTURE_SCHEMA_VERSION
949
1011
  };
950
1012
  }
@@ -968,6 +1030,29 @@ function extractQueryKeys(querystring) {
968
1030
  }
969
1031
  return keys.length > 0 ? keys : void 0;
970
1032
  }
1033
+ var MAX_QUERY_PARAMS = 16;
1034
+ var MAX_QUERY_VALUE_CHARS = 256;
1035
+ function extractAllowlistedQueryParams(querystring, allowlist) {
1036
+ if (!querystring || !allowlist || allowlist.length === 0) return void 0;
1037
+ let params;
1038
+ try {
1039
+ params = new URLSearchParams(querystring);
1040
+ } catch {
1041
+ return void 0;
1042
+ }
1043
+ const matches = (name) => allowlist.some(
1044
+ (entry) => entry.endsWith("*") ? name.startsWith(entry.slice(0, -1)) : name === entry
1045
+ );
1046
+ const out = {};
1047
+ let count = 0;
1048
+ for (const [key, value] of params.entries()) {
1049
+ const name = key.toLowerCase().slice(0, MAX_QUERY_KEY_CHARS);
1050
+ if (!name || out[name] !== void 0 || !matches(name)) continue;
1051
+ out[name] = value.slice(0, MAX_QUERY_VALUE_CHARS);
1052
+ if (++count >= MAX_QUERY_PARAMS) break;
1053
+ }
1054
+ return count > 0 ? out : void 0;
1055
+ }
971
1056
 
972
1057
  // src/edge-core/detect.ts
973
1058
  var SD_JWT_PATTERN = /^eyJ[\w-]+\.[\w-]*\.[\w-]+~/;
@@ -1127,7 +1212,8 @@ function resolvePolicy(config, path) {
1127
1212
  return {
1128
1213
  mode: rule.mode ?? config.mode,
1129
1214
  depth: rule.depth ?? config.depth,
1130
- skip: rule.skip === true
1215
+ skip: rule.skip === true,
1216
+ ...rule.sampling && { sampling: rule.sampling }
1131
1217
  };
1132
1218
  }
1133
1219
  function classify(req, host, depth) {
@@ -1139,7 +1225,7 @@ function classify(req, host, depth) {
1139
1225
  if (!credentials.astraId && (isAccountApiKey(credentials.jwt) || isAccountApiKey(credentials.apiKey))) {
1140
1226
  return { tier: "self", evidence: { firstPartyApiKey: true } };
1141
1227
  }
1142
- if (credentials.astraId || credentials.apiKey || credentials.jwt) {
1228
+ if (credentials.astraId) {
1143
1229
  return { tier: "verified", protocol: "x-astra" };
1144
1230
  }
1145
1231
  const { apiKeyFormat, platformHeaders } = sanitizeHeaders(req.headers);
@@ -1421,7 +1507,9 @@ async function withBudget(promise, ms) {
1421
1507
  if (timer) clearTimeout(timer);
1422
1508
  }
1423
1509
  }
1424
- async function emitBeacon(options, req, classification, budgetMs) {
1510
+ async function emitBeacon(options, req, classification, budgetMs, queryValueAllowlist) {
1511
+ const attemptId = extractAttemptId(req);
1512
+ const declaredSource = normalizeDeclaredSource(headerValue(req, "x-astra-source"));
1425
1513
  const budgeted = withBudget(
1426
1514
  reportUnregisteredAttempt(
1427
1515
  { apiBaseUrl: options.apiBaseUrl, counterpartyId: options.counterpartyId },
@@ -1432,12 +1520,20 @@ async function emitBeacon(options, req, classification, budgetMs) {
1432
1520
  userAgent: headerValue(req, "user-agent"),
1433
1521
  requestPath: req.uri,
1434
1522
  requestMethod: req.method,
1523
+ // Attempt-chain handle (header or ?astra_attempt= deep link) — joins
1524
+ // this beacon into the agent's research chain via pe_attempt_idx.
1525
+ ...attemptId && { attemptId },
1526
+ // First-class referer + accept: traffic-source and surface-classifier
1527
+ // inputs (previously buried inside observedMetadata.headers).
1528
+ referer: headerValue(req, "referer"),
1529
+ accept: headerValue(req, "accept"),
1530
+ ...declaredSource && { declaredSource },
1435
1531
  // Evidence fields the backend persists into the event record.
1436
1532
  protocol: classification.protocol,
1437
1533
  evidence: classification.evidence,
1438
1534
  // The full sanitized header + connection capture for the
1439
1535
  // unregistered caller (fire-and-forget, so free).
1440
- observedMetadata: buildObservedMetadata(req)
1536
+ observedMetadata: buildObservedMetadata(req, queryValueAllowlist)
1441
1537
  }
1442
1538
  ),
1443
1539
  budgetMs
@@ -1463,13 +1559,14 @@ function baseOutcome(classification) {
1463
1559
  protocol: classification.protocol
1464
1560
  };
1465
1561
  }
1466
- function buildVerificationRequest(options, req, classification, includeArtifacts) {
1562
+ function buildVerificationRequest(options, req, classification, includeArtifacts, queryValueAllowlist) {
1467
1563
  const pdlss = resolveHttpPdlss({
1468
1564
  method: req.method,
1469
1565
  astraPurpose: headerValue(req, "x-astra-purpose"),
1470
1566
  astraAction: headerValue(req, "x-astra-action")
1471
1567
  });
1472
1568
  const attemptId = headerValue(req, "x-astra-attempt-id");
1569
+ const declaredSource = normalizeDeclaredSource(headerValue(req, "x-astra-source"));
1473
1570
  return {
1474
1571
  ...attemptId && /^att_[0-9a-f]{32}$/.test(attemptId) && { attemptId },
1475
1572
  credentials: extractCredentials(req.headers, {}),
@@ -1484,10 +1581,11 @@ function buildVerificationRequest(options, req, classification, includeArtifacts
1484
1581
  userAgent: headerValue(req, "user-agent"),
1485
1582
  referer: headerValue(req, "referer"),
1486
1583
  host: headerValue(req, "host"),
1584
+ ...declaredSource && { declaredSource },
1487
1585
  // The full sanitized header + connection capture. The backend stores
1488
1586
  // it fire-and-forget (zero decision latency) and uses the key-format
1489
1587
  // / platform headers for attribution.
1490
- observedMetadata: buildObservedMetadata(req)
1588
+ observedMetadata: buildObservedMetadata(req, queryValueAllowlist)
1491
1589
  },
1492
1590
  ...includeArtifacts && classification.artifacts && { commerceArtifacts: classification.artifacts }
1493
1591
  };
@@ -1534,7 +1632,8 @@ function unavailableOutcome(classification, policy, reason, correlationId) {
1534
1632
  function isApiErrorResult(result) {
1535
1633
  return (result.failures ?? []).some((f) => f.dimension === "verify_access.api_error") === true && !result.misconfigured;
1536
1634
  }
1537
- async function runTier(options, req, classification, policy, apiKey, sampling) {
1635
+ async function runTier(options, req, classification, policy, apiKey, capture) {
1636
+ const { sampling, queryValueAllowlist } = capture;
1538
1637
  const budgets = options.budgets ?? {};
1539
1638
  const beaconMs = budgets.beaconMs ?? 300;
1540
1639
  const verifyMs = policy.mode === "enforce" ? budgets.verifyEnforceMs ?? 3e3 : budgets.verifyObserveMs ?? 1500;
@@ -1555,7 +1654,13 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1555
1654
  const result = await withBudget(
1556
1655
  verify(
1557
1656
  gatewayConfig,
1558
- buildVerificationRequest(options, req, classification, policy.depth === "authorize")
1657
+ buildVerificationRequest(
1658
+ options,
1659
+ req,
1660
+ classification,
1661
+ policy.depth === "authorize",
1662
+ queryValueAllowlist
1663
+ )
1559
1664
  ),
1560
1665
  verifyMs
1561
1666
  );
@@ -1579,7 +1684,10 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1579
1684
  case "identified": {
1580
1685
  if (policy.depth === "authorize" && classification.artifacts) {
1581
1686
  const result = await withBudget(
1582
- verify(gatewayConfig, buildVerificationRequest(options, req, classification, true)),
1687
+ verify(
1688
+ gatewayConfig,
1689
+ buildVerificationRequest(options, req, classification, true, queryValueAllowlist)
1690
+ ),
1583
1691
  verifyMs
1584
1692
  );
1585
1693
  if (!result) {
@@ -1599,7 +1707,7 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1599
1707
  }
1600
1708
  return outcomeFromVerifyResult(classification, result);
1601
1709
  }
1602
- await emitBeacon(options, req, classification, beaconMs);
1710
+ await emitBeacon(options, req, classification, beaconMs, queryValueAllowlist);
1603
1711
  const outcome = baseOutcome(classification);
1604
1712
  if (policy.mode === "enforce" && policy.depth !== "classify") {
1605
1713
  outcome.decision = "deny";
@@ -1613,7 +1721,8 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1613
1721
  options,
1614
1722
  req,
1615
1723
  { ...classification, protocol: classification.protocol ?? "ua-heuristic" },
1616
- beaconMs
1724
+ beaconMs,
1725
+ queryValueAllowlist
1617
1726
  );
1618
1727
  }
1619
1728
  return baseOutcome(classification);
@@ -1640,7 +1749,10 @@ async function evaluateEdgeRequest(options, req, config, apiKey) {
1640
1749
  if (classification.tier === "human" || classification.tier === "self") {
1641
1750
  return { policy, classification, application: passUntouched() };
1642
1751
  }
1643
- const outcome = await runTier(options, req, classification, policy, apiKey, config.sampling);
1752
+ const outcome = await runTier(options, req, classification, policy, apiKey, {
1753
+ sampling: policy.sampling ?? config.sampling,
1754
+ queryValueAllowlist: config.queryValueAllowlist
1755
+ });
1644
1756
  if (outcome.decision !== "allow") {
1645
1757
  options.log?.(
1646
1758
  "info",