@astrasyncai/verification-gateway 5.11.0 → 5.13.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 (98) hide show
  1. package/README.md +4 -0
  2. package/dist/adapters/express.d.mts +1 -1
  3. package/dist/adapters/express.d.ts +1 -1
  4. package/dist/adapters/express.js +394 -39
  5. package/dist/adapters/express.js.map +1 -1
  6. package/dist/adapters/express.mjs +394 -39
  7. package/dist/adapters/express.mjs.map +1 -1
  8. package/dist/adapters/mcp.d.mts +5 -1
  9. package/dist/adapters/mcp.d.ts +5 -1
  10. package/dist/adapters/mcp.js +193 -49
  11. package/dist/adapters/mcp.js.map +1 -1
  12. package/dist/adapters/mcp.mjs +193 -49
  13. package/dist/adapters/mcp.mjs.map +1 -1
  14. package/dist/adapters/nextjs.d.mts +1 -1
  15. package/dist/adapters/nextjs.d.ts +1 -1
  16. package/dist/adapters/nextjs.js +387 -22
  17. package/dist/adapters/nextjs.js.map +1 -1
  18. package/dist/adapters/nextjs.mjs +387 -22
  19. package/dist/adapters/nextjs.mjs.map +1 -1
  20. package/dist/adapters/sdk.d.mts +9 -1
  21. package/dist/adapters/sdk.d.ts +9 -1
  22. package/dist/adapters/sdk.js +125 -16
  23. package/dist/adapters/sdk.js.map +1 -1
  24. package/dist/adapters/sdk.mjs +125 -16
  25. package/dist/adapters/sdk.mjs.map +1 -1
  26. package/dist/agent/index.js +1 -1
  27. package/dist/agent/index.js.map +1 -1
  28. package/dist/agent/index.mjs +1 -1
  29. package/dist/agent/index.mjs.map +1 -1
  30. package/dist/bin/astrasync-claude-hook.js +309 -15
  31. package/dist/bin/astrasync-codex-hook.js +309 -15
  32. package/dist/bin/astrasync-guard.js +309 -15
  33. package/dist/bin/astrasync.js +322 -17
  34. package/dist/browser/background.js +309 -15
  35. package/dist/browser/background.js.map +1 -1
  36. package/dist/browser/background.mjs +309 -15
  37. package/dist/browser/background.mjs.map +1 -1
  38. package/dist/cli/index.js +1 -1
  39. package/dist/cli/index.js.map +1 -1
  40. package/dist/cli/index.mjs +1 -1
  41. package/dist/cli/index.mjs.map +1 -1
  42. package/dist/codex/index.js +309 -15
  43. package/dist/codex/index.js.map +1 -1
  44. package/dist/codex/index.mjs +309 -15
  45. package/dist/codex/index.mjs.map +1 -1
  46. package/dist/cursor/extension.js +309 -15
  47. package/dist/cursor/extension.js.map +1 -1
  48. package/dist/cursor/extension.mjs +309 -15
  49. package/dist/cursor/extension.mjs.map +1 -1
  50. package/dist/edge-config.d.mts +1 -1
  51. package/dist/edge-config.d.ts +1 -1
  52. package/dist/edge-config.js +1 -1
  53. package/dist/edge-config.js.map +1 -1
  54. package/dist/edge-config.mjs +1 -1
  55. package/dist/edge-config.mjs.map +1 -1
  56. package/dist/edge-core/index.d.mts +128 -13
  57. package/dist/edge-core/index.d.ts +128 -13
  58. package/dist/edge-core/index.js +362 -63
  59. package/dist/edge-core/index.js.map +1 -1
  60. package/dist/edge-core/index.mjs +359 -63
  61. package/dist/edge-core/index.mjs.map +1 -1
  62. package/dist/gateway/gateway.js +309 -15
  63. package/dist/gateway/gateway.js.map +1 -1
  64. package/dist/gateway/gateway.mjs +309 -15
  65. package/dist/gateway/gateway.mjs.map +1 -1
  66. package/dist/git-trigger/git-hooks.d.mts +1 -1
  67. package/dist/git-trigger/git-hooks.d.ts +1 -1
  68. package/dist/index.d.mts +118 -15
  69. package/dist/index.d.ts +118 -15
  70. package/dist/index.js +521 -72
  71. package/dist/index.js.map +1 -1
  72. package/dist/index.mjs +515 -72
  73. package/dist/index.mjs.map +1 -1
  74. package/dist/platform-signatures.js +4 -1
  75. package/dist/platform-signatures.js.map +1 -1
  76. package/dist/platform-signatures.mjs +4 -1
  77. package/dist/platform-signatures.mjs.map +1 -1
  78. package/dist/registration/index.js +1 -1
  79. package/dist/registration/index.js.map +1 -1
  80. package/dist/registration/index.mjs +1 -1
  81. package/dist/registration/index.mjs.map +1 -1
  82. package/dist/transport/index.js +1 -1
  83. package/dist/transport/index.js.map +1 -1
  84. package/dist/transport/index.mjs +1 -1
  85. package/dist/transport/index.mjs.map +1 -1
  86. package/dist/{types-CTmUpNpS.d.mts → types-BCkwBA84.d.mts} +12 -0
  87. package/dist/{types-CTmUpNpS.d.ts → types-BCkwBA84.d.ts} +12 -0
  88. package/dist/{types-CtFXmDzm.d.ts → types-C_b4QTyO.d.ts} +18 -0
  89. package/dist/{types-DQrn_kei.d.mts → types-DlshIIR-.d.mts} +18 -0
  90. package/dist/ui/index.d.mts +1 -1
  91. package/dist/ui/index.d.ts +1 -1
  92. package/dist/verify.d.mts +35 -14
  93. package/dist/verify.d.ts +35 -14
  94. package/dist/verify.js +165 -25
  95. package/dist/verify.js.map +1 -1
  96. package/dist/verify.mjs +164 -25
  97. package/dist/verify.mjs.map +1 -1
  98. package/package.json +3 -2
@@ -458,6 +458,18 @@ interface VerificationResult {
458
458
  * on misconfig (deterministic — retrying will not help) and on real denials.
459
459
  */
460
460
  retryable?: boolean;
461
+ /**
462
+ * 5.12.0: HTTP status the verify-access backend answered with on a
463
+ * non-2xx (e.g. 429, 503). Lets adapters and integrators tell a platform
464
+ * rate limit apart from an outage. Absent on network errors / timeouts.
465
+ */
466
+ httpStatus?: number;
467
+ /**
468
+ * 5.12.0: the backend's `Retry-After`, in milliseconds, when it sent one
469
+ * (429 / 503). Adapters relay it on their own 503 so callers back off for
470
+ * as long as the platform asked.
471
+ */
472
+ retryAfterMs?: number;
461
473
  /** Whether step-up authentication is required */
462
474
  requiresStepUp?: boolean;
463
475
  /** Whether approval is required */
@@ -458,6 +458,18 @@ interface VerificationResult {
458
458
  * on misconfig (deterministic — retrying will not help) and on real denials.
459
459
  */
460
460
  retryable?: boolean;
461
+ /**
462
+ * 5.12.0: HTTP status the verify-access backend answered with on a
463
+ * non-2xx (e.g. 429, 503). Lets adapters and integrators tell a platform
464
+ * rate limit apart from an outage. Absent on network errors / timeouts.
465
+ */
466
+ httpStatus?: number;
467
+ /**
468
+ * 5.12.0: the backend's `Retry-After`, in milliseconds, when it sent one
469
+ * (429 / 503). Adapters relay it on their own 503 so callers back off for
470
+ * as long as the platform asked.
471
+ */
472
+ retryAfterMs?: number;
461
473
  /** Whether step-up authentication is required */
462
474
  requiresStepUp?: boolean;
463
475
  /** Whether approval is required */
@@ -400,6 +400,18 @@ interface VerificationResult {
400
400
  * on misconfig (deterministic — retrying will not help) and on real denials.
401
401
  */
402
402
  retryable?: boolean;
403
+ /**
404
+ * 5.12.0: HTTP status the verify-access backend answered with on a
405
+ * non-2xx (e.g. 429, 503). Lets adapters and integrators tell a platform
406
+ * rate limit apart from an outage. Absent on network errors / timeouts.
407
+ */
408
+ httpStatus?: number;
409
+ /**
410
+ * 5.12.0: the backend's `Retry-After`, in milliseconds, when it sent one
411
+ * (429 / 503). Adapters relay it on their own 503 so callers back off for
412
+ * as long as the platform asked.
413
+ */
414
+ retryAfterMs?: number;
403
415
  /** Whether step-up authentication is required */
404
416
  requiresStepUp?: boolean;
405
417
  /** Whether approval is required */
@@ -764,6 +776,12 @@ interface AttemptReport {
764
776
  agentId?: string;
765
777
  considerationSet?: ConsiderationSet;
766
778
  outcome?: AttemptOutcome;
779
+ /**
780
+ * Where a catalog view was answered from: `bridge_cache` (the AstraSync
781
+ * bridge's anonymous cache — no load on the merchant's site) or `merchant`
782
+ * (fetched fresh). Attribution only.
783
+ */
784
+ servedFrom?: 'bridge_cache' | 'merchant';
767
785
  }
768
786
  /**
769
787
  * Raw commerce-protocol artifacts as verify-access accepts them (backend
@@ -400,6 +400,18 @@ interface VerificationResult {
400
400
  * on misconfig (deterministic — retrying will not help) and on real denials.
401
401
  */
402
402
  retryable?: boolean;
403
+ /**
404
+ * 5.12.0: HTTP status the verify-access backend answered with on a
405
+ * non-2xx (e.g. 429, 503). Lets adapters and integrators tell a platform
406
+ * rate limit apart from an outage. Absent on network errors / timeouts.
407
+ */
408
+ httpStatus?: number;
409
+ /**
410
+ * 5.12.0: the backend's `Retry-After`, in milliseconds, when it sent one
411
+ * (429 / 503). Adapters relay it on their own 503 so callers back off for
412
+ * as long as the platform asked.
413
+ */
414
+ retryAfterMs?: number;
403
415
  /** Whether step-up authentication is required */
404
416
  requiresStepUp?: boolean;
405
417
  /** Whether approval is required */
@@ -764,6 +776,12 @@ interface AttemptReport {
764
776
  agentId?: string;
765
777
  considerationSet?: ConsiderationSet;
766
778
  outcome?: AttemptOutcome;
779
+ /**
780
+ * Where a catalog view was answered from: `bridge_cache` (the AstraSync
781
+ * bridge's anonymous cache — no load on the merchant's site) or `merchant`
782
+ * (fetched fresh). Attribution only.
783
+ */
784
+ servedFrom?: 'bridge_cache' | 'merchant';
767
785
  }
768
786
  /**
769
787
  * Raw commerce-protocol artifacts as verify-access accepts them (backend
@@ -1,4 +1,4 @@
1
- import { V as VerificationInterstitialProps, d as VerificationResult, A as AgentCredentials, b as GuidanceInfo, T as TrustLevel } from '../types-CTmUpNpS.mjs';
1
+ import { V as VerificationInterstitialProps, d as VerificationResult, A as AgentCredentials, b as GuidanceInfo, T as TrustLevel } from '../types-BCkwBA84.mjs';
2
2
 
3
3
  /**
4
4
  * AstraSync Verification Interstitial Component
@@ -1,4 +1,4 @@
1
- import { V as VerificationInterstitialProps, d as VerificationResult, A as AgentCredentials, b as GuidanceInfo, T as TrustLevel } from '../types-CTmUpNpS.js';
1
+ import { V as VerificationInterstitialProps, d as VerificationResult, A as AgentCredentials, b as GuidanceInfo, T as TrustLevel } from '../types-BCkwBA84.js';
2
2
 
3
3
  /**
4
4
  * AstraSync Verification Interstitial Component
package/dist/verify.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AgentCredentials, G as GatewayConfig, a as AttemptReport, V as VerificationRequest, c as VerificationResult } from './types-DQrn_kei.mjs';
1
+ import { A as AgentCredentials, G as GatewayConfig, a as AttemptReport, V as VerificationRequest, c as VerificationResult } from './types-DlshIIR-.mjs';
2
2
  import { ObservedMetadata } from './metadata-capture.mjs';
3
3
 
4
4
  /**
@@ -22,6 +22,15 @@ declare function extractCredentials(headers: Record<string, string | string[] |
22
22
  * Check if credentials are present
23
23
  */
24
24
  declare function hasCredentials(credentials: AgentCredentials): boolean;
25
+ /**
26
+ * 5.12.0: `Retry-After` (delta-seconds or HTTP-date) → milliseconds, or
27
+ * undefined when absent/unparseable. Clamped to [0, 15 min].
28
+ */
29
+ declare function parseRetryAfterMs(response: {
30
+ headers?: {
31
+ get?(name: string): string | null;
32
+ };
33
+ }): number | undefined;
25
34
  /**
26
35
  * Options for a single verify() call (as opposed to GatewayConfig, which is
27
36
  * per-gateway). Mirrors the Java SDK's `verify(request, bypassCache)`.
@@ -52,19 +61,24 @@ declare function recordDecision(config: GatewayConfig, sessionId: string, decisi
52
61
  * Authenticated with the same credentials as verify(); the backend responds
53
62
  * 202 and folds the data into the attempt chain keyed by `attemptId`.
54
63
  *
55
- * Fire-and-forget — errors are silently swallowed, never throws.
56
- */
57
- declare function reportAttempt(config: GatewayConfig, report: AttemptReport): Promise<void>;
58
- /**
59
- * Fetch the per-route policy for an endpoint from the AstraSync backend.
60
- * v2.9.7 moved policy authority into the dashboard — the SDK no longer
61
- * accepts `routes` from merchant-side source code, it fetches them from
62
- * here on init (and refreshes periodically).
63
- *
64
- * Returns `null` when the request fails for any reason — the caller decides
65
- * how to fall back (the middleware allows-all when no policy is loaded so
66
- * a misconfigured init doesn't take down the merchant's API).
64
+ * Fire-and-forget — never throws. 5.12.0: a 429/5xx is retried once
65
+ * (Retry-After honoured, capped at 2s) off the caller's path; a lost report
66
+ * is surfaced via `options.onFailure`.
67
67
  */
68
+ declare function reportAttempt(config: GatewayConfig, report: AttemptReport, options?: ReportAttemptOptions): Promise<void>;
69
+ /** 5.12.0: options for {@link reportAttempt}. */
70
+ interface ReportAttemptOptions {
71
+ /**
72
+ * Called once when the report is finally lost (non-retryable status,
73
+ * network error, or the single retry failed). For counters/telemetry;
74
+ * exceptions it throws are swallowed.
75
+ */
76
+ onFailure?: (failure: {
77
+ status?: number;
78
+ error?: string;
79
+ retried: boolean;
80
+ }) => void;
81
+ }
68
82
  declare function fetchRoutes(config: GatewayConfig, counterpartyId: string): Promise<RouteAccessConfigShape[] | null>;
69
83
  /**
70
84
  * Minimal shape of an EndpointRoute as the SDK consumes it. Mirrors the
@@ -171,6 +185,13 @@ declare function quickVerify(config: GatewayConfig, credentials: AgentCredential
171
185
  identityVerified: boolean;
172
186
  policyAllowed: boolean;
173
187
  reason?: string;
188
+ /**
189
+ * 5.12.0: verification infrastructure was unavailable (timeout / 5xx /
190
+ * the platform's 429) — NOT a denial. Callers should fail open on reads
191
+ * or answer 503 + Retry-After (`retryAfterMs`, else 30s), never 401.
192
+ */
193
+ unavailable?: true;
194
+ retryAfterMs?: number;
174
195
  }>;
175
196
 
176
- export { type RouteAccessConfigShape, type VerifyOptions, _resetInitCheck, clearCache, extractCredentials, fetchRoutes, hasCredentials, quickVerify, recordDecision, reportAttempt, reportCounterpartyPreCheckFailure, reportUnregisteredAttempt, verify, verifyAndRecord };
197
+ export { type ReportAttemptOptions, type RouteAccessConfigShape, type VerifyOptions, _resetInitCheck, clearCache, extractCredentials, fetchRoutes, hasCredentials, parseRetryAfterMs, quickVerify, recordDecision, reportAttempt, reportCounterpartyPreCheckFailure, reportUnregisteredAttempt, verify, verifyAndRecord };
package/dist/verify.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AgentCredentials, G as GatewayConfig, a as AttemptReport, V as VerificationRequest, c as VerificationResult } from './types-CtFXmDzm.js';
1
+ import { A as AgentCredentials, G as GatewayConfig, a as AttemptReport, V as VerificationRequest, c as VerificationResult } from './types-C_b4QTyO.js';
2
2
  import { ObservedMetadata } from './metadata-capture.js';
3
3
 
4
4
  /**
@@ -22,6 +22,15 @@ declare function extractCredentials(headers: Record<string, string | string[] |
22
22
  * Check if credentials are present
23
23
  */
24
24
  declare function hasCredentials(credentials: AgentCredentials): boolean;
25
+ /**
26
+ * 5.12.0: `Retry-After` (delta-seconds or HTTP-date) → milliseconds, or
27
+ * undefined when absent/unparseable. Clamped to [0, 15 min].
28
+ */
29
+ declare function parseRetryAfterMs(response: {
30
+ headers?: {
31
+ get?(name: string): string | null;
32
+ };
33
+ }): number | undefined;
25
34
  /**
26
35
  * Options for a single verify() call (as opposed to GatewayConfig, which is
27
36
  * per-gateway). Mirrors the Java SDK's `verify(request, bypassCache)`.
@@ -52,19 +61,24 @@ declare function recordDecision(config: GatewayConfig, sessionId: string, decisi
52
61
  * Authenticated with the same credentials as verify(); the backend responds
53
62
  * 202 and folds the data into the attempt chain keyed by `attemptId`.
54
63
  *
55
- * Fire-and-forget — errors are silently swallowed, never throws.
56
- */
57
- declare function reportAttempt(config: GatewayConfig, report: AttemptReport): Promise<void>;
58
- /**
59
- * Fetch the per-route policy for an endpoint from the AstraSync backend.
60
- * v2.9.7 moved policy authority into the dashboard — the SDK no longer
61
- * accepts `routes` from merchant-side source code, it fetches them from
62
- * here on init (and refreshes periodically).
63
- *
64
- * Returns `null` when the request fails for any reason — the caller decides
65
- * how to fall back (the middleware allows-all when no policy is loaded so
66
- * a misconfigured init doesn't take down the merchant's API).
64
+ * Fire-and-forget — never throws. 5.12.0: a 429/5xx is retried once
65
+ * (Retry-After honoured, capped at 2s) off the caller's path; a lost report
66
+ * is surfaced via `options.onFailure`.
67
67
  */
68
+ declare function reportAttempt(config: GatewayConfig, report: AttemptReport, options?: ReportAttemptOptions): Promise<void>;
69
+ /** 5.12.0: options for {@link reportAttempt}. */
70
+ interface ReportAttemptOptions {
71
+ /**
72
+ * Called once when the report is finally lost (non-retryable status,
73
+ * network error, or the single retry failed). For counters/telemetry;
74
+ * exceptions it throws are swallowed.
75
+ */
76
+ onFailure?: (failure: {
77
+ status?: number;
78
+ error?: string;
79
+ retried: boolean;
80
+ }) => void;
81
+ }
68
82
  declare function fetchRoutes(config: GatewayConfig, counterpartyId: string): Promise<RouteAccessConfigShape[] | null>;
69
83
  /**
70
84
  * Minimal shape of an EndpointRoute as the SDK consumes it. Mirrors the
@@ -171,6 +185,13 @@ declare function quickVerify(config: GatewayConfig, credentials: AgentCredential
171
185
  identityVerified: boolean;
172
186
  policyAllowed: boolean;
173
187
  reason?: string;
188
+ /**
189
+ * 5.12.0: verification infrastructure was unavailable (timeout / 5xx /
190
+ * the platform's 429) — NOT a denial. Callers should fail open on reads
191
+ * or answer 503 + Retry-After (`retryAfterMs`, else 30s), never 401.
192
+ */
193
+ unavailable?: true;
194
+ retryAfterMs?: number;
174
195
  }>;
175
196
 
176
- export { type RouteAccessConfigShape, type VerifyOptions, _resetInitCheck, clearCache, extractCredentials, fetchRoutes, hasCredentials, quickVerify, recordDecision, reportAttempt, reportCounterpartyPreCheckFailure, reportUnregisteredAttempt, verify, verifyAndRecord };
197
+ export { type ReportAttemptOptions, type RouteAccessConfigShape, type VerifyOptions, _resetInitCheck, clearCache, extractCredentials, fetchRoutes, hasCredentials, parseRetryAfterMs, quickVerify, recordDecision, reportAttempt, reportCounterpartyPreCheckFailure, reportUnregisteredAttempt, verify, verifyAndRecord };
package/dist/verify.js CHANGED
@@ -25,6 +25,7 @@ __export(verify_exports, {
25
25
  extractCredentials: () => extractCredentials,
26
26
  fetchRoutes: () => fetchRoutes,
27
27
  hasCredentials: () => hasCredentials,
28
+ parseRetryAfterMs: () => parseRetryAfterMs,
28
29
  quickVerify: () => quickVerify,
29
30
  recordDecision: () => recordDecision,
30
31
  reportAttempt: () => reportAttempt,
@@ -36,7 +37,7 @@ __export(verify_exports, {
36
37
  module.exports = __toCommonJS(verify_exports);
37
38
 
38
39
  // src/version.ts
39
- var SDK_VERSION = "5.11.0";
40
+ var SDK_VERSION = "5.13.0";
40
41
 
41
42
  // src/http.ts
42
43
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -71,6 +72,29 @@ function getCachedWellKnownUrls(apiBaseUrl) {
71
72
  return cache.get(apiBaseUrl)?.data;
72
73
  }
73
74
 
75
+ // src/failure-posture.ts
76
+ var DEFAULT_UNAVAILABLE_RETRY_AFTER_S = 30;
77
+ var REJECTED_IDENTITY_DIMENSIONS = /* @__PURE__ */ new Set([
78
+ "identity.invalid_agent_id",
79
+ "identity.unknown_agent",
80
+ "agent.lookup"
81
+ ]);
82
+ var UNKNOWN_AGENT_GUIDANCE = "Register your agent with AstraSync (or, inside an MCP host, add the AstraSync MCP connector for keyless, human-approved registration), then present the canonical ASTRA-* id issued after owner approval.";
83
+ var UNAVAILABLE_DIMENSIONS = /* @__PURE__ */ new Set([
84
+ "verify_access.api_error",
85
+ "middleware.internal_error"
86
+ ]);
87
+ function isVerificationUnavailable(result) {
88
+ if (result.misconfigured) return false;
89
+ return (result.failures ?? []).some((f) => UNAVAILABLE_DIMENSIONS.has(f.dimension));
90
+ }
91
+ function unavailableRetryAfterSeconds(result) {
92
+ if (typeof result.retryAfterMs === "number" && Number.isFinite(result.retryAfterMs)) {
93
+ return Math.max(1, Math.ceil(result.retryAfterMs / 1e3));
94
+ }
95
+ return DEFAULT_UNAVAILABLE_RETRY_AFTER_S;
96
+ }
97
+
74
98
  // src/verify.ts
75
99
  var DEFAULT_CONFIG = {
76
100
  apiBaseUrl: "https://astrasync.ai/api",
@@ -86,7 +110,7 @@ function _resetInitCheck() {
86
110
  initCheckPerformed = false;
87
111
  }
88
112
  var deprecationWarningShown = false;
89
- async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
113
+ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey, counterparty) {
90
114
  initCheckPerformed = true;
91
115
  try {
92
116
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
@@ -104,7 +128,8 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
104
128
  );
105
129
  }
106
130
  if (apiKey) {
107
- const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
131
+ const q = counterparty?.id ? `?counterpartyId=${encodeURIComponent(counterparty.id)}` : counterparty?.url ? `?counterpartyUrl=${encodeURIComponent(counterparty.url)}` : "";
132
+ const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check${q}`, {
108
133
  headers: { Authorization: `Bearer ${apiKey}` }
109
134
  });
110
135
  if (selfCheck.status === 401) {
@@ -116,6 +141,13 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
116
141
  console.error(message);
117
142
  } else if (selfCheck.ok) {
118
143
  const body = await selfCheck.json().catch(() => ({}));
144
+ if (body.counterparty && body.counterparty.canVerify === false) {
145
+ const message = `[VerificationGateway] the configured AstraSync API key cannot verify for this endpoint (${body.counterparty.message ?? "endpoint not found or owned by another account"}). Every inbound agent will be turned away until the key or counterparty is corrected.`;
146
+ if (strictInit) {
147
+ throw new Error(`${message} (strictInit=true)`);
148
+ }
149
+ console.error(message);
150
+ }
119
151
  if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
120
152
  console.warn(
121
153
  `[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
@@ -260,11 +292,11 @@ function createGuidanceResponse(_config, reason, options = {}) {
260
292
  const isMisconfig = source === "merchant_misconfig";
261
293
  const urls = options.urls;
262
294
  const guidance = isMisconfig ? {
263
- 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.",
295
+ message: "This site's AstraSync integration is misconfigured (its API key was revoked, expired, rotated, or belongs to another account). Your identity and the AstraSync platform are fine \u2014 contact the site operator. Retrying will not help.",
264
296
  registrationUrl: urls?.registrationUrl ?? "",
265
297
  documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
266
298
  steps: [
267
- "Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
299
+ "Report the failure to the site operator \u2014 their AstraSync API key needs replacing",
268
300
  "Do not retry: the failure is deterministic until the operator updates their key"
269
301
  ]
270
302
  } : isApiError ? {
@@ -325,11 +357,44 @@ function createGuidanceResponse(_config, reason, options = {}) {
325
357
  // coercing the absent recommendation to a policy 'deny'. Misconfig is
326
358
  // deterministic and intentionally NOT marked retryable.
327
359
  ...isApiError && { retryable: true },
360
+ ...options.httpStatus !== void 0 && { httpStatus: options.httpStatus },
361
+ ...options.retryAfterMs !== void 0 && { retryAfterMs: options.retryAfterMs },
328
362
  correlationId: options.correlationId,
329
363
  attemptId: options.attemptId,
330
364
  verifiedAt: /* @__PURE__ */ new Date()
331
365
  };
332
366
  }
367
+ async function readJsonSafe(response) {
368
+ try {
369
+ const parsed = await response.json();
370
+ return parsed && typeof parsed === "object" ? parsed : {};
371
+ } catch {
372
+ return {};
373
+ }
374
+ }
375
+ function rejectedIdentityGuidance(failures) {
376
+ const f = failures?.find((x) => REJECTED_IDENTITY_DIMENSIONS.has(x.dimension));
377
+ if (!f) return void 0;
378
+ if (f.dimension === "agent.lookup") {
379
+ return `The presented agent identifier is not registered with AstraSync. ${UNKNOWN_AGENT_GUIDANCE}`;
380
+ }
381
+ return f.guidance ? `${f.message} ${f.guidance}` : f.message;
382
+ }
383
+ var MAX_RETRY_AFTER_MS = 15 * 60 * 1e3;
384
+ function parseRetryAfterMs(response) {
385
+ const raw = response.headers?.get?.("retry-after");
386
+ if (!raw) return void 0;
387
+ const trimmed = raw.trim();
388
+ let ms;
389
+ if (/^\d+(\.\d+)?$/.test(trimmed)) {
390
+ ms = Number(trimmed) * 1e3;
391
+ } else {
392
+ const at = Date.parse(trimmed);
393
+ if (Number.isNaN(at)) return void 0;
394
+ ms = at - Date.now();
395
+ }
396
+ return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, Math.round(ms)));
397
+ }
333
398
  async function callVerifyAccessAPI(config, request) {
334
399
  const { credentials, ...requestData } = request;
335
400
  const body = {
@@ -386,7 +451,8 @@ async function callVerifyAccessAPI(config, request) {
386
451
  body: JSON.stringify(body),
387
452
  signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
388
453
  });
389
- const data = await response.json();
454
+ const data = await readJsonSafe(response);
455
+ const retryAfterMs = parseRetryAfterMs(response);
390
456
  if (response.status === 410) {
391
457
  return {
392
458
  success: true,
@@ -424,13 +490,31 @@ async function callVerifyAccessAPI(config, request) {
424
490
  }
425
491
  };
426
492
  }
493
+ if (response.status === 404 && credentials.astraId && (data?.error === "AGENT_NOT_FOUND" || typeof data?.message === "string" && /agent/i.test(data.message))) {
494
+ return {
495
+ success: true,
496
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
497
+ access: {
498
+ allowed: false,
499
+ reason: "unknown_agent",
500
+ failures: [
501
+ {
502
+ dimension: "identity.unknown_agent",
503
+ message: "The presented agent identifier is not registered with AstraSync.",
504
+ guidance: UNKNOWN_AGENT_GUIDANCE
505
+ }
506
+ ]
507
+ }
508
+ };
509
+ }
427
510
  if (!response.ok) {
428
- if (response.status === 401) {
511
+ const keyMismatch = response.status === 403 && data?.error === "COUNTERPARTY_KEY_MISMATCH";
512
+ if (response.status === 401 || keyMismatch) {
429
513
  return {
430
514
  success: false,
431
515
  error: data.message || data.error || "Integration API key rejected",
432
516
  misconfig: true,
433
- misconfigCode: typeof data?.code === "string" ? data.code : void 0,
517
+ misconfigCode: keyMismatch ? "counterparty_key_mismatch" : typeof data?.code === "string" ? data.code : void 0,
434
518
  remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
435
519
  correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
436
520
  attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
@@ -438,9 +522,11 @@ async function callVerifyAccessAPI(config, request) {
438
522
  }
439
523
  return {
440
524
  success: false,
441
- error: data.message || data.error || `API returned ${response.status}`,
525
+ error: typeof data?.message === "string" && data.message || typeof data?.error === "string" && data.error || `API returned ${response.status}`,
442
526
  correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
443
- attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
527
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
528
+ httpStatus: response.status,
529
+ ...retryAfterMs !== void 0 && { retryAfterMs }
444
530
  };
445
531
  }
446
532
  return data;
@@ -461,14 +547,22 @@ async function verify(config, request, options) {
461
547
  mergedConfig.apiBaseUrl,
462
548
  mergedConfig.debug,
463
549
  true,
464
- mergedConfig.apiKey
550
+ mergedConfig.apiKey,
551
+ {
552
+ id: mergedConfig.counterpartyId,
553
+ url: mergedConfig.counterpartyUrl ?? request.counterpartyUrl
554
+ }
465
555
  );
466
556
  } else {
467
557
  void performInitCheck(
468
558
  mergedConfig.apiBaseUrl,
469
559
  mergedConfig.debug,
470
560
  false,
471
- mergedConfig.apiKey
561
+ mergedConfig.apiKey,
562
+ {
563
+ id: mergedConfig.counterpartyId,
564
+ url: mergedConfig.counterpartyUrl ?? request.counterpartyUrl
565
+ }
472
566
  );
473
567
  }
474
568
  }
@@ -512,12 +606,14 @@ async function verify(config, request, options) {
512
606
  correlationId: apiResponse.correlationId,
513
607
  attemptId: apiResponse.attemptId,
514
608
  remediation: apiResponse.remediation,
609
+ httpStatus: apiResponse.httpStatus,
610
+ retryAfterMs: apiResponse.retryAfterMs,
515
611
  urls
516
612
  });
517
613
  }
518
614
  if (!apiResponse.access?.allowed) {
519
615
  const aggregatedFailures = apiResponse.access?.failures;
520
- const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true;
616
+ const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
521
617
  const result2 = {
522
618
  identityVerified: idVerifiedFromBackend,
523
619
  policyAllowed: false,
@@ -529,7 +625,10 @@ async function verify(config, request, options) {
529
625
  requiresStepUp: apiResponse.access?.requiresStepUp,
530
626
  requiresApproval: apiResponse.access?.requiresApproval,
531
627
  guidance: {
532
- message: apiResponse.access?.reason || "Access denied by PDLSS policy",
628
+ // 5.12.0: a presented-but-rejected id (malformed / unknown) carries
629
+ // actionable registration guidance on its failure — surface it
630
+ // instead of the bare machine reason ('unknown_agent').
631
+ message: rejectedIdentityGuidance(aggregatedFailures) ?? (apiResponse.access?.reason || "Access denied by PDLSS policy"),
533
632
  registrationUrl: urls?.registrationUrl ?? "",
534
633
  documentationUrl: urls?.documentationUrl ?? "",
535
634
  // 5.1.0: anonymous callers land on this branch — steer MCP-hosted
@@ -629,7 +728,7 @@ async function verify(config, request, options) {
629
728
  registrationUrl: urls?.registrationUrl ?? "",
630
729
  documentationUrl: urls?.documentationUrl ?? ""
631
730
  };
632
- } else if (result.recommendation === "step_up_required") {
731
+ } else if (result.recommendation === "step_up_required" && result.identityVerified) {
633
732
  result.requiresStepUp = true;
634
733
  result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Step-up verification required"];
635
734
  }
@@ -652,7 +751,7 @@ async function recordDecision(config, sessionId, decision, reason) {
652
751
  }).catch(() => {
653
752
  });
654
753
  }
655
- async function reportAttempt(config, report) {
754
+ async function reportAttempt(config, report, options = {}) {
656
755
  const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
657
756
  const headers = { "Content-Type": "application/json" };
658
757
  if (config.apiKey) {
@@ -663,13 +762,38 @@ async function reportAttempt(config, report) {
663
762
  ...report,
664
763
  ...!report.counterpartyId && config.counterpartyId && { counterpartyId: config.counterpartyId }
665
764
  };
666
- await sdkFetch(`${apiBaseUrl}/agents/verify-access/attempt-report`, {
667
- method: "POST",
668
- headers,
669
- body: JSON.stringify(body)
670
- }).catch(() => {
671
- });
765
+ const url = `${apiBaseUrl}/agents/verify-access/attempt-report`;
766
+ const init = { method: "POST", headers, body: JSON.stringify(body) };
767
+ const fail = (failure) => {
768
+ try {
769
+ options.onFailure?.(failure);
770
+ } catch {
771
+ }
772
+ };
773
+ let response;
774
+ try {
775
+ response = await sdkFetch(url, init);
776
+ } catch (err) {
777
+ fail({ error: err instanceof Error ? err.message : String(err), retried: false });
778
+ return;
779
+ }
780
+ if (response.ok) return;
781
+ if (response.status !== 429 && response.status < 500) {
782
+ fail({ status: response.status, retried: false });
783
+ return;
784
+ }
785
+ const delayMs = Math.min(ATTEMPT_REPORT_MAX_RETRY_DELAY_MS, parseRetryAfterMs(response) ?? 500);
786
+ const timer = setTimeout(() => {
787
+ sdkFetch(url, init).then((retry) => {
788
+ if (!retry.ok) fail({ status: retry.status, retried: true });
789
+ }).catch((err) => {
790
+ fail({ error: err instanceof Error ? err.message : String(err), retried: true });
791
+ });
792
+ }, delayMs);
793
+ timer.unref?.();
672
794
  }
795
+ var ATTEMPT_REPORT_MAX_RETRY_DELAY_MS = 2e3;
796
+ var refusedPolicyReads = /* @__PURE__ */ new Set();
673
797
  async function fetchRoutes(config, counterpartyId) {
674
798
  if (!counterpartyId) return null;
675
799
  const headers = { "Content-Type": "application/json" };
@@ -682,7 +806,15 @@ async function fetchRoutes(config, counterpartyId) {
682
806
  `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,
683
807
  { method: "GET", headers }
684
808
  );
685
- if (!response.ok) return null;
809
+ if (!response.ok) {
810
+ if ((response.status === 401 || response.status === 403 || response.status === 404) && !refusedPolicyReads.has(counterpartyId)) {
811
+ refusedPolicyReads.add(counterpartyId);
812
+ console.error(
813
+ `[VerificationGateway] the configured API key cannot read the route policy for ${counterpartyId} (HTTP ${response.status}). The key belongs to an account that does not own this endpoint, or the counterpartyId is wrong. The gateway is in PASS-THROUGH mode: no agent is being verified.`
814
+ );
815
+ }
816
+ return null;
817
+ }
686
818
  const body = await response.json();
687
819
  return body.data?.routes ?? [];
688
820
  } catch {
@@ -714,7 +846,10 @@ async function reportUnregisteredAttempt(config, data) {
714
846
  };
715
847
  await sdkFetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
716
848
  method: "POST",
717
- headers: { "Content-Type": "application/json" },
849
+ headers: {
850
+ "Content-Type": "application/json",
851
+ ...config.apiKey && { Authorization: `Bearer ${config.apiKey}` }
852
+ },
718
853
  body: JSON.stringify(body)
719
854
  }).catch(() => {
720
855
  });
@@ -736,7 +871,11 @@ async function quickVerify(config, credentials) {
736
871
  return {
737
872
  identityVerified: result.identityVerified,
738
873
  policyAllowed: result.policyAllowed,
739
- reason: result.denialReasons?.[0]
874
+ reason: result.denialReasons?.[0],
875
+ ...isVerificationUnavailable(result) && {
876
+ unavailable: true,
877
+ retryAfterMs: unavailableRetryAfterSeconds(result) * 1e3
878
+ }
740
879
  };
741
880
  }
742
881
  // Annotate the CommonJS export names for ESM import in node:
@@ -746,6 +885,7 @@ async function quickVerify(config, credentials) {
746
885
  extractCredentials,
747
886
  fetchRoutes,
748
887
  hasCredentials,
888
+ parseRetryAfterMs,
749
889
  quickVerify,
750
890
  recordDecision,
751
891
  reportAttempt,