@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
package/dist/bin/astrasync.js
CHANGED
|
@@ -5000,7 +5000,7 @@ var SDK_VERSION;
|
|
|
5000
5000
|
var init_version = __esm({
|
|
5001
5001
|
"src/version.ts"() {
|
|
5002
5002
|
"use strict";
|
|
5003
|
-
SDK_VERSION = "
|
|
5003
|
+
SDK_VERSION = "4.0.0";
|
|
5004
5004
|
}
|
|
5005
5005
|
});
|
|
5006
5006
|
|
|
@@ -5018,7 +5018,7 @@ var init_well_known = __esm({
|
|
|
5018
5018
|
});
|
|
5019
5019
|
|
|
5020
5020
|
// src/verify.ts
|
|
5021
|
-
async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
5021
|
+
async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
|
|
5022
5022
|
initCheckPerformed = true;
|
|
5023
5023
|
try {
|
|
5024
5024
|
const probeUrl = `${apiBaseUrl}/agents/verify-access`;
|
|
@@ -5035,6 +5035,28 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
|
5035
5035
|
`[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
|
|
5036
5036
|
);
|
|
5037
5037
|
}
|
|
5038
|
+
if (apiKey) {
|
|
5039
|
+
const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
|
|
5040
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
5041
|
+
});
|
|
5042
|
+
if (selfCheck.status === 401) {
|
|
5043
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
5044
|
+
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}` : "") + `.`;
|
|
5045
|
+
if (strictInit) {
|
|
5046
|
+
throw new Error(`${message} (strictInit=true)`);
|
|
5047
|
+
}
|
|
5048
|
+
console.error(message);
|
|
5049
|
+
} else if (selfCheck.ok) {
|
|
5050
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
5051
|
+
if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
|
|
5052
|
+
console.warn(
|
|
5053
|
+
`[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
|
|
5054
|
+
);
|
|
5055
|
+
} else if (debug) {
|
|
5056
|
+
console.log("[VerificationGateway] API key self-check passed");
|
|
5057
|
+
}
|
|
5058
|
+
}
|
|
5059
|
+
}
|
|
5038
5060
|
} catch (err) {
|
|
5039
5061
|
if (strictInit) {
|
|
5040
5062
|
throw err;
|
|
@@ -5110,8 +5132,17 @@ function cacheResult(request2, result, configuredTtl, counterpartyId) {
|
|
|
5110
5132
|
function createGuidanceResponse(_config, reason, options = {}) {
|
|
5111
5133
|
const source = options.source ?? "no_credentials";
|
|
5112
5134
|
const isApiError = source === "api_error";
|
|
5135
|
+
const isMisconfig = source === "merchant_misconfig";
|
|
5113
5136
|
const urls = options.urls;
|
|
5114
|
-
const guidance =
|
|
5137
|
+
const guidance = isMisconfig ? {
|
|
5138
|
+
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.",
|
|
5139
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
5140
|
+
documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
|
|
5141
|
+
steps: [
|
|
5142
|
+
"Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
|
|
5143
|
+
"Do not retry: the failure is deterministic until the operator updates their key"
|
|
5144
|
+
]
|
|
5145
|
+
} : isApiError ? {
|
|
5115
5146
|
message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
|
|
5116
5147
|
registrationUrl: urls?.registrationUrl ?? "",
|
|
5117
5148
|
documentationUrl: urls?.documentationUrl ?? "",
|
|
@@ -5149,14 +5180,24 @@ function createGuidanceResponse(_config, reason, options = {}) {
|
|
|
5149
5180
|
// partners (and their custom onDenied handlers) can branch on
|
|
5150
5181
|
// dimension. Without this, the synthesised stub was indistinguishable
|
|
5151
5182
|
// from a real policy deny.
|
|
5152
|
-
failures:
|
|
5183
|
+
failures: isMisconfig ? [
|
|
5184
|
+
{
|
|
5185
|
+
dimension: "verify_access.merchant_misconfigured",
|
|
5186
|
+
message: reason ?? "The integration API key was rejected by AstraSync",
|
|
5187
|
+
guidance: guidance.message
|
|
5188
|
+
}
|
|
5189
|
+
] : isApiError ? [
|
|
5153
5190
|
{
|
|
5154
5191
|
dimension: "verify_access.api_error",
|
|
5155
5192
|
message: reason ?? "Verification temporarily unavailable",
|
|
5156
5193
|
guidance: guidance.message
|
|
5157
5194
|
}
|
|
5158
5195
|
] : void 0,
|
|
5196
|
+
// 4.0.0: typed marker so adapters render the misconfig envelope (503 +
|
|
5197
|
+
// MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
|
|
5198
|
+
...isMisconfig && { misconfigured: true },
|
|
5159
5199
|
correlationId: options.correlationId,
|
|
5200
|
+
attemptId: options.attemptId,
|
|
5160
5201
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
5161
5202
|
};
|
|
5162
5203
|
}
|
|
@@ -5186,6 +5227,8 @@ async function callVerifyAccessAPI(config, request2) {
|
|
|
5186
5227
|
body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
|
|
5187
5228
|
if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
|
|
5188
5229
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
5230
|
+
if (requestData.attemptId) body.attemptId = requestData.attemptId;
|
|
5231
|
+
if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
|
|
5189
5232
|
body.sdkVersion = SDK_VERSION;
|
|
5190
5233
|
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
5191
5234
|
const meta = {
|
|
@@ -5207,12 +5250,16 @@ async function callVerifyAccessAPI(config, request2) {
|
|
|
5207
5250
|
const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
5208
5251
|
method: "POST",
|
|
5209
5252
|
headers,
|
|
5210
|
-
body: JSON.stringify(body)
|
|
5253
|
+
body: JSON.stringify(body),
|
|
5254
|
+
signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
|
|
5211
5255
|
});
|
|
5212
5256
|
const data = await response.json();
|
|
5213
5257
|
if (response.status === 410) {
|
|
5214
5258
|
return {
|
|
5215
5259
|
success: true,
|
|
5260
|
+
// 3.12.0 (Trust Record): keep the server-echoed attempt handle even on
|
|
5261
|
+
// the synthesised 410 deny shape (echoed on every branch).
|
|
5262
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
|
|
5216
5263
|
access: {
|
|
5217
5264
|
allowed: false,
|
|
5218
5265
|
accessLevel: "none",
|
|
@@ -5228,10 +5275,22 @@ async function callVerifyAccessAPI(config, request2) {
|
|
|
5228
5275
|
};
|
|
5229
5276
|
}
|
|
5230
5277
|
if (!response.ok) {
|
|
5278
|
+
if (response.status === 401) {
|
|
5279
|
+
return {
|
|
5280
|
+
success: false,
|
|
5281
|
+
error: data.message || data.error || "Integration API key rejected",
|
|
5282
|
+
misconfig: true,
|
|
5283
|
+
misconfigCode: typeof data?.code === "string" ? data.code : void 0,
|
|
5284
|
+
remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
|
|
5285
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
5286
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
5287
|
+
};
|
|
5288
|
+
}
|
|
5231
5289
|
return {
|
|
5232
5290
|
success: false,
|
|
5233
5291
|
error: data.message || data.error || `API returned ${response.status}`,
|
|
5234
|
-
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0
|
|
5292
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
5293
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
5235
5294
|
};
|
|
5236
5295
|
}
|
|
5237
5296
|
return data;
|
|
@@ -5248,9 +5307,19 @@ async function verify(config, request2, options) {
|
|
|
5248
5307
|
const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
|
|
5249
5308
|
if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
|
|
5250
5309
|
if (mergedConfig.strictInit) {
|
|
5251
|
-
await performInitCheck(
|
|
5310
|
+
await performInitCheck(
|
|
5311
|
+
mergedConfig.apiBaseUrl,
|
|
5312
|
+
mergedConfig.debug,
|
|
5313
|
+
true,
|
|
5314
|
+
mergedConfig.apiKey
|
|
5315
|
+
);
|
|
5252
5316
|
} else {
|
|
5253
|
-
void performInitCheck(
|
|
5317
|
+
void performInitCheck(
|
|
5318
|
+
mergedConfig.apiBaseUrl,
|
|
5319
|
+
mergedConfig.debug,
|
|
5320
|
+
false,
|
|
5321
|
+
mergedConfig.apiKey
|
|
5322
|
+
);
|
|
5254
5323
|
}
|
|
5255
5324
|
}
|
|
5256
5325
|
if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
|
|
@@ -5265,7 +5334,13 @@ async function verify(config, request2, options) {
|
|
|
5265
5334
|
if (mergedConfig.debug) {
|
|
5266
5335
|
console.log("[VerificationGateway] Returning cached result");
|
|
5267
5336
|
}
|
|
5268
|
-
|
|
5337
|
+
const hit = { ...cached };
|
|
5338
|
+
if (request2.attemptId) {
|
|
5339
|
+
hit.attemptId = request2.attemptId;
|
|
5340
|
+
} else {
|
|
5341
|
+
delete hit.attemptId;
|
|
5342
|
+
}
|
|
5343
|
+
return hit;
|
|
5269
5344
|
}
|
|
5270
5345
|
}
|
|
5271
5346
|
const enrichedRequest = { ...request2 };
|
|
@@ -5283,8 +5358,10 @@ async function verify(config, request2, options) {
|
|
|
5283
5358
|
const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
|
|
5284
5359
|
if (!apiResponse.success) {
|
|
5285
5360
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
5286
|
-
source: "api_error",
|
|
5361
|
+
source: apiResponse.misconfig ? "merchant_misconfig" : "api_error",
|
|
5287
5362
|
correlationId: apiResponse.correlationId,
|
|
5363
|
+
attemptId: apiResponse.attemptId,
|
|
5364
|
+
remediation: apiResponse.remediation,
|
|
5288
5365
|
urls
|
|
5289
5366
|
});
|
|
5290
5367
|
}
|
|
@@ -5320,6 +5397,9 @@ async function verify(config, request2, options) {
|
|
|
5320
5397
|
// Anonymous traffic has no session → correlationId is the per-attempt
|
|
5321
5398
|
// linking key (the sessionId-equivalent for anonymous callers).
|
|
5322
5399
|
correlationId: apiResponse.correlationId,
|
|
5400
|
+
// 3.12.0 (Trust Record): server echoes the attempt-chain handle on
|
|
5401
|
+
// every branch — denials included (the funnel outlives one deny).
|
|
5402
|
+
attemptId: apiResponse.attemptId,
|
|
5323
5403
|
recommendation: apiResponse.recommendation,
|
|
5324
5404
|
recommendationReasons: apiResponse.recommendationReasons,
|
|
5325
5405
|
stepUpApproval: apiResponse.stepUpApproval,
|
|
@@ -5371,6 +5451,8 @@ async function verify(config, request2, options) {
|
|
|
5371
5451
|
// v2.3.10 (defect #34, round-4): anonymous responses surface correlationId
|
|
5372
5452
|
// (no session row exists for unverified callers).
|
|
5373
5453
|
correlationId: apiResponse.correlationId,
|
|
5454
|
+
// 3.12.0 (Trust Record): server-echoed attempt-chain handle.
|
|
5455
|
+
attemptId: apiResponse.attemptId,
|
|
5374
5456
|
runtimeChallenge: apiResponse.runtimeChallenge,
|
|
5375
5457
|
tokenGuidance: apiResponse.tokenGuidance,
|
|
5376
5458
|
recommendation: apiResponse.recommendation,
|
|
@@ -5949,6 +6031,7 @@ var init_src = __esm({
|
|
|
5949
6031
|
init_edge_config();
|
|
5950
6032
|
init_platform_signatures();
|
|
5951
6033
|
init_verify();
|
|
6034
|
+
init_verify();
|
|
5952
6035
|
init_metadata_capture();
|
|
5953
6036
|
init_version();
|
|
5954
6037
|
}
|
|
@@ -3938,7 +3938,7 @@ function getTrustLevel(score) {
|
|
|
3938
3938
|
}
|
|
3939
3939
|
|
|
3940
3940
|
// src/version.ts
|
|
3941
|
-
var SDK_VERSION = "
|
|
3941
|
+
var SDK_VERSION = "4.0.0";
|
|
3942
3942
|
|
|
3943
3943
|
// src/well-known.ts
|
|
3944
3944
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -3964,7 +3964,7 @@ var DEFAULT_CONFIG = {
|
|
|
3964
3964
|
};
|
|
3965
3965
|
var initCheckPerformed = false;
|
|
3966
3966
|
var deprecationWarningShown = false;
|
|
3967
|
-
async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
3967
|
+
async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
|
|
3968
3968
|
initCheckPerformed = true;
|
|
3969
3969
|
try {
|
|
3970
3970
|
const probeUrl = `${apiBaseUrl}/agents/verify-access`;
|
|
@@ -3981,6 +3981,28 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
|
|
|
3981
3981
|
`[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
|
|
3982
3982
|
);
|
|
3983
3983
|
}
|
|
3984
|
+
if (apiKey) {
|
|
3985
|
+
const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
|
|
3986
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
3987
|
+
});
|
|
3988
|
+
if (selfCheck.status === 401) {
|
|
3989
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
3990
|
+
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}` : "") + `.`;
|
|
3991
|
+
if (strictInit) {
|
|
3992
|
+
throw new Error(`${message} (strictInit=true)`);
|
|
3993
|
+
}
|
|
3994
|
+
console.error(message);
|
|
3995
|
+
} else if (selfCheck.ok) {
|
|
3996
|
+
const body = await selfCheck.json().catch(() => ({}));
|
|
3997
|
+
if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
|
|
3998
|
+
console.warn(
|
|
3999
|
+
`[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
|
|
4000
|
+
);
|
|
4001
|
+
} else if (debug) {
|
|
4002
|
+
console.log("[VerificationGateway] API key self-check passed");
|
|
4003
|
+
}
|
|
4004
|
+
}
|
|
4005
|
+
}
|
|
3984
4006
|
} catch (err) {
|
|
3985
4007
|
if (strictInit) {
|
|
3986
4008
|
throw err;
|
|
@@ -4058,8 +4080,17 @@ function cacheResult(request, result, configuredTtl, counterpartyId) {
|
|
|
4058
4080
|
function createGuidanceResponse(_config, reason, options = {}) {
|
|
4059
4081
|
const source = options.source ?? "no_credentials";
|
|
4060
4082
|
const isApiError = source === "api_error";
|
|
4083
|
+
const isMisconfig = source === "merchant_misconfig";
|
|
4061
4084
|
const urls = options.urls;
|
|
4062
|
-
const guidance =
|
|
4085
|
+
const guidance = isMisconfig ? {
|
|
4086
|
+
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.",
|
|
4087
|
+
registrationUrl: urls?.registrationUrl ?? "",
|
|
4088
|
+
documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
|
|
4089
|
+
steps: [
|
|
4090
|
+
"Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
|
|
4091
|
+
"Do not retry: the failure is deterministic until the operator updates their key"
|
|
4092
|
+
]
|
|
4093
|
+
} : isApiError ? {
|
|
4063
4094
|
message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
|
|
4064
4095
|
registrationUrl: urls?.registrationUrl ?? "",
|
|
4065
4096
|
documentationUrl: urls?.documentationUrl ?? "",
|
|
@@ -4097,14 +4128,24 @@ function createGuidanceResponse(_config, reason, options = {}) {
|
|
|
4097
4128
|
// partners (and their custom onDenied handlers) can branch on
|
|
4098
4129
|
// dimension. Without this, the synthesised stub was indistinguishable
|
|
4099
4130
|
// from a real policy deny.
|
|
4100
|
-
failures:
|
|
4131
|
+
failures: isMisconfig ? [
|
|
4132
|
+
{
|
|
4133
|
+
dimension: "verify_access.merchant_misconfigured",
|
|
4134
|
+
message: reason ?? "The integration API key was rejected by AstraSync",
|
|
4135
|
+
guidance: guidance.message
|
|
4136
|
+
}
|
|
4137
|
+
] : isApiError ? [
|
|
4101
4138
|
{
|
|
4102
4139
|
dimension: "verify_access.api_error",
|
|
4103
4140
|
message: reason ?? "Verification temporarily unavailable",
|
|
4104
4141
|
guidance: guidance.message
|
|
4105
4142
|
}
|
|
4106
4143
|
] : void 0,
|
|
4144
|
+
// 4.0.0: typed marker so adapters render the misconfig envelope (503 +
|
|
4145
|
+
// MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
|
|
4146
|
+
...isMisconfig && { misconfigured: true },
|
|
4107
4147
|
correlationId: options.correlationId,
|
|
4148
|
+
attemptId: options.attemptId,
|
|
4108
4149
|
verifiedAt: /* @__PURE__ */ new Date()
|
|
4109
4150
|
};
|
|
4110
4151
|
}
|
|
@@ -4134,6 +4175,8 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
4134
4175
|
body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
|
|
4135
4176
|
if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
|
|
4136
4177
|
if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
|
|
4178
|
+
if (requestData.attemptId) body.attemptId = requestData.attemptId;
|
|
4179
|
+
if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
|
|
4137
4180
|
body.sdkVersion = SDK_VERSION;
|
|
4138
4181
|
if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
|
|
4139
4182
|
const meta = {
|
|
@@ -4155,12 +4198,16 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
4155
4198
|
const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
4156
4199
|
method: "POST",
|
|
4157
4200
|
headers,
|
|
4158
|
-
body: JSON.stringify(body)
|
|
4201
|
+
body: JSON.stringify(body),
|
|
4202
|
+
signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
|
|
4159
4203
|
});
|
|
4160
4204
|
const data = await response.json();
|
|
4161
4205
|
if (response.status === 410) {
|
|
4162
4206
|
return {
|
|
4163
4207
|
success: true,
|
|
4208
|
+
// 3.12.0 (Trust Record): keep the server-echoed attempt handle even on
|
|
4209
|
+
// the synthesised 410 deny shape (echoed on every branch).
|
|
4210
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
|
|
4164
4211
|
access: {
|
|
4165
4212
|
allowed: false,
|
|
4166
4213
|
accessLevel: "none",
|
|
@@ -4176,10 +4223,22 @@ async function callVerifyAccessAPI(config, request) {
|
|
|
4176
4223
|
};
|
|
4177
4224
|
}
|
|
4178
4225
|
if (!response.ok) {
|
|
4226
|
+
if (response.status === 401) {
|
|
4227
|
+
return {
|
|
4228
|
+
success: false,
|
|
4229
|
+
error: data.message || data.error || "Integration API key rejected",
|
|
4230
|
+
misconfig: true,
|
|
4231
|
+
misconfigCode: typeof data?.code === "string" ? data.code : void 0,
|
|
4232
|
+
remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
|
|
4233
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
4234
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
4235
|
+
};
|
|
4236
|
+
}
|
|
4179
4237
|
return {
|
|
4180
4238
|
success: false,
|
|
4181
4239
|
error: data.message || data.error || `API returned ${response.status}`,
|
|
4182
|
-
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0
|
|
4240
|
+
correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
|
|
4241
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
|
|
4183
4242
|
};
|
|
4184
4243
|
}
|
|
4185
4244
|
return data;
|
|
@@ -4196,9 +4255,19 @@ async function verify(config, request, options) {
|
|
|
4196
4255
|
const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
|
|
4197
4256
|
if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
|
|
4198
4257
|
if (mergedConfig.strictInit) {
|
|
4199
|
-
await performInitCheck(
|
|
4258
|
+
await performInitCheck(
|
|
4259
|
+
mergedConfig.apiBaseUrl,
|
|
4260
|
+
mergedConfig.debug,
|
|
4261
|
+
true,
|
|
4262
|
+
mergedConfig.apiKey
|
|
4263
|
+
);
|
|
4200
4264
|
} else {
|
|
4201
|
-
void performInitCheck(
|
|
4265
|
+
void performInitCheck(
|
|
4266
|
+
mergedConfig.apiBaseUrl,
|
|
4267
|
+
mergedConfig.debug,
|
|
4268
|
+
false,
|
|
4269
|
+
mergedConfig.apiKey
|
|
4270
|
+
);
|
|
4202
4271
|
}
|
|
4203
4272
|
}
|
|
4204
4273
|
if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
|
|
@@ -4213,7 +4282,13 @@ async function verify(config, request, options) {
|
|
|
4213
4282
|
if (mergedConfig.debug) {
|
|
4214
4283
|
console.log("[VerificationGateway] Returning cached result");
|
|
4215
4284
|
}
|
|
4216
|
-
|
|
4285
|
+
const hit = { ...cached };
|
|
4286
|
+
if (request.attemptId) {
|
|
4287
|
+
hit.attemptId = request.attemptId;
|
|
4288
|
+
} else {
|
|
4289
|
+
delete hit.attemptId;
|
|
4290
|
+
}
|
|
4291
|
+
return hit;
|
|
4217
4292
|
}
|
|
4218
4293
|
}
|
|
4219
4294
|
const enrichedRequest = { ...request };
|
|
@@ -4231,8 +4306,10 @@ async function verify(config, request, options) {
|
|
|
4231
4306
|
const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
|
|
4232
4307
|
if (!apiResponse.success) {
|
|
4233
4308
|
return createGuidanceResponse(mergedConfig, apiResponse.error, {
|
|
4234
|
-
source: "api_error",
|
|
4309
|
+
source: apiResponse.misconfig ? "merchant_misconfig" : "api_error",
|
|
4235
4310
|
correlationId: apiResponse.correlationId,
|
|
4311
|
+
attemptId: apiResponse.attemptId,
|
|
4312
|
+
remediation: apiResponse.remediation,
|
|
4236
4313
|
urls
|
|
4237
4314
|
});
|
|
4238
4315
|
}
|
|
@@ -4268,6 +4345,9 @@ async function verify(config, request, options) {
|
|
|
4268
4345
|
// Anonymous traffic has no session → correlationId is the per-attempt
|
|
4269
4346
|
// linking key (the sessionId-equivalent for anonymous callers).
|
|
4270
4347
|
correlationId: apiResponse.correlationId,
|
|
4348
|
+
// 3.12.0 (Trust Record): server echoes the attempt-chain handle on
|
|
4349
|
+
// every branch — denials included (the funnel outlives one deny).
|
|
4350
|
+
attemptId: apiResponse.attemptId,
|
|
4271
4351
|
recommendation: apiResponse.recommendation,
|
|
4272
4352
|
recommendationReasons: apiResponse.recommendationReasons,
|
|
4273
4353
|
stepUpApproval: apiResponse.stepUpApproval,
|
|
@@ -4319,6 +4399,8 @@ async function verify(config, request, options) {
|
|
|
4319
4399
|
// v2.3.10 (defect #34, round-4): anonymous responses surface correlationId
|
|
4320
4400
|
// (no session row exists for unverified callers).
|
|
4321
4401
|
correlationId: apiResponse.correlationId,
|
|
4402
|
+
// 3.12.0 (Trust Record): server-echoed attempt-chain handle.
|
|
4403
|
+
attemptId: apiResponse.attemptId,
|
|
4322
4404
|
runtimeChallenge: apiResponse.runtimeChallenge,
|
|
4323
4405
|
tokenGuidance: apiResponse.tokenGuidance,
|
|
4324
4406
|
recommendation: apiResponse.recommendation,
|