@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
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var SDK_VERSION = "5.8.0";
2
+ var SDK_VERSION = "5.10.0";
3
3
 
4
4
  // src/http.ts
5
5
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -25,7 +25,7 @@ var DEFAULT_EDGE_CONFIG = Object.freeze({
25
25
  mode: "observe",
26
26
  depth: "classify",
27
27
  pathRules: [],
28
- sampling: Object.freeze({ anonymousBeaconRate: 0.1 }),
28
+ sampling: Object.freeze({ anonymousBeaconRate: 1 }),
29
29
  failurePosture: "open"
30
30
  });
31
31
  var DEFAULT_TTL_MS = 60 * 1e3;
@@ -111,6 +111,12 @@ var KEY_FORMAT_PREFIXES = [
111
111
  var MAX_HEADERS = 64;
112
112
  var MAX_HEADER_VALUE_BYTES = 1024;
113
113
  var MAX_TOTAL_BYTES = 16 * 1024;
114
+ var DECLARED_SOURCE_MAX = 64;
115
+ var DECLARED_SOURCE_PATTERN = /^[a-z0-9][a-z0-9 ._/-]{0,63}$/;
116
+ function normalizeDeclaredSource(value) {
117
+ const trimmed = value?.trim().slice(0, DECLARED_SOURCE_MAX).toLowerCase();
118
+ return trimmed && DECLARED_SOURCE_PATTERN.test(trimmed) ? trimmed : void 0;
119
+ }
114
120
  function byteLength(s) {
115
121
  let bytes = 0;
116
122
  for (let i = 0; i < s.length; i++) {
@@ -214,7 +220,20 @@ var PLATFORM_AGENT_SIGNATURES = [
214
220
  {
215
221
  vendor: "gemini",
216
222
  displayName: "Google Gemini",
217
- uaPatterns: [/gemini/i, /google-gemini/i, /bard/i],
223
+ uaPatterns: [
224
+ /gemini/i,
225
+ /google-gemini/i,
226
+ /bard/i,
227
+ // Google's AI/agent fetcher tokens (VI uplift 1.3). These are the
228
+ // AI-training/agent crawlers, NOT the Search crawler — googlebot IP
229
+ // ranges attribute Search and are deliberately absent from
230
+ // vendor-ip-ranges. Anchored tokens: none appears in stock browser
231
+ // UAs, and `-` counts as a \b boundary so GoogleOther-Image/-Video
232
+ // match too.
233
+ /\bGoogle-Extended\b/i,
234
+ /\bGoogleOther\b/i,
235
+ /\bGoogle-CloudVertexBot\b/i
236
+ ],
218
237
  agentCardPatterns: [/gemini\.google\.com/i, /ai\.google\.dev/i],
219
238
  apiKeyFormatPatterns: [/^aiza/i],
220
239
  headerPatterns: [/^x-goog-user-project/i, /^x-goog-api-client/i]
@@ -260,6 +279,16 @@ var PLATFORM_AGENT_SIGNATURES = [
260
279
  uaPatterns: [/\bcomet\/\d/i],
261
280
  headerPatterns: [/^sec-ch-ua: .*comet/i]
262
281
  },
282
+ // The MCP bridge's own catalog fetches (VI uplift 1.5). Deliberately a
283
+ // DISTINCT UA from `astrasync-sdk/`: bridge fetches are buyer-agent
284
+ // traffic merchants should see (identified · unregistered), so this
285
+ // vendor is kept OUT of the self-traffic filter and the edge's SELF
286
+ // short-circuit.
287
+ {
288
+ vendor: "astrasync-bridge",
289
+ displayName: "AstraSync MCP bridge (buyer-agent catalog fetch)",
290
+ uaPatterns: [/^astrasync-bridge\//i]
291
+ },
263
292
  // Our own SDK self-identifies (sdkFetch stamps this UA) — first-party
264
293
  // traffic must never pollute the unknown/anonymous pool it exists to audit.
265
294
  {
@@ -651,6 +680,24 @@ async function callVerifyAccessAPI(config, request) {
651
680
  }
652
681
  };
653
682
  }
683
+ if (response.status === 400 && data?.error === "INVALID_AGENT_ID") {
684
+ const message = typeof data?.message === "string" ? data.message : "Agent identifier must be a canonical ASTRA-* id.";
685
+ return {
686
+ success: true,
687
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
688
+ access: {
689
+ allowed: false,
690
+ reason: "invalid_agent_id",
691
+ failures: [
692
+ {
693
+ dimension: "identity.invalid_agent_id",
694
+ message,
695
+ guidance: typeof data?.guidance === "string" ? data.guidance : "Present your canonical ASTRA-* id (discover it via GET /api/agents/request-registration/{requestId} after owner approval)."
696
+ }
697
+ ]
698
+ }
699
+ };
700
+ }
654
701
  if (!response.ok) {
655
702
  if (response.status === 401) {
656
703
  return {
@@ -790,7 +837,7 @@ async function verify(config, request, options) {
790
837
  name: apiResponse.agent.name,
791
838
  trustScore: apiResponse.agent.trustScore,
792
839
  trustLevel: getTrustLevel(apiResponse.agent.trustScore),
793
- blockchainVerified: apiResponse.agent.blockchainStatus === "verified",
840
+ blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
794
841
  status: apiResponse.agent.agentStatus
795
842
  } : void 0;
796
843
  const developer = apiResponse.developer ? {
@@ -890,10 +937,24 @@ function requestUrl(req, host) {
890
937
  const qs = req.querystring ? `?${req.querystring}` : "";
891
938
  return `https://${host}${req.uri}${qs}`;
892
939
  }
893
- function buildObservedMetadata(req) {
940
+ var ATTEMPT_ID_RE = /^att_[0-9a-f]{32}$/;
941
+ function extractAttemptId(req) {
942
+ const header = headerValue(req, "x-astra-attempt-id");
943
+ if (header && ATTEMPT_ID_RE.test(header)) return header;
944
+ if (req.querystring) {
945
+ try {
946
+ const fromQuery = new URLSearchParams(req.querystring).get("astra_attempt");
947
+ if (fromQuery && ATTEMPT_ID_RE.test(fromQuery)) return fromQuery;
948
+ } catch {
949
+ }
950
+ }
951
+ return void 0;
952
+ }
953
+ function buildObservedMetadata(req, queryValueAllowlist) {
894
954
  const { headers, apiKeyFormat, platformHeaders, cookieCount } = sanitizeHeaders(req.headers);
895
955
  const connection = req.connection ?? {};
896
956
  const queryKeys = extractQueryKeys(req.querystring);
957
+ const queryParams = extractAllowlistedQueryParams(req.querystring, queryValueAllowlist);
897
958
  return {
898
959
  headers,
899
960
  ...apiKeyFormat && { apiKeyFormat },
@@ -901,6 +962,7 @@ function buildObservedMetadata(req) {
901
962
  ...Object.keys(connection).length > 0 && { connection },
902
963
  ...cookieCount !== void 0 && { cookieCount },
903
964
  ...queryKeys && { queryKeys },
965
+ ...queryParams && { queryParams },
904
966
  schemaVersion: CAPTURE_SCHEMA_VERSION
905
967
  };
906
968
  }
@@ -924,6 +986,29 @@ function extractQueryKeys(querystring) {
924
986
  }
925
987
  return keys.length > 0 ? keys : void 0;
926
988
  }
989
+ var MAX_QUERY_PARAMS = 16;
990
+ var MAX_QUERY_VALUE_CHARS = 256;
991
+ function extractAllowlistedQueryParams(querystring, allowlist) {
992
+ if (!querystring || !allowlist || allowlist.length === 0) return void 0;
993
+ let params;
994
+ try {
995
+ params = new URLSearchParams(querystring);
996
+ } catch {
997
+ return void 0;
998
+ }
999
+ const matches = (name) => allowlist.some(
1000
+ (entry) => entry.endsWith("*") ? name.startsWith(entry.slice(0, -1)) : name === entry
1001
+ );
1002
+ const out = {};
1003
+ let count = 0;
1004
+ for (const [key, value] of params.entries()) {
1005
+ const name = key.toLowerCase().slice(0, MAX_QUERY_KEY_CHARS);
1006
+ if (!name || out[name] !== void 0 || !matches(name)) continue;
1007
+ out[name] = value.slice(0, MAX_QUERY_VALUE_CHARS);
1008
+ if (++count >= MAX_QUERY_PARAMS) break;
1009
+ }
1010
+ return count > 0 ? out : void 0;
1011
+ }
927
1012
 
928
1013
  // src/edge-core/detect.ts
929
1014
  var SD_JWT_PATTERN = /^eyJ[\w-]+\.[\w-]*\.[\w-]+~/;
@@ -1083,7 +1168,8 @@ function resolvePolicy(config, path) {
1083
1168
  return {
1084
1169
  mode: rule.mode ?? config.mode,
1085
1170
  depth: rule.depth ?? config.depth,
1086
- skip: rule.skip === true
1171
+ skip: rule.skip === true,
1172
+ ...rule.sampling && { sampling: rule.sampling }
1087
1173
  };
1088
1174
  }
1089
1175
  function classify(req, host, depth) {
@@ -1095,7 +1181,7 @@ function classify(req, host, depth) {
1095
1181
  if (!credentials.astraId && (isAccountApiKey(credentials.jwt) || isAccountApiKey(credentials.apiKey))) {
1096
1182
  return { tier: "self", evidence: { firstPartyApiKey: true } };
1097
1183
  }
1098
- if (credentials.astraId || credentials.apiKey || credentials.jwt) {
1184
+ if (credentials.astraId) {
1099
1185
  return { tier: "verified", protocol: "x-astra" };
1100
1186
  }
1101
1187
  const { apiKeyFormat, platformHeaders } = sanitizeHeaders(req.headers);
@@ -1377,7 +1463,9 @@ async function withBudget(promise, ms) {
1377
1463
  if (timer) clearTimeout(timer);
1378
1464
  }
1379
1465
  }
1380
- async function emitBeacon(options, req, classification, budgetMs) {
1466
+ async function emitBeacon(options, req, classification, budgetMs, queryValueAllowlist) {
1467
+ const attemptId = extractAttemptId(req);
1468
+ const declaredSource = normalizeDeclaredSource(headerValue(req, "x-astra-source"));
1381
1469
  const budgeted = withBudget(
1382
1470
  reportUnregisteredAttempt(
1383
1471
  { apiBaseUrl: options.apiBaseUrl, counterpartyId: options.counterpartyId },
@@ -1388,12 +1476,20 @@ async function emitBeacon(options, req, classification, budgetMs) {
1388
1476
  userAgent: headerValue(req, "user-agent"),
1389
1477
  requestPath: req.uri,
1390
1478
  requestMethod: req.method,
1479
+ // Attempt-chain handle (header or ?astra_attempt= deep link) — joins
1480
+ // this beacon into the agent's research chain via pe_attempt_idx.
1481
+ ...attemptId && { attemptId },
1482
+ // First-class referer + accept: traffic-source and surface-classifier
1483
+ // inputs (previously buried inside observedMetadata.headers).
1484
+ referer: headerValue(req, "referer"),
1485
+ accept: headerValue(req, "accept"),
1486
+ ...declaredSource && { declaredSource },
1391
1487
  // Evidence fields the backend persists into the event record.
1392
1488
  protocol: classification.protocol,
1393
1489
  evidence: classification.evidence,
1394
1490
  // The full sanitized header + connection capture for the
1395
1491
  // unregistered caller (fire-and-forget, so free).
1396
- observedMetadata: buildObservedMetadata(req)
1492
+ observedMetadata: buildObservedMetadata(req, queryValueAllowlist)
1397
1493
  }
1398
1494
  ),
1399
1495
  budgetMs
@@ -1419,13 +1515,14 @@ function baseOutcome(classification) {
1419
1515
  protocol: classification.protocol
1420
1516
  };
1421
1517
  }
1422
- function buildVerificationRequest(options, req, classification, includeArtifacts) {
1518
+ function buildVerificationRequest(options, req, classification, includeArtifacts, queryValueAllowlist) {
1423
1519
  const pdlss = resolveHttpPdlss({
1424
1520
  method: req.method,
1425
1521
  astraPurpose: headerValue(req, "x-astra-purpose"),
1426
1522
  astraAction: headerValue(req, "x-astra-action")
1427
1523
  });
1428
1524
  const attemptId = headerValue(req, "x-astra-attempt-id");
1525
+ const declaredSource = normalizeDeclaredSource(headerValue(req, "x-astra-source"));
1429
1526
  return {
1430
1527
  ...attemptId && /^att_[0-9a-f]{32}$/.test(attemptId) && { attemptId },
1431
1528
  credentials: extractCredentials(req.headers, {}),
@@ -1440,10 +1537,11 @@ function buildVerificationRequest(options, req, classification, includeArtifacts
1440
1537
  userAgent: headerValue(req, "user-agent"),
1441
1538
  referer: headerValue(req, "referer"),
1442
1539
  host: headerValue(req, "host"),
1540
+ ...declaredSource && { declaredSource },
1443
1541
  // The full sanitized header + connection capture. The backend stores
1444
1542
  // it fire-and-forget (zero decision latency) and uses the key-format
1445
1543
  // / platform headers for attribution.
1446
- observedMetadata: buildObservedMetadata(req)
1544
+ observedMetadata: buildObservedMetadata(req, queryValueAllowlist)
1447
1545
  },
1448
1546
  ...includeArtifacts && classification.artifacts && { commerceArtifacts: classification.artifacts }
1449
1547
  };
@@ -1490,7 +1588,8 @@ function unavailableOutcome(classification, policy, reason, correlationId) {
1490
1588
  function isApiErrorResult(result) {
1491
1589
  return (result.failures ?? []).some((f) => f.dimension === "verify_access.api_error") === true && !result.misconfigured;
1492
1590
  }
1493
- async function runTier(options, req, classification, policy, apiKey, sampling) {
1591
+ async function runTier(options, req, classification, policy, apiKey, capture) {
1592
+ const { sampling, queryValueAllowlist } = capture;
1494
1593
  const budgets = options.budgets ?? {};
1495
1594
  const beaconMs = budgets.beaconMs ?? 300;
1496
1595
  const verifyMs = policy.mode === "enforce" ? budgets.verifyEnforceMs ?? 3e3 : budgets.verifyObserveMs ?? 1500;
@@ -1511,7 +1610,13 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1511
1610
  const result = await withBudget(
1512
1611
  verify(
1513
1612
  gatewayConfig,
1514
- buildVerificationRequest(options, req, classification, policy.depth === "authorize")
1613
+ buildVerificationRequest(
1614
+ options,
1615
+ req,
1616
+ classification,
1617
+ policy.depth === "authorize",
1618
+ queryValueAllowlist
1619
+ )
1515
1620
  ),
1516
1621
  verifyMs
1517
1622
  );
@@ -1535,7 +1640,10 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1535
1640
  case "identified": {
1536
1641
  if (policy.depth === "authorize" && classification.artifacts) {
1537
1642
  const result = await withBudget(
1538
- verify(gatewayConfig, buildVerificationRequest(options, req, classification, true)),
1643
+ verify(
1644
+ gatewayConfig,
1645
+ buildVerificationRequest(options, req, classification, true, queryValueAllowlist)
1646
+ ),
1539
1647
  verifyMs
1540
1648
  );
1541
1649
  if (!result) {
@@ -1555,7 +1663,7 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1555
1663
  }
1556
1664
  return outcomeFromVerifyResult(classification, result);
1557
1665
  }
1558
- await emitBeacon(options, req, classification, beaconMs);
1666
+ await emitBeacon(options, req, classification, beaconMs, queryValueAllowlist);
1559
1667
  const outcome = baseOutcome(classification);
1560
1668
  if (policy.mode === "enforce" && policy.depth !== "classify") {
1561
1669
  outcome.decision = "deny";
@@ -1569,7 +1677,8 @@ async function runTier(options, req, classification, policy, apiKey, sampling) {
1569
1677
  options,
1570
1678
  req,
1571
1679
  { ...classification, protocol: classification.protocol ?? "ua-heuristic" },
1572
- beaconMs
1680
+ beaconMs,
1681
+ queryValueAllowlist
1573
1682
  );
1574
1683
  }
1575
1684
  return baseOutcome(classification);
@@ -1596,7 +1705,10 @@ async function evaluateEdgeRequest(options, req, config, apiKey) {
1596
1705
  if (classification.tier === "human" || classification.tier === "self") {
1597
1706
  return { policy, classification, application: passUntouched() };
1598
1707
  }
1599
- const outcome = await runTier(options, req, classification, policy, apiKey, config.sampling);
1708
+ const outcome = await runTier(options, req, classification, policy, apiKey, {
1709
+ sampling: policy.sampling ?? config.sampling,
1710
+ queryValueAllowlist: config.queryValueAllowlist
1711
+ });
1600
1712
  if (outcome.decision !== "allow") {
1601
1713
  options.log?.(
1602
1714
  "info",