@astrasyncai/verification-gateway 3.11.1 → 4.0.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/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 +106 -10
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +106 -10
- 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 +111 -10
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +111 -10
- 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 +107 -10
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +107 -10
- 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 +92 -10
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +92 -10
- 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/bin/astrasync-claude-hook.js +92 -10
- package/dist/bin/astrasync-codex-hook.js +92 -10
- package/dist/bin/astrasync-guard.js +92 -10
- package/dist/bin/astrasync.js +93 -10
- package/dist/browser/background.js +92 -10
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +92 -10
- 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/claude-code/claude-code-adapter.d.mts +2 -2
- package/dist/claude-code/claude-code-adapter.d.ts +2 -2
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.d.ts +2 -2
- package/dist/codex/index.d.mts +2 -2
- package/dist/codex/index.d.ts +2 -2
- package/dist/codex/index.js +92 -10
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +92 -10
- package/dist/codex/index.mjs.map +1 -1
- 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 +92 -10
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +92 -10
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +1 -1
- package/dist/edge-config.d.ts +1 -1
- package/dist/{express-DCXa1oqj.d.mts → express-BZajRs4i.d.mts} +1 -1
- package/dist/{express-ClNtDhhc.d.ts → express-CjCUB1k7.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 +92 -10
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +92 -10
- 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-BrNKDmiR.d.mts → index-B0cyMZDL.d.mts} +1 -1
- package/dist/{index-Dr_XiN65.d.mts → index-BRYteOqO.d.mts} +1 -1
- package/dist/{index-CfHurO1P.d.ts → index-BZQdVqNw.d.ts} +1 -1
- package/dist/{index-D2ztkumS.d.ts → index-adgKhujR.d.ts} +1 -1
- package/dist/index.d.mts +9 -9
- package/dist/index.d.ts +9 -9
- package/dist/index.js +160 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +159 -10
- 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-CEBVBsdi.d.ts → nextjs-D_iFf5k-.d.ts} +1 -1
- package/dist/{nextjs-DcQIk6Zj.d.mts → nextjs-DeUTnOBd.d.mts} +1 -1
- package/dist/{sdk-H0JCLW2y.d.ts → sdk-BM3mwEAq.d.ts} +1 -1
- package/dist/{sdk-CZkbSOeO.d.mts → sdk-_il1Q41f.d.mts} +1 -1
- package/dist/transport/index.d.mts +2 -2
- package/dist/transport/index.d.ts +2 -2
- package/dist/{types-sy3tq8lp.d.mts → types-BcDf9Kk0.d.mts} +118 -1
- package/dist/{types-DhFPiZ3t.d.ts → types-CHKCgDFC.d.ts} +1 -1
- package/dist/{types-cQVCMeNV.d.mts → types-DfnP7JiM.d.mts} +1 -1
- package/dist/{types-9tns4wyl.d.ts → types-fTQD448H.d.ts} +118 -1
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +15 -2
- package/dist/verify.d.ts +15 -2
- package/dist/verify.js +117 -10
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +115 -10
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -3701,7 +3701,7 @@ function getTrustLevel(score) {
|
|
|
3701
3701
|
}
|
|
3702
3702
|
|
|
3703
3703
|
// src/version.ts
|
|
3704
|
-
var SDK_VERSION = "
|
|
3704
|
+
var SDK_VERSION = "4.0.0";
|
|
3705
3705
|
|
|
3706
3706
|
// src/well-known.ts
|
|
3707
3707
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -3727,7 +3727,7 @@ var DEFAULT_CONFIG = {
|
|
|
3727
3727
|
};
|
|
3728
3728
|
var initCheckPerformed = false;
|
|
3729
3729
|
var deprecationWarningShown = false;
|
|
3730
|
-
async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
3730
|
+
async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
|
|
3731
3731
|
initCheckPerformed = true;
|
|
3732
3732
|
try {
|
|
3733
3733
|
const probeUrl = `${apiBaseUrl}/agents/verify-access`;
|
|
@@ -3744,6 +3744,28 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
|
3744
3744
|
`[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
|
|
3745
3745
|
);
|
|
3746
3746
|
}
|
|
3747
|
+
if (apiKey) {
|
|
3748
|
+
const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
|
|
3749
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
3750
|
+
});
|
|
3751
|
+
if (selfCheck.status === 401) {
|
|
3752
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
3753
|
+
const message = `[VerificationGateway] the configured AstraSync API key was REJECTED at startup (${body.code ?? "api_key_invalid"}: ${body.message ?? "invalid key"}). Every inbound agent will be turned away until the key is rotated` + (body.remediation?.manageUrl ? ` at ${body.remediation.manageUrl}` : "") + `.`;
|
|
3754
|
+
if (strictInit) {
|
|
3755
|
+
throw new Error(`${message} (strictInit=true)`);
|
|
3756
|
+
}
|
|
3757
|
+
console.error(message);
|
|
3758
|
+
} else if (selfCheck.ok) {
|
|
3759
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
3760
|
+
if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
|
|
3761
|
+
console.warn(
|
|
3762
|
+
`[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
|
|
3763
|
+
);
|
|
3764
|
+
} else if (debug) {
|
|
3765
|
+
console.log("[VerificationGateway] API key self-check passed");
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3768
|
+
}
|
|
3747
3769
|
} catch (err) {
|
|
3748
3770
|
if (strictInit) {
|
|
3749
3771
|
throw err;
|
|
@@ -3821,8 +3843,17 @@ function cacheResult(request, result, configuredTtl, counterpartyId) {
|
|
|
3821
3843
|
function createGuidanceResponse(_config, reason, options = {}) {
|
|
3822
3844
|
const source = options.source ?? "no_credentials";
|
|
3823
3845
|
const isApiError = source === "api_error";
|
|
3846
|
+
const isMisconfig = source === "merchant_misconfig";
|
|
3824
3847
|
const urls = options.urls;
|
|
3825
|
-
const guidance =
|
|
3848
|
+
const guidance = isMisconfig ? {
|
|
3849
|
+
message: "This site's AstraSync integration is misconfigured (its API key was revoked, expired, or rotated). Your identity and the AstraSync platform are fine \u2014 contact the site operator. Retrying will not help.",
|
|
3850
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
3851
|
+
documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
|
|
3852
|
+
steps: [
|
|
3853
|
+
"Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
|
|
3854
|
+
"Do not retry: the failure is deterministic until the operator updates their key"
|
|
3855
|
+
]
|
|
3856
|
+
} : isApiError ? {
|
|
3826
3857
|
message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
|
|
3827
3858
|
registrationUrl: urls?.registrationUrl ?? "",
|
|
3828
3859
|
documentationUrl: urls?.documentationUrl ?? "",
|
|
@@ -3860,14 +3891,24 @@ function createGuidanceResponse(_config, reason, options = {}) {
|
|
|
3860
3891
|
// partners (and their custom onDenied handlers) can branch on
|
|
3861
3892
|
// dimension. Without this, the synthesised stub was indistinguishable
|
|
3862
3893
|
// from a real policy deny.
|
|
3863
|
-
failures:
|
|
3894
|
+
failures: isMisconfig ? [
|
|
3895
|
+
{
|
|
3896
|
+
dimension: "verify_access.merchant_misconfigured",
|
|
3897
|
+
message: reason ?? "The integration API key was rejected by AstraSync",
|
|
3898
|
+
guidance: guidance.message
|
|
3899
|
+
}
|
|
3900
|
+
] : isApiError ? [
|
|
3864
3901
|
{
|
|
3865
3902
|
dimension: "verify_access.api_error",
|
|
3866
3903
|
message: reason ?? "Verification temporarily unavailable",
|
|
3867
3904
|
guidance: guidance.message
|
|
3868
3905
|
}
|
|
3869
3906
|
] : void 0,
|
|
3907
|
+
// 4.0.0: typed marker so adapters render the misconfig envelope (503 +
|
|
3908
|
+
// MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
|
|
3909
|
+
...isMisconfig && { misconfigured: true },
|
|
3870
3910
|
correlationId: options.correlationId,
|
|
3911
|
+
attemptId: options.attemptId,
|
|
3871
3912
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
3872
3913
|
};
|
|
3873
3914
|
}
|
|
@@ -3897,6 +3938,8 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3897
3938
|
body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
|
|
3898
3939
|
if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
|
|
3899
3940
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
3941
|
+
if (requestData.attemptId) body.attemptId = requestData.attemptId;
|
|
3942
|
+
if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
|
|
3900
3943
|
body.sdkVersion = SDK_VERSION;
|
|
3901
3944
|
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
3902
3945
|
const meta = {
|
|
@@ -3918,12 +3961,16 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3918
3961
|
const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
3919
3962
|
method: "POST",
|
|
3920
3963
|
headers,
|
|
3921
|
-
body: JSON.stringify(body)
|
|
3964
|
+
body: JSON.stringify(body),
|
|
3965
|
+
signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
|
|
3922
3966
|
});
|
|
3923
3967
|
const data = await response.json();
|
|
3924
3968
|
if (response.status === 410) {
|
|
3925
3969
|
return {
|
|
3926
3970
|
success: true,
|
|
3971
|
+
// 3.12.0 (Trust Record): keep the server-echoed attempt handle even on
|
|
3972
|
+
// the synthesised 410 deny shape (echoed on every branch).
|
|
3973
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
|
|
3927
3974
|
access: {
|
|
3928
3975
|
allowed: false,
|
|
3929
3976
|
accessLevel: "none",
|
|
@@ -3939,10 +3986,22 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3939
3986
|
};
|
|
3940
3987
|
}
|
|
3941
3988
|
if (!response.ok) {
|
|
3989
|
+
if (response.status === 401) {
|
|
3990
|
+
return {
|
|
3991
|
+
success: false,
|
|
3992
|
+
error: data.message || data.error || "Integration API key rejected",
|
|
3993
|
+
misconfig: true,
|
|
3994
|
+
misconfigCode: typeof data?.code === "string" ? data.code : void 0,
|
|
3995
|
+
remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
|
|
3996
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
3997
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
3998
|
+
};
|
|
3999
|
+
}
|
|
3942
4000
|
return {
|
|
3943
4001
|
success: false,
|
|
3944
4002
|
error: data.message || data.error || `API returned ${response.status}`,
|
|
3945
|
-
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0
|
|
4003
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
4004
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
3946
4005
|
};
|
|
3947
4006
|
}
|
|
3948
4007
|
return data;
|
|
@@ -3959,9 +4018,19 @@ async function verify(config, request, options) {
|
|
|
3959
4018
|
const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
|
|
3960
4019
|
if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
|
|
3961
4020
|
if (mergedConfig.strictInit) {
|
|
3962
|
-
await performInitCheck(
|
|
4021
|
+
await performInitCheck(
|
|
4022
|
+
mergedConfig.apiBaseUrl,
|
|
4023
|
+
mergedConfig.debug,
|
|
4024
|
+
true,
|
|
4025
|
+
mergedConfig.apiKey
|
|
4026
|
+
);
|
|
3963
4027
|
} else {
|
|
3964
|
-
void performInitCheck(
|
|
4028
|
+
void performInitCheck(
|
|
4029
|
+
mergedConfig.apiBaseUrl,
|
|
4030
|
+
mergedConfig.debug,
|
|
4031
|
+
false,
|
|
4032
|
+
mergedConfig.apiKey
|
|
4033
|
+
);
|
|
3965
4034
|
}
|
|
3966
4035
|
}
|
|
3967
4036
|
if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
|
|
@@ -3976,7 +4045,13 @@ async function verify(config, request, options) {
|
|
|
3976
4045
|
if (mergedConfig.debug) {
|
|
3977
4046
|
console.log("[VerificationGateway] Returning cached result");
|
|
3978
4047
|
}
|
|
3979
|
-
|
|
4048
|
+
const hit = { ...cached };
|
|
4049
|
+
if (request.attemptId) {
|
|
4050
|
+
hit.attemptId = request.attemptId;
|
|
4051
|
+
} else {
|
|
4052
|
+
delete hit.attemptId;
|
|
4053
|
+
}
|
|
4054
|
+
return hit;
|
|
3980
4055
|
}
|
|
3981
4056
|
}
|
|
3982
4057
|
const enrichedRequest = { ...request };
|
|
@@ -3994,8 +4069,10 @@ async function verify(config, request, options) {
|
|
|
3994
4069
|
const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
|
|
3995
4070
|
if (!apiResponse.success) {
|
|
3996
4071
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
3997
|
-
source: "api_error",
|
|
4072
|
+
source: apiResponse.misconfig ? "merchant_misconfig" : "api_error",
|
|
3998
4073
|
correlationId: apiResponse.correlationId,
|
|
4074
|
+
attemptId: apiResponse.attemptId,
|
|
4075
|
+
remediation: apiResponse.remediation,
|
|
3999
4076
|
urls
|
|
4000
4077
|
});
|
|
4001
4078
|
}
|
|
@@ -4031,6 +4108,9 @@ async function verify(config, request, options) {
|
|
|
4031
4108
|
// Anonymous traffic has no session → correlationId is the per-attempt
|
|
4032
4109
|
// linking key (the sessionId-equivalent for anonymous callers).
|
|
4033
4110
|
correlationId: apiResponse.correlationId,
|
|
4111
|
+
// 3.12.0 (Trust Record): server echoes the attempt-chain handle on
|
|
4112
|
+
// every branch — denials included (the funnel outlives one deny).
|
|
4113
|
+
attemptId: apiResponse.attemptId,
|
|
4034
4114
|
recommendation: apiResponse.recommendation,
|
|
4035
4115
|
recommendationReasons: apiResponse.recommendationReasons,
|
|
4036
4116
|
stepUpApproval: apiResponse.stepUpApproval,
|
|
@@ -4082,6 +4162,8 @@ async function verify(config, request, options) {
|
|
|
4082
4162
|
// v2.3.10 (defect #34, round-4): anonymous responses surface correlationId
|
|
4083
4163
|
// (no session row exists for unverified callers).
|
|
4084
4164
|
correlationId: apiResponse.correlationId,
|
|
4165
|
+
// 3.12.0 (Trust Record): server-echoed attempt-chain handle.
|
|
4166
|
+
attemptId: apiResponse.attemptId,
|
|
4085
4167
|
runtimeChallenge: apiResponse.runtimeChallenge,
|
|
4086
4168
|
tokenGuidance: apiResponse.tokenGuidance,
|
|
4087
4169
|
recommendation: apiResponse.recommendation,
|
|
@@ -3700,7 +3700,7 @@ function getTrustLevel(score) {
|
|
|
3700
3700
|
}
|
|
3701
3701
|
|
|
3702
3702
|
// src/version.ts
|
|
3703
|
-
var SDK_VERSION = "
|
|
3703
|
+
var SDK_VERSION = "4.0.0";
|
|
3704
3704
|
|
|
3705
3705
|
// src/well-known.ts
|
|
3706
3706
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -3726,7 +3726,7 @@ var DEFAULT_CONFIG = {
|
|
|
3726
3726
|
};
|
|
3727
3727
|
var initCheckPerformed = false;
|
|
3728
3728
|
var deprecationWarningShown = false;
|
|
3729
|
-
async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
3729
|
+
async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
|
|
3730
3730
|
initCheckPerformed = true;
|
|
3731
3731
|
try {
|
|
3732
3732
|
const probeUrl = `${apiBaseUrl}/agents/verify-access`;
|
|
@@ -3743,6 +3743,28 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
|
3743
3743
|
`[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
|
|
3744
3744
|
);
|
|
3745
3745
|
}
|
|
3746
|
+
if (apiKey) {
|
|
3747
|
+
const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
|
|
3748
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
3749
|
+
});
|
|
3750
|
+
if (selfCheck.status === 401) {
|
|
3751
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
3752
|
+
const message = `[VerificationGateway] the configured AstraSync API key was REJECTED at startup (${body.code ?? "api_key_invalid"}: ${body.message ?? "invalid key"}). Every inbound agent will be turned away until the key is rotated` + (body.remediation?.manageUrl ? ` at ${body.remediation.manageUrl}` : "") + `.`;
|
|
3753
|
+
if (strictInit) {
|
|
3754
|
+
throw new Error(`${message} (strictInit=true)`);
|
|
3755
|
+
}
|
|
3756
|
+
console.error(message);
|
|
3757
|
+
} else if (selfCheck.ok) {
|
|
3758
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
3759
|
+
if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
|
|
3760
|
+
console.warn(
|
|
3761
|
+
`[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
|
|
3762
|
+
);
|
|
3763
|
+
} else if (debug) {
|
|
3764
|
+
console.log("[VerificationGateway] API key self-check passed");
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3746
3768
|
} catch (err) {
|
|
3747
3769
|
if (strictInit) {
|
|
3748
3770
|
throw err;
|
|
@@ -3820,8 +3842,17 @@ function cacheResult(request, result, configuredTtl, counterpartyId) {
|
|
|
3820
3842
|
function createGuidanceResponse(_config, reason, options = {}) {
|
|
3821
3843
|
const source = options.source ?? "no_credentials";
|
|
3822
3844
|
const isApiError = source === "api_error";
|
|
3845
|
+
const isMisconfig = source === "merchant_misconfig";
|
|
3823
3846
|
const urls = options.urls;
|
|
3824
|
-
const guidance =
|
|
3847
|
+
const guidance = isMisconfig ? {
|
|
3848
|
+
message: "This site's AstraSync integration is misconfigured (its API key was revoked, expired, or rotated). Your identity and the AstraSync platform are fine \u2014 contact the site operator. Retrying will not help.",
|
|
3849
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
3850
|
+
documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
|
|
3851
|
+
steps: [
|
|
3852
|
+
"Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
|
|
3853
|
+
"Do not retry: the failure is deterministic until the operator updates their key"
|
|
3854
|
+
]
|
|
3855
|
+
} : isApiError ? {
|
|
3825
3856
|
message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
|
|
3826
3857
|
registrationUrl: urls?.registrationUrl ?? "",
|
|
3827
3858
|
documentationUrl: urls?.documentationUrl ?? "",
|
|
@@ -3859,14 +3890,24 @@ function createGuidanceResponse(_config, reason, options = {}) {
|
|
|
3859
3890
|
// partners (and their custom onDenied handlers) can branch on
|
|
3860
3891
|
// dimension. Without this, the synthesised stub was indistinguishable
|
|
3861
3892
|
// from a real policy deny.
|
|
3862
|
-
failures:
|
|
3893
|
+
failures: isMisconfig ? [
|
|
3894
|
+
{
|
|
3895
|
+
dimension: "verify_access.merchant_misconfigured",
|
|
3896
|
+
message: reason ?? "The integration API key was rejected by AstraSync",
|
|
3897
|
+
guidance: guidance.message
|
|
3898
|
+
}
|
|
3899
|
+
] : isApiError ? [
|
|
3863
3900
|
{
|
|
3864
3901
|
dimension: "verify_access.api_error",
|
|
3865
3902
|
message: reason ?? "Verification temporarily unavailable",
|
|
3866
3903
|
guidance: guidance.message
|
|
3867
3904
|
}
|
|
3868
3905
|
] : void 0,
|
|
3906
|
+
// 4.0.0: typed marker so adapters render the misconfig envelope (503 +
|
|
3907
|
+
// MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
|
|
3908
|
+
...isMisconfig && { misconfigured: true },
|
|
3869
3909
|
correlationId: options.correlationId,
|
|
3910
|
+
attemptId: options.attemptId,
|
|
3870
3911
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
3871
3912
|
};
|
|
3872
3913
|
}
|
|
@@ -3896,6 +3937,8 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3896
3937
|
body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
|
|
3897
3938
|
if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
|
|
3898
3939
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
3940
|
+
if (requestData.attemptId) body.attemptId = requestData.attemptId;
|
|
3941
|
+
if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
|
|
3899
3942
|
body.sdkVersion = SDK_VERSION;
|
|
3900
3943
|
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
3901
3944
|
const meta = {
|
|
@@ -3917,12 +3960,16 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3917
3960
|
const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
3918
3961
|
method: "POST",
|
|
3919
3962
|
headers,
|
|
3920
|
-
body: JSON.stringify(body)
|
|
3963
|
+
body: JSON.stringify(body),
|
|
3964
|
+
signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
|
|
3921
3965
|
});
|
|
3922
3966
|
const data = await response.json();
|
|
3923
3967
|
if (response.status === 410) {
|
|
3924
3968
|
return {
|
|
3925
3969
|
success: true,
|
|
3970
|
+
// 3.12.0 (Trust Record): keep the server-echoed attempt handle even on
|
|
3971
|
+
// the synthesised 410 deny shape (echoed on every branch).
|
|
3972
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
|
|
3926
3973
|
access: {
|
|
3927
3974
|
allowed: false,
|
|
3928
3975
|
accessLevel: "none",
|
|
@@ -3938,10 +3985,22 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
3938
3985
|
};
|
|
3939
3986
|
}
|
|
3940
3987
|
if (!response.ok) {
|
|
3988
|
+
if (response.status === 401) {
|
|
3989
|
+
return {
|
|
3990
|
+
success: false,
|
|
3991
|
+
error: data.message || data.error || "Integration API key rejected",
|
|
3992
|
+
misconfig: true,
|
|
3993
|
+
misconfigCode: typeof data?.code === "string" ? data.code : void 0,
|
|
3994
|
+
remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
|
|
3995
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
3996
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
3997
|
+
};
|
|
3998
|
+
}
|
|
3941
3999
|
return {
|
|
3942
4000
|
success: false,
|
|
3943
4001
|
error: data.message || data.error || `API returned ${response.status}`,
|
|
3944
|
-
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0
|
|
4002
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
4003
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
3945
4004
|
};
|
|
3946
4005
|
}
|
|
3947
4006
|
return data;
|
|
@@ -3958,9 +4017,19 @@ async function verify(config, request, options) {
|
|
|
3958
4017
|
const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
|
|
3959
4018
|
if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
|
|
3960
4019
|
if (mergedConfig.strictInit) {
|
|
3961
|
-
await performInitCheck(
|
|
4020
|
+
await performInitCheck(
|
|
4021
|
+
mergedConfig.apiBaseUrl,
|
|
4022
|
+
mergedConfig.debug,
|
|
4023
|
+
true,
|
|
4024
|
+
mergedConfig.apiKey
|
|
4025
|
+
);
|
|
3962
4026
|
} else {
|
|
3963
|
-
void performInitCheck(
|
|
4027
|
+
void performInitCheck(
|
|
4028
|
+
mergedConfig.apiBaseUrl,
|
|
4029
|
+
mergedConfig.debug,
|
|
4030
|
+
false,
|
|
4031
|
+
mergedConfig.apiKey
|
|
4032
|
+
);
|
|
3964
4033
|
}
|
|
3965
4034
|
}
|
|
3966
4035
|
if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
|
|
@@ -3975,7 +4044,13 @@ async function verify(config, request, options) {
|
|
|
3975
4044
|
if (mergedConfig.debug) {
|
|
3976
4045
|
console.log("[VerificationGateway] Returning cached result");
|
|
3977
4046
|
}
|
|
3978
|
-
|
|
4047
|
+
const hit = { ...cached };
|
|
4048
|
+
if (request.attemptId) {
|
|
4049
|
+
hit.attemptId = request.attemptId;
|
|
4050
|
+
} else {
|
|
4051
|
+
delete hit.attemptId;
|
|
4052
|
+
}
|
|
4053
|
+
return hit;
|
|
3979
4054
|
}
|
|
3980
4055
|
}
|
|
3981
4056
|
const enrichedRequest = { ...request };
|
|
@@ -3993,8 +4068,10 @@ async function verify(config, request, options) {
|
|
|
3993
4068
|
const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
|
|
3994
4069
|
if (!apiResponse.success) {
|
|
3995
4070
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
3996
|
-
source: "api_error",
|
|
4071
|
+
source: apiResponse.misconfig ? "merchant_misconfig" : "api_error",
|
|
3997
4072
|
correlationId: apiResponse.correlationId,
|
|
4073
|
+
attemptId: apiResponse.attemptId,
|
|
4074
|
+
remediation: apiResponse.remediation,
|
|
3998
4075
|
urls
|
|
3999
4076
|
});
|
|
4000
4077
|
}
|
|
@@ -4030,6 +4107,9 @@ async function verify(config, request, options) {
|
|
|
4030
4107
|
// Anonymous traffic has no session → correlationId is the per-attempt
|
|
4031
4108
|
// linking key (the sessionId-equivalent for anonymous callers).
|
|
4032
4109
|
correlationId: apiResponse.correlationId,
|
|
4110
|
+
// 3.12.0 (Trust Record): server echoes the attempt-chain handle on
|
|
4111
|
+
// every branch — denials included (the funnel outlives one deny).
|
|
4112
|
+
attemptId: apiResponse.attemptId,
|
|
4033
4113
|
recommendation: apiResponse.recommendation,
|
|
4034
4114
|
recommendationReasons: apiResponse.recommendationReasons,
|
|
4035
4115
|
stepUpApproval: apiResponse.stepUpApproval,
|
|
@@ -4081,6 +4161,8 @@ async function verify(config, request, options) {
|
|
|
4081
4161
|
// v2.3.10 (defect #34, round-4): anonymous responses surface correlationId
|
|
4082
4162
|
// (no session row exists for unverified callers).
|
|
4083
4163
|
correlationId: apiResponse.correlationId,
|
|
4164
|
+
// 3.12.0 (Trust Record): server-echoed attempt-chain handle.
|
|
4165
|
+
attemptId: apiResponse.attemptId,
|
|
4084
4166
|
runtimeChallenge: apiResponse.runtimeChallenge,
|
|
4085
4167
|
tokenGuidance: apiResponse.tokenGuidance,
|
|
4086
4168
|
recommendation: apiResponse.recommendation,
|
|
@@ -4609,7 +4609,7 @@ function getTrustLevel(score) {
|
|
|
4609
4609
|
}
|
|
4610
4610
|
|
|
4611
4611
|
// src/version.ts
|
|
4612
|
-
var SDK_VERSION = "
|
|
4612
|
+
var SDK_VERSION = "4.0.0";
|
|
4613
4613
|
|
|
4614
4614
|
// src/well-known.ts
|
|
4615
4615
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -4635,7 +4635,7 @@ var DEFAULT_CONFIG = {
|
|
|
4635
4635
|
};
|
|
4636
4636
|
var initCheckPerformed = false;
|
|
4637
4637
|
var deprecationWarningShown = false;
|
|
4638
|
-
async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
4638
|
+
async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
|
|
4639
4639
|
initCheckPerformed = true;
|
|
4640
4640
|
try {
|
|
4641
4641
|
const probeUrl = `${apiBaseUrl}/agents/verify-access`;
|
|
@@ -4652,6 +4652,28 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
|
4652
4652
|
`[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
|
|
4653
4653
|
);
|
|
4654
4654
|
}
|
|
4655
|
+
if (apiKey) {
|
|
4656
|
+
const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
|
|
4657
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
4658
|
+
});
|
|
4659
|
+
if (selfCheck.status === 401) {
|
|
4660
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
4661
|
+
const message = `[VerificationGateway] the configured AstraSync API key was REJECTED at startup (${body.code ?? "api_key_invalid"}: ${body.message ?? "invalid key"}). Every inbound agent will be turned away until the key is rotated` + (body.remediation?.manageUrl ? ` at ${body.remediation.manageUrl}` : "") + `.`;
|
|
4662
|
+
if (strictInit) {
|
|
4663
|
+
throw new Error(`${message} (strictInit=true)`);
|
|
4664
|
+
}
|
|
4665
|
+
console.error(message);
|
|
4666
|
+
} else if (selfCheck.ok) {
|
|
4667
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
4668
|
+
if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
|
|
4669
|
+
console.warn(
|
|
4670
|
+
`[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
|
|
4671
|
+
);
|
|
4672
|
+
} else if (debug) {
|
|
4673
|
+
console.log("[VerificationGateway] API key self-check passed");
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
}
|
|
4655
4677
|
} catch (err) {
|
|
4656
4678
|
if (strictInit) {
|
|
4657
4679
|
throw err;
|
|
@@ -4729,8 +4751,17 @@ function cacheResult(request2, result, configuredTtl, counterpartyId) {
|
|
|
4729
4751
|
function createGuidanceResponse(_config, reason, options = {}) {
|
|
4730
4752
|
const source = options.source ?? "no_credentials";
|
|
4731
4753
|
const isApiError = source === "api_error";
|
|
4754
|
+
const isMisconfig = source === "merchant_misconfig";
|
|
4732
4755
|
const urls = options.urls;
|
|
4733
|
-
const guidance =
|
|
4756
|
+
const guidance = isMisconfig ? {
|
|
4757
|
+
message: "This site's AstraSync integration is misconfigured (its API key was revoked, expired, or rotated). Your identity and the AstraSync platform are fine \u2014 contact the site operator. Retrying will not help.",
|
|
4758
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
4759
|
+
documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
|
|
4760
|
+
steps: [
|
|
4761
|
+
"Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
|
|
4762
|
+
"Do not retry: the failure is deterministic until the operator updates their key"
|
|
4763
|
+
]
|
|
4764
|
+
} : isApiError ? {
|
|
4734
4765
|
message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
|
|
4735
4766
|
registrationUrl: urls?.registrationUrl ?? "",
|
|
4736
4767
|
documentationUrl: urls?.documentationUrl ?? "",
|
|
@@ -4768,14 +4799,24 @@ function createGuidanceResponse(_config, reason, options = {}) {
|
|
|
4768
4799
|
// partners (and their custom onDenied handlers) can branch on
|
|
4769
4800
|
// dimension. Without this, the synthesised stub was indistinguishable
|
|
4770
4801
|
// from a real policy deny.
|
|
4771
|
-
failures:
|
|
4802
|
+
failures: isMisconfig ? [
|
|
4803
|
+
{
|
|
4804
|
+
dimension: "verify_access.merchant_misconfigured",
|
|
4805
|
+
message: reason ?? "The integration API key was rejected by AstraSync",
|
|
4806
|
+
guidance: guidance.message
|
|
4807
|
+
}
|
|
4808
|
+
] : isApiError ? [
|
|
4772
4809
|
{
|
|
4773
4810
|
dimension: "verify_access.api_error",
|
|
4774
4811
|
message: reason ?? "Verification temporarily unavailable",
|
|
4775
4812
|
guidance: guidance.message
|
|
4776
4813
|
}
|
|
4777
4814
|
] : void 0,
|
|
4815
|
+
// 4.0.0: typed marker so adapters render the misconfig envelope (503 +
|
|
4816
|
+
// MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
|
|
4817
|
+
...isMisconfig && { misconfigured: true },
|
|
4778
4818
|
correlationId: options.correlationId,
|
|
4819
|
+
attemptId: options.attemptId,
|
|
4779
4820
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
4780
4821
|
};
|
|
4781
4822
|
}
|
|
@@ -4805,6 +4846,8 @@ async function callVerifyAccessAPI(config, request2) {
|
|
|
4805
4846
|
body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
|
|
4806
4847
|
if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
|
|
4807
4848
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
4849
|
+
if (requestData.attemptId) body.attemptId = requestData.attemptId;
|
|
4850
|
+
if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
|
|
4808
4851
|
body.sdkVersion = SDK_VERSION;
|
|
4809
4852
|
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
4810
4853
|
const meta = {
|
|
@@ -4826,12 +4869,16 @@ async function callVerifyAccessAPI(config, request2) {
|
|
|
4826
4869
|
const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
4827
4870
|
method: "POST",
|
|
4828
4871
|
headers,
|
|
4829
|
-
body: JSON.stringify(body)
|
|
4872
|
+
body: JSON.stringify(body),
|
|
4873
|
+
signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
|
|
4830
4874
|
});
|
|
4831
4875
|
const data = await response.json();
|
|
4832
4876
|
if (response.status === 410) {
|
|
4833
4877
|
return {
|
|
4834
4878
|
success: true,
|
|
4879
|
+
// 3.12.0 (Trust Record): keep the server-echoed attempt handle even on
|
|
4880
|
+
// the synthesised 410 deny shape (echoed on every branch).
|
|
4881
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
|
|
4835
4882
|
access: {
|
|
4836
4883
|
allowed: false,
|
|
4837
4884
|
accessLevel: "none",
|
|
@@ -4847,10 +4894,22 @@ async function callVerifyAccessAPI(config, request2) {
|
|
|
4847
4894
|
};
|
|
4848
4895
|
}
|
|
4849
4896
|
if (!response.ok) {
|
|
4897
|
+
if (response.status === 401) {
|
|
4898
|
+
return {
|
|
4899
|
+
success: false,
|
|
4900
|
+
error: data.message || data.error || "Integration API key rejected",
|
|
4901
|
+
misconfig: true,
|
|
4902
|
+
misconfigCode: typeof data?.code === "string" ? data.code : void 0,
|
|
4903
|
+
remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
|
|
4904
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
4905
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
4906
|
+
};
|
|
4907
|
+
}
|
|
4850
4908
|
return {
|
|
4851
4909
|
success: false,
|
|
4852
4910
|
error: data.message || data.error || `API returned ${response.status}`,
|
|
4853
|
-
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0
|
|
4911
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
4912
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
4854
4913
|
};
|
|
4855
4914
|
}
|
|
4856
4915
|
return data;
|
|
@@ -4867,9 +4926,19 @@ async function verify(config, request2, options) {
|
|
|
4867
4926
|
const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
|
|
4868
4927
|
if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
|
|
4869
4928
|
if (mergedConfig.strictInit) {
|
|
4870
|
-
await performInitCheck(
|
|
4929
|
+
await performInitCheck(
|
|
4930
|
+
mergedConfig.apiBaseUrl,
|
|
4931
|
+
mergedConfig.debug,
|
|
4932
|
+
true,
|
|
4933
|
+
mergedConfig.apiKey
|
|
4934
|
+
);
|
|
4871
4935
|
} else {
|
|
4872
|
-
void performInitCheck(
|
|
4936
|
+
void performInitCheck(
|
|
4937
|
+
mergedConfig.apiBaseUrl,
|
|
4938
|
+
mergedConfig.debug,
|
|
4939
|
+
false,
|
|
4940
|
+
mergedConfig.apiKey
|
|
4941
|
+
);
|
|
4873
4942
|
}
|
|
4874
4943
|
}
|
|
4875
4944
|
if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
|
|
@@ -4884,7 +4953,13 @@ async function verify(config, request2, options) {
|
|
|
4884
4953
|
if (mergedConfig.debug) {
|
|
4885
4954
|
console.log("[VerificationGateway] Returning cached result");
|
|
4886
4955
|
}
|
|
4887
|
-
|
|
4956
|
+
const hit = { ...cached };
|
|
4957
|
+
if (request2.attemptId) {
|
|
4958
|
+
hit.attemptId = request2.attemptId;
|
|
4959
|
+
} else {
|
|
4960
|
+
delete hit.attemptId;
|
|
4961
|
+
}
|
|
4962
|
+
return hit;
|
|
4888
4963
|
}
|
|
4889
4964
|
}
|
|
4890
4965
|
const enrichedRequest = { ...request2 };
|
|
@@ -4902,8 +4977,10 @@ async function verify(config, request2, options) {
|
|
|
4902
4977
|
const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
|
|
4903
4978
|
if (!apiResponse.success) {
|
|
4904
4979
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
4905
|
-
source: "api_error",
|
|
4980
|
+
source: apiResponse.misconfig ? "merchant_misconfig" : "api_error",
|
|
4906
4981
|
correlationId: apiResponse.correlationId,
|
|
4982
|
+
attemptId: apiResponse.attemptId,
|
|
4983
|
+
remediation: apiResponse.remediation,
|
|
4907
4984
|
urls
|
|
4908
4985
|
});
|
|
4909
4986
|
}
|
|
@@ -4939,6 +5016,9 @@ async function verify(config, request2, options) {
|
|
|
4939
5016
|
// Anonymous traffic has no session → correlationId is the per-attempt
|
|
4940
5017
|
// linking key (the sessionId-equivalent for anonymous callers).
|
|
4941
5018
|
correlationId: apiResponse.correlationId,
|
|
5019
|
+
// 3.12.0 (Trust Record): server echoes the attempt-chain handle on
|
|
5020
|
+
// every branch — denials included (the funnel outlives one deny).
|
|
5021
|
+
attemptId: apiResponse.attemptId,
|
|
4942
5022
|
recommendation: apiResponse.recommendation,
|
|
4943
5023
|
recommendationReasons: apiResponse.recommendationReasons,
|
|
4944
5024
|
stepUpApproval: apiResponse.stepUpApproval,
|
|
@@ -4990,6 +5070,8 @@ async function verify(config, request2, options) {
|
|
|
4990
5070
|
// v2.3.10 (defect #34, round-4): anonymous responses surface correlationId
|
|
4991
5071
|
// (no session row exists for unverified callers).
|
|
4992
5072
|
correlationId: apiResponse.correlationId,
|
|
5073
|
+
// 3.12.0 (Trust Record): server-echoed attempt-chain handle.
|
|
5074
|
+
attemptId: apiResponse.attemptId,
|
|
4993
5075
|
runtimeChallenge: apiResponse.runtimeChallenge,
|
|
4994
5076
|
tokenGuidance: apiResponse.tokenGuidance,
|
|
4995
5077
|
recommendation: apiResponse.recommendation,
|