@astrasyncai/verification-gateway 5.18.1 → 5.19.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 (113) hide show
  1. package/CHANGELOG.md +149 -0
  2. package/README.md +168 -4
  3. package/dist/adapters/express.d.mts +9 -1
  4. package/dist/adapters/express.d.ts +9 -1
  5. package/dist/adapters/express.js +96 -37
  6. package/dist/adapters/express.js.map +1 -1
  7. package/dist/adapters/express.mjs +96 -37
  8. package/dist/adapters/express.mjs.map +1 -1
  9. package/dist/adapters/http-pdlss.d.mts +7 -1
  10. package/dist/adapters/http-pdlss.d.ts +7 -1
  11. package/dist/adapters/http-pdlss.js +18 -2
  12. package/dist/adapters/http-pdlss.js.map +1 -1
  13. package/dist/adapters/http-pdlss.mjs +16 -1
  14. package/dist/adapters/http-pdlss.mjs.map +1 -1
  15. package/dist/adapters/kit-express.d.mts +93 -1
  16. package/dist/adapters/kit-express.d.ts +93 -1
  17. package/dist/adapters/kit-express.js +181 -2
  18. package/dist/adapters/kit-express.js.map +1 -1
  19. package/dist/adapters/kit-express.mjs +180 -2
  20. package/dist/adapters/kit-express.mjs.map +1 -1
  21. package/dist/adapters/mcp.d.mts +80 -9
  22. package/dist/adapters/mcp.d.ts +80 -9
  23. package/dist/adapters/mcp.js +153 -5
  24. package/dist/adapters/mcp.js.map +1 -1
  25. package/dist/adapters/mcp.mjs +151 -5
  26. package/dist/adapters/mcp.mjs.map +1 -1
  27. package/dist/adapters/nextjs.d.mts +1 -1
  28. package/dist/adapters/nextjs.d.ts +1 -1
  29. package/dist/adapters/nextjs.js +41 -4
  30. package/dist/adapters/nextjs.js.map +1 -1
  31. package/dist/adapters/nextjs.mjs +41 -4
  32. package/dist/adapters/nextjs.mjs.map +1 -1
  33. package/dist/adapters/sdk.d.mts +44 -1
  34. package/dist/adapters/sdk.d.ts +44 -1
  35. package/dist/adapters/sdk.js +76 -2
  36. package/dist/adapters/sdk.js.map +1 -1
  37. package/dist/adapters/sdk.mjs +76 -2
  38. package/dist/adapters/sdk.mjs.map +1 -1
  39. package/dist/agent/index.js +1 -1
  40. package/dist/agent/index.js.map +1 -1
  41. package/dist/agent/index.mjs +1 -1
  42. package/dist/agent/index.mjs.map +1 -1
  43. package/dist/bin/astrasync-claude-hook.js +46 -6
  44. package/dist/bin/astrasync-codex-hook.js +46 -6
  45. package/dist/bin/astrasync-guard.js +46 -6
  46. package/dist/bin/astrasync.js +77 -5
  47. package/dist/browser/background.js +46 -6
  48. package/dist/browser/background.js.map +1 -1
  49. package/dist/browser/background.mjs +46 -6
  50. package/dist/browser/background.mjs.map +1 -1
  51. package/dist/cli/index.js +1 -1
  52. package/dist/cli/index.js.map +1 -1
  53. package/dist/cli/index.mjs +1 -1
  54. package/dist/cli/index.mjs.map +1 -1
  55. package/dist/codex/index.js +46 -6
  56. package/dist/codex/index.js.map +1 -1
  57. package/dist/codex/index.mjs +46 -6
  58. package/dist/codex/index.mjs.map +1 -1
  59. package/dist/cursor/extension.js +46 -6
  60. package/dist/cursor/extension.js.map +1 -1
  61. package/dist/cursor/extension.mjs +46 -6
  62. package/dist/cursor/extension.mjs.map +1 -1
  63. package/dist/edge-config.d.mts +1 -1
  64. package/dist/edge-config.d.ts +1 -1
  65. package/dist/edge-config.js +1 -1
  66. package/dist/edge-config.js.map +1 -1
  67. package/dist/edge-config.mjs +1 -1
  68. package/dist/edge-config.mjs.map +1 -1
  69. package/dist/edge-core/index.d.mts +1 -1
  70. package/dist/edge-core/index.d.ts +1 -1
  71. package/dist/edge-core/index.js +21 -2
  72. package/dist/edge-core/index.js.map +1 -1
  73. package/dist/edge-core/index.mjs +21 -2
  74. package/dist/edge-core/index.mjs.map +1 -1
  75. package/dist/gateway/gateway.js +46 -6
  76. package/dist/gateway/gateway.js.map +1 -1
  77. package/dist/gateway/gateway.mjs +46 -6
  78. package/dist/gateway/gateway.mjs.map +1 -1
  79. package/dist/git-trigger/git-hooks.d.mts +1 -1
  80. package/dist/git-trigger/git-hooks.d.ts +1 -1
  81. package/dist/index.d.mts +541 -29
  82. package/dist/index.d.ts +541 -29
  83. package/dist/index.js +1171 -183
  84. package/dist/index.js.map +1 -1
  85. package/dist/index.mjs +1157 -173
  86. package/dist/index.mjs.map +1 -1
  87. package/dist/registration/index.js +1 -1
  88. package/dist/registration/index.js.map +1 -1
  89. package/dist/registration/index.mjs +1 -1
  90. package/dist/registration/index.mjs.map +1 -1
  91. package/dist/transport/index.js +3 -2
  92. package/dist/transport/index.js.map +1 -1
  93. package/dist/transport/index.mjs +3 -2
  94. package/dist/transport/index.mjs.map +1 -1
  95. package/dist/{types-3ObBpsnf.d.mts → types-BoGjyon0.d.mts} +81 -2
  96. package/dist/{types-Cns4l8gX.d.mts → types-DqWPkiYl.d.mts} +90 -12
  97. package/dist/{types-Cns4l8gX.d.ts → types-DqWPkiYl.d.ts} +90 -12
  98. package/dist/{types-BoxZEYPS.d.ts → types-eWyZuz-3.d.ts} +81 -2
  99. package/dist/ui/index.d.mts +1 -1
  100. package/dist/ui/index.d.ts +1 -1
  101. package/dist/verify.d.mts +23 -2
  102. package/dist/verify.d.ts +23 -2
  103. package/dist/verify.js +23 -4
  104. package/dist/verify.js.map +1 -1
  105. package/dist/verify.mjs +23 -4
  106. package/dist/verify.mjs.map +1 -1
  107. package/dist/webhooks.d.mts +16 -3
  108. package/dist/webhooks.d.ts +16 -3
  109. package/dist/webhooks.js +24 -13
  110. package/dist/webhooks.js.map +1 -1
  111. package/dist/webhooks.mjs +24 -13
  112. package/dist/webhooks.mjs.map +1 -1
  113. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var SDK_VERSION = "5.18.1";
2
+ var SDK_VERSION = "5.19.0";
3
3
 
4
4
  // src/http.ts
5
5
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -241,7 +241,12 @@ function getCacheKey(request, counterpartyId) {
241
241
  // its start_checkout quote was served the cached quote-leg grant (no
242
242
  // settlementOutcome) and never reached the backend. Same F-A1-07 bug class.
243
243
  request.commercePhase || "",
244
- request.checkoutSessionId || ""
244
+ request.checkoutSessionId || "",
245
+ // 5.19.0: a route_config purpose claim is checked server-side against
246
+ // the stored rule for this method + path, so it changes the verdict.
247
+ request.purposeSource || "",
248
+ request.requestMethod || "",
249
+ request.requestPath || ""
245
250
  ].join("|");
246
251
  }
247
252
  function getCachedResult(request, counterpartyId) {
@@ -449,6 +454,11 @@ async function callVerifyAccessAPI(config, request) {
449
454
  if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
450
455
  if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
451
456
  if (requestData.attemptId) body.attemptId = requestData.attemptId;
457
+ if (requestData.purposeSource) body.purposeSource = requestData.purposeSource;
458
+ if (requestData.agentArtifacts) body.agentArtifacts = requestData.agentArtifacts;
459
+ if (requestData.metadata) body.metadata = requestData.metadata;
460
+ if (requestData.requestMethod) body.requestMethod = requestData.requestMethod;
461
+ if (requestData.requestPath) body.requestPath = requestData.requestPath;
452
462
  if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
453
463
  body.sdkVersion = SDK_VERSION;
454
464
  if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
@@ -638,9 +648,18 @@ async function verify(config, request, options) {
638
648
  if (!apiResponse.access?.allowed) {
639
649
  const aggregatedFailures = apiResponse.access?.failures;
640
650
  const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
651
+ const denyAgent = idVerifiedFromBackend && apiResponse.agent ? {
652
+ astraId: apiResponse.agent.astraId,
653
+ name: apiResponse.agent.name,
654
+ trustScore: apiResponse.agent.trustScore,
655
+ trustLevel: getTrustLevel(apiResponse.agent.trustScore),
656
+ blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
657
+ status: apiResponse.agent.agentStatus
658
+ } : void 0;
641
659
  const result2 = {
642
660
  identityVerified: idVerifiedFromBackend,
643
661
  policyAllowed: false,
662
+ ...denyAgent && { agent: denyAgent },
644
663
  // 3.6.0: the server now emits top-level denialReasons on every deny
645
664
  // path — prefer it verbatim; the failure-message reconstruction remains
646
665
  // as the fallback for older backends.
@@ -789,6 +808,34 @@ async function recordDecision(config, sessionId, decision, reason) {
789
808
  }).catch(() => {
790
809
  });
791
810
  }
811
+ var refusedPolicyReads = /* @__PURE__ */ new Set();
812
+ async function fetchRoutes(config, counterpartyId, options = {}) {
813
+ if (!counterpartyId) return null;
814
+ const headers = { "Content-Type": "application/json" };
815
+ if (config.apiKey) {
816
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
817
+ headers["X-API-Key"] = config.apiKey;
818
+ }
819
+ try {
820
+ const response = await sdkFetch(
821
+ `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes` + (options.codeGates?.length ? `?codeGates=${options.codeGates.map(encodeURIComponent).join(",")}` : ""),
822
+ { method: "GET", headers }
823
+ );
824
+ if (!response.ok) {
825
+ if ((response.status === 401 || response.status === 403 || response.status === 404) && !refusedPolicyReads.has(counterpartyId)) {
826
+ refusedPolicyReads.add(counterpartyId);
827
+ console.error(
828
+ `[VerificationGateway] the configured API key cannot read the route policy for ${counterpartyId} (HTTP ${response.status}). The key belongs to an account that does not own this endpoint, or the counterpartyId is wrong. The gateway is in PASS-THROUGH mode: no agent is being verified.`
829
+ );
830
+ }
831
+ return null;
832
+ }
833
+ const body = await response.json();
834
+ return body.data?.routes ?? [];
835
+ } catch {
836
+ return null;
837
+ }
838
+ }
792
839
 
793
840
  // src/metadata-capture.ts
794
841
  var CAPTURE_SCHEMA_VERSION = 1;
@@ -1111,6 +1158,42 @@ async function awaitStepUpApproval(config, approval) {
1111
1158
  return "timeout";
1112
1159
  }
1113
1160
 
1161
+ // src/adapters/routes-cache.ts
1162
+ var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
1163
+ function createRoutesCache(config, opts = {}) {
1164
+ const refreshMs = opts.refreshMs ?? DEFAULT_ROUTES_REFRESH_MS;
1165
+ let cached = [];
1166
+ let lastFetchAt = 0;
1167
+ let refreshing = null;
1168
+ async function refresh() {
1169
+ if (!config.counterpartyId) {
1170
+ opts.onNoCounterparty?.();
1171
+ return;
1172
+ }
1173
+ const fetched = await fetchRoutes(config, config.counterpartyId, opts.fetchOptions);
1174
+ if (fetched) {
1175
+ cached = fetched;
1176
+ lastFetchAt = Date.now();
1177
+ opts.onFetched?.(fetched);
1178
+ }
1179
+ }
1180
+ function start() {
1181
+ refreshing = refresh().catch(() => void 0).finally(() => {
1182
+ refreshing = null;
1183
+ });
1184
+ }
1185
+ start();
1186
+ return {
1187
+ async current() {
1188
+ if (refreshing) await refreshing.catch(() => {
1189
+ });
1190
+ if (config.counterpartyId && Date.now() - lastFetchAt > refreshMs) start();
1191
+ return cached;
1192
+ },
1193
+ peek: () => cached
1194
+ };
1195
+ }
1196
+
1114
1197
  // src/verified-hop.ts
1115
1198
  var MCP_VERIFIED_HOP_HEADER = "X-Astra-Verified-Hop";
1116
1199
  var MCP_VERIFIED_HOP_MAX_AGE_MS = 6e4;
@@ -1331,6 +1414,21 @@ function defaultMcpDenied(result, req, res) {
1331
1414
  }
1332
1415
  });
1333
1416
  }
1417
+ function dashboardToolRules(routes) {
1418
+ const out = /* @__PURE__ */ new Map();
1419
+ for (const r of routes) {
1420
+ if (typeof r.tool !== "string" || !r.tool || r.legacy === true) continue;
1421
+ if (out.has(r.tool)) continue;
1422
+ out.set(r.tool, {
1423
+ tool: r.tool,
1424
+ ...r.purpose && { purpose: r.purpose },
1425
+ ...r.action && { action: r.action },
1426
+ ...r.resource && { resource: r.resource },
1427
+ ...r.observe === true && { observe: true }
1428
+ });
1429
+ }
1430
+ return out;
1431
+ }
1334
1432
  function resolveGate(parsed, opts) {
1335
1433
  if (!parsed.toolName) {
1336
1434
  const methodGate = opts.methodGates?.[parsed.method];
@@ -1340,8 +1438,30 @@ function resolveGate(parsed, opts) {
1340
1438
  return { enforce: false, source: "discovery_default" };
1341
1439
  }
1342
1440
  const toolGate = opts.toolGates?.[parsed.toolName];
1441
+ const rule = opts.dashboardRules?.get(parsed.toolName);
1442
+ const fromRule = (r) => r.observe ? { enforce: false, source: "dashboard" } : {
1443
+ enforce: true,
1444
+ config: {
1445
+ ...r.purpose && { purpose: r.purpose },
1446
+ ...r.action && { action: r.action },
1447
+ ...r.resource && { resource: r.resource }
1448
+ },
1449
+ source: "dashboard"
1450
+ };
1451
+ const codeGated = toolGate !== void 0 && toolGate !== "observe";
1452
+ if (rule && (opts.toolGatePrecedence === "dashboard" || !codeGated)) return fromRule(rule);
1343
1453
  if (toolGate !== void 0) {
1344
- return toolGate === "observe" ? { enforce: false, source: "toolGate" } : { enforce: true, config: toolGate, source: "toolGate" };
1454
+ if (toolGate === "observe") return { enforce: false, source: "toolGate" };
1455
+ if (rule && !rule.observe && rule.purpose && (rule.purpose !== toolGate.purpose || rule.action && rule.action !== toolGate.action)) {
1456
+ const extra = fromRule(rule).config;
1457
+ return {
1458
+ enforce: true,
1459
+ config: toolGate,
1460
+ additional: { ...extra, ...!extra.resource && toolGate.resource && { resource: toolGate.resource } },
1461
+ source: "toolGate"
1462
+ };
1463
+ }
1464
+ return { enforce: true, config: toolGate, source: "toolGate" };
1345
1465
  }
1346
1466
  return { enforce: mcpDefaultEnforced(parsed), source: "tier" };
1347
1467
  }
@@ -1356,13 +1476,20 @@ function createMcpMiddleware(options) {
1356
1476
  verifiedHopMaxAgeMs,
1357
1477
  recordDecisions,
1358
1478
  enableRuntimeChallenge = true,
1359
- failOnError = "open",
1479
+ failOnError = "closed",
1480
+ toolGatePrecedence = "code",
1481
+ routesRefreshMs,
1360
1482
  ...config
1361
1483
  } = options;
1362
1484
  if (config.apiBaseUrl) {
1363
1485
  prefetchWellKnown(config.apiBaseUrl).catch(() => {
1364
1486
  });
1365
1487
  }
1488
+ const codeGatedTools = Object.entries(toolGates ?? {}).filter(([, g]) => g !== "observe").map(([name]) => name);
1489
+ const rulesCache = config.apiKey && config.counterpartyId ? createRoutesCache(config, {
1490
+ ...routesRefreshMs !== void 0 && { refreshMs: routesRefreshMs },
1491
+ ...codeGatedTools.length && { fetchOptions: { codeGates: codeGatedTools } }
1492
+ }) : void 0;
1366
1493
  return async (req, res, next) => {
1367
1494
  try {
1368
1495
  if (skip) return next();
@@ -1411,9 +1538,12 @@ function createMcpMiddleware(options) {
1411
1538
  return next();
1412
1539
  }
1413
1540
  }
1541
+ const dashboardRules = rulesCache ? dashboardToolRules(await rulesCache.current()) : void 0;
1414
1542
  const gateDecision = resolveGate(parsed, {
1415
1543
  toolGates,
1416
- methodGates
1544
+ methodGates,
1545
+ dashboardRules,
1546
+ toolGatePrecedence
1417
1547
  });
1418
1548
  const credentials = extractCredentials(
1419
1549
  req.headers,
@@ -1511,6 +1641,20 @@ function createMcpMiddleware(options) {
1511
1641
  result.stepUpOutcome = outcome;
1512
1642
  }
1513
1643
  }
1644
+ if (shouldEnforce && gateDecision.additional?.purpose && result.policyAllowed && !requiresHumanApproval(result)) {
1645
+ const extra = mcpToPdlss(parsed, req.path, void 0, void 0, gateDecision.additional);
1646
+ const extraResult = await verify(config, {
1647
+ ...verificationRequest,
1648
+ purpose: extra.purpose,
1649
+ action: extra.action,
1650
+ resource: extra.resource
1651
+ });
1652
+ if (!extraResult.policyAllowed || requiresHumanApproval(extraResult)) {
1653
+ result = extraResult;
1654
+ req.agentVerification = result;
1655
+ sessionId = result.sessionId;
1656
+ }
1657
+ }
1514
1658
  if (!result.policyAllowed && isVerificationUnavailable(result) && (!shouldEnforce || isReadOnlyMcpMethod(parsed) && !credentials.astraId && !credentials.jwt)) {
1515
1659
  res.setHeader(VERIFICATION_STATUS_HEADER, "unavailable");
1516
1660
  return next();
@@ -1595,11 +1739,13 @@ function createMcpMiddleware(options) {
1595
1739
  export {
1596
1740
  MCP_VERIFIED_HOP_HEADER,
1597
1741
  createMcpMiddleware,
1742
+ dashboardToolRules,
1598
1743
  isVerifiedHopValidFor,
1599
1744
  mcpDefaultEnforced,
1600
1745
  mcpToPdlss,
1601
1746
  parseMcpJsonRpc,
1602
1747
  parseVerifiedHop,
1748
+ resolveGate,
1603
1749
  serializeVerifiedHop
1604
1750
  };
1605
1751
  //# sourceMappingURL=mcp.mjs.map