@astrasyncai/verification-gateway 3.5.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 (80) hide show
  1. package/README.md +16 -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 +96 -20
  7. package/dist/adapters/express.js.map +1 -1
  8. package/dist/adapters/express.mjs +96 -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-BH5ADAyb.d.mts → express-BnMO-H3y.d.mts} +1 -1
  47. package/dist/{express-jUzLIoep.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-aZHAWujT.d.mts → index-BT_aRn-I.d.mts} +1 -1
  57. package/dist/{index-DlCnmpJH.d.ts → index-D8-dvUFA.d.ts} +1 -1
  58. package/dist/{index-BR2nmxBU.d.mts → index-WHKq2v17.d.mts} +1 -1
  59. package/dist/{index-DEixUCu0.d.ts → index-rftma0ln.d.ts} +1 -1
  60. package/dist/index.d.mts +55 -9
  61. package/dist/index.d.ts +55 -9
  62. package/dist/index.js +145 -30
  63. package/dist/index.js.map +1 -1
  64. package/dist/index.mjs +143 -30
  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-LTeoPqMH.d.mts → nextjs-DFKYhxe6.d.mts} +1 -1
  69. package/dist/{nextjs-DfXOd0Au.d.ts → nextjs-DPj7ZNlq.d.ts} +1 -1
  70. package/dist/{sdk-LmvyDVpL.d.ts → sdk-CAcHgB5x.d.ts} +1 -1
  71. package/dist/{sdk-DKhwVL9X.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/{types-C8HyQEaz.d.mts → types-B-ubjHER.d.mts} +1 -1
  75. package/dist/{types-xofemo0G.d.ts → types-Bgn5gxHQ.d.ts} +1 -1
  76. package/dist/{types-DrDIouvO.d.mts → types-CKe8O0lR.d.mts} +41 -1
  77. package/dist/{types-DrDIouvO.d.ts → types-CKe8O0lR.d.ts} +41 -1
  78. package/dist/ui/index.d.mts +1 -1
  79. package/dist/ui/index.d.ts +1 -1
  80. package/package.json +1 -1
@@ -1,3 +1,61 @@
1
+ // src/adapters/stepup-poll.ts
2
+ var DEFAULT_POLL_INTERVAL_MS = 3e3;
3
+ var MIN_POLL_INTERVAL_MS = 250;
4
+ var FALLBACK_MAX_WAIT_MS = 5 * 60 * 1e3;
5
+ var EXPIRY_GRACE_MS = 5e3;
6
+ var POLL_REQUEST_TIMEOUT_MS = 1e4;
7
+ function resolvePollUrl(config, pollUrl) {
8
+ if (pollUrl.startsWith("http")) return pollUrl;
9
+ const origin = (config.apiBaseUrl ?? "").replace(/\/api\/?$/, "");
10
+ return origin + pollUrl;
11
+ }
12
+ async function pollStepUpStatus(config, approval) {
13
+ if (!approval.pollUrl) return null;
14
+ try {
15
+ const res = await fetch(resolvePollUrl(config, approval.pollUrl), {
16
+ method: "GET",
17
+ signal: AbortSignal.timeout(POLL_REQUEST_TIMEOUT_MS)
18
+ });
19
+ if (!res.ok) return null;
20
+ const body = await res.json();
21
+ const data = body?.data;
22
+ const status = data && typeof data === "object" ? data.status : body?.status;
23
+ return typeof status === "string" ? status : null;
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+ function resolveDeadline(config, approval) {
29
+ const now = Date.now();
30
+ const maxWait = config.stepUpMaxWaitMs ?? 0;
31
+ if (maxWait > 0) return now + maxWait;
32
+ if (approval.expiresAt) {
33
+ const expiry = Date.parse(approval.expiresAt);
34
+ if (!Number.isNaN(expiry)) return Math.max(now, expiry) + EXPIRY_GRACE_MS;
35
+ }
36
+ return now + FALLBACK_MAX_WAIT_MS;
37
+ }
38
+ function sleep(ms) {
39
+ return new Promise((resolve) => setTimeout(resolve, ms));
40
+ }
41
+ async function awaitStepUpApproval(config, approval) {
42
+ const deadline = resolveDeadline(config, approval);
43
+ const pollInterval = Math.max(
44
+ MIN_POLL_INTERVAL_MS,
45
+ config.stepUpPollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS
46
+ );
47
+ while (Date.now() < deadline) {
48
+ const status = await pollStepUpStatus(config, approval);
49
+ if (status && status !== "pending") {
50
+ return status;
51
+ }
52
+ const remaining = deadline - Date.now();
53
+ if (remaining <= 0) break;
54
+ await sleep(Math.min(pollInterval, remaining));
55
+ }
56
+ return "timeout";
57
+ }
58
+
1
59
  // src/access-levels.ts
2
60
  function getTrustLevel(score) {
3
61
  if (score >= 80) return "PLATINUM";
@@ -7,7 +65,7 @@ function getTrustLevel(score) {
7
65
  }
8
66
 
9
67
  // src/version.ts
10
- var SDK_VERSION = "3.5.0";
68
+ var SDK_VERSION = "3.6.0";
11
69
 
12
70
  // src/well-known.ts
13
71
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -25,10 +83,10 @@ var DEFAULT_CONFIG = {
25
83
  // through (`hasMinimumAccess('guidance', 'guidance') === true`).
26
84
  defaultAccessLevel: "none",
27
85
  // minTrustScore + minTrustScoreForFull deprecated in v2.3.0 — server decides.
28
- // Round-18.5 F4: cacheTtl deliberately unset. When undefined, cacheResult
29
- // applies the split default (60s autonomous / 300s step-up). When the
30
- // caller sets cacheTtl explicitly, that value is honoured uniformly.
31
- // Set cacheTtl: 0 to disable caching entirely.
86
+ // cacheTtl deliberately unset. When undefined, cacheResult applies the 60s
87
+ // default; the caller's explicit value is honoured for cacheable results.
88
+ // Denials and step-up escalations are NEVER cached (3.6.0) regardless of
89
+ // cacheTtl. Set cacheTtl: 0 to disable caching entirely.
32
90
  debug: false
33
91
  };
34
92
  var initCheckPerformed = false;
@@ -115,10 +173,9 @@ function getCachedResult(request, counterpartyId) {
115
173
  }
116
174
  return null;
117
175
  }
118
- var DEFAULT_AUTONOMOUS_TTL_SECONDS = 60;
119
- var DEFAULT_STEP_UP_TTL_SECONDS = 300;
176
+ var DEFAULT_CACHE_TTL_SECONDS = 60;
120
177
  function cacheResult(request, result, configuredTtl, counterpartyId) {
121
- const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : result.requiresStepUp ? DEFAULT_STEP_UP_TTL_SECONDS : DEFAULT_AUTONOMOUS_TTL_SECONDS;
178
+ const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : DEFAULT_CACHE_TTL_SECONDS;
122
179
  const key = getCacheKey(request, counterpartyId);
123
180
  verificationCache.set(key, {
124
181
  result,
@@ -260,7 +317,7 @@ async function callVerifyAccessAPI(config, request) {
260
317
  };
261
318
  }
262
319
  }
263
- async function verify(config, request) {
320
+ async function verify(config, request, options) {
264
321
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
265
322
  const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
266
323
  if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
@@ -276,7 +333,7 @@ async function verify(config, request) {
276
333
  "[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."
277
334
  );
278
335
  }
279
- if (mergedConfig.cacheTtl !== 0) {
336
+ if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache) {
280
337
  const cached = getCachedResult(request, mergedConfig.counterpartyId);
281
338
  if (cached) {
282
339
  if (mergedConfig.debug) {
@@ -296,6 +353,8 @@ async function verify(config, request) {
296
353
  console.log("[VerificationGateway] Calling verify-access API");
297
354
  }
298
355
  const apiResponse = await callVerifyAccessAPI(mergedConfig, enrichedRequest);
356
+ const rawServerDenialReasons = apiResponse.denialReasons;
357
+ const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
299
358
  if (!apiResponse.success) {
300
359
  return createGuidanceResponse(mergedConfig, apiResponse.error, {
301
360
  source: "api_error",
@@ -317,7 +376,10 @@ async function verify(config, request) {
317
376
  // ALSO short-circuit on `!identityVerified || !policyAllowed` before
318
377
  // the gate check — belt-and-braces.
319
378
  accessLevel: "none",
320
- denialReasons: aggregatedFailures && aggregatedFailures.length > 0 ? aggregatedFailures.map((f) => f.message) : apiResponse.access?.reason ? [apiResponse.access.reason] : ["Access denied"],
379
+ // 3.6.0: the server now emits top-level denialReasons on every deny
380
+ // path — prefer it verbatim; the failure-message reconstruction remains
381
+ // as the fallback for older backends.
382
+ denialReasons: serverDenialReasons ?? (aggregatedFailures && aggregatedFailures.length > 0 ? aggregatedFailures.map((f) => f.message) : apiResponse.access?.reason ? [apiResponse.access.reason] : ["Access denied"]),
321
383
  failures: aggregatedFailures,
322
384
  requiresStepUp: apiResponse.access?.requiresStepUp,
323
385
  requiresApproval: apiResponse.access?.requiresApproval,
@@ -394,9 +456,7 @@ async function verify(config, request) {
394
456
  if (result.recommendation === "deny") {
395
457
  result.policyAllowed = false;
396
458
  result.accessLevel = "none";
397
- result.denialReasons = result.recommendationReasons || [
398
- "Access denied by AstraSync recommendation"
399
- ];
459
+ result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Access denied by AstraSync recommendation"];
400
460
  result.guidance = result.runtimeChallenge ? {
401
461
  message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
402
462
  registrationUrl: urls?.registrationUrl ?? "",
@@ -408,9 +468,10 @@ async function verify(config, request) {
408
468
  };
409
469
  } else if (result.recommendation === "step_up_required") {
410
470
  result.requiresStepUp = true;
411
- result.denialReasons = result.recommendationReasons || ["Step-up verification required"];
471
+ result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Step-up verification required"];
412
472
  }
413
- if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny") {
473
+ const escalates = result.requiresStepUp === true || result.requiresApproval === true || result.recommendation === "step_up_required";
474
+ if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny" && !escalates) {
414
475
  cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
415
476
  }
416
477
  return result;
@@ -971,7 +1032,7 @@ function createMiddleware(options) {
971
1032
  }
972
1033
  const forwardedFor = request.headers.get("x-forwarded-for") || void 0;
973
1034
  const originalClientIp = forwardedFor?.split(",")[0]?.trim();
974
- const result = await verify(config, {
1035
+ const verificationRequest = {
975
1036
  credentials,
976
1037
  purpose,
977
1038
  action: pdlssPair.action,
@@ -988,7 +1049,17 @@ function createMiddleware(options) {
988
1049
  forwardedFor,
989
1050
  agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0
990
1051
  }
991
- });
1052
+ };
1053
+ let result = await verify(config, verificationRequest);
1054
+ let stepUpHoldOutcome;
1055
+ if (config.stepUpMaxWaitMs !== void 0 && result.identityVerified && requiresHumanApproval(result) && result.stepUpApproval?.pollUrl) {
1056
+ stepUpHoldOutcome = await awaitStepUpApproval(config, result.stepUpApproval);
1057
+ if (stepUpHoldOutcome === "approved") {
1058
+ result = await verify(config, verificationRequest, { bypassCache: true });
1059
+ } else {
1060
+ result.stepUpOutcome = stepUpHoldOutcome;
1061
+ }
1062
+ }
992
1063
  const approvalRequired = result.identityVerified && result.policyAllowed && requiresHumanApproval(result);
993
1064
  if (approvalRequired) annotateApprovalRequired(result);
994
1065
  if (!result.identityVerified || !result.policyAllowed || approvalRequired) {
@@ -1003,10 +1074,17 @@ function createMiddleware(options) {
1003
1074
  message: result.denialReasons?.[0] || "Access denied",
1004
1075
  guidance: result.guidance,
1005
1076
  failures: result.failures,
1006
- stepUpApproval: result.stepUpApproval
1077
+ stepUpApproval: result.stepUpApproval,
1078
+ // 3.6.0: terminal outcome of an opt-in hold-and-poll wait.
1079
+ ...result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }
1007
1080
  }
1008
1081
  },
1009
- { status: !result.identityVerified ? 401 : 403 }
1082
+ {
1083
+ status: !result.identityVerified ? 401 : 403,
1084
+ ...stepUpHoldOutcome && {
1085
+ headers: { "X-Astra-Step-Up": stepUpHoldOutcome }
1086
+ }
1087
+ }
1010
1088
  );
1011
1089
  }
1012
1090
  if (showCommerceShield) {
@@ -1025,6 +1103,9 @@ function createMiddleware(options) {
1025
1103
  "X-AstraSync-Verified",
1026
1104
  (result.identityVerified && result.policyAllowed).toString()
1027
1105
  );
1106
+ if (stepUpHoldOutcome) {
1107
+ response.headers.set("X-Astra-Step-Up", stepUpHoldOutcome);
1108
+ }
1028
1109
  response.headers.set("X-AstraSync-Identity-Verified", result.identityVerified.toString());
1029
1110
  response.headers.set("X-AstraSync-Policy-Allowed", result.policyAllowed.toString());
1030
1111
  response.headers.set("X-AstraSync-Access-Level", result.accessLevel);