@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
package/dist/verify.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var SDK_VERSION = "5.11.0";
2
+ var SDK_VERSION = "5.13.0";
3
3
 
4
4
  // src/http.ts
5
5
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -34,6 +34,29 @@ function getCachedWellKnownUrls(apiBaseUrl) {
34
34
  return cache.get(apiBaseUrl)?.data;
35
35
  }
36
36
 
37
+ // src/failure-posture.ts
38
+ var DEFAULT_UNAVAILABLE_RETRY_AFTER_S = 30;
39
+ var REJECTED_IDENTITY_DIMENSIONS = /* @__PURE__ */ new Set([
40
+ "identity.invalid_agent_id",
41
+ "identity.unknown_agent",
42
+ "agent.lookup"
43
+ ]);
44
+ 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.";
45
+ var UNAVAILABLE_DIMENSIONS = /* @__PURE__ */ new Set([
46
+ "verify_access.api_error",
47
+ "middleware.internal_error"
48
+ ]);
49
+ function isVerificationUnavailable(result) {
50
+ if (result.misconfigured) return false;
51
+ return (result.failures ?? []).some((f) => UNAVAILABLE_DIMENSIONS.has(f.dimension));
52
+ }
53
+ function unavailableRetryAfterSeconds(result) {
54
+ if (typeof result.retryAfterMs === "number" && Number.isFinite(result.retryAfterMs)) {
55
+ return Math.max(1, Math.ceil(result.retryAfterMs / 1e3));
56
+ }
57
+ return DEFAULT_UNAVAILABLE_RETRY_AFTER_S;
58
+ }
59
+
37
60
  // src/verify.ts
38
61
  var DEFAULT_CONFIG = {
39
62
  apiBaseUrl: "https://astrasync.ai/api",
@@ -49,7 +72,7 @@ function _resetInitCheck() {
49
72
  initCheckPerformed = false;
50
73
  }
51
74
  var deprecationWarningShown = false;
52
- async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
75
+ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey, counterparty) {
53
76
  initCheckPerformed = true;
54
77
  try {
55
78
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
@@ -67,7 +90,8 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
67
90
  );
68
91
  }
69
92
  if (apiKey) {
70
- const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
93
+ const q = counterparty?.id ? `?counterpartyId=${encodeURIComponent(counterparty.id)}` : counterparty?.url ? `?counterpartyUrl=${encodeURIComponent(counterparty.url)}` : "";
94
+ const selfCheck = await sdkFetch(`${apiBaseUrl}/agents/verify-access/self-check${q}`, {
71
95
  headers: { Authorization: `Bearer ${apiKey}` }
72
96
  });
73
97
  if (selfCheck.status === 401) {
@@ -79,6 +103,13 @@ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
79
103
  console.error(message);
80
104
  } else if (selfCheck.ok) {
81
105
  const body = await selfCheck.json().catch(() => ({}));
106
+ if (body.counterparty && body.counterparty.canVerify === false) {
107
+ 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.`;
108
+ if (strictInit) {
109
+ throw new Error(`${message} (strictInit=true)`);
110
+ }
111
+ console.error(message);
112
+ }
82
113
  if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
83
114
  console.warn(
84
115
  `[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
@@ -223,11 +254,11 @@ function createGuidanceResponse(_config, reason, options = {}) {
223
254
  const isMisconfig = source === "merchant_misconfig";
224
255
  const urls = options.urls;
225
256
  const guidance = isMisconfig ? {
226
- 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.",
257
+ 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.",
227
258
  registrationUrl: urls?.registrationUrl ?? "",
228
259
  documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
229
260
  steps: [
230
- "Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
261
+ "Report the failure to the site operator \u2014 their AstraSync API key needs replacing",
231
262
  "Do not retry: the failure is deterministic until the operator updates their key"
232
263
  ]
233
264
  } : isApiError ? {
@@ -288,11 +319,44 @@ function createGuidanceResponse(_config, reason, options = {}) {
288
319
  // coercing the absent recommendation to a policy 'deny'. Misconfig is
289
320
  // deterministic and intentionally NOT marked retryable.
290
321
  ...isApiError && { retryable: true },
322
+ ...options.httpStatus !== void 0 && { httpStatus: options.httpStatus },
323
+ ...options.retryAfterMs !== void 0 && { retryAfterMs: options.retryAfterMs },
291
324
  correlationId: options.correlationId,
292
325
  attemptId: options.attemptId,
293
326
  verifiedAt: /* @__PURE__ */ new Date()
294
327
  };
295
328
  }
329
+ async function readJsonSafe(response) {
330
+ try {
331
+ const parsed = await response.json();
332
+ return parsed && typeof parsed === "object" ? parsed : {};
333
+ } catch {
334
+ return {};
335
+ }
336
+ }
337
+ function rejectedIdentityGuidance(failures) {
338
+ const f = failures?.find((x) => REJECTED_IDENTITY_DIMENSIONS.has(x.dimension));
339
+ if (!f) return void 0;
340
+ if (f.dimension === "agent.lookup") {
341
+ return `The presented agent identifier is not registered with AstraSync. ${UNKNOWN_AGENT_GUIDANCE}`;
342
+ }
343
+ return f.guidance ? `${f.message} ${f.guidance}` : f.message;
344
+ }
345
+ var MAX_RETRY_AFTER_MS = 15 * 60 * 1e3;
346
+ function parseRetryAfterMs(response) {
347
+ const raw = response.headers?.get?.("retry-after");
348
+ if (!raw) return void 0;
349
+ const trimmed = raw.trim();
350
+ let ms;
351
+ if (/^\d+(\.\d+)?$/.test(trimmed)) {
352
+ ms = Number(trimmed) * 1e3;
353
+ } else {
354
+ const at = Date.parse(trimmed);
355
+ if (Number.isNaN(at)) return void 0;
356
+ ms = at - Date.now();
357
+ }
358
+ return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, Math.round(ms)));
359
+ }
296
360
  async function callVerifyAccessAPI(config, request) {
297
361
  const { credentials, ...requestData } = request;
298
362
  const body = {
@@ -349,7 +413,8 @@ async function callVerifyAccessAPI(config, request) {
349
413
  body: JSON.stringify(body),
350
414
  signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
351
415
  });
352
- const data = await response.json();
416
+ const data = await readJsonSafe(response);
417
+ const retryAfterMs = parseRetryAfterMs(response);
353
418
  if (response.status === 410) {
354
419
  return {
355
420
  success: true,
@@ -387,13 +452,31 @@ async function callVerifyAccessAPI(config, request) {
387
452
  }
388
453
  };
389
454
  }
455
+ if (response.status === 404 && credentials.astraId && (data?.error === "AGENT_NOT_FOUND" || typeof data?.message === "string" && /agent/i.test(data.message))) {
456
+ return {
457
+ success: true,
458
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
459
+ access: {
460
+ allowed: false,
461
+ reason: "unknown_agent",
462
+ failures: [
463
+ {
464
+ dimension: "identity.unknown_agent",
465
+ message: "The presented agent identifier is not registered with AstraSync.",
466
+ guidance: UNKNOWN_AGENT_GUIDANCE
467
+ }
468
+ ]
469
+ }
470
+ };
471
+ }
390
472
  if (!response.ok) {
391
- if (response.status === 401) {
473
+ const keyMismatch = response.status === 403 && data?.error === "COUNTERPARTY_KEY_MISMATCH";
474
+ if (response.status === 401 || keyMismatch) {
392
475
  return {
393
476
  success: false,
394
477
  error: data.message || data.error || "Integration API key rejected",
395
478
  misconfig: true,
396
- misconfigCode: typeof data?.code === "string" ? data.code : void 0,
479
+ misconfigCode: keyMismatch ? "counterparty_key_mismatch" : typeof data?.code === "string" ? data.code : void 0,
397
480
  remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
398
481
  correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
399
482
  attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
@@ -401,9 +484,11 @@ async function callVerifyAccessAPI(config, request) {
401
484
  }
402
485
  return {
403
486
  success: false,
404
- error: data.message || data.error || `API returned ${response.status}`,
487
+ error: typeof data?.message === "string" && data.message || typeof data?.error === "string" && data.error || `API returned ${response.status}`,
405
488
  correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
406
- attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
489
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
490
+ httpStatus: response.status,
491
+ ...retryAfterMs !== void 0 && { retryAfterMs }
407
492
  };
408
493
  }
409
494
  return data;
@@ -424,14 +509,22 @@ async function verify(config, request, options) {
424
509
  mergedConfig.apiBaseUrl,
425
510
  mergedConfig.debug,
426
511
  true,
427
- mergedConfig.apiKey
512
+ mergedConfig.apiKey,
513
+ {
514
+ id: mergedConfig.counterpartyId,
515
+ url: mergedConfig.counterpartyUrl ?? request.counterpartyUrl
516
+ }
428
517
  );
429
518
  } else {
430
519
  void performInitCheck(
431
520
  mergedConfig.apiBaseUrl,
432
521
  mergedConfig.debug,
433
522
  false,
434
- mergedConfig.apiKey
523
+ mergedConfig.apiKey,
524
+ {
525
+ id: mergedConfig.counterpartyId,
526
+ url: mergedConfig.counterpartyUrl ?? request.counterpartyUrl
527
+ }
435
528
  );
436
529
  }
437
530
  }
@@ -475,12 +568,14 @@ async function verify(config, request, options) {
475
568
  correlationId: apiResponse.correlationId,
476
569
  attemptId: apiResponse.attemptId,
477
570
  remediation: apiResponse.remediation,
571
+ httpStatus: apiResponse.httpStatus,
572
+ retryAfterMs: apiResponse.retryAfterMs,
478
573
  urls
479
574
  });
480
575
  }
481
576
  if (!apiResponse.access?.allowed) {
482
577
  const aggregatedFailures = apiResponse.access?.failures;
483
- const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true;
578
+ const idVerifiedFromBackend = apiResponse.verificationContext?.idVerified === true && !aggregatedFailures?.some((f) => REJECTED_IDENTITY_DIMENSIONS.has(f.dimension));
484
579
  const result2 = {
485
580
  identityVerified: idVerifiedFromBackend,
486
581
  policyAllowed: false,
@@ -492,7 +587,10 @@ async function verify(config, request, options) {
492
587
  requiresStepUp: apiResponse.access?.requiresStepUp,
493
588
  requiresApproval: apiResponse.access?.requiresApproval,
494
589
  guidance: {
495
- message: apiResponse.access?.reason || "Access denied by PDLSS policy",
590
+ // 5.12.0: a presented-but-rejected id (malformed / unknown) carries
591
+ // actionable registration guidance on its failure — surface it
592
+ // instead of the bare machine reason ('unknown_agent').
593
+ message: rejectedIdentityGuidance(aggregatedFailures) ?? (apiResponse.access?.reason || "Access denied by PDLSS policy"),
496
594
  registrationUrl: urls?.registrationUrl ?? "",
497
595
  documentationUrl: urls?.documentationUrl ?? "",
498
596
  // 5.1.0: anonymous callers land on this branch — steer MCP-hosted
@@ -592,7 +690,7 @@ async function verify(config, request, options) {
592
690
  registrationUrl: urls?.registrationUrl ?? "",
593
691
  documentationUrl: urls?.documentationUrl ?? ""
594
692
  };
595
- } else if (result.recommendation === "step_up_required") {
693
+ } else if (result.recommendation === "step_up_required" && result.identityVerified) {
596
694
  result.requiresStepUp = true;
597
695
  result.denialReasons = serverDenialReasons ?? result.recommendationReasons ?? ["Step-up verification required"];
598
696
  }
@@ -615,7 +713,7 @@ async function recordDecision(config, sessionId, decision, reason) {
615
713
  }).catch(() => {
616
714
  });
617
715
  }
618
- async function reportAttempt(config, report) {
716
+ async function reportAttempt(config, report, options = {}) {
619
717
  const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
620
718
  const headers = { "Content-Type": "application/json" };
621
719
  if (config.apiKey) {
@@ -626,13 +724,38 @@ async function reportAttempt(config, report) {
626
724
  ...report,
627
725
  ...!report.counterpartyId && config.counterpartyId && { counterpartyId: config.counterpartyId }
628
726
  };
629
- await sdkFetch(`${apiBaseUrl}/agents/verify-access/attempt-report`, {
630
- method: "POST",
631
- headers,
632
- body: JSON.stringify(body)
633
- }).catch(() => {
634
- });
727
+ const url = `${apiBaseUrl}/agents/verify-access/attempt-report`;
728
+ const init = { method: "POST", headers, body: JSON.stringify(body) };
729
+ const fail = (failure) => {
730
+ try {
731
+ options.onFailure?.(failure);
732
+ } catch {
733
+ }
734
+ };
735
+ let response;
736
+ try {
737
+ response = await sdkFetch(url, init);
738
+ } catch (err) {
739
+ fail({ error: err instanceof Error ? err.message : String(err), retried: false });
740
+ return;
741
+ }
742
+ if (response.ok) return;
743
+ if (response.status !== 429 && response.status < 500) {
744
+ fail({ status: response.status, retried: false });
745
+ return;
746
+ }
747
+ const delayMs = Math.min(ATTEMPT_REPORT_MAX_RETRY_DELAY_MS, parseRetryAfterMs(response) ?? 500);
748
+ const timer = setTimeout(() => {
749
+ sdkFetch(url, init).then((retry) => {
750
+ if (!retry.ok) fail({ status: retry.status, retried: true });
751
+ }).catch((err) => {
752
+ fail({ error: err instanceof Error ? err.message : String(err), retried: true });
753
+ });
754
+ }, delayMs);
755
+ timer.unref?.();
635
756
  }
757
+ var ATTEMPT_REPORT_MAX_RETRY_DELAY_MS = 2e3;
758
+ var refusedPolicyReads = /* @__PURE__ */ new Set();
636
759
  async function fetchRoutes(config, counterpartyId) {
637
760
  if (!counterpartyId) return null;
638
761
  const headers = { "Content-Type": "application/json" };
@@ -645,7 +768,15 @@ async function fetchRoutes(config, counterpartyId) {
645
768
  `${config.apiBaseUrl}/endpoints/${encodeURIComponent(counterpartyId)}/routes`,
646
769
  { method: "GET", headers }
647
770
  );
648
- if (!response.ok) return null;
771
+ if (!response.ok) {
772
+ if ((response.status === 401 || response.status === 403 || response.status === 404) && !refusedPolicyReads.has(counterpartyId)) {
773
+ refusedPolicyReads.add(counterpartyId);
774
+ console.error(
775
+ `[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.`
776
+ );
777
+ }
778
+ return null;
779
+ }
649
780
  const body = await response.json();
650
781
  return body.data?.routes ?? [];
651
782
  } catch {
@@ -677,7 +808,10 @@ async function reportUnregisteredAttempt(config, data) {
677
808
  };
678
809
  await sdkFetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
679
810
  method: "POST",
680
- headers: { "Content-Type": "application/json" },
811
+ headers: {
812
+ "Content-Type": "application/json",
813
+ ...config.apiKey && { Authorization: `Bearer ${config.apiKey}` }
814
+ },
681
815
  body: JSON.stringify(body)
682
816
  }).catch(() => {
683
817
  });
@@ -699,7 +833,11 @@ async function quickVerify(config, credentials) {
699
833
  return {
700
834
  identityVerified: result.identityVerified,
701
835
  policyAllowed: result.policyAllowed,
702
- reason: result.denialReasons?.[0]
836
+ reason: result.denialReasons?.[0],
837
+ ...isVerificationUnavailable(result) && {
838
+ unavailable: true,
839
+ retryAfterMs: unavailableRetryAfterSeconds(result) * 1e3
840
+ }
703
841
  };
704
842
  }
705
843
  export {
@@ -708,6 +846,7 @@ export {
708
846
  extractCredentials,
709
847
  fetchRoutes,
710
848
  hasCredentials,
849
+ parseRetryAfterMs,
711
850
  quickVerify,
712
851
  recordDecision,
713
852
  reportAttempt,