@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
@@ -479,7 +479,7 @@ function routePolicyOf(route) {
479
479
  }
480
480
 
481
481
  // src/version.ts
482
- var SDK_VERSION = "5.18.1";
482
+ var SDK_VERSION = "5.19.0";
483
483
 
484
484
  // src/http.ts
485
485
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -797,7 +797,12 @@ function getCacheKey(request, counterpartyId) {
797
797
  // its start_checkout quote was served the cached quote-leg grant (no
798
798
  // settlementOutcome) and never reached the backend. Same F-A1-07 bug class.
799
799
  request.commercePhase || "",
800
- request.checkoutSessionId || ""
800
+ request.checkoutSessionId || "",
801
+ // 5.19.0: a route_config purpose claim is checked server-side against
802
+ // the stored rule for this method + path, so it changes the verdict.
803
+ request.purposeSource || "",
804
+ request.requestMethod || "",
805
+ request.requestPath || ""
801
806
  ].join("|");
802
807
  }
803
808
  function getCachedResult(request, counterpartyId) {
@@ -1005,6 +1010,11 @@ async function callVerifyAccessAPI(config, request) {
1005
1010
  if (requestData.buyerEmail) body.buyerEmail = requestData.buyerEmail;
1006
1011
  if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
1007
1012
  if (requestData.attemptId) body.attemptId = requestData.attemptId;
1013
+ if (requestData.purposeSource) body.purposeSource = requestData.purposeSource;
1014
+ if (requestData.agentArtifacts) body.agentArtifacts = requestData.agentArtifacts;
1015
+ if (requestData.metadata) body.metadata = requestData.metadata;
1016
+ if (requestData.requestMethod) body.requestMethod = requestData.requestMethod;
1017
+ if (requestData.requestPath) body.requestPath = requestData.requestPath;
1008
1018
  if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
1009
1019
  body.sdkVersion = SDK_VERSION;
1010
1020
  if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
@@ -1194,9 +1204,18 @@ async function verify(config, request, options) {
1194
1204
  if (!apiResponse.access?.allowed) {
1195
1205
  const aggregatedFailures = apiResponse.access?.failures;
1196
1206
  const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
1207
+ const denyAgent = idVerifiedFromBackend && apiResponse.agent ? {
1208
+ astraId: apiResponse.agent.astraId,
1209
+ name: apiResponse.agent.name,
1210
+ trustScore: apiResponse.agent.trustScore,
1211
+ trustLevel: getTrustLevel(apiResponse.agent.trustScore),
1212
+ blockchainAnchored: apiResponse.agent.blockchainStatus === "anchored",
1213
+ status: apiResponse.agent.agentStatus
1214
+ } : void 0;
1197
1215
  const result2 = {
1198
1216
  identityVerified: idVerifiedFromBackend,
1199
1217
  policyAllowed: false,
1218
+ ...denyAgent && { agent: denyAgent },
1200
1219
  // 3.6.0: the server now emits top-level denialReasons on every deny
1201
1220
  // path — prefer it verbatim; the failure-message reconstruction remains
1202
1221
  // as the fallback for older backends.
@@ -1346,7 +1365,7 @@ async function recordDecision(config, sessionId, decision, reason) {
1346
1365
  });
1347
1366
  }
1348
1367
  var refusedPolicyReads = /* @__PURE__ */ new Set();
1349
- async function fetchRoutes(config, counterpartyId) {
1368
+ async function fetchRoutes(config, counterpartyId, options = {}) {
1350
1369
  if (!counterpartyId) return null;
1351
1370
  const headers = { "Content-Type": "application/json" };
1352
1371
  if (config.apiKey) {
@@ -1355,7 +1374,7 @@ async function fetchRoutes(config, counterpartyId) {
1355
1374
  }
1356
1375
  try {
1357
1376
  const response = await sdkFetch(
1358
- `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,
1377
+ `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes` + (options.codeGates?.length ? `?codeGates=${options.codeGates.map(encodeURIComponent).join(",")}` : ""),
1359
1378
  { method: "GET", headers }
1360
1379
  );
1361
1380
  if (!response.ok) {
@@ -1401,6 +1420,42 @@ async function reportCounterpartyPreCheckFailure(config, data) {
1401
1420
  });
1402
1421
  }
1403
1422
 
1423
+ // src/adapters/routes-cache.ts
1424
+ var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
1425
+ function createRoutesCache(config, opts = {}) {
1426
+ const refreshMs = opts.refreshMs ?? DEFAULT_ROUTES_REFRESH_MS;
1427
+ let cached = [];
1428
+ let lastFetchAt = 0;
1429
+ let refreshing = null;
1430
+ async function refresh() {
1431
+ if (!config.counterpartyId) {
1432
+ opts.onNoCounterparty?.();
1433
+ return;
1434
+ }
1435
+ const fetched = await fetchRoutes(config, config.counterpartyId, opts.fetchOptions);
1436
+ if (fetched) {
1437
+ cached = fetched;
1438
+ lastFetchAt = Date.now();
1439
+ opts.onFetched?.(fetched);
1440
+ }
1441
+ }
1442
+ function start() {
1443
+ refreshing = refresh().catch(() => void 0).finally(() => {
1444
+ refreshing = null;
1445
+ });
1446
+ }
1447
+ start();
1448
+ return {
1449
+ async current() {
1450
+ if (refreshing) await refreshing.catch(() => {
1451
+ });
1452
+ if (config.counterpartyId && Date.now() - lastFetchAt > refreshMs) start();
1453
+ return cached;
1454
+ },
1455
+ peek: () => cached
1456
+ };
1457
+ }
1458
+
1404
1459
  // src/transport/http.ts
1405
1460
  var HEADER_PREFIX = "X-Astra-";
1406
1461
  function extractHttpCredentials(headers) {
@@ -1550,6 +1605,20 @@ function resolveHttpPdlss(input) {
1550
1605
  }
1551
1606
  return { purpose, action, purposeSource, actionSource };
1552
1607
  }
1608
+ function wirePurposeSource(source) {
1609
+ switch (source) {
1610
+ case "route_config":
1611
+ return "route_config";
1612
+ case "header":
1613
+ case "legacy_header":
1614
+ case "query":
1615
+ return "header";
1616
+ case "custom_extractor":
1617
+ return "body";
1618
+ default:
1619
+ return "default";
1620
+ }
1621
+ }
1553
1622
 
1554
1623
  // src/adapters/approval-gate.ts
1555
1624
  var APPROVAL_REASON = "Transaction is above the autonomous limit and requires human approval. The agent owner can approve or deny this transaction in the AstraSync dashboard.";
@@ -2350,7 +2419,6 @@ function defaultOnDenied(result, _req, res) {
2350
2419
  }
2351
2420
  });
2352
2421
  }
2353
- var DEFAULT_ROUTES_REFRESH_MS = 5 * 60 * 1e3;
2354
2422
  function createMiddleware(options) {
2355
2423
  if ("routes" in options) {
2356
2424
  console.warn(
@@ -2366,7 +2434,7 @@ function createMiddleware(options) {
2366
2434
  recordDecisions,
2367
2435
  enableRuntimeChallenge = true,
2368
2436
  routesRefreshMs = DEFAULT_ROUTES_REFRESH_MS,
2369
- failOnError = "open",
2437
+ failOnError = "closed",
2370
2438
  caseInsensitiveRouteMatch = false,
2371
2439
  anonymousBeacon = true,
2372
2440
  trustVerifiedHop = false,
@@ -2390,26 +2458,19 @@ function createMiddleware(options) {
2390
2458
  rawHeaders: req.headers
2391
2459
  });
2392
2460
  } : void 0;
2393
- let cachedRoutes = [];
2394
- let lastFetchAt = 0;
2395
- let refreshing = null;
2396
2461
  let warnedNoCounterparty = false;
2397
2462
  let warnedEmptyRoutes = false;
2398
- async function refreshRoutes() {
2399
- if (!config.counterpartyId) {
2400
- if (!warnedNoCounterparty) {
2401
- console.warn(
2402
- "[VerificationGateway] No counterpartyId configured \u2014 falling through (allow all). Per-route policy lives in the AstraSync dashboard now; register the endpoint and set counterpartyId in your middleware config to enforce policy."
2403
- );
2404
- warnedNoCounterparty = true;
2405
- }
2406
- return;
2407
- }
2408
- const fetched = await fetchRoutes(config, config.counterpartyId);
2409
- if (fetched) {
2410
- cachedRoutes = fetched;
2411
- lastFetchAt = Date.now();
2412
- if (cachedRoutes.length === 0 && !warnedEmptyRoutes) {
2463
+ const routesCache = createRoutesCache(config, {
2464
+ refreshMs: routesRefreshMs,
2465
+ onNoCounterparty: () => {
2466
+ if (warnedNoCounterparty) return;
2467
+ console.warn(
2468
+ "[VerificationGateway] No counterpartyId configured \u2014 falling through (allow all). Per-route policy lives in the AstraSync dashboard now; register the endpoint and set counterpartyId in your middleware config to enforce policy."
2469
+ );
2470
+ warnedNoCounterparty = true;
2471
+ },
2472
+ onFetched: (routes) => {
2473
+ if (routes.length === 0 && !warnedEmptyRoutes) {
2413
2474
  const dashboard = config.dashboardUrl ?? "https://astrasync.ai/dashboard";
2414
2475
  console.warn(
2415
2476
  `[VerificationGateway] No route policy configured for ${config.counterpartyId}. Gateway is in pass-through mode for ALL traffic until you add at least one route. Configure at ${dashboard}/dashboard/endpoints/${config.counterpartyId}/routes`
@@ -2417,9 +2478,6 @@ function createMiddleware(options) {
2417
2478
  warnedEmptyRoutes = true;
2418
2479
  }
2419
2480
  }
2420
- }
2421
- refreshing = refreshRoutes().finally(() => {
2422
- refreshing = null;
2423
2481
  });
2424
2482
  return async (req, res, next) => {
2425
2483
  try {
@@ -2427,15 +2485,9 @@ function createMiddleware(options) {
2427
2485
  if (shouldSkip) {
2428
2486
  return next();
2429
2487
  }
2430
- if (refreshing) {
2431
- await refreshing.catch(() => {
2432
- });
2433
- }
2434
- if (config.counterpartyId && Date.now() - lastFetchAt > routesRefreshMs) {
2435
- refreshing = refreshRoutes().finally(() => {
2436
- refreshing = null;
2437
- });
2438
- }
2488
+ const cachedRoutes = (await routesCache.current()).filter(
2489
+ (r) => typeof r.pattern === "string" && !r.tool
2490
+ );
2439
2491
  const correlationId = req.headers["x-request-id"] || req.headers["x-correlation-id"];
2440
2492
  const matchedRoute = findRouteConfig(cachedRoutes, req.path, req.method, {
2441
2493
  caseInsensitive: caseInsensitiveRouteMatch,
@@ -2559,6 +2611,12 @@ function createMiddleware(options) {
2559
2611
  ...commerceArtifacts && { commerceArtifacts },
2560
2612
  purpose,
2561
2613
  action: pdlssPair.action,
2614
+ // 5.19.0: the source + the request line let verify-access check a
2615
+ // route purpose against the stored rule (item 20: an MPP paid leg
2616
+ // keeps `shopping.purchase` instead of `commerce.payment.execute`).
2617
+ purposeSource: wirePurposeSource(pdlssPair.purposeSource),
2618
+ requestMethod: req.method,
2619
+ requestPath: req.path,
2562
2620
  resource: req.path,
2563
2621
  createSession: shouldRecordDecisions,
2564
2622
  counterpartyUrl,
@@ -2636,7 +2694,8 @@ function createMiddleware(options) {
2636
2694
  return;
2637
2695
  }
2638
2696
  if (routeConfig.minTrustScore && result.agent) {
2639
- if (result.agent.trustScore < routeConfig.minTrustScore) {
2697
+ const score = result.agent.trustScore;
2698
+ if (typeof score !== "number" || score < routeConfig.minTrustScore) {
2640
2699
  const trustFailure = {
2641
2700
  dimension: "endpoint.trust",
2642
2701
  message: "Trust below the route requirement for this endpoint.",