@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
package/dist/index.mjs CHANGED
@@ -126,7 +126,7 @@ function getCapabilities(accessLevel) {
126
126
  }
127
127
 
128
128
  // src/version.ts
129
- var SDK_VERSION = "3.11.1";
129
+ var SDK_VERSION = "4.0.0";
130
130
 
131
131
  // src/well-known.ts
132
132
  var CACHE_TTL_MS = 60 * 60 * 1e3;
@@ -204,7 +204,7 @@ var DEFAULT_CONFIG = {
204
204
  };
205
205
  var initCheckPerformed = false;
206
206
  var deprecationWarningShown = false;
207
- async function performInitCheck(apiBaseUrl, debug, strictInit) {
207
+ async function performInitCheck(apiBaseUrl, debug, strictInit, apiKey) {
208
208
  initCheckPerformed = true;
209
209
  try {
210
210
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
@@ -221,6 +221,28 @@ async function performInitCheck(apiBaseUrl, debug, strictInit) {
221
221
  `[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
222
222
  );
223
223
  }
224
+ if (apiKey) {
225
+ const selfCheck = await fetch(`${apiBaseUrl}/agents/verify-access/self-check`, {
226
+ headers: { Authorization: `Bearer ${apiKey}` }
227
+ });
228
+ if (selfCheck.status === 401) {
229
+ const body = await selfCheck.json().catch(() => ({}));
230
+ 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}` : "") + `.`;
231
+ if (strictInit) {
232
+ throw new Error(`${message} (strictInit=true)`);
233
+ }
234
+ console.error(message);
235
+ } else if (selfCheck.ok) {
236
+ const body = await selfCheck.json().catch(() => ({}));
237
+ if (typeof body.daysToExpiry === "number" && body.daysToExpiry <= 7) {
238
+ console.warn(
239
+ `[VerificationGateway] the configured AstraSync API key expires in ${body.daysToExpiry} day(s) \u2014 rotate it at Settings \u2192 Developer Tools before integrations start failing.`
240
+ );
241
+ } else if (debug) {
242
+ console.log("[VerificationGateway] API key self-check passed");
243
+ }
244
+ }
245
+ }
224
246
  } catch (err) {
225
247
  if (strictInit) {
226
248
  throw err;
@@ -338,8 +360,17 @@ function hasCredentials(credentials) {
338
360
  function createGuidanceResponse(_config, reason, options = {}) {
339
361
  const source = options.source ?? "no_credentials";
340
362
  const isApiError = source === "api_error";
363
+ const isMisconfig = source === "merchant_misconfig";
341
364
  const urls = options.urls;
342
- const guidance = isApiError ? {
365
+ const guidance = isMisconfig ? {
366
+ 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.",
367
+ registrationUrl: urls?.registrationUrl ?? "",
368
+ documentationUrl: options.remediation?.docsUrl ?? urls?.documentationUrl ?? "",
369
+ steps: [
370
+ "Report the failure to the site operator \u2014 their AstraSync API key needs rotating",
371
+ "Do not retry: the failure is deterministic until the operator updates their key"
372
+ ]
373
+ } : isApiError ? {
343
374
  message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
344
375
  registrationUrl: urls?.registrationUrl ?? "",
345
376
  documentationUrl: urls?.documentationUrl ?? "",
@@ -377,14 +408,24 @@ function createGuidanceResponse(_config, reason, options = {}) {
377
408
  // partners (and their custom onDenied handlers) can branch on
378
409
  // dimension. Without this, the synthesised stub was indistinguishable
379
410
  // from a real policy deny.
380
- failures: isApiError ? [
411
+ failures: isMisconfig ? [
412
+ {
413
+ dimension: "verify_access.merchant_misconfigured",
414
+ message: reason ?? "The integration API key was rejected by AstraSync",
415
+ guidance: guidance.message
416
+ }
417
+ ] : isApiError ? [
381
418
  {
382
419
  dimension: "verify_access.api_error",
383
420
  message: reason ?? "Verification temporarily unavailable",
384
421
  guidance: guidance.message
385
422
  }
386
423
  ] : void 0,
424
+ // 4.0.0: typed marker so adapters render the misconfig envelope (503 +
425
+ // MERCHANT_VERIFICATION_MISCONFIGURED) without string-matching.
426
+ ...isMisconfig && { misconfigured: true },
387
427
  correlationId: options.correlationId,
428
+ attemptId: options.attemptId,
388
429
  verifiedAt: /* @__PURE__ */ new Date()
389
430
  };
390
431
  }
@@ -414,6 +455,8 @@ async function callVerifyAccessAPI(config, request) {
414
455
  body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
415
456
  if (requestData.invocationProtocol) body.invocationProtocol = requestData.invocationProtocol;
416
457
  if (requestData.commerceArtifacts) body.commerceArtifacts = requestData.commerceArtifacts;
458
+ if (requestData.attemptId) body.attemptId = requestData.attemptId;
459
+ if (requestData.considerationSet) body.considerationSet = requestData.considerationSet;
417
460
  body.sdkVersion = SDK_VERSION;
418
461
  if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
419
462
  const meta = {
@@ -435,12 +478,16 @@ async function callVerifyAccessAPI(config, request) {
435
478
  const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
436
479
  method: "POST",
437
480
  headers,
438
- body: JSON.stringify(body)
481
+ body: JSON.stringify(body),
482
+ signal: AbortSignal.timeout(config.verifyTimeoutMs ?? 1e4)
439
483
  });
440
484
  const data = await response.json();
441
485
  if (response.status === 410) {
442
486
  return {
443
487
  success: true,
488
+ // 3.12.0 (Trust Record): keep the server-echoed attempt handle even on
489
+ // the synthesised 410 deny shape (echoed on every branch).
490
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
444
491
  access: {
445
492
  allowed: false,
446
493
  accessLevel: "none",
@@ -456,10 +503,22 @@ async function callVerifyAccessAPI(config, request) {
456
503
  };
457
504
  }
458
505
  if (!response.ok) {
506
+ if (response.status === 401) {
507
+ return {
508
+ success: false,
509
+ error: data.message || data.error || "Integration API key rejected",
510
+ misconfig: true,
511
+ misconfigCode: typeof data?.code === "string" ? data.code : void 0,
512
+ remediation: data?.remediation && typeof data.remediation === "object" ? data.remediation : void 0,
513
+ correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
514
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
515
+ };
516
+ }
459
517
  return {
460
518
  success: false,
461
519
  error: data.message || data.error || `API returned ${response.status}`,
462
- correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0
520
+ correlationId: typeof data?.correlationId === "string" ? data.correlationId : void 0,
521
+ attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0
463
522
  };
464
523
  }
465
524
  return data;
@@ -476,9 +535,19 @@ async function verify(config, request, options) {
476
535
  const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
477
536
  if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
478
537
  if (mergedConfig.strictInit) {
479
- await performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, true);
538
+ await performInitCheck(
539
+ mergedConfig.apiBaseUrl,
540
+ mergedConfig.debug,
541
+ true,
542
+ mergedConfig.apiKey
543
+ );
480
544
  } else {
481
- void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, false);
545
+ void performInitCheck(
546
+ mergedConfig.apiBaseUrl,
547
+ mergedConfig.debug,
548
+ false,
549
+ mergedConfig.apiKey
550
+ );
482
551
  }
483
552
  }
484
553
  if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
@@ -493,7 +562,13 @@ async function verify(config, request, options) {
493
562
  if (mergedConfig.debug) {
494
563
  console.log("[VerificationGateway] Returning cached result");
495
564
  }
496
- return cached;
565
+ const hit = { ...cached };
566
+ if (request.attemptId) {
567
+ hit.attemptId = request.attemptId;
568
+ } else {
569
+ delete hit.attemptId;
570
+ }
571
+ return hit;
497
572
  }
498
573
  }
499
574
  const enrichedRequest = { ...request };
@@ -511,8 +586,10 @@ async function verify(config, request, options) {
511
586
  const serverDenialReasons = Array.isArray(rawServerDenialReasons) && rawServerDenialReasons.length > 0 ? rawServerDenialReasons : void 0;
512
587
  if (!apiResponse.success) {
513
588
  return createGuidanceResponse(mergedConfig, apiResponse.error, {
514
- source: "api_error",
589
+ source: apiResponse.misconfig ? "merchant_misconfig" : "api_error",
515
590
  correlationId: apiResponse.correlationId,
591
+ attemptId: apiResponse.attemptId,
592
+ remediation: apiResponse.remediation,
516
593
  urls
517
594
  });
518
595
  }
@@ -548,6 +625,9 @@ async function verify(config, request, options) {
548
625
  // Anonymous traffic has no session → correlationId is the per-attempt
549
626
  // linking key (the sessionId-equivalent for anonymous callers).
550
627
  correlationId: apiResponse.correlationId,
628
+ // 3.12.0 (Trust Record): server echoes the attempt-chain handle on
629
+ // every branch — denials included (the funnel outlives one deny).
630
+ attemptId: apiResponse.attemptId,
551
631
  recommendation: apiResponse.recommendation,
552
632
  recommendationReasons: apiResponse.recommendationReasons,
553
633
  stepUpApproval: apiResponse.stepUpApproval,
@@ -599,6 +679,8 @@ async function verify(config, request, options) {
599
679
  // v2.3.10 (defect #34, round-4): anonymous responses surface correlationId
600
680
  // (no session row exists for unverified callers).
601
681
  correlationId: apiResponse.correlationId,
682
+ // 3.12.0 (Trust Record): server-echoed attempt-chain handle.
683
+ attemptId: apiResponse.attemptId,
602
684
  runtimeChallenge: apiResponse.runtimeChallenge,
603
685
  tokenGuidance: apiResponse.tokenGuidance,
604
686
  recommendation: apiResponse.recommendation,
@@ -643,6 +725,24 @@ async function recordDecision(config, sessionId, decision, reason) {
643
725
  }).catch(() => {
644
726
  });
645
727
  }
728
+ async function reportAttempt(config, report) {
729
+ const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
730
+ const headers = { "Content-Type": "application/json" };
731
+ if (config.apiKey) {
732
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
733
+ headers["X-API-Key"] = config.apiKey;
734
+ }
735
+ const body = {
736
+ ...report,
737
+ ...!report.counterpartyId && config.counterpartyId && { counterpartyId: config.counterpartyId }
738
+ };
739
+ await fetch(`${apiBaseUrl}/agents/verify-access/attempt-report`, {
740
+ method: "POST",
741
+ headers,
742
+ body: JSON.stringify(body)
743
+ }).catch(() => {
744
+ });
745
+ }
646
746
  async function fetchRoutes(config, counterpartyId) {
647
747
  if (!counterpartyId) return null;
648
748
  const headers = { "Content-Type": "application/json" };
@@ -1237,6 +1337,20 @@ function dedupeFailures(result) {
1237
1337
  }
1238
1338
  }
1239
1339
  function defaultOnDenied(result, _req, res) {
1340
+ if (result.misconfigured) {
1341
+ res.setHeader("X-Astra-Gateway-Mode", "enforced");
1342
+ res.status(503).json({
1343
+ success: false,
1344
+ error: {
1345
+ code: "MERCHANT_VERIFICATION_MISCONFIGURED",
1346
+ message: result.denialReasons?.[0] || "This site's AstraSync integration is misconfigured",
1347
+ guidance: result.guidance,
1348
+ failures: result.failures,
1349
+ correlationId: result.correlationId
1350
+ }
1351
+ });
1352
+ return;
1353
+ }
1240
1354
  const statusCode = !result.identityVerified ? 401 : 403;
1241
1355
  res.setHeader("X-Astra-Gateway-Mode", "enforced");
1242
1356
  res.status(statusCode).json({
@@ -1953,6 +2067,21 @@ function createMiddleware2(options) {
1953
2067
  const approvalRequired = result.identityVerified && result.policyAllowed && requiresHumanApproval(result);
1954
2068
  if (approvalRequired) annotateApprovalRequired(result);
1955
2069
  if (!result.identityVerified || !result.policyAllowed || approvalRequired) {
2070
+ if (result.misconfigured && pathname.startsWith("/api/")) {
2071
+ return NextResponse.json(
2072
+ {
2073
+ success: false,
2074
+ error: {
2075
+ code: "MERCHANT_VERIFICATION_MISCONFIGURED",
2076
+ message: result.denialReasons?.[0] || "This site's AstraSync integration is misconfigured",
2077
+ guidance: result.guidance,
2078
+ failures: result.failures,
2079
+ correlationId: result.correlationId
2080
+ }
2081
+ },
2082
+ { status: 503 }
2083
+ );
2084
+ }
1956
2085
  if (pathname.startsWith("/api/")) {
1957
2086
  return NextResponse.json(
1958
2087
  {
@@ -4879,6 +5008,24 @@ function dedupeFailures2(result) {
4879
5008
  }
4880
5009
  function defaultMcpDenied(result, req, res) {
4881
5010
  const id = req.body?.id ?? null;
5011
+ if (result.misconfigured) {
5012
+ res.setHeader("X-Astra-Gateway-Mode", "enforced");
5013
+ res.status(503).json({
5014
+ jsonrpc: "2.0",
5015
+ id,
5016
+ error: {
5017
+ // -32002 → merchant verification misconfigured (see -32000/-32001 below)
5018
+ code: -32002,
5019
+ message: result.denialReasons?.[0] ?? "This server's AstraSync integration is misconfigured",
5020
+ data: {
5021
+ guidance: result.guidance,
5022
+ failures: result.failures,
5023
+ correlationId: result.correlationId
5024
+ }
5025
+ }
5026
+ });
5027
+ return;
5028
+ }
4882
5029
  const status = !result.identityVerified ? 401 : 403;
4883
5030
  res.setHeader("X-Astra-Gateway-Mode", "enforced");
4884
5031
  res.status(status).json({
@@ -4888,6 +5035,7 @@ function defaultMcpDenied(result, req, res) {
4888
5035
  // JSON-RPC error codes:
4889
5036
  // -32000 → unauthorized (no identity resolved)
4890
5037
  // -32001 → insufficient access (identity OK, policy denied)
5038
+ // -32002 → merchant verification misconfigured (handled above)
4891
5039
  code: !result.identityVerified ? -32e3 : -32001,
4892
5040
  message: result.denialReasons?.[0] ?? "Access denied",
4893
5041
  data: {
@@ -6100,6 +6248,7 @@ export {
6100
6248
  prefetchWellKnown,
6101
6249
  quickVerify,
6102
6250
  recordDecision2 as recordDecision,
6251
+ reportAttempt,
6103
6252
  reportUnregisteredAttempt,
6104
6253
  sanitizeHeaders,
6105
6254
  sdk_exports as sdk,