@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
|
@@ -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;
|
|
@@ -77,10 +135,10 @@ var DEFAULT_CONFIG = {
|
|
|
77
135
|
// through (`hasMinimumAccess('guidance', 'guidance') === true`).
|
|
78
136
|
defaultAccessLevel: "none",
|
|
79
137
|
// minTrustScore + minTrustScoreForFull deprecated in v2.3.0 — server decides.
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
// Set cacheTtl: 0 to disable caching entirely.
|
|
138
|
+
// cacheTtl deliberately unset. When undefined, cacheResult applies the 60s
|
|
139
|
+
// default; the caller's explicit value is honoured for cacheable results.
|
|
140
|
+
// Denials and step-up escalations are NEVER cached (3.6.0) regardless of
|
|
141
|
+
// cacheTtl. Set cacheTtl: 0 to disable caching entirely.
|
|
84
142
|
debug: false
|
|
85
143
|
};
|
|
86
144
|
var initCheckPerformed = false;
|
|
@@ -167,10 +225,9 @@ function getCachedResult(request, counterpartyId) {
|
|
|
167
225
|
}
|
|
168
226
|
return null;
|
|
169
227
|
}
|
|
170
|
-
var
|
|
171
|
-
var DEFAULT_STEP_UP_TTL_SECONDS = 300;
|
|
228
|
+
var DEFAULT_CACHE_TTL_SECONDS = 60;
|
|
172
229
|
function cacheResult(request, result, configuredTtl, counterpartyId) {
|
|
173
|
-
const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl :
|
|
230
|
+
const ttlSeconds = configuredTtl && configuredTtl > 0 ? configuredTtl : DEFAULT_CACHE_TTL_SECONDS;
|
|
174
231
|
const key = getCacheKey(request, counterpartyId);
|
|
175
232
|
verificationCache.set(key, {
|
|
176
233
|
result,
|
|
@@ -346,7 +403,7 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
346
403
|
};
|
|
347
404
|
}
|
|
348
405
|
}
|
|
349
|
-
async function verify(config, request) {
|
|
406
|
+
async function verify(config, request, options) {
|
|
350
407
|
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
351
408
|
const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
|
|
352
409
|
if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
|
|
@@ -362,7 +419,7 @@ async function verify(config, request) {
|
|
|
362
419
|
"[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."
|
|
363
420
|
);
|
|
364
421
|
}
|
|
365
|
-
if (mergedConfig.cacheTtl !== 0) {
|
|
422
|
+
if (mergedConfig.cacheTtl !== 0 && !options?.bypassCache) {
|
|
366
423
|
const cached = getCachedResult(request, mergedConfig.counterpartyId);
|
|
367
424
|
if (cached) {
|
|
368
425
|
if (mergedConfig.debug) {
|
|
@@ -382,6 +439,8 @@ async function verify(config, request) {
|
|
|
382
439
|
console.log("[VerificationGateway] Calling verify-access API");
|
|
383
440
|
}
|
|
384
441
|
const apiResponse = await callVerifyAccessAPI(mergedConfig, enrichedRequest);
|
|
442
|
+
const rawServerDenialReasons = apiResponse.denialReasons;
|
|
443
|
+
const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
|
|
385
444
|
if (!apiResponse.success) {
|
|
386
445
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
387
446
|
source: "api_error",
|
|
@@ -403,7 +462,10 @@ async function verify(config, request) {
|
|
|
403
462
|
// ALSO short-circuit on `!identityVerified || !policyAllowed` before
|
|
404
463
|
// the gate check — belt-and-braces.
|
|
405
464
|
accessLevel: "none",
|
|
406
|
-
|
|
465
|
+
// 3.6.0: the server now emits top-level denialReasons on every deny
|
|
466
|
+
// path — prefer it verbatim; the failure-message reconstruction remains
|
|
467
|
+
// as the fallback for older backends.
|
|
468
|
+
denialReasons: serverDenialReasons ?? (aggregatedFailures && aggregatedFailures.length > 0 ? aggregatedFailures.map((f) => f.message) : apiResponse.access?.reason ? [apiResponse.access.reason] : ["Access denied"]),
|
|
407
469
|
failures: aggregatedFailures,
|
|
408
470
|
requiresStepUp: apiResponse.access?.requiresStepUp,
|
|
409
471
|
requiresApproval: apiResponse.access?.requiresApproval,
|
|
@@ -480,9 +542,7 @@ async function verify(config, request) {
|
|
|
480
542
|
if (result.recommendation === "deny") {
|
|
481
543
|
result.policyAllowed = false;
|
|
482
544
|
result.accessLevel = "none";
|
|
483
|
-
result.denialReasons = result.recommendationReasons
|
|
484
|
-
"Access denied by AstraSync recommendation"
|
|
485
|
-
];
|
|
545
|
+
result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Access denied by AstraSync recommendation"];
|
|
486
546
|
result.guidance = result.runtimeChallenge ? {
|
|
487
547
|
message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
|
|
488
548
|
registrationUrl: urls?.registrationUrl ?? "",
|
|
@@ -494,9 +554,10 @@ async function verify(config, request) {
|
|
|
494
554
|
};
|
|
495
555
|
} else if (result.recommendation === "step_up_required") {
|
|
496
556
|
result.requiresStepUp = true;
|
|
497
|
-
result.denialReasons = result.recommendationReasons
|
|
557
|
+
result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Step-up verification required"];
|
|
498
558
|
}
|
|
499
|
-
|
|
559
|
+
const escalates = result.requiresStepUp === true || result.requiresApproval === true || result.recommendation === "step_up_required";
|
|
560
|
+
if (mergedConfig.cacheTtl !== 0 && result.recommendation !== "deny" && !escalates) {
|
|
500
561
|
cacheResult(request, result, mergedConfig.cacheTtl, mergedConfig.counterpartyId);
|
|
501
562
|
}
|
|
502
563
|
return result;
|
|
@@ -809,7 +870,10 @@ function defaultOnDenied(result, _req, res) {
|
|
|
809
870
|
// Round-10: aggregated per-dimension detail + correlation handle.
|
|
810
871
|
failures: result.failures,
|
|
811
872
|
correlationId: result.correlationId,
|
|
812
|
-
stepUpApproval: result.stepUpApproval
|
|
873
|
+
stepUpApproval: result.stepUpApproval,
|
|
874
|
+
// 3.6.0: terminal outcome of an opt-in hold-and-poll wait (denied /
|
|
875
|
+
// expired / consumed / timeout). Absent when the feature is off.
|
|
876
|
+
...result.stepUpOutcome && { stepUpOutcome: result.stepUpOutcome }
|
|
813
877
|
}
|
|
814
878
|
});
|
|
815
879
|
}
|
|
@@ -974,7 +1038,7 @@ function createMiddleware(options) {
|
|
|
974
1038
|
}
|
|
975
1039
|
}
|
|
976
1040
|
}
|
|
977
|
-
const
|
|
1041
|
+
const verificationRequest = {
|
|
978
1042
|
credentials,
|
|
979
1043
|
purpose,
|
|
980
1044
|
action: pdlssPair.action,
|
|
@@ -994,9 +1058,21 @@ function createMiddleware(options) {
|
|
|
994
1058
|
forwardedFor: forwardedForStr,
|
|
995
1059
|
agentCardUrl
|
|
996
1060
|
}
|
|
997
|
-
}
|
|
1061
|
+
};
|
|
1062
|
+
let result = await verify(config, verificationRequest);
|
|
998
1063
|
req.agentVerification = result;
|
|
999
|
-
|
|
1064
|
+
let sessionId = result.sessionId;
|
|
1065
|
+
if (config.stepUpMaxWaitMs !== void 0 && result.identityVerified && requiresHumanApproval(result) && result.stepUpApproval?.pollUrl) {
|
|
1066
|
+
const outcome = await awaitStepUpApproval(config, result.stepUpApproval);
|
|
1067
|
+
res.setHeader("X-Astra-Step-Up", outcome);
|
|
1068
|
+
if (outcome === "approved") {
|
|
1069
|
+
result = await verify(config, verificationRequest, { bypassCache: true });
|
|
1070
|
+
req.agentVerification = result;
|
|
1071
|
+
sessionId = result.sessionId;
|
|
1072
|
+
} else {
|
|
1073
|
+
result.stepUpOutcome = outcome;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1000
1076
|
if (!result.identityVerified || !result.policyAllowed) {
|
|
1001
1077
|
if (shouldRecordDecisions && sessionId) {
|
|
1002
1078
|
recordDecision(config, sessionId, "denied", result.denialReasons?.[0]).catch(() => {
|