@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.
- package/README.md +16 -0
- package/dist/adapter-interface/interface.d.mts +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +2 -2
- package/dist/adapters/express.d.ts +2 -2
- package/dist/adapters/express.js +96 -20
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +96 -20
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +1 -1
- package/dist/adapters/mcp.d.ts +1 -1
- package/dist/adapters/mcp.js +96 -20
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +96 -20
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +2 -2
- package/dist/adapters/nextjs.d.ts +2 -2
- package/dist/adapters/nextjs.js +101 -20
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +101 -20
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +2 -2
- package/dist/adapters/sdk.d.ts +2 -2
- package/dist/adapters/sdk.js +19 -16
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +19 -16
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +2 -2
- package/dist/agent/index.d.ts +2 -2
- package/dist/browser/background.js +22 -16
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +22 -16
- package/dist/browser/background.mjs.map +1 -1
- package/dist/browser/browser-adapter.d.mts +2 -2
- package/dist/browser/browser-adapter.d.ts +2 -2
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.d.ts +2 -2
- package/dist/cursor/cursor-adapter.d.mts +2 -2
- package/dist/cursor/cursor-adapter.d.ts +2 -2
- package/dist/cursor/extension.d.mts +2 -2
- package/dist/cursor/extension.d.ts +2 -2
- package/dist/cursor/extension.js +22 -16
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +22 -16
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/{express-BH5ADAyb.d.mts → express-BnMO-H3y.d.mts} +1 -1
- package/dist/{express-jUzLIoep.d.ts → express-DQhDzNAt.d.ts} +1 -1
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +22 -16
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +22 -16
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +2 -2
- package/dist/git-trigger/git-hooks.d.ts +2 -2
- package/dist/{index-aZHAWujT.d.mts → index-BT_aRn-I.d.mts} +1 -1
- package/dist/{index-DlCnmpJH.d.ts → index-D8-dvUFA.d.ts} +1 -1
- package/dist/{index-BR2nmxBU.d.mts → index-WHKq2v17.d.mts} +1 -1
- package/dist/{index-DEixUCu0.d.ts → index-rftma0ln.d.ts} +1 -1
- package/dist/index.d.mts +55 -9
- package/dist/index.d.ts +55 -9
- package/dist/index.js +145 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +143 -30
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +2 -2
- package/dist/local-evaluator/evaluator.d.ts +2 -2
- package/dist/{nextjs-LTeoPqMH.d.mts → nextjs-DFKYhxe6.d.mts} +1 -1
- package/dist/{nextjs-DfXOd0Au.d.ts → nextjs-DPj7ZNlq.d.ts} +1 -1
- package/dist/{sdk-LmvyDVpL.d.ts → sdk-CAcHgB5x.d.ts} +1 -1
- package/dist/{sdk-DKhwVL9X.d.mts → sdk-Cy3wAmDt.d.mts} +1 -1
- package/dist/transport/index.d.mts +2 -2
- package/dist/transport/index.d.ts +2 -2
- package/dist/{types-C8HyQEaz.d.mts → types-B-ubjHER.d.mts} +1 -1
- package/dist/{types-xofemo0G.d.ts → types-Bgn5gxHQ.d.ts} +1 -1
- package/dist/{types-DrDIouvO.d.mts → types-CKe8O0lR.d.mts} +41 -1
- package/dist/{types-DrDIouvO.d.ts → types-CKe8O0lR.d.ts} +41 -1
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/adapters/nextjs.mjs
CHANGED
|
@@ -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.
|
|
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
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
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
|
|
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 :
|
|
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
|
-
|
|
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
|
|
471
|
+
result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Step-up verification required"];
|
|
412
472
|
}
|
|
413
|
-
|
|
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
|
|
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
|
-
{
|
|
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);
|