@astrasyncai/verification-gateway 5.11.0 → 5.12.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 +359 -30
  5. package/dist/adapters/express.js.map +1 -1
  6. package/dist/adapters/express.mjs +359 -30
  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 +168 -41
  11. package/dist/adapters/mcp.js.map +1 -1
  12. package/dist/adapters/mcp.mjs +168 -41
  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 +352 -13
  17. package/dist/adapters/nextjs.js.map +1 -1
  18. package/dist/adapters/nextjs.mjs +352 -13
  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 +100 -8
  23. package/dist/adapters/sdk.js.map +1 -1
  24. package/dist/adapters/sdk.mjs +100 -8
  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 +284 -7
  31. package/dist/bin/astrasync-codex-hook.js +284 -7
  32. package/dist/bin/astrasync-guard.js +284 -7
  33. package/dist/bin/astrasync.js +297 -9
  34. package/dist/browser/background.js +284 -7
  35. package/dist/browser/background.js.map +1 -1
  36. package/dist/browser/background.mjs +284 -7
  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 +284 -7
  43. package/dist/codex/index.js.map +1 -1
  44. package/dist/codex/index.mjs +284 -7
  45. package/dist/codex/index.mjs.map +1 -1
  46. package/dist/cursor/extension.js +284 -7
  47. package/dist/cursor/extension.js.map +1 -1
  48. package/dist/cursor/extension.mjs +284 -7
  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 +337 -55
  59. package/dist/edge-core/index.js.map +1 -1
  60. package/dist/edge-core/index.mjs +334 -55
  61. package/dist/edge-core/index.mjs.map +1 -1
  62. package/dist/gateway/gateway.js +284 -7
  63. package/dist/gateway/gateway.js.map +1 -1
  64. package/dist/gateway/gateway.mjs +284 -7
  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 -5
  69. package/dist/index.d.ts +118 -5
  70. package/dist/index.js +486 -63
  71. package/dist/index.js.map +1 -1
  72. package/dist/index.mjs +480 -63
  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 -4
  93. package/dist/verify.d.ts +35 -4
  94. package/dist/verify.js +130 -16
  95. package/dist/verify.js.map +1 -1
  96. package/dist/verify.mjs +129 -16
  97. package/dist/verify.mjs.map +1 -1
  98. package/package.json +1 -1
@@ -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,9 +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.
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`.
56
67
  */
57
- declare function reportAttempt(config: GatewayConfig, report: AttemptReport): Promise<void>;
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
+ }
58
82
  /**
59
83
  * Fetch the per-route policy for an endpoint from the AstraSync backend.
60
84
  * v2.9.7 moved policy authority into the dashboard — the SDK no longer
@@ -171,6 +195,13 @@ declare function quickVerify(config: GatewayConfig, credentials: AgentCredential
171
195
  identityVerified: boolean;
172
196
  policyAllowed: boolean;
173
197
  reason?: string;
198
+ /**
199
+ * 5.12.0: verification infrastructure was unavailable (timeout / 5xx /
200
+ * the platform's 429) — NOT a denial. Callers should fail open on reads
201
+ * or answer 503 + Retry-After (`retryAfterMs`, else 30s), never 401.
202
+ */
203
+ unavailable?: true;
204
+ retryAfterMs?: number;
174
205
  }>;
175
206
 
176
- export { type RouteAccessConfigShape, type VerifyOptions, _resetInitCheck, clearCache, extractCredentials, fetchRoutes, hasCredentials, quickVerify, recordDecision, reportAttempt, reportCounterpartyPreCheckFailure, reportUnregisteredAttempt, verify, verifyAndRecord };
207
+ 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,9 +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.
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`.
56
67
  */
57
- declare function reportAttempt(config: GatewayConfig, report: AttemptReport): Promise<void>;
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
+ }
58
82
  /**
59
83
  * Fetch the per-route policy for an endpoint from the AstraSync backend.
60
84
  * v2.9.7 moved policy authority into the dashboard — the SDK no longer
@@ -171,6 +195,13 @@ declare function quickVerify(config: GatewayConfig, credentials: AgentCredential
171
195
  identityVerified: boolean;
172
196
  policyAllowed: boolean;
173
197
  reason?: string;
198
+ /**
199
+ * 5.12.0: verification infrastructure was unavailable (timeout / 5xx /
200
+ * the platform's 429) — NOT a denial. Callers should fail open on reads
201
+ * or answer 503 + Retry-After (`retryAfterMs`, else 30s), never 401.
202
+ */
203
+ unavailable?: true;
204
+ retryAfterMs?: number;
174
205
  }>;
175
206
 
176
- export { type RouteAccessConfigShape, type VerifyOptions, _resetInitCheck, clearCache, extractCredentials, fetchRoutes, hasCredentials, quickVerify, recordDecision, reportAttempt, reportCounterpartyPreCheckFailure, reportUnregisteredAttempt, verify, verifyAndRecord };
207
+ 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.12.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",
@@ -325,11 +349,44 @@ function createGuidanceResponse(_config, reason, options = {}) {
325
349
  // coercing the absent recommendation to a policy 'deny'. Misconfig is
326
350
  // deterministic and intentionally NOT marked retryable.
327
351
  ...isApiError && { retryable: true },
352
+ ...options.httpStatus !== void 0 && { httpStatus: options.httpStatus },
353
+ ...options.retryAfterMs !== void 0 && { retryAfterMs: options.retryAfterMs },
328
354
  correlationId: options.correlationId,
329
355
  attemptId: options.attemptId,
330
356
  verifiedAt: /* @__PURE__ */ new Date()
331
357
  };
332
358
  }
359
+ async function readJsonSafe(response) {
360
+ try {
361
+ const parsed = await response.json();
362
+ return parsed && typeof parsed === "object" ? parsed : {};
363
+ } catch {
364
+ return {};
365
+ }
366
+ }
367
+ function rejectedIdentityGuidance(failures) {
368
+ const f = failures?.find((x) => REJECTED_IDENTITY_DIMENSIONS.has(x.dimension));
369
+ if (!f) return void 0;
370
+ if (f.dimension === "agent.lookup") {
371
+ return `The presented agent identifier is not registered with AstraSync. ${UNKNOWN_AGENT_GUIDANCE}`;
372
+ }
373
+ return f.guidance ? `${f.message} ${f.guidance}` : f.message;
374
+ }
375
+ var MAX_RETRY_AFTER_MS = 15 * 60 * 1e3;
376
+ function parseRetryAfterMs(response) {
377
+ const raw = response.headers?.get?.("retry-after");
378
+ if (!raw) return void 0;
379
+ const trimmed = raw.trim();
380
+ let ms;
381
+ if (/^\d+(\.\d+)?$/.test(trimmed)) {
382
+ ms = Number(trimmed) * 1e3;
383
+ } else {
384
+ const at = Date.parse(trimmed);
385
+ if (Number.isNaN(at)) return void 0;
386
+ ms = at - Date.now();
387
+ }
388
+ return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, Math.round(ms)));
389
+ }
333
390
  async function callVerifyAccessAPI(config, request) {
334
391
  const { credentials, ...requestData } = request;
335
392
  const body = {
@@ -386,7 +443,8 @@ async function callVerifyAccessAPI(config, request) {
386
443
  body: JSON.stringify(body),
387
444
  signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
388
445
  });
389
- const data = await response.json();
446
+ const data = await readJsonSafe(response);
447
+ const retryAfterMs = parseRetryAfterMs(response);
390
448
  if (response.status === 410) {
391
449
  return {
392
450
  success: true,
@@ -424,6 +482,23 @@ async function callVerifyAccessAPI(config, request) {
424
482
  }
425
483
  };
426
484
  }
485
+ if (response.status === 404 && credentials.astraId && (data?.error === "AGENT_NOT_FOUND" || typeof data?.message === "string" && /agent/i.test(data.message))) {
486
+ return {
487
+ success: true,
488
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
489
+ access: {
490
+ allowed: false,
491
+ reason: "unknown_agent",
492
+ failures: [
493
+ {
494
+ dimension: "identity.unknown_agent",
495
+ message: "The presented agent identifier is not registered with AstraSync.",
496
+ guidance: UNKNOWN_AGENT_GUIDANCE
497
+ }
498
+ ]
499
+ }
500
+ };
501
+ }
427
502
  if (!response.ok) {
428
503
  if (response.status === 401) {
429
504
  return {
@@ -438,9 +513,11 @@ async function callVerifyAccessAPI(config, request) {
438
513
  }
439
514
  return {
440
515
  success: false,
441
- error: data.message || data.error || `API returned ${response.status}`,
516
+ error: typeof data?.message === "string" && data.message || typeof data?.error === "string" && data.error || `API returned ${response.status}`,
442
517
  correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
443
- attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
518
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
519
+ httpStatus: response.status,
520
+ ...retryAfterMs !== void 0 && { retryAfterMs }
444
521
  };
445
522
  }
446
523
  return data;
@@ -512,12 +589,14 @@ async function verify(config, request, options) {
512
589
  correlationId: apiResponse.correlationId,
513
590
  attemptId: apiResponse.attemptId,
514
591
  remediation: apiResponse.remediation,
592
+ httpStatus: apiResponse.httpStatus,
593
+ retryAfterMs: apiResponse.retryAfterMs,
515
594
  urls
516
595
  });
517
596
  }
518
597
  if (!apiResponse.access?.allowed) {
519
598
  const aggregatedFailures = apiResponse.access?.failures;
520
- const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true;
599
+ const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
521
600
  const result2 = {
522
601
  identityVerified: idVerifiedFromBackend,
523
602
  policyAllowed: false,
@@ -529,7 +608,10 @@ async function verify(config, request, options) {
529
608
  requiresStepUp: apiResponse.access?.requiresStepUp,
530
609
  requiresApproval: apiResponse.access?.requiresApproval,
531
610
  guidance: {
532
- message: apiResponse.access?.reason || "Access denied by PDLSS policy",
611
+ // 5.12.0: a presented-but-rejected id (malformed / unknown) carries
612
+ // actionable registration guidance on its failure — surface it
613
+ // instead of the bare machine reason ('unknown_agent').
614
+ message: rejectedIdentityGuidance(aggregatedFailures) ?? (apiResponse.access?.reason || "Access denied by PDLSS policy"),
533
615
  registrationUrl: urls?.registrationUrl ?? "",
534
616
  documentationUrl: urls?.documentationUrl ?? "",
535
617
  // 5.1.0: anonymous callers land on this branch — steer MCP-hosted
@@ -629,7 +711,7 @@ async function verify(config, request, options) {
629
711
  registrationUrl: urls?.registrationUrl ?? "",
630
712
  documentationUrl: urls?.documentationUrl ?? ""
631
713
  };
632
- } else if (result.recommendation === "step_up_required") {
714
+ } else if (result.recommendation === "step_up_required" && result.identityVerified) {
633
715
  result.requiresStepUp = true;
634
716
  result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Step-up verification required"];
635
717
  }
@@ -652,7 +734,7 @@ async function recordDecision(config, sessionId, decision, reason) {
652
734
  }).catch(() => {
653
735
  });
654
736
  }
655
- async function reportAttempt(config, report) {
737
+ async function reportAttempt(config, report, options = {}) {
656
738
  const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
657
739
  const headers = { "Content-Type": "application/json" };
658
740
  if (config.apiKey) {
@@ -663,13 +745,37 @@ async function reportAttempt(config, report) {
663
745
  ...report,
664
746
  ...!report.counterpartyId && config.counterpartyId && { counterpartyId: config.counterpartyId }
665
747
  };
666
- await sdkFetch(`${apiBaseUrl}/agents/verify-access/attempt-report`, {
667
- method: "POST",
668
- headers,
669
- body: JSON.stringify(body)
670
- }).catch(() => {
671
- });
748
+ const url = `${apiBaseUrl}/agents/verify-access/attempt-report`;
749
+ const init = { method: "POST", headers, body: JSON.stringify(body) };
750
+ const fail = (failure) => {
751
+ try {
752
+ options.onFailure?.(failure);
753
+ } catch {
754
+ }
755
+ };
756
+ let response;
757
+ try {
758
+ response = await sdkFetch(url, init);
759
+ } catch (err) {
760
+ fail({ error: err instanceof Error ? err.message : String(err), retried: false });
761
+ return;
762
+ }
763
+ if (response.ok) return;
764
+ if (response.status !== 429 && response.status < 500) {
765
+ fail({ status: response.status, retried: false });
766
+ return;
767
+ }
768
+ const delayMs = Math.min(ATTEMPT_REPORT_MAX_RETRY_DELAY_MS, parseRetryAfterMs(response) ?? 500);
769
+ const timer = setTimeout(() => {
770
+ sdkFetch(url, init).then((retry) => {
771
+ if (!retry.ok) fail({ status: retry.status, retried: true });
772
+ }).catch((err) => {
773
+ fail({ error: err instanceof Error ? err.message : String(err), retried: true });
774
+ });
775
+ }, delayMs);
776
+ timer.unref?.();
672
777
  }
778
+ var ATTEMPT_REPORT_MAX_RETRY_DELAY_MS = 2e3;
673
779
  async function fetchRoutes(config, counterpartyId) {
674
780
  if (!counterpartyId) return null;
675
781
  const headers = { "Content-Type": "application/json" };
@@ -714,7 +820,10 @@ async function reportUnregisteredAttempt(config, data) {
714
820
  };
715
821
  await sdkFetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
716
822
  method: "POST",
717
- headers: { "Content-Type": "application/json" },
823
+ headers: {
824
+ "Content-Type": "application/json",
825
+ ...config.apiKey && { Authorization: `Bearer ${config.apiKey}` }
826
+ },
718
827
  body: JSON.stringify(body)
719
828
  }).catch(() => {
720
829
  });
@@ -736,7 +845,11 @@ async function quickVerify(config, credentials) {
736
845
  return {
737
846
  identityVerified: result.identityVerified,
738
847
  policyAllowed: result.policyAllowed,
739
- reason: result.denialReasons?.[0]
848
+ reason: result.denialReasons?.[0],
849
+ ...isVerificationUnavailable(result) && {
850
+ unavailable: true,
851
+ retryAfterMs: unavailableRetryAfterSeconds(result) * 1e3
852
+ }
740
853
  };
741
854
  }
742
855
  // Annotate the CommonJS export names for ESM import in node:
@@ -746,6 +859,7 @@ async function quickVerify(config, credentials) {
746
859
  extractCredentials,
747
860
  fetchRoutes,
748
861
  hasCredentials,
862
+ parseRetryAfterMs,
749
863
  quickVerify,
750
864
  recordDecision,
751
865
  reportAttempt,