@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.
Files changed (99) hide show
  1. package/dist/adapter-interface/interface.d.mts +2 -2
  2. package/dist/adapter-interface/interface.d.ts +2 -2
  3. package/dist/adapters/express.d.mts +2 -2
  4. package/dist/adapters/express.d.ts +2 -2
  5. package/dist/adapters/express.js +106 -10
  6. package/dist/adapters/express.js.map +1 -1
  7. package/dist/adapters/express.mjs +106 -10
  8. package/dist/adapters/express.mjs.map +1 -1
  9. package/dist/adapters/mcp.d.mts +1 -1
  10. package/dist/adapters/mcp.d.ts +1 -1
  11. package/dist/adapters/mcp.js +111 -10
  12. package/dist/adapters/mcp.js.map +1 -1
  13. package/dist/adapters/mcp.mjs +111 -10
  14. package/dist/adapters/mcp.mjs.map +1 -1
  15. package/dist/adapters/nextjs.d.mts +2 -2
  16. package/dist/adapters/nextjs.d.ts +2 -2
  17. package/dist/adapters/nextjs.js +107 -10
  18. package/dist/adapters/nextjs.js.map +1 -1
  19. package/dist/adapters/nextjs.mjs +107 -10
  20. package/dist/adapters/nextjs.mjs.map +1 -1
  21. package/dist/adapters/sdk.d.mts +2 -2
  22. package/dist/adapters/sdk.d.ts +2 -2
  23. package/dist/adapters/sdk.js +92 -10
  24. package/dist/adapters/sdk.js.map +1 -1
  25. package/dist/adapters/sdk.mjs +92 -10
  26. package/dist/adapters/sdk.mjs.map +1 -1
  27. package/dist/agent/index.d.mts +2 -2
  28. package/dist/agent/index.d.ts +2 -2
  29. package/dist/bin/astrasync-claude-hook.js +92 -10
  30. package/dist/bin/astrasync-codex-hook.js +92 -10
  31. package/dist/bin/astrasync-guard.js +92 -10
  32. package/dist/bin/astrasync.js +93 -10
  33. package/dist/browser/background.js +92 -10
  34. package/dist/browser/background.js.map +1 -1
  35. package/dist/browser/background.mjs +92 -10
  36. package/dist/browser/background.mjs.map +1 -1
  37. package/dist/browser/browser-adapter.d.mts +2 -2
  38. package/dist/browser/browser-adapter.d.ts +2 -2
  39. package/dist/claude-code/claude-code-adapter.d.mts +2 -2
  40. package/dist/claude-code/claude-code-adapter.d.ts +2 -2
  41. package/dist/cli/index.d.mts +2 -2
  42. package/dist/cli/index.d.ts +2 -2
  43. package/dist/codex/index.d.mts +2 -2
  44. package/dist/codex/index.d.ts +2 -2
  45. package/dist/codex/index.js +92 -10
  46. package/dist/codex/index.js.map +1 -1
  47. package/dist/codex/index.mjs +92 -10
  48. package/dist/codex/index.mjs.map +1 -1
  49. package/dist/cursor/cursor-adapter.d.mts +2 -2
  50. package/dist/cursor/cursor-adapter.d.ts +2 -2
  51. package/dist/cursor/extension.d.mts +2 -2
  52. package/dist/cursor/extension.d.ts +2 -2
  53. package/dist/cursor/extension.js +92 -10
  54. package/dist/cursor/extension.js.map +1 -1
  55. package/dist/cursor/extension.mjs +92 -10
  56. package/dist/cursor/extension.mjs.map +1 -1
  57. package/dist/edge-config.d.mts +1 -1
  58. package/dist/edge-config.d.ts +1 -1
  59. package/dist/{express-DCXa1oqj.d.mts → express-BZajRs4i.d.mts} +1 -1
  60. package/dist/{express-ClNtDhhc.d.ts → express-CjCUB1k7.d.ts} +1 -1
  61. package/dist/gateway/gateway.d.mts +2 -2
  62. package/dist/gateway/gateway.d.ts +2 -2
  63. package/dist/gateway/gateway.js +92 -10
  64. package/dist/gateway/gateway.js.map +1 -1
  65. package/dist/gateway/gateway.mjs +92 -10
  66. package/dist/gateway/gateway.mjs.map +1 -1
  67. package/dist/git-trigger/git-hooks.d.mts +2 -2
  68. package/dist/git-trigger/git-hooks.d.ts +2 -2
  69. package/dist/{index-BrNKDmiR.d.mts → index-B0cyMZDL.d.mts} +1 -1
  70. package/dist/{index-Dr_XiN65.d.mts → index-BRYteOqO.d.mts} +1 -1
  71. package/dist/{index-CfHurO1P.d.ts → index-BZQdVqNw.d.ts} +1 -1
  72. package/dist/{index-D2ztkumS.d.ts → index-adgKhujR.d.ts} +1 -1
  73. package/dist/index.d.mts +9 -9
  74. package/dist/index.d.ts +9 -9
  75. package/dist/index.js +160 -10
  76. package/dist/index.js.map +1 -1
  77. package/dist/index.mjs +159 -10
  78. package/dist/index.mjs.map +1 -1
  79. package/dist/local-evaluator/evaluator.d.mts +2 -2
  80. package/dist/local-evaluator/evaluator.d.ts +2 -2
  81. package/dist/{nextjs-CEBVBsdi.d.ts → nextjs-D_iFf5k-.d.ts} +1 -1
  82. package/dist/{nextjs-DcQIk6Zj.d.mts → nextjs-DeUTnOBd.d.mts} +1 -1
  83. package/dist/{sdk-H0JCLW2y.d.ts → sdk-BM3mwEAq.d.ts} +1 -1
  84. package/dist/{sdk-CZkbSOeO.d.mts → sdk-_il1Q41f.d.mts} +1 -1
  85. package/dist/transport/index.d.mts +2 -2
  86. package/dist/transport/index.d.ts +2 -2
  87. package/dist/{types-sy3tq8lp.d.mts → types-BcDf9Kk0.d.mts} +118 -1
  88. package/dist/{types-DhFPiZ3t.d.ts → types-CHKCgDFC.d.ts} +1 -1
  89. package/dist/{types-cQVCMeNV.d.mts → types-DfnP7JiM.d.mts} +1 -1
  90. package/dist/{types-9tns4wyl.d.ts → types-fTQD448H.d.ts} +118 -1
  91. package/dist/ui/index.d.mts +1 -1
  92. package/dist/ui/index.d.ts +1 -1
  93. package/dist/verify.d.mts +15 -2
  94. package/dist/verify.d.ts +15 -2
  95. package/dist/verify.js +117 -10
  96. package/dist/verify.js.map +1 -1
  97. package/dist/verify.mjs +115 -10
  98. package/dist/verify.mjs.map +1 -1
  99. 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 = "3.11.1";
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 = isApiError ? {
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: isApiError ? [
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(mergedConfig.apiBaseUrl, mergedConfig.debug, true);
4021
+ await performInitCheck(
4022
+ mergedConfig.apiBaseUrl,
4023
+ mergedConfig.debug,
4024
+ true,
4025
+ mergedConfig.apiKey
4026
+ );
3963
4027
  } else {
3964
- void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, false);
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
- return cached;
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 = "3.11.1";
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 = isApiError ? {
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: isApiError ? [
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(mergedConfig.apiBaseUrl, mergedConfig.debug, true);
4020
+ await performInitCheck(
4021
+ mergedConfig.apiBaseUrl,
4022
+ mergedConfig.debug,
4023
+ true,
4024
+ mergedConfig.apiKey
4025
+ );
3962
4026
  } else {
3963
- void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, false);
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
- return cached;
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 = "3.11.1";
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 = isApiError ? {
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: isApiError ? [
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(mergedConfig.apiBaseUrl, mergedConfig.debug, true);
4929
+ await performInitCheck(
4930
+ mergedConfig.apiBaseUrl,
4931
+ mergedConfig.debug,
4932
+ true,
4933
+ mergedConfig.apiKey
4934
+ );
4871
4935
  } else {
4872
- void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, false);
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
- return cached;
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,