@astrasyncai/verification-gateway 5.19.0 → 5.21.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 (111) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +53 -4
  3. package/dist/adapter-interface/interface.d.mts +2 -2
  4. package/dist/adapter-interface/interface.d.ts +2 -2
  5. package/dist/adapters/express.d.mts +1 -1
  6. package/dist/adapters/express.d.ts +1 -1
  7. package/dist/adapters/express.js +65 -16
  8. package/dist/adapters/express.js.map +1 -1
  9. package/dist/adapters/express.mjs +65 -16
  10. package/dist/adapters/express.mjs.map +1 -1
  11. package/dist/adapters/mcp.d.mts +23 -1
  12. package/dist/adapters/mcp.d.ts +23 -1
  13. package/dist/adapters/mcp.js +91 -16
  14. package/dist/adapters/mcp.js.map +1 -1
  15. package/dist/adapters/mcp.mjs +91 -16
  16. package/dist/adapters/mcp.mjs.map +1 -1
  17. package/dist/adapters/nextjs.d.mts +1 -1
  18. package/dist/adapters/nextjs.d.ts +1 -1
  19. package/dist/adapters/nextjs.js +57 -11
  20. package/dist/adapters/nextjs.js.map +1 -1
  21. package/dist/adapters/nextjs.mjs +57 -11
  22. package/dist/adapters/nextjs.mjs.map +1 -1
  23. package/dist/adapters/sdk.d.mts +35 -2
  24. package/dist/adapters/sdk.d.ts +35 -2
  25. package/dist/adapters/sdk.js +110 -11
  26. package/dist/adapters/sdk.js.map +1 -1
  27. package/dist/adapters/sdk.mjs +110 -11
  28. package/dist/adapters/sdk.mjs.map +1 -1
  29. package/dist/agent/index.d.mts +1 -1
  30. package/dist/agent/index.d.ts +1 -1
  31. package/dist/agent/index.js +1 -1
  32. package/dist/agent/index.js.map +1 -1
  33. package/dist/agent/index.mjs +1 -1
  34. package/dist/agent/index.mjs.map +1 -1
  35. package/dist/bin/astrasync-claude-hook.js +50 -12
  36. package/dist/bin/astrasync-codex-hook.js +50 -12
  37. package/dist/bin/astrasync-guard.js +50 -12
  38. package/dist/bin/astrasync.js +65 -13
  39. package/dist/browser/background.js +50 -12
  40. package/dist/browser/background.js.map +1 -1
  41. package/dist/browser/background.mjs +50 -12
  42. package/dist/browser/background.mjs.map +1 -1
  43. package/dist/cli/index.js +1 -1
  44. package/dist/cli/index.js.map +1 -1
  45. package/dist/cli/index.mjs +1 -1
  46. package/dist/cli/index.mjs.map +1 -1
  47. package/dist/codex/index.js +50 -12
  48. package/dist/codex/index.js.map +1 -1
  49. package/dist/codex/index.mjs +50 -12
  50. package/dist/codex/index.mjs.map +1 -1
  51. package/dist/cursor/extension.js +50 -12
  52. package/dist/cursor/extension.js.map +1 -1
  53. package/dist/cursor/extension.mjs +50 -12
  54. package/dist/cursor/extension.mjs.map +1 -1
  55. package/dist/edge-config.d.mts +1 -1
  56. package/dist/edge-config.d.ts +1 -1
  57. package/dist/edge-config.js +1 -1
  58. package/dist/edge-config.js.map +1 -1
  59. package/dist/edge-config.mjs +1 -1
  60. package/dist/edge-config.mjs.map +1 -1
  61. package/dist/edge-core/index.d.mts +1 -1
  62. package/dist/edge-core/index.d.ts +1 -1
  63. package/dist/edge-core/index.js +49 -11
  64. package/dist/edge-core/index.js.map +1 -1
  65. package/dist/edge-core/index.mjs +49 -11
  66. package/dist/edge-core/index.mjs.map +1 -1
  67. package/dist/gateway/gateway.d.mts +2 -2
  68. package/dist/gateway/gateway.d.ts +2 -2
  69. package/dist/gateway/gateway.js +50 -12
  70. package/dist/gateway/gateway.js.map +1 -1
  71. package/dist/gateway/gateway.mjs +50 -12
  72. package/dist/gateway/gateway.mjs.map +1 -1
  73. package/dist/git-trigger/git-hooks.d.mts +1 -1
  74. package/dist/git-trigger/git-hooks.d.ts +1 -1
  75. package/dist/index.d.mts +286 -8
  76. package/dist/index.d.ts +286 -8
  77. package/dist/index.js +532 -49
  78. package/dist/index.js.map +1 -1
  79. package/dist/index.mjs +522 -49
  80. package/dist/index.mjs.map +1 -1
  81. package/dist/local-evaluator/evaluator.d.mts +2 -2
  82. package/dist/local-evaluator/evaluator.d.ts +2 -2
  83. package/dist/registration/index.d.mts +11 -2
  84. package/dist/registration/index.d.ts +11 -2
  85. package/dist/registration/index.js +1 -1
  86. package/dist/registration/index.js.map +1 -1
  87. package/dist/registration/index.mjs +1 -1
  88. package/dist/registration/index.mjs.map +1 -1
  89. package/dist/transport/index.d.mts +1 -1
  90. package/dist/transport/index.d.ts +1 -1
  91. package/dist/transport/index.js +1 -1
  92. package/dist/transport/index.js.map +1 -1
  93. package/dist/transport/index.mjs +1 -1
  94. package/dist/transport/index.mjs.map +1 -1
  95. package/dist/{types-BoGjyon0.d.mts → types-B4zhOAlq.d.mts} +30 -1
  96. package/dist/{types-BRz2U0Pn.d.ts → types-B_HLhZ9n.d.ts} +1 -1
  97. package/dist/{types-BfILnheI.d.mts → types-CU17R4Nr.d.mts} +11 -0
  98. package/dist/{types-BfILnheI.d.ts → types-CU17R4Nr.d.ts} +11 -0
  99. package/dist/{types-eWyZuz-3.d.ts → types-CtBXnWuV.d.ts} +30 -1
  100. package/dist/{types-DqWPkiYl.d.mts → types-DHHyXtuZ.d.mts} +30 -1
  101. package/dist/{types-DqWPkiYl.d.ts → types-DHHyXtuZ.d.ts} +30 -1
  102. package/dist/{types-CfBpm3w5.d.mts → types-Djpz-L0w.d.mts} +1 -1
  103. package/dist/ui/index.d.mts +1 -1
  104. package/dist/ui/index.d.ts +1 -1
  105. package/dist/verify.d.mts +28 -3
  106. package/dist/verify.d.ts +28 -3
  107. package/dist/verify.js +71 -11
  108. package/dist/verify.js.map +1 -1
  109. package/dist/verify.mjs +69 -11
  110. package/dist/verify.mjs.map +1 -1
  111. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { Request, Response, RequestHandler } from 'express';
2
- import { e as VerificationResult, G as GatewayConfig } from '../types-DqWPkiYl.mjs';
2
+ import { e as VerificationResult, G as GatewayConfig } from '../types-DHHyXtuZ.mjs';
3
3
 
4
4
  /**
5
5
  * X-Astra-Verified-Hop — cross-hop verify-access dedupe marker.
@@ -401,6 +401,28 @@ interface McpMiddlewareOptions extends GatewayConfig {
401
401
  toolGatePrecedence?: 'code' | 'dashboard';
402
402
  /** 5.19.0: refresh interval (ms) for the dashboard tool rules. Default 5 minutes. */
403
403
  routesRefreshMs?: number;
404
+ /**
405
+ * 5.20.0: tools and JSON-RPC methods that pass through with NO verify-access
406
+ * call at all — not even the audit evaluation `evaluateAlwaysIfCredentialed`
407
+ * adds for credentialed callers. Applies only while the call is not
408
+ * enforced (an `'observe'` gate, or a handshake/introspection method with
409
+ * no `methodGates` entry); a dashboard rule that enforces a listed tool
410
+ * still verifies.
411
+ *
412
+ * Use it for:
413
+ * - `methods`: handshake and introspection (`initialize`, `tools/list`,
414
+ * `resources/list`, `resources/read`) — nothing to attribute, and a
415
+ * backend round trip slows the host's first card fetch;
416
+ * - `tools`: observe tools whose handler calls verify-access itself, so
417
+ * the gate's evaluation would be a second backend verify for the same
418
+ * call (the MCP bridge measured ~3 backend calls per `verify_agent`).
419
+ *
420
+ * Listed calls leave `req.agentVerification` unset.
421
+ */
422
+ skipEvaluation?: {
423
+ tools?: readonly string[];
424
+ methods?: readonly string[];
425
+ };
404
426
  /**
405
427
  * Posture when the MCP middleware itself throws an internal error.
406
428
  *
@@ -1,5 +1,5 @@
1
1
  import { Request, Response, RequestHandler } from 'express';
2
- import { e as VerificationResult, G as GatewayConfig } from '../types-DqWPkiYl.js';
2
+ import { e as VerificationResult, G as GatewayConfig } from '../types-DHHyXtuZ.js';
3
3
 
4
4
  /**
5
5
  * X-Astra-Verified-Hop — cross-hop verify-access dedupe marker.
@@ -401,6 +401,28 @@ interface McpMiddlewareOptions extends GatewayConfig {
401
401
  toolGatePrecedence?: 'code' | 'dashboard';
402
402
  /** 5.19.0: refresh interval (ms) for the dashboard tool rules. Default 5 minutes. */
403
403
  routesRefreshMs?: number;
404
+ /**
405
+ * 5.20.0: tools and JSON-RPC methods that pass through with NO verify-access
406
+ * call at all — not even the audit evaluation `evaluateAlwaysIfCredentialed`
407
+ * adds for credentialed callers. Applies only while the call is not
408
+ * enforced (an `'observe'` gate, or a handshake/introspection method with
409
+ * no `methodGates` entry); a dashboard rule that enforces a listed tool
410
+ * still verifies.
411
+ *
412
+ * Use it for:
413
+ * - `methods`: handshake and introspection (`initialize`, `tools/list`,
414
+ * `resources/list`, `resources/read`) — nothing to attribute, and a
415
+ * backend round trip slows the host's first card fetch;
416
+ * - `tools`: observe tools whose handler calls verify-access itself, so
417
+ * the gate's evaluation would be a second backend verify for the same
418
+ * call (the MCP bridge measured ~3 backend calls per `verify_agent`).
419
+ *
420
+ * Listed calls leave `req.agentVerification` unset.
421
+ */
422
+ skipEvaluation?: {
423
+ tools?: readonly string[];
424
+ methods?: readonly string[];
425
+ };
404
426
  /**
405
427
  * Posture when the MCP middleware itself throws an internal error.
406
428
  *
@@ -34,7 +34,7 @@ __export(mcp_exports, {
34
34
  module.exports = __toCommonJS(mcp_exports);
35
35
 
36
36
  // src/version.ts
37
- var SDK_VERSION = "5.19.0";
37
+ var SDK_VERSION = "5.21.0";
38
38
 
39
39
  // src/http.ts
40
40
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -473,6 +473,9 @@ async function callVerifyAccessAPI(config, request) {
473
473
  if (requestData.enableRuntimeChallenge)
474
474
  body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
475
475
  if (requestData.routePolicy) body.routePolicy = requestData.routePolicy;
476
+ if (config.actingProof?.connectorToken) {
477
+ body.actingProof = { connectorToken: config.actingProof.connectorToken };
478
+ }
476
479
  if (requestData.approvalHeldByRoute) body.approvalHeldByRoute = true;
477
480
  if (requestData.createSession) body.createSession = requestData.createSession;
478
481
  if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;
@@ -640,22 +643,46 @@ async function verify(config, request, options) {
640
643
  "[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access decisions (verified ID + runtime challenge + PDLSS + trust score). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side."
641
644
  );
642
645
  }
643
- const uncacheable = Boolean(request.commerceArtifacts);
646
+ const uncacheable = Boolean(request.commerceArtifacts) || Boolean(mergedConfig.actingProof);
644
647
  if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
645
648
  const cached = getCachedResult(request, mergedConfig.counterpartyId);
646
649
  if (cached) {
647
650
  if (mergedConfig.debug) {
648
651
  console.log("[VerificationGateway] Returning cached result");
649
652
  }
650
- const hit = { ...cached };
651
- if (request.attemptId) {
652
- hit.attemptId = request.attemptId;
653
- } else {
654
- delete hit.attemptId;
655
- }
656
- return hit;
653
+ return sharedVerdict(cached, request);
654
+ }
655
+ }
656
+ if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache && !uncacheable) {
657
+ const key = getCacheKey(request, mergedConfig.counterpartyId);
658
+ const pending = inflightVerifies.get(key);
659
+ if (pending) return sharedVerdict(await pending, request);
660
+ const flight = verifyViaApi(mergedConfig, request, urls, uncacheable);
661
+ inflightVerifies.set(key, flight);
662
+ try {
663
+ return await flight;
664
+ } finally {
665
+ inflightVerifies.delete(key);
657
666
  }
658
667
  }
668
+ return verifyViaApi(mergedConfig, request, urls, uncacheable);
669
+ }
670
+ var inflightVerifies = /* @__PURE__ */ new Map();
671
+ var sharedVerdicts = /* @__PURE__ */ new WeakSet();
672
+ function isSharedVerdict(result) {
673
+ return sharedVerdicts.has(result);
674
+ }
675
+ function sharedVerdict(source, request) {
676
+ const hit = { ...source };
677
+ if (request.attemptId) {
678
+ hit.attemptId = request.attemptId;
679
+ } else {
680
+ delete hit.attemptId;
681
+ }
682
+ sharedVerdicts.add(hit);
683
+ return hit;
684
+ }
685
+ async function verifyViaApi(mergedConfig, request, urls, uncacheable) {
659
686
  const enrichedRequest = { ...request };
660
687
  if (!enrichedRequest.counterpartyUrl && mergedConfig.counterpartyUrl) {
661
688
  enrichedRequest.counterpartyUrl = mergedConfig.counterpartyUrl;
@@ -734,7 +761,9 @@ async function verify(config, request, options) {
734
761
  fulfilment: apiResponse.fulfilment,
735
762
  mandates: apiResponse.mandates,
736
763
  kyaToken: apiResponse.kyaToken,
737
- aep: apiResponse.aep
764
+ aep: apiResponse.aep,
765
+ // 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
766
+ warnings: apiResponse.warnings
738
767
  };
739
768
  return result2;
740
769
  }
@@ -802,7 +831,9 @@ async function verify(config, request, options) {
802
831
  // 5.15.0: merchant-lane AP2 mandates + KYAPay identity token.
803
832
  mandates: apiResponse.mandates,
804
833
  kyaToken: apiResponse.kyaToken,
805
- aep: apiResponse.aep
834
+ aep: apiResponse.aep,
835
+ // 5.20.0 (round 29.1): non-fatal integration warnings (e.g. events_url_missing).
836
+ warnings: apiResponse.warnings
806
837
  };
807
838
  if (result.recommendation === "deny") {
808
839
  result.policyAllowed = false;
@@ -828,8 +859,18 @@ async function verify(config, request, options) {
828
859
  cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
829
860
  }
830
861
  }
862
+ notifyVerificationListeners(request, result);
831
863
  return result;
832
864
  }
865
+ var verificationListeners = /* @__PURE__ */ new Set();
866
+ function notifyVerificationListeners(request, result) {
867
+ for (const listener of verificationListeners) {
868
+ try {
869
+ listener(result, request);
870
+ } catch {
871
+ }
872
+ }
873
+ }
833
874
  async function recordDecision(config, sessionId, decision, reason) {
834
875
  const headers = { "Content-Type": "application/json" };
835
876
  if (config.apiKey) {
@@ -852,6 +893,7 @@ async function fetchRoutes(config, counterpartyId, options = {}) {
852
893
  headers["X-API-Key"] = config.apiKey;
853
894
  }
854
895
  try {
896
+ headers["X-AstraSync-SDK-Version"] = SDK_VERSION;
855
897
  const response = await sdkFetch(
856
898
  `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes` + (options.codeGates?.length ? `?codeGates=${options.codeGates.map(encodeURIComponent).join(",")}` : ""),
857
899
  { method: "GET", headers }
@@ -866,6 +908,13 @@ async function fetchRoutes(config, counterpartyId, options = {}) {
866
908
  return null;
867
909
  }
868
910
  const body = await response.json();
911
+ const type = body.data?.counterpartyType;
912
+ if (typeof type === "string" && options.onEndpointType) {
913
+ try {
914
+ options.onEndpointType(type);
915
+ } catch {
916
+ }
917
+ }
869
918
  return body.data?.routes ?? [];
870
919
  } catch {
871
920
  return null;
@@ -1514,16 +1563,30 @@ function createMcpMiddleware(options) {
1514
1563
  failOnError = "closed",
1515
1564
  toolGatePrecedence = "code",
1516
1565
  routesRefreshMs,
1566
+ skipEvaluation,
1517
1567
  ...config
1518
1568
  } = options;
1569
+ const skipTools = new Set(skipEvaluation?.tools ?? []);
1570
+ const skipMethods = new Set(skipEvaluation?.methods ?? []);
1519
1571
  if (config.apiBaseUrl) {
1520
1572
  prefetchWellKnown(config.apiBaseUrl).catch(() => {
1521
1573
  });
1522
1574
  }
1523
1575
  const codeGatedTools = Object.entries(toolGates ?? {}).filter(([, g]) => g !== "observe").map(([name]) => name);
1576
+ let warnedEndpointType = false;
1577
+ const onEndpointType = (counterpartyType) => {
1578
+ if (counterpartyType === "mcp_server" || warnedEndpointType) return;
1579
+ warnedEndpointType = true;
1580
+ console.warn(
1581
+ `[VerificationGateway/MCP] counterpartyId ${config.counterpartyId} is a '${counterpartyType}' endpoint, not an 'mcp_server' endpoint. Dashboard tool rules are read from an mcp_server endpoint only: register a separate MCP endpoint for this server (same owner) and use its id here. See https://astrasync.ai/docs/mcp-integration#tool-rules.`
1582
+ );
1583
+ };
1524
1584
  const rulesCache = config.apiKey && config.counterpartyId ? createRoutesCache(config, {
1525
1585
  ...routesRefreshMs !== void 0 && { refreshMs: routesRefreshMs },
1526
- ...codeGatedTools.length && { fetchOptions: { codeGates: codeGatedTools } }
1586
+ fetchOptions: {
1587
+ ...codeGatedTools.length && { codeGates: codeGatedTools },
1588
+ onEndpointType
1589
+ }
1527
1590
  }) : void 0;
1528
1591
  return async (req, res, next) => {
1529
1592
  try {
@@ -1573,6 +1636,9 @@ function createMcpMiddleware(options) {
1573
1636
  return next();
1574
1637
  }
1575
1638
  }
1639
+ if (!parsed.toolName && skipMethods.has(parsed.method) && methodGates?.[parsed.method] === void 0) {
1640
+ return next();
1641
+ }
1576
1642
  const dashboardRules = rulesCache ? dashboardToolRules(await rulesCache.current()) : void 0;
1577
1643
  const gateDecision = resolveGate(parsed, {
1578
1644
  toolGates,
@@ -1580,6 +1646,9 @@ function createMcpMiddleware(options) {
1580
1646
  dashboardRules,
1581
1647
  toolGatePrecedence
1582
1648
  });
1649
+ if (!gateDecision.enforce && (parsed.toolName && skipTools.has(parsed.toolName) || !parsed.toolName && skipMethods.has(parsed.method))) {
1650
+ return next();
1651
+ }
1583
1652
  const credentials = extractCredentials(
1584
1653
  req.headers,
1585
1654
  req.query
@@ -1636,8 +1705,14 @@ function createMcpMiddleware(options) {
1636
1705
  const forwardedFor = req.headers["x-forwarded-for"];
1637
1706
  const forwardedForStr = Array.isArray(forwardedFor) ? forwardedFor.join(", ") : forwardedFor;
1638
1707
  const sourceIp = req.ip ?? (forwardedForStr ? forwardedForStr.split(",")[0].trim() : void 0);
1708
+ const attemptRaw = readSingleHeader(req.headers["x-astra-attempt-id"]);
1709
+ const metaAttempt = req.body?.params?._meta?.astrasync?.attemptId;
1710
+ const attemptId = [attemptRaw, metaAttempt].find(
1711
+ (v) => typeof v === "string" && /^att_[0-9a-f]{32}$/.test(v)
1712
+ );
1639
1713
  const verificationRequest = {
1640
1714
  credentials,
1715
+ ...attemptId && { attemptId },
1641
1716
  purpose: pdlss.purpose,
1642
1717
  action: pdlss.action,
1643
1718
  resource: pdlss.resource,
@@ -1699,14 +1774,14 @@ function createMcpMiddleware(options) {
1699
1774
  res.setHeader("X-Astra-Gateway-Mode", "enforced");
1700
1775
  res.setHeader("X-Astra-Gateway-Reason", "evaluated-not-enforced");
1701
1776
  }
1702
- if (shouldRecordDecisions && sessionId) {
1777
+ if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
1703
1778
  recordDecision(config, sessionId, "granted").catch(() => {
1704
1779
  });
1705
1780
  }
1706
1781
  return next();
1707
1782
  }
1708
1783
  if (!result.policyAllowed) {
1709
- if (shouldRecordDecisions && sessionId) {
1784
+ if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
1710
1785
  recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
1711
1786
  });
1712
1787
  }
@@ -1716,7 +1791,7 @@ function createMcpMiddleware(options) {
1716
1791
  }
1717
1792
  if (requiresHumanApproval(result)) {
1718
1793
  annotateApprovalRequired(result);
1719
- if (shouldRecordDecisions && sessionId) {
1794
+ if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
1720
1795
  recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
1721
1796
  });
1722
1797
  }
@@ -1734,7 +1809,7 @@ function createMcpMiddleware(options) {
1734
1809
  })
1735
1810
  );
1736
1811
  }
1737
- if (shouldRecordDecisions && sessionId) {
1812
+ if (shouldRecordDecisions && sessionId && !isSharedVerdict(result)) {
1738
1813
  recordDecision(config, sessionId, "granted").catch(() => {
1739
1814
  });
1740
1815
  }