@astrasyncai/verification-gateway 3.4.0 → 3.6.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 (84) hide show
  1. package/README.md +102 -0
  2. package/dist/adapter-interface/interface.d.mts +2 -2
  3. package/dist/adapter-interface/interface.d.ts +2 -2
  4. package/dist/adapters/express.d.mts +2 -2
  5. package/dist/adapters/express.d.ts +2 -2
  6. package/dist/adapters/express.js +113 -20
  7. package/dist/adapters/express.js.map +1 -1
  8. package/dist/adapters/express.mjs +113 -20
  9. package/dist/adapters/express.mjs.map +1 -1
  10. package/dist/adapters/mcp.d.mts +1 -1
  11. package/dist/adapters/mcp.d.ts +1 -1
  12. package/dist/adapters/mcp.js +96 -20
  13. package/dist/adapters/mcp.js.map +1 -1
  14. package/dist/adapters/mcp.mjs +96 -20
  15. package/dist/adapters/mcp.mjs.map +1 -1
  16. package/dist/adapters/nextjs.d.mts +2 -2
  17. package/dist/adapters/nextjs.d.ts +2 -2
  18. package/dist/adapters/nextjs.js +101 -20
  19. package/dist/adapters/nextjs.js.map +1 -1
  20. package/dist/adapters/nextjs.mjs +101 -20
  21. package/dist/adapters/nextjs.mjs.map +1 -1
  22. package/dist/adapters/sdk.d.mts +2 -2
  23. package/dist/adapters/sdk.d.ts +2 -2
  24. package/dist/adapters/sdk.js +19 -16
  25. package/dist/adapters/sdk.js.map +1 -1
  26. package/dist/adapters/sdk.mjs +19 -16
  27. package/dist/adapters/sdk.mjs.map +1 -1
  28. package/dist/agent/index.d.mts +2 -2
  29. package/dist/agent/index.d.ts +2 -2
  30. package/dist/browser/background.js +22 -16
  31. package/dist/browser/background.js.map +1 -1
  32. package/dist/browser/background.mjs +22 -16
  33. package/dist/browser/background.mjs.map +1 -1
  34. package/dist/browser/browser-adapter.d.mts +2 -2
  35. package/dist/browser/browser-adapter.d.ts +2 -2
  36. package/dist/cli/index.d.mts +2 -2
  37. package/dist/cli/index.d.ts +2 -2
  38. package/dist/cursor/cursor-adapter.d.mts +2 -2
  39. package/dist/cursor/cursor-adapter.d.ts +2 -2
  40. package/dist/cursor/extension.d.mts +2 -2
  41. package/dist/cursor/extension.d.ts +2 -2
  42. package/dist/cursor/extension.js +22 -16
  43. package/dist/cursor/extension.js.map +1 -1
  44. package/dist/cursor/extension.mjs +22 -16
  45. package/dist/cursor/extension.mjs.map +1 -1
  46. package/dist/{express-CeFvNWDD.d.mts → express-BnMO-H3y.d.mts} +1 -1
  47. package/dist/{express-RIh05wW2.d.ts → express-DQhDzNAt.d.ts} +1 -1
  48. package/dist/gateway/gateway.d.mts +2 -2
  49. package/dist/gateway/gateway.d.ts +2 -2
  50. package/dist/gateway/gateway.js +22 -16
  51. package/dist/gateway/gateway.js.map +1 -1
  52. package/dist/gateway/gateway.mjs +22 -16
  53. package/dist/gateway/gateway.mjs.map +1 -1
  54. package/dist/git-trigger/git-hooks.d.mts +2 -2
  55. package/dist/git-trigger/git-hooks.d.ts +2 -2
  56. package/dist/{index-DgVBEiwI.d.mts → index-BT_aRn-I.d.mts} +1 -1
  57. package/dist/{index-BYu1FKMy.d.ts → index-D8-dvUFA.d.ts} +1 -1
  58. package/dist/{index-Bw4FeHMY.d.mts → index-WHKq2v17.d.mts} +5 -1
  59. package/dist/{index-C-K0WCrk.d.ts → index-rftma0ln.d.ts} +5 -1
  60. package/dist/index.d.mts +55 -9
  61. package/dist/index.d.ts +55 -9
  62. package/dist/index.js +184 -34
  63. package/dist/index.js.map +1 -1
  64. package/dist/index.mjs +182 -34
  65. package/dist/index.mjs.map +1 -1
  66. package/dist/local-evaluator/evaluator.d.mts +2 -2
  67. package/dist/local-evaluator/evaluator.d.ts +2 -2
  68. package/dist/{nextjs-xciaMpsZ.d.mts → nextjs-DFKYhxe6.d.mts} +1 -1
  69. package/dist/{nextjs--xR9zbSJ.d.ts → nextjs-DPj7ZNlq.d.ts} +1 -1
  70. package/dist/{sdk-FP7xT9F8.d.ts → sdk-CAcHgB5x.d.ts} +1 -1
  71. package/dist/{sdk-CJYCLMI0.d.mts → sdk-Cy3wAmDt.d.mts} +1 -1
  72. package/dist/transport/index.d.mts +2 -2
  73. package/dist/transport/index.d.ts +2 -2
  74. package/dist/transport/index.js +22 -4
  75. package/dist/transport/index.js.map +1 -1
  76. package/dist/transport/index.mjs +22 -4
  77. package/dist/transport/index.mjs.map +1 -1
  78. package/dist/{types-Cj92yKeA.d.mts → types-B-ubjHER.d.mts} +1 -1
  79. package/dist/{types-DOeL-dIw.d.ts → types-Bgn5gxHQ.d.ts} +1 -1
  80. package/dist/{types-Cwrvo30g.d.mts → types-CKe8O0lR.d.mts} +65 -3
  81. package/dist/{types-Cwrvo30g.d.ts → types-CKe8O0lR.d.ts} +65 -3
  82. package/dist/ui/index.d.mts +1 -1
  83. package/dist/ui/index.d.ts +1 -1
  84. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -126,7 +126,7 @@ function getCapabilities(accessLevel) {
126
126
  }
127
127
 
128
128
  // src/version.ts
129
- var SDK_VERSION = "3.3.0";
129
+ var SDK_VERSION = "3.6.0";
130
130
 
131
131
  // src/well-known.ts
132
132
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -196,10 +196,10 @@ var DEFAULT_CONFIG = {
196
196
  // through (`hasMinimumAccess('guidance', 'guidance') === true`).
197
197
  defaultAccessLevel: "none",
198
198
  // minTrustScore + minTrustScoreForFull deprecated in v2.3.0 — server decides.
199
- // Round-18.5 F4: cacheTtl deliberately unset. When undefined, cacheResult
200
- // applies the split default (60s autonomous / 300s step-up). When the
201
- // caller sets cacheTtl explicitly, that value is honoured uniformly.
202
- // Set cacheTtl: 0 to disable caching entirely.
199
+ // cacheTtl deliberately unset. When undefined, cacheResult applies the 60s
200
+ // default; the caller's explicit value is honoured for cacheable results.
201
+ // Denials and step-up escalations are NEVER cached (3.6.0) regardless of
202
+ // cacheTtl. Set cacheTtl: 0 to disable caching entirely.
203
203
  debug: false
204
204
  };
205
205
  var initCheckPerformed = false;
@@ -286,10 +286,9 @@ function getCachedResult(request, counterpartyId) {
286
286
  }
287
287
  return null;
288
288
  }
289
- var DEFAULT_AUTONOMOUS_TTL_SECONDS = 60;
290
- var DEFAULT_STEP_UP_TTL_SECONDS = 300;
289
+ var DEFAULT_CACHE_TTL_SECONDS = 60;
291
290
  function cacheResult(request, result, configuredTtl, counterpartyId) {
292
- const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : result.requiresStepUp ? DEFAULT_STEP_UP_TTL_SECONDS : DEFAULT_AUTONOMOUS_TTL_SECONDS;
291
+ const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : DEFAULT_CACHE_TTL_SECONDS;
293
292
  const key = getCacheKey(request, counterpartyId);
294
293
  verificationCache.set(key, {
295
294
  result,
@@ -471,7 +470,7 @@ async function callVerifyAccessAPI(config, request) {
471
470
  };
472
471
  }
473
472
  }
474
- async function verify(config, request) {
473
+ async function verify(config, request, options) {
475
474
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
476
475
  const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
477
476
  if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
@@ -487,7 +486,7 @@ async function verify(config, request) {
487
486
  "[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access-level decisions (the SDK reads access.accessLevel from the verify-access response). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side."
488
487
  );
489
488
  }
490
- if (mergedConfig.cacheTtl !== 0) {
489
+ if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache) {
491
490
  const cached = getCachedResult(request, mergedConfig.counterpartyId);
492
491
  if (cached) {
493
492
  if (mergedConfig.debug) {
@@ -507,6 +506,8 @@ async function verify(config, request) {
507
506
  console.log("[VerificationGateway] Calling verify-access API");
508
507
  }
509
508
  const apiResponse = await callVerifyAccessAPI(mergedConfig, enrichedRequest);
509
+ const rawServerDenialReasons = apiResponse.denialReasons;
510
+ const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
510
511
  if (!apiResponse.success) {
511
512
  return createGuidanceResponse(mergedConfig, apiResponse.error, {
512
513
  source: "api_error",
@@ -528,7 +529,10 @@ async function verify(config, request) {
528
529
  // ALSO short-circuit on `!identityVerified || !policyAllowed` before
529
530
  // the gate check — belt-and-braces.
530
531
  accessLevel: "none",
531
- denialReasons: aggregatedFailures && aggregatedFailures.length > 0 ? aggregatedFailures.map((f) => f.message) : apiResponse.access?.reason ? [apiResponse.access.reason] : ["Access denied"],
532
+ // 3.6.0: the server now emits top-level denialReasons on every deny
533
+ // path — prefer it verbatim; the failure-message reconstruction remains
534
+ // as the fallback for older backends.
535
+ denialReasons: serverDenialReasons ?? (aggregatedFailures && aggregatedFailures.length > 0 ? aggregatedFailures.map((f) => f.message) : apiResponse.access?.reason ? [apiResponse.access.reason] : ["Access denied"]),
532
536
  failures: aggregatedFailures,
533
537
  requiresStepUp: apiResponse.access?.requiresStepUp,
534
538
  requiresApproval: apiResponse.access?.requiresApproval,
@@ -605,9 +609,7 @@ async function verify(config, request) {
605
609
  if (result.recommendation === "deny") {
606
610
  result.policyAllowed = false;
607
611
  result.accessLevel = "none";
608
- result.denialReasons = result.recommendationReasons || [
609
- "Access denied by AstraSync recommendation"
610
- ];
612
+ result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Access denied by AstraSync recommendation"];
611
613
  result.guidance = result.runtimeChallenge ? {
612
614
  message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
613
615
  registrationUrl: urls?.registrationUrl ?? "",
@@ -619,9 +621,10 @@ async function verify(config, request) {
619
621
  };
620
622
  } else if (result.recommendation === "step_up_required") {
621
623
  result.requiresStepUp = true;
622
- result.denialReasons = result.recommendationReasons || ["Step-up verification required"];
624
+ result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Step-up verification required"];
623
625
  }
624
- if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny") {
626
+ const escalates = result.requiresStepUp === true || result.requiresApproval === true || result.recommendation === "step_up_required";
627
+ if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny" && !escalates) {
625
628
  cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
626
629
  }
627
630
  return result;
@@ -680,6 +683,64 @@ async function quickVerify(config, credentials) {
680
683
  };
681
684
  }
682
685
 
686
+ // src/adapters/stepup-poll.ts
687
+ var DEFAULT_POLL_INTERVAL_MS = 3e3;
688
+ var MIN_POLL_INTERVAL_MS = 250;
689
+ var FALLBACK_MAX_WAIT_MS = 5 * 60 * 1e3;
690
+ var EXPIRY_GRACE_MS = 5e3;
691
+ var POLL_REQUEST_TIMEOUT_MS = 1e4;
692
+ function resolvePollUrl(config, pollUrl) {
693
+ if (pollUrl.startsWith("http")) return pollUrl;
694
+ const origin = (config.apiBaseUrl ?? "").replace(/\/api\/?$/, "");
695
+ return origin + pollUrl;
696
+ }
697
+ async function pollStepUpStatus(config, approval) {
698
+ if (!approval.pollUrl) return null;
699
+ try {
700
+ const res = await fetch(resolvePollUrl(config, approval.pollUrl), {
701
+ method: "GET",
702
+ signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS)
703
+ });
704
+ if (!res.ok) return null;
705
+ const body = await res.json();
706
+ const data = body?.data;
707
+ const status = data && typeof data === "object" ? data.status : body?.status;
708
+ return typeof status === "string" ? status : null;
709
+ } catch {
710
+ return null;
711
+ }
712
+ }
713
+ function resolveDeadline(config, approval) {
714
+ const now = Date.now();
715
+ const maxWait = config.stepUpMaxWaitMs ?? 0;
716
+ if (maxWait > 0) return now + maxWait;
717
+ if (approval.expiresAt) {
718
+ const expiry = Date.parse(approval.expiresAt);
719
+ if (!Number.isNaN(expiry)) return Math.max(now, expiry) + EXPIRY_GRACE_MS;
720
+ }
721
+ return now + FALLBACK_MAX_WAIT_MS;
722
+ }
723
+ function sleep(ms) {
724
+ return new Promise((resolve) => setTimeout(resolve, ms));
725
+ }
726
+ async function awaitStepUpApproval(config, approval) {
727
+ const deadline = resolveDeadline(config, approval);
728
+ const pollInterval = Math.max(
729
+ MIN_POLL_INTERVAL_MS,
730
+ config.stepUpPollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS
731
+ );
732
+ while (Date.now() < deadline) {
733
+ const status = await pollStepUpStatus(config, approval);
734
+ if (status && status !== "pending") {
735
+ return status;
736
+ }
737
+ const remaining = deadline - Date.now();
738
+ if (remaining <= 0) break;
739
+ await sleep(Math.min(pollInterval, remaining));
740
+ }
741
+ return "timeout";
742
+ }
743
+
683
744
  // src/adapters/approval-gate.ts
684
745
  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.";
685
746
  function requiresHumanApproval(result) {
@@ -1026,7 +1087,10 @@ function defaultOnDenied(result, _req, res) {
1026
1087
  // Round-10: aggregated per-dimension detail + correlation handle.
1027
1088
  failures: result.failures,
1028
1089
  correlationId: result.correlationId,
1029
- stepUpApproval: result.stepUpApproval
1090
+ stepUpApproval: result.stepUpApproval,
1091
+ // 3.6.0: terminal outcome of an opt-in hold-and-poll wait (denied /
1092
+ // expired / consumed / timeout). Absent when the feature is off.
1093
+ ...result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }
1030
1094
  }
1031
1095
  });
1032
1096
  }
@@ -1176,7 +1240,22 @@ function createMiddleware(options) {
1176
1240
  );
1177
1241
  }
1178
1242
  const agentCardUrl = typeof req.headers["x-astrasync-agent-card"] === "string" ? req.headers["x-astrasync-agent-card"] : void 0;
1179
- const result = await verify(config, {
1243
+ let txValue;
1244
+ let txCurrency;
1245
+ if (config.extractTransactionValue) {
1246
+ try {
1247
+ const extracted = config.extractTransactionValue(req);
1248
+ if (extracted) {
1249
+ txValue = extracted.value;
1250
+ txCurrency = extracted.currency;
1251
+ }
1252
+ } catch (e) {
1253
+ if (config.debug) {
1254
+ console.warn("[VerificationGateway] extractTransactionValue threw:", e);
1255
+ }
1256
+ }
1257
+ }
1258
+ const verificationRequest = {
1180
1259
  credentials,
1181
1260
  purpose,
1182
1261
  action: pdlssPair.action,
@@ -1186,6 +1265,8 @@ function createMiddleware(options) {
1186
1265
  counterpartyType: config.counterpartyType || "api",
1187
1266
  enableRuntimeChallenge,
1188
1267
  durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,
1268
+ ...txValue !== void 0 && { transactionValue: txValue },
1269
+ ...txCurrency && { currency: txCurrency },
1189
1270
  callerMetadata: {
1190
1271
  sourceIp: originalClientIp,
1191
1272
  userAgent: req.headers["user-agent"],
@@ -1194,9 +1275,21 @@ function createMiddleware(options) {
1194
1275
  forwardedFor: forwardedForStr,
1195
1276
  agentCardUrl
1196
1277
  }
1197
- });
1278
+ };
1279
+ let result = await verify(config, verificationRequest);
1198
1280
  req.agentVerification = result;
1199
- const sessionId = result.sessionId;
1281
+ let sessionId = result.sessionId;
1282
+ if (config.stepUpMaxWaitMs !== void 0 && result.identityVerified && requiresHumanApproval(result) && result.stepUpApproval?.pollUrl) {
1283
+ const outcome = await awaitStepUpApproval(config, result.stepUpApproval);
1284
+ res.setHeader("X-Astra-Step-Up", outcome);
1285
+ if (outcome === "approved") {
1286
+ result = await verify(config, verificationRequest, { bypassCache: true });
1287
+ req.agentVerification = result;
1288
+ sessionId = result.sessionId;
1289
+ } else {
1290
+ result.stepUpOutcome = outcome;
1291
+ }
1292
+ }
1200
1293
  if (!result.identityVerified || !result.policyAllowed) {
1201
1294
  if (shouldRecordDecisions && sessionId) {
1202
1295
  recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
@@ -1645,7 +1738,7 @@ function createMiddleware2(options) {
1645
1738
  }
1646
1739
  const forwardedFor = request.headers.get("x-forwarded-for") || void 0;
1647
1740
  const originalClientIp = forwardedFor?.split(",")[0]?.trim();
1648
- const result = await verify(config, {
1741
+ const verificationRequest = {
1649
1742
  credentials,
1650
1743
  purpose,
1651
1744
  action: pdlssPair.action,
@@ -1662,7 +1755,17 @@ function createMiddleware2(options) {
1662
1755
  forwardedFor,
1663
1756
  agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0
1664
1757
  }
1665
- });
1758
+ };
1759
+ let result = await verify(config, verificationRequest);
1760
+ let stepUpHoldOutcome;
1761
+ if (config.stepUpMaxWaitMs !== void 0 && result.identityVerified && requiresHumanApproval(result) && result.stepUpApproval?.pollUrl) {
1762
+ stepUpHoldOutcome = await awaitStepUpApproval(config, result.stepUpApproval);
1763
+ if (stepUpHoldOutcome === "approved") {
1764
+ result = await verify(config, verificationRequest, { bypassCache: true });
1765
+ } else {
1766
+ result.stepUpOutcome = stepUpHoldOutcome;
1767
+ }
1768
+ }
1666
1769
  const approvalRequired = result.identityVerified && result.policyAllowed && requiresHumanApproval(result);
1667
1770
  if (approvalRequired) annotateApprovalRequired(result);
1668
1771
  if (!result.identityVerified || !result.policyAllowed || approvalRequired) {
@@ -1677,10 +1780,17 @@ function createMiddleware2(options) {
1677
1780
  message: result.denialReasons?.[0] || "Access denied",
1678
1781
  guidance: result.guidance,
1679
1782
  failures: result.failures,
1680
- stepUpApproval: result.stepUpApproval
1783
+ stepUpApproval: result.stepUpApproval,
1784
+ // 3.6.0: terminal outcome of an opt-in hold-and-poll wait.
1785
+ ...result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }
1681
1786
  }
1682
1787
  },
1683
- { status: !result.identityVerified ? 401 : 403 }
1788
+ {
1789
+ status: !result.identityVerified ? 401 : 403,
1790
+ ...stepUpHoldOutcome && {
1791
+ headers: { "X-Astra-Step-Up": stepUpHoldOutcome }
1792
+ }
1793
+ }
1684
1794
  );
1685
1795
  }
1686
1796
  if (showCommerceShield) {
@@ -1699,6 +1809,9 @@ function createMiddleware2(options) {
1699
1809
  "X-AstraSync-Verified",
1700
1810
  (result.identityVerified && result.policyAllowed).toString()
1701
1811
  );
1812
+ if (stepUpHoldOutcome) {
1813
+ response.headers.set("X-Astra-Step-Up", stepUpHoldOutcome);
1814
+ }
1702
1815
  response.headers.set("X-AstraSync-Identity-Verified", result.identityVerified.toString());
1703
1816
  response.headers.set("X-AstraSync-Policy-Allowed", result.policyAllowed.toString());
1704
1817
  response.headers.set("X-AstraSync-Access-Level", result.accessLevel);
@@ -2166,15 +2279,33 @@ function extractMPPTransactionValue(challenge) {
2166
2279
  source: `challenge.request.amount (method=${challenge.method ?? "unknown"})`
2167
2280
  };
2168
2281
  }
2282
+ var KNOWN_TOKEN_DECIMALS = {
2283
+ USDC: 6,
2284
+ USDT: 6,
2285
+ DAI: 18,
2286
+ ETH: 18,
2287
+ WETH: 18
2288
+ };
2169
2289
  function extractX402TransactionValue(req) {
2170
- const amount = req.maxAmountRequired ?? req.amount;
2290
+ const rawAmount = req.maxAmountRequired ?? req.amount;
2171
2291
  const currency = req.currency ?? req.asset;
2172
- if (typeof amount !== "number" || !currency) return null;
2292
+ if (typeof rawAmount !== "number" || !currency) return null;
2293
+ const source = req.maxAmountRequired !== void 0 ? "maxAmountRequired" : "amount";
2294
+ const decimals = KNOWN_TOKEN_DECIMALS[currency.toUpperCase()];
2295
+ if (decimals !== void 0) {
2296
+ return {
2297
+ protocol: "x402",
2298
+ amount: rawAmount / Math.pow(10, decimals),
2299
+ currency,
2300
+ source
2301
+ };
2302
+ }
2173
2303
  return {
2174
2304
  protocol: "x402",
2175
- amount,
2305
+ amount: rawAmount,
2176
2306
  currency,
2177
- source: req.maxAmountRequired !== void 0 ? "maxAmountRequired" : "amount"
2307
+ source,
2308
+ rawUnits: true
2178
2309
  };
2179
2310
  }
2180
2311
 
@@ -4581,7 +4712,10 @@ function defaultMcpDenied(result, req, res) {
4581
4712
  // Round-10: aggregated per-dimension detail + correlation handle.
4582
4713
  failures: result.failures,
4583
4714
  correlationId: result.correlationId,
4584
- stepUpApproval: result.stepUpApproval
4715
+ stepUpApproval: result.stepUpApproval,
4716
+ // 3.6.0: terminal outcome of an opt-in hold-and-poll wait (denied /
4717
+ // expired / consumed / timeout). Absent when the feature is off.
4718
+ ...result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }
4585
4719
  }
4586
4720
  }
4587
4721
  });
@@ -4722,7 +4856,7 @@ function createMcpMiddleware(options) {
4722
4856
  }
4723
4857
  const counterpartyUrl = config.counterpartyUrl || `${req.protocol}://${req.get("host")}${req.path}`;
4724
4858
  const shouldRecordDecisions = recordDecisions !== false;
4725
- const result = await verify(config, {
4859
+ const verificationRequest = {
4726
4860
  credentials,
4727
4861
  purpose: pdlss.purpose,
4728
4862
  action: pdlss.action,
@@ -4740,9 +4874,21 @@ function createMcpMiddleware(options) {
4740
4874
  userAgent: req.headers["user-agent"],
4741
4875
  host: req.headers.host
4742
4876
  }
4743
- });
4877
+ };
4878
+ let result = await verify(config, verificationRequest);
4744
4879
  req.agentVerification = result;
4745
- const sessionId = result.sessionId;
4880
+ let sessionId = result.sessionId;
4881
+ if (config.stepUpMaxWaitMs !== void 0 && result.identityVerified && requiresHumanApproval(result) && result.stepUpApproval?.pollUrl) {
4882
+ const outcome = await awaitStepUpApproval(config, result.stepUpApproval);
4883
+ res.setHeader("X-Astra-Step-Up", outcome);
4884
+ if (outcome === "approved") {
4885
+ result = await verify(config, verificationRequest, { bypassCache: true });
4886
+ req.agentVerification = result;
4887
+ sessionId = result.sessionId;
4888
+ } else {
4889
+ result.stepUpOutcome = outcome;
4890
+ }
4891
+ }
4746
4892
  if (!result.identityVerified || !result.policyAllowed) {
4747
4893
  if (shouldRecordDecisions && sessionId) {
4748
4894
  recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
@@ -4896,7 +5042,7 @@ var RegistrationTimeoutError = class extends AstraSyncError {
4896
5042
 
4897
5043
  // src/registration/api.ts
4898
5044
  var DEFAULT_BASE_URL = "https://astrasync.ai";
4899
- var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
5045
+ var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
4900
5046
  var AstraSync = class {
4901
5047
  constructor(config = {}) {
4902
5048
  let raw = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(
@@ -5058,7 +5204,7 @@ var AstraSync = class {
5058
5204
  if (result.state === "expired") {
5059
5205
  throw new RegistrationExpiredError(requestId);
5060
5206
  }
5061
- await sleep(pollIntervalMs);
5207
+ await sleep2(pollIntervalMs);
5062
5208
  }
5063
5209
  throw new RegistrationTimeoutError(requestId);
5064
5210
  }
@@ -5527,6 +5673,7 @@ export {
5527
5673
  VERSION,
5528
5674
  agent_exports as agent,
5529
5675
  authorizeSettlement,
5676
+ awaitStepUpApproval,
5530
5677
  buildGuidance,
5531
5678
  clearCache,
5532
5679
  createMcpMiddleware,
@@ -5542,6 +5689,7 @@ export {
5542
5689
  hasCredentials,
5543
5690
  hasMinimumAccess,
5544
5691
  nextjs_exports as nextjs,
5692
+ pollStepUpStatus,
5545
5693
  prefetchWellKnown,
5546
5694
  quickVerify,
5547
5695
  recordDecision2 as recordDecision,