@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.js CHANGED
@@ -46,6 +46,7 @@ __export(src_exports, {
46
46
  VERSION: () => VERSION,
47
47
  agent: () => agent_exports,
48
48
  authorizeSettlement: () => authorizeSettlement,
49
+ awaitStepUpApproval: () => awaitStepUpApproval,
49
50
  buildGuidance: () => buildGuidance,
50
51
  clearCache: () => clearCache,
51
52
  createMcpMiddleware: () => createMcpMiddleware,
@@ -61,6 +62,7 @@ __export(src_exports, {
61
62
  hasCredentials: () => hasCredentials,
62
63
  hasMinimumAccess: () => hasMinimumAccess,
63
64
  nextjs: () => nextjs_exports,
65
+ pollStepUpStatus: () => pollStepUpStatus,
64
66
  prefetchWellKnown: () => prefetchWellKnown,
65
67
  quickVerify: () => quickVerify,
66
68
  recordDecision: () => recordDecision2,
@@ -193,7 +195,7 @@ function getCapabilities(accessLevel) {
193
195
  }
194
196
 
195
197
  // src/version.ts
196
- var SDK_VERSION = "3.3.0";
198
+ var SDK_VERSION = "3.6.0";
197
199
 
198
200
  // src/well-known.ts
199
201
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -263,10 +265,10 @@ var DEFAULT_CONFIG = {
263
265
  // through (`hasMinimumAccess('guidance', 'guidance') === true`).
264
266
  defaultAccessLevel: "none",
265
267
  // minTrustScore + minTrustScoreForFull deprecated in v2.3.0 — server decides.
266
- // Round-18.5 F4: cacheTtl deliberately unset. When undefined, cacheResult
267
- // applies the split default (60s autonomous / 300s step-up). When the
268
- // caller sets cacheTtl explicitly, that value is honoured uniformly.
269
- // Set cacheTtl: 0 to disable caching entirely.
268
+ // cacheTtl deliberately unset. When undefined, cacheResult applies the 60s
269
+ // default; the caller's explicit value is honoured for cacheable results.
270
+ // Denials and step-up escalations are NEVER cached (3.6.0) regardless of
271
+ // cacheTtl. Set cacheTtl: 0 to disable caching entirely.
270
272
  debug: false
271
273
  };
272
274
  var initCheckPerformed = false;
@@ -353,10 +355,9 @@ function getCachedResult(request, counterpartyId) {
353
355
  }
354
356
  return null;
355
357
  }
356
- var DEFAULT_AUTONOMOUS_TTL_SECONDS = 60;
357
- var DEFAULT_STEP_UP_TTL_SECONDS = 300;
358
+ var DEFAULT_CACHE_TTL_SECONDS = 60;
358
359
  function cacheResult(request, result, configuredTtl, counterpartyId) {
359
- const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : result.requiresStepUp ? DEFAULT_STEP_UP_TTL_SECONDS : DEFAULT_AUTONOMOUS_TTL_SECONDS;
360
+ const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : DEFAULT_CACHE_TTL_SECONDS;
360
361
  const key = getCacheKey(request, counterpartyId);
361
362
  verificationCache.set(key, {
362
363
  result,
@@ -538,7 +539,7 @@ async function callVerifyAccessAPI(config, request) {
538
539
  };
539
540
  }
540
541
  }
541
- async function verify(config, request) {
542
+ async function verify(config, request, options) {
542
543
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
543
544
  const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
544
545
  if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
@@ -554,7 +555,7 @@ async function verify(config, request) {
554
555
  "[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."
555
556
  );
556
557
  }
557
- if (mergedConfig.cacheTtl !== 0) {
558
+ if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache) {
558
559
  const cached = getCachedResult(request, mergedConfig.counterpartyId);
559
560
  if (cached) {
560
561
  if (mergedConfig.debug) {
@@ -574,6 +575,8 @@ async function verify(config, request) {
574
575
  console.log("[VerificationGateway] Calling verify-access API");
575
576
  }
576
577
  const apiResponse = await callVerifyAccessAPI(mergedConfig, enrichedRequest);
578
+ const rawServerDenialReasons = apiResponse.denialReasons;
579
+ const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
577
580
  if (!apiResponse.success) {
578
581
  return createGuidanceResponse(mergedConfig, apiResponse.error, {
579
582
  source: "api_error",
@@ -595,7 +598,10 @@ async function verify(config, request) {
595
598
  // ALSO short-circuit on `!identityVerified || !policyAllowed` before
596
599
  // the gate check — belt-and-braces.
597
600
  accessLevel: "none",
598
- denialReasons: aggregatedFailures && aggregatedFailures.length > 0 ? aggregatedFailures.map((f) => f.message) : apiResponse.access?.reason ? [apiResponse.access.reason] : ["Access denied"],
601
+ // 3.6.0: the server now emits top-level denialReasons on every deny
602
+ // path — prefer it verbatim; the failure-message reconstruction remains
603
+ // as the fallback for older backends.
604
+ denialReasons: serverDenialReasons ?? (aggregatedFailures && aggregatedFailures.length > 0 ? aggregatedFailures.map((f) => f.message) : apiResponse.access?.reason ? [apiResponse.access.reason] : ["Access denied"]),
599
605
  failures: aggregatedFailures,
600
606
  requiresStepUp: apiResponse.access?.requiresStepUp,
601
607
  requiresApproval: apiResponse.access?.requiresApproval,
@@ -672,9 +678,7 @@ async function verify(config, request) {
672
678
  if (result.recommendation === "deny") {
673
679
  result.policyAllowed = false;
674
680
  result.accessLevel = "none";
675
- result.denialReasons = result.recommendationReasons || [
676
- "Access denied by AstraSync recommendation"
677
- ];
681
+ result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Access denied by AstraSync recommendation"];
678
682
  result.guidance = result.runtimeChallenge ? {
679
683
  message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
680
684
  registrationUrl: urls?.registrationUrl ?? "",
@@ -686,9 +690,10 @@ async function verify(config, request) {
686
690
  };
687
691
  } else if (result.recommendation === "step_up_required") {
688
692
  result.requiresStepUp = true;
689
- result.denialReasons = result.recommendationReasons || ["Step-up verification required"];
693
+ result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Step-up verification required"];
690
694
  }
691
- if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny") {
695
+ const escalates = result.requiresStepUp === true || result.requiresApproval === true || result.recommendation === "step_up_required";
696
+ if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny" && !escalates) {
692
697
  cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
693
698
  }
694
699
  return result;
@@ -747,6 +752,64 @@ async function quickVerify(config, credentials) {
747
752
  };
748
753
  }
749
754
 
755
+ // src/adapters/stepup-poll.ts
756
+ var DEFAULT_POLL_INTERVAL_MS = 3e3;
757
+ var MIN_POLL_INTERVAL_MS = 250;
758
+ var FALLBACK_MAX_WAIT_MS = 5 * 60 * 1e3;
759
+ var EXPIRY_GRACE_MS = 5e3;
760
+ var POLL_REQUEST_TIMEOUT_MS = 1e4;
761
+ function resolvePollUrl(config, pollUrl) {
762
+ if (pollUrl.startsWith("http")) return pollUrl;
763
+ const origin = (config.apiBaseUrl ?? "").replace(/\/api\/?$/, "");
764
+ return origin + pollUrl;
765
+ }
766
+ async function pollStepUpStatus(config, approval) {
767
+ if (!approval.pollUrl) return null;
768
+ try {
769
+ const res = await fetch(resolvePollUrl(config, approval.pollUrl), {
770
+ method: "GET",
771
+ signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS)
772
+ });
773
+ if (!res.ok) return null;
774
+ const body = await res.json();
775
+ const data = body?.data;
776
+ const status = data && typeof data === "object" ? data.status : body?.status;
777
+ return typeof status === "string" ? status : null;
778
+ } catch {
779
+ return null;
780
+ }
781
+ }
782
+ function resolveDeadline(config, approval) {
783
+ const now = Date.now();
784
+ const maxWait = config.stepUpMaxWaitMs ?? 0;
785
+ if (maxWait > 0) return now + maxWait;
786
+ if (approval.expiresAt) {
787
+ const expiry = Date.parse(approval.expiresAt);
788
+ if (!Number.isNaN(expiry)) return Math.max(now, expiry) + EXPIRY_GRACE_MS;
789
+ }
790
+ return now + FALLBACK_MAX_WAIT_MS;
791
+ }
792
+ function sleep(ms) {
793
+ return new Promise((resolve) => setTimeout(resolve, ms));
794
+ }
795
+ async function awaitStepUpApproval(config, approval) {
796
+ const deadline = resolveDeadline(config, approval);
797
+ const pollInterval = Math.max(
798
+ MIN_POLL_INTERVAL_MS,
799
+ config.stepUpPollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS
800
+ );
801
+ while (Date.now() < deadline) {
802
+ const status = await pollStepUpStatus(config, approval);
803
+ if (status && status !== "pending") {
804
+ return status;
805
+ }
806
+ const remaining = deadline - Date.now();
807
+ if (remaining <= 0) break;
808
+ await sleep(Math.min(pollInterval, remaining));
809
+ }
810
+ return "timeout";
811
+ }
812
+
750
813
  // src/adapters/approval-gate.ts
751
814
  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.";
752
815
  function requiresHumanApproval(result) {
@@ -1093,7 +1156,10 @@ function defaultOnDenied(result, _req, res) {
1093
1156
  // Round-10: aggregated per-dimension detail + correlation handle.
1094
1157
  failures: result.failures,
1095
1158
  correlationId: result.correlationId,
1096
- stepUpApproval: result.stepUpApproval
1159
+ stepUpApproval: result.stepUpApproval,
1160
+ // 3.6.0: terminal outcome of an opt-in hold-and-poll wait (denied /
1161
+ // expired / consumed / timeout). Absent when the feature is off.
1162
+ ...result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }
1097
1163
  }
1098
1164
  });
1099
1165
  }
@@ -1243,7 +1309,22 @@ function createMiddleware(options) {
1243
1309
  );
1244
1310
  }
1245
1311
  const agentCardUrl = typeof req.headers["x-astrasync-agent-card"] === "string" ? req.headers["x-astrasync-agent-card"] : void 0;
1246
- const result = await verify(config, {
1312
+ let txValue;
1313
+ let txCurrency;
1314
+ if (config.extractTransactionValue) {
1315
+ try {
1316
+ const extracted = config.extractTransactionValue(req);
1317
+ if (extracted) {
1318
+ txValue = extracted.value;
1319
+ txCurrency = extracted.currency;
1320
+ }
1321
+ } catch (e) {
1322
+ if (config.debug) {
1323
+ console.warn("[VerificationGateway] extractTransactionValue threw:", e);
1324
+ }
1325
+ }
1326
+ }
1327
+ const verificationRequest = {
1247
1328
  credentials,
1248
1329
  purpose,
1249
1330
  action: pdlssPair.action,
@@ -1253,6 +1334,8 @@ function createMiddleware(options) {
1253
1334
  counterpartyType: config.counterpartyType || "api",
1254
1335
  enableRuntimeChallenge,
1255
1336
  durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,
1337
+ ...txValue !== void 0 && { transactionValue: txValue },
1338
+ ...txCurrency && { currency: txCurrency },
1256
1339
  callerMetadata: {
1257
1340
  sourceIp: originalClientIp,
1258
1341
  userAgent: req.headers["user-agent"],
@@ -1261,9 +1344,21 @@ function createMiddleware(options) {
1261
1344
  forwardedFor: forwardedForStr,
1262
1345
  agentCardUrl
1263
1346
  }
1264
- });
1347
+ };
1348
+ let result = await verify(config, verificationRequest);
1265
1349
  req.agentVerification = result;
1266
- const sessionId = result.sessionId;
1350
+ let sessionId = result.sessionId;
1351
+ if (config.stepUpMaxWaitMs !== void 0 && result.identityVerified && requiresHumanApproval(result) && result.stepUpApproval?.pollUrl) {
1352
+ const outcome = await awaitStepUpApproval(config, result.stepUpApproval);
1353
+ res.setHeader("X-Astra-Step-Up", outcome);
1354
+ if (outcome === "approved") {
1355
+ result = await verify(config, verificationRequest, { bypassCache: true });
1356
+ req.agentVerification = result;
1357
+ sessionId = result.sessionId;
1358
+ } else {
1359
+ result.stepUpOutcome = outcome;
1360
+ }
1361
+ }
1267
1362
  if (!result.identityVerified || !result.policyAllowed) {
1268
1363
  if (shouldRecordDecisions && sessionId) {
1269
1364
  recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
@@ -1712,7 +1807,7 @@ function createMiddleware2(options) {
1712
1807
  }
1713
1808
  const forwardedFor = request.headers.get("x-forwarded-for") || void 0;
1714
1809
  const originalClientIp = forwardedFor?.split(",")[0]?.trim();
1715
- const result = await verify(config, {
1810
+ const verificationRequest = {
1716
1811
  credentials,
1717
1812
  purpose,
1718
1813
  action: pdlssPair.action,
@@ -1729,7 +1824,17 @@ function createMiddleware2(options) {
1729
1824
  forwardedFor,
1730
1825
  agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0
1731
1826
  }
1732
- });
1827
+ };
1828
+ let result = await verify(config, verificationRequest);
1829
+ let stepUpHoldOutcome;
1830
+ if (config.stepUpMaxWaitMs !== void 0 && result.identityVerified && requiresHumanApproval(result) && result.stepUpApproval?.pollUrl) {
1831
+ stepUpHoldOutcome = await awaitStepUpApproval(config, result.stepUpApproval);
1832
+ if (stepUpHoldOutcome === "approved") {
1833
+ result = await verify(config, verificationRequest, { bypassCache: true });
1834
+ } else {
1835
+ result.stepUpOutcome = stepUpHoldOutcome;
1836
+ }
1837
+ }
1733
1838
  const approvalRequired = result.identityVerified && result.policyAllowed && requiresHumanApproval(result);
1734
1839
  if (approvalRequired) annotateApprovalRequired(result);
1735
1840
  if (!result.identityVerified || !result.policyAllowed || approvalRequired) {
@@ -1744,10 +1849,17 @@ function createMiddleware2(options) {
1744
1849
  message: result.denialReasons?.[0] || "Access denied",
1745
1850
  guidance: result.guidance,
1746
1851
  failures: result.failures,
1747
- stepUpApproval: result.stepUpApproval
1852
+ stepUpApproval: result.stepUpApproval,
1853
+ // 3.6.0: terminal outcome of an opt-in hold-and-poll wait.
1854
+ ...result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }
1748
1855
  }
1749
1856
  },
1750
- { status: !result.identityVerified ? 401 : 403 }
1857
+ {
1858
+ status: !result.identityVerified ? 401 : 403,
1859
+ ...stepUpHoldOutcome && {
1860
+ headers: { "X-Astra-Step-Up": stepUpHoldOutcome }
1861
+ }
1862
+ }
1751
1863
  );
1752
1864
  }
1753
1865
  if (showCommerceShield) {
@@ -1766,6 +1878,9 @@ function createMiddleware2(options) {
1766
1878
  "X-AstraSync-Verified",
1767
1879
  (result.identityVerified && result.policyAllowed).toString()
1768
1880
  );
1881
+ if (stepUpHoldOutcome) {
1882
+ response.headers.set("X-Astra-Step-Up", stepUpHoldOutcome);
1883
+ }
1769
1884
  response.headers.set("X-AstraSync-Identity-Verified", result.identityVerified.toString());
1770
1885
  response.headers.set("X-AstraSync-Policy-Allowed", result.policyAllowed.toString());
1771
1886
  response.headers.set("X-AstraSync-Access-Level", result.accessLevel);
@@ -2233,15 +2348,33 @@ function extractMPPTransactionValue(challenge) {
2233
2348
  source: `challenge.request.amount (method=${challenge.method ?? "unknown"})`
2234
2349
  };
2235
2350
  }
2351
+ var KNOWN_TOKEN_DECIMALS = {
2352
+ USDC: 6,
2353
+ USDT: 6,
2354
+ DAI: 18,
2355
+ ETH: 18,
2356
+ WETH: 18
2357
+ };
2236
2358
  function extractX402TransactionValue(req) {
2237
- const amount = req.maxAmountRequired ?? req.amount;
2359
+ const rawAmount = req.maxAmountRequired ?? req.amount;
2238
2360
  const currency = req.currency ?? req.asset;
2239
- if (typeof amount !== "number" || !currency) return null;
2361
+ if (typeof rawAmount !== "number" || !currency) return null;
2362
+ const source = req.maxAmountRequired !== void 0 ? "maxAmountRequired" : "amount";
2363
+ const decimals = KNOWN_TOKEN_DECIMALS[currency.toUpperCase()];
2364
+ if (decimals !== void 0) {
2365
+ return {
2366
+ protocol: "x402",
2367
+ amount: rawAmount / Math.pow(10, decimals),
2368
+ currency,
2369
+ source
2370
+ };
2371
+ }
2240
2372
  return {
2241
2373
  protocol: "x402",
2242
- amount,
2374
+ amount: rawAmount,
2243
2375
  currency,
2244
- source: req.maxAmountRequired !== void 0 ? "maxAmountRequired" : "amount"
2376
+ source,
2377
+ rawUnits: true
2245
2378
  };
2246
2379
  }
2247
2380
 
@@ -4645,7 +4778,10 @@ function defaultMcpDenied(result, req, res) {
4645
4778
  // Round-10: aggregated per-dimension detail + correlation handle.
4646
4779
  failures: result.failures,
4647
4780
  correlationId: result.correlationId,
4648
- stepUpApproval: result.stepUpApproval
4781
+ stepUpApproval: result.stepUpApproval,
4782
+ // 3.6.0: terminal outcome of an opt-in hold-and-poll wait (denied /
4783
+ // expired / consumed / timeout). Absent when the feature is off.
4784
+ ...result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }
4649
4785
  }
4650
4786
  }
4651
4787
  });
@@ -4786,7 +4922,7 @@ function createMcpMiddleware(options) {
4786
4922
  }
4787
4923
  const counterpartyUrl = config.counterpartyUrl || `${req.protocol}://${req.get("host")}${req.path}`;
4788
4924
  const shouldRecordDecisions = recordDecisions !== false;
4789
- const result = await verify(config, {
4925
+ const verificationRequest = {
4790
4926
  credentials,
4791
4927
  purpose: pdlss.purpose,
4792
4928
  action: pdlss.action,
@@ -4804,9 +4940,21 @@ function createMcpMiddleware(options) {
4804
4940
  userAgent: req.headers["user-agent"],
4805
4941
  host: req.headers.host
4806
4942
  }
4807
- });
4943
+ };
4944
+ let result = await verify(config, verificationRequest);
4808
4945
  req.agentVerification = result;
4809
- const sessionId = result.sessionId;
4946
+ let sessionId = result.sessionId;
4947
+ if (config.stepUpMaxWaitMs !== void 0 && result.identityVerified && requiresHumanApproval(result) && result.stepUpApproval?.pollUrl) {
4948
+ const outcome = await awaitStepUpApproval(config, result.stepUpApproval);
4949
+ res.setHeader("X-Astra-Step-Up", outcome);
4950
+ if (outcome === "approved") {
4951
+ result = await verify(config, verificationRequest, { bypassCache: true });
4952
+ req.agentVerification = result;
4953
+ sessionId = result.sessionId;
4954
+ } else {
4955
+ result.stepUpOutcome = outcome;
4956
+ }
4957
+ }
4810
4958
  if (!result.identityVerified || !result.policyAllowed) {
4811
4959
  if (shouldRecordDecisions && sessionId) {
4812
4960
  recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
@@ -4960,7 +5108,7 @@ var RegistrationTimeoutError = class extends AstraSyncError {
4960
5108
 
4961
5109
  // src/registration/api.ts
4962
5110
  var DEFAULT_BASE_URL = "https://astrasync.ai";
4963
- var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
5111
+ var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
4964
5112
  var AstraSync = class {
4965
5113
  constructor(config = {}) {
4966
5114
  let raw = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(
@@ -5122,7 +5270,7 @@ var AstraSync = class {
5122
5270
  if (result.state === "expired") {
5123
5271
  throw new RegistrationExpiredError(requestId);
5124
5272
  }
5125
- await sleep(pollIntervalMs);
5273
+ await sleep2(pollIntervalMs);
5126
5274
  }
5127
5275
  throw new RegistrationTimeoutError(requestId);
5128
5276
  }
@@ -5592,6 +5740,7 @@ var VERSION = "3.4.0";
5592
5740
  VERSION,
5593
5741
  agent,
5594
5742
  authorizeSettlement,
5743
+ awaitStepUpApproval,
5595
5744
  buildGuidance,
5596
5745
  clearCache,
5597
5746
  createMcpMiddleware,
@@ -5607,6 +5756,7 @@ var VERSION = "3.4.0";
5607
5756
  hasCredentials,
5608
5757
  hasMinimumAccess,
5609
5758
  nextjs,
5759
+ pollStepUpStatus,
5610
5760
  prefetchWellKnown,
5611
5761
  quickVerify,
5612
5762
  recordDecision,