@astrasyncai/verification-gateway 2.4.12 → 2.5.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 (91) 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 +224 -42
  6. package/dist/adapters/express.js.map +1 -1
  7. package/dist/adapters/express.mjs +224 -42
  8. package/dist/adapters/express.mjs.map +1 -1
  9. package/dist/adapters/mcp.d.mts +101 -57
  10. package/dist/adapters/mcp.d.ts +101 -57
  11. package/dist/adapters/mcp.js +215 -44
  12. package/dist/adapters/mcp.js.map +1 -1
  13. package/dist/adapters/mcp.mjs +215 -44
  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 +87 -34
  18. package/dist/adapters/nextjs.js.map +1 -1
  19. package/dist/adapters/nextjs.mjs +87 -34
  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 +61 -28
  24. package/dist/adapters/sdk.js.map +1 -1
  25. package/dist/adapters/sdk.mjs +61 -28
  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/agent/index.js +29 -0
  30. package/dist/agent/index.js.map +1 -1
  31. package/dist/agent/index.mjs +29 -0
  32. package/dist/agent/index.mjs.map +1 -1
  33. package/dist/browser/background.js +102 -30
  34. package/dist/browser/background.js.map +1 -1
  35. package/dist/browser/background.mjs +102 -30
  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/cli/index.d.mts +2 -2
  40. package/dist/cli/index.d.ts +2 -2
  41. package/dist/cursor/cursor-adapter.d.mts +2 -2
  42. package/dist/cursor/cursor-adapter.d.ts +2 -2
  43. package/dist/cursor/extension.d.mts +2 -2
  44. package/dist/cursor/extension.d.ts +2 -2
  45. package/dist/cursor/extension.js +102 -30
  46. package/dist/cursor/extension.js.map +1 -1
  47. package/dist/cursor/extension.mjs +102 -30
  48. package/dist/cursor/extension.mjs.map +1 -1
  49. package/dist/{express-C1ePFB7n.d.ts → express-CrfwoNAR.d.ts} +1 -1
  50. package/dist/{express-4WStX3PV.d.mts → express-ienhAXps.d.mts} +1 -1
  51. package/dist/gateway/gateway.d.mts +2 -2
  52. package/dist/gateway/gateway.d.ts +2 -2
  53. package/dist/gateway/gateway.js +102 -30
  54. package/dist/gateway/gateway.js.map +1 -1
  55. package/dist/gateway/gateway.mjs +102 -30
  56. package/dist/gateway/gateway.mjs.map +1 -1
  57. package/dist/git-trigger/git-hooks.d.mts +2 -2
  58. package/dist/git-trigger/git-hooks.d.ts +2 -2
  59. package/dist/{index-ChPX4WHl.d.mts → index-B5e2IDWU.d.mts} +1 -1
  60. package/dist/{index-CzJMCgEy.d.ts → index-CCdZxvAr.d.ts} +71 -6
  61. package/dist/{index-D8IEntil.d.mts → index-CEg_WG6y.d.mts} +71 -6
  62. package/dist/{index-Cjm-zBeZ.d.ts → index-DC5f8eoQ.d.ts} +1 -1
  63. package/dist/index.d.mts +39 -9
  64. package/dist/index.d.ts +39 -9
  65. package/dist/index.js +500 -94
  66. package/dist/index.js.map +1 -1
  67. package/dist/index.mjs +497 -94
  68. package/dist/index.mjs.map +1 -1
  69. package/dist/local-evaluator/evaluator.d.mts +2 -2
  70. package/dist/local-evaluator/evaluator.d.ts +2 -2
  71. package/dist/local-evaluator/evaluator.js +12 -2
  72. package/dist/local-evaluator/evaluator.js.map +1 -1
  73. package/dist/local-evaluator/evaluator.mjs +12 -2
  74. package/dist/local-evaluator/evaluator.mjs.map +1 -1
  75. package/dist/{nextjs-BIORS__0.d.ts → nextjs-66R1KW8e.d.ts} +1 -1
  76. package/dist/{nextjs-CjzHdaXA.d.mts → nextjs-DSpisQst.d.mts} +1 -1
  77. package/dist/{sdk-Chhz-FcT.d.mts → sdk-5U_CBRpr.d.mts} +1 -1
  78. package/dist/{sdk-CqTEQAc6.d.ts → sdk-Bm8np66n.d.ts} +1 -1
  79. package/dist/transport/index.d.mts +2 -2
  80. package/dist/transport/index.d.ts +2 -2
  81. package/dist/transport/index.js +146 -28
  82. package/dist/transport/index.js.map +1 -1
  83. package/dist/transport/index.mjs +146 -28
  84. package/dist/transport/index.mjs.map +1 -1
  85. package/dist/{types-L15pYd2c.d.mts → types-B3USs-Kx.d.mts} +42 -1
  86. package/dist/{types-L15pYd2c.d.ts → types-B3USs-Kx.d.ts} +42 -1
  87. package/dist/{types-DNK2BgIf.d.mts → types-CgDCUfo8.d.mts} +1 -1
  88. package/dist/{types-DoWIuzfj.d.ts → types-R5N4ET6x.d.ts} +1 -1
  89. package/dist/ui/index.d.mts +1 -1
  90. package/dist/ui/index.d.ts +1 -1
  91. package/package.json +1 -1
@@ -55,7 +55,14 @@ function hasMinimumAccess(actual, required) {
55
55
  }
56
56
 
57
57
  // src/version.ts
58
- var SDK_VERSION = "2.4.12";
58
+ var SDK_VERSION = "2.4.13";
59
+
60
+ // src/well-known.ts
61
+ var CACHE_TTL_MS = 60 * 60 * 1e3;
62
+ var cache = /* @__PURE__ */ new Map();
63
+ function getCachedWellKnownUrls(apiBaseUrl) {
64
+ return cache.get(apiBaseUrl)?.data;
65
+ }
59
66
 
60
67
  // src/verify.ts
61
68
  var DEFAULT_CONFIG = {
@@ -74,22 +81,27 @@ var DEFAULT_CONFIG = {
74
81
  };
75
82
  var initCheckPerformed = false;
76
83
  var deprecationWarningShown = false;
77
- async function performInitCheck(apiBaseUrl, debug) {
84
+ async function performInitCheck(apiBaseUrl, debug, strictInit) {
78
85
  initCheckPerformed = true;
79
86
  try {
80
87
  const probeUrl = `${apiBaseUrl}/agents/verify-access`;
81
88
  const response = await fetch(probeUrl, { method: "HEAD" });
82
89
  const contentType = response.headers.get("content-type") ?? "";
83
90
  if (contentType.startsWith("text/html")) {
84
- console.warn(
85
- `[VerificationGateway] apiBaseUrl '${apiBaseUrl}' returned HTML (content-type: ${contentType}). This usually means apiBaseUrl is pointing at a marketing site instead of the API. Expected: 'https://astrasync.ai/api' (prod) or 'https://staging.astrasync.ai/api' (staging). Set disableInitChecks: true on GatewayConfig to silence this warning.`
86
- );
91
+ const message = `[VerificationGateway] apiBaseUrl '${apiBaseUrl}' returned HTML (content-type: ${contentType}). This usually means apiBaseUrl is pointing at a marketing site instead of the API. Expected: 'https://astrasync.ai/api' (prod) or 'https://staging.astrasync.ai/api' (staging).`;
92
+ if (strictInit) {
93
+ throw new Error(`${message} (strictInit=true)`);
94
+ }
95
+ console.warn(`${message} Set disableInitChecks: true on GatewayConfig to silence.`);
87
96
  } else if (debug) {
88
97
  console.log(
89
98
  `[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
90
99
  );
91
100
  }
92
101
  } catch (err) {
102
+ if (strictInit) {
103
+ throw err;
104
+ }
93
105
  if (debug) {
94
106
  console.log(`[VerificationGateway] init check failed (non-blocking): ${String(err)}`);
95
107
  }
@@ -113,7 +125,23 @@ function getCacheKey(request) {
113
125
  request.counterpartyType || "",
114
126
  request.isSubAgentRequest ? "1" : "0",
115
127
  request.parentAgentId || "",
116
- request.subAgentDepth ?? ""
128
+ request.subAgentDepth ?? "",
129
+ // Audit F-A1-07: previously-missing dimensions that DO affect the
130
+ // backend verdict. Without these, two requests with different
131
+ // durations (e.g. 60s vs 86400s) collided on the same cache key and
132
+ // the shorter-duration allow served the longer-duration request.
133
+ request.durationRequired ?? "",
134
+ request.invocationProtocol || "",
135
+ request.enableRuntimeChallenge ? "1" : "0",
136
+ // callerMetadata fields contribute to risk model; include the ones
137
+ // backend reads. sourceIp/userAgent/forwardedFor change per-request
138
+ // so their inclusion effectively forces a re-check for any varying
139
+ // client (the right behavior — IP-driven anomaly scoring shouldn't
140
+ // be cached across IPs).
141
+ request.callerMetadata?.sourceIp || "",
142
+ request.callerMetadata?.userAgent || "",
143
+ request.callerMetadata?.forwardedFor || "",
144
+ request.callerMetadata?.agentCardUrl || ""
117
145
  ].join("|");
118
146
  }
119
147
  function getCachedResult(request) {
@@ -137,21 +165,22 @@ function cacheResult(request, result, configuredTtl) {
137
165
  expiresAt: Date.now() + ttlSeconds * 1e3
138
166
  });
139
167
  }
140
- function createGuidanceResponse(config, reason, options = {}) {
168
+ function createGuidanceResponse(_config, reason, options = {}) {
141
169
  const source = options.source ?? "no_credentials";
142
170
  const isApiError = source === "api_error";
171
+ const urls = options.urls;
143
172
  const guidance = isApiError ? {
144
173
  message: "Verification is temporarily unavailable. Retry with exponential backoff; if the issue persists, contact support with the correlationId.",
145
- registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/register`,
146
- documentationUrl: `${config.apiBaseUrl.replace("/api", "")}/docs/agent-access`,
174
+ registrationUrl: urls?.registrationUrl ?? "",
175
+ documentationUrl: urls?.documentationUrl ?? "",
147
176
  steps: [
148
177
  "Retry the request with exponential backoff",
149
178
  "If failures persist, share the correlationId with support"
150
179
  ]
151
180
  } : {
152
181
  message: "This service verifies AI agents before granting access. Please register your agent with AstraSync.",
153
- registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/register`,
154
- documentationUrl: `${config.apiBaseUrl.replace("/api", "")}/docs/agent-access`,
182
+ registrationUrl: urls?.registrationUrl ?? "",
183
+ documentationUrl: urls?.documentationUrl ?? "",
155
184
  steps: [
156
185
  "Register for an AstraSync account",
157
186
  "Create and register your agent",
@@ -193,7 +222,7 @@ async function callVerifyAccessAPI(config, request) {
193
222
  const { credentials, ...requestData } = request;
194
223
  const body = {
195
224
  ...credentials.astraId && { agentId: credentials.astraId },
196
- purpose: requestData.purpose || "general"
225
+ ...requestData.purpose && { purpose: requestData.purpose }
197
226
  };
198
227
  if (requestData.action) body.action = requestData.action;
199
228
  if (requestData.resourceType) body.resourceType = requestData.resourceType;
@@ -227,12 +256,8 @@ async function callVerifyAccessAPI(config, request) {
227
256
  "Content-Type": "application/json",
228
257
  ...config.customHeaders
229
258
  };
230
- if (credentials.authorizationHeader) {
231
- headers["Authorization"] = credentials.authorizationHeader;
232
- } else if (config.apiKey) {
233
- headers["Authorization"] = `Bearer ${config.apiKey}`;
234
- }
235
259
  if (config.apiKey) {
260
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
236
261
  headers["X-API-Key"] = config.apiKey;
237
262
  }
238
263
  try {
@@ -277,8 +302,13 @@ async function callVerifyAccessAPI(config, request) {
277
302
  }
278
303
  async function verify(config, request) {
279
304
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
305
+ const urls = mergedConfig.apiBaseUrl ? getCachedWellKnownUrls(mergedConfig.apiBaseUrl) : void 0;
280
306
  if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
281
- void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug);
307
+ if (mergedConfig.strictInit) {
308
+ await performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, true);
309
+ } else {
310
+ void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug, false);
311
+ }
282
312
  }
283
313
  if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
284
314
  deprecationWarningShown = true;
@@ -309,7 +339,8 @@ async function verify(config, request) {
309
339
  if (!apiResponse.success) {
310
340
  return createGuidanceResponse(mergedConfig, apiResponse.error, {
311
341
  source: "api_error",
312
- correlationId: apiResponse.correlationId
342
+ correlationId: apiResponse.correlationId,
343
+ urls
313
344
  });
314
345
  }
315
346
  if (!apiResponse.access?.allowed) {
@@ -332,8 +363,8 @@ async function verify(config, request) {
332
363
  requiresApproval: apiResponse.access?.requiresApproval,
333
364
  guidance: {
334
365
  message: apiResponse.access?.reason || "Access denied by PDLSS policy",
335
- registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/register`,
336
- documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/pdlss`
366
+ registrationUrl: urls?.registrationUrl ?? "",
367
+ documentationUrl: urls?.documentationUrl ?? ""
337
368
  },
338
369
  verifiedAt: /* @__PURE__ */ new Date(),
339
370
  // Extract sessionId so decisions can be recorded for denials too
@@ -402,13 +433,15 @@ async function verify(config, request) {
402
433
  result.denialReasons = result.recommendationReasons || [
403
434
  "Access denied by AstraSync recommendation"
404
435
  ];
405
- if (result.runtimeChallenge) {
406
- result.guidance = {
407
- message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
408
- registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/register`,
409
- documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/runtime-challenge`
410
- };
411
- }
436
+ result.guidance = result.runtimeChallenge ? {
437
+ message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
438
+ registrationUrl: urls?.registrationUrl ?? "",
439
+ documentationUrl: urls?.documentationUrl ?? ""
440
+ } : {
441
+ message: result.recommendationReasons?.[0] || "Access denied by AstraSync recommendation",
442
+ registrationUrl: urls?.registrationUrl ?? "",
443
+ documentationUrl: urls?.documentationUrl ?? ""
444
+ };
412
445
  } else if (result.recommendation === "step_up_required") {
413
446
  result.requiresStepUp = true;
414
447
  if (ACCESS_LEVEL_HIERARCHY[result.accessLevel] > ACCESS_LEVEL_HIERARCHY["read-only"]) {
@@ -538,6 +571,18 @@ function performCounterpartyPreCheck(routeConfig, astraCreds, purpose) {
538
571
  }
539
572
 
540
573
  // src/adapters/nextjs.ts
574
+ function escapeHtml(value) {
575
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
576
+ }
577
+ function sanitizeUrl(value, fallback) {
578
+ if (typeof value !== "string" || value.length === 0) return escapeHtml(fallback);
579
+ const trimmed = value.trim();
580
+ if (/^javascript:|^data:|^vbscript:/i.test(trimmed)) return escapeHtml(fallback);
581
+ if (/^https?:\/\//i.test(trimmed) || trimmed.startsWith("/")) {
582
+ return escapeHtml(trimmed);
583
+ }
584
+ return escapeHtml(fallback);
585
+ }
541
586
  function extractCredentialsFromNextRequest(request) {
542
587
  const credentials = {};
543
588
  const astraId = request.headers.get("x-astra-id") || request.headers.get("X-Astra-Id");
@@ -609,10 +654,18 @@ function extractPurpose(request) {
609
654
  }
610
655
  }
611
656
  function generateCommerceShieldHtml(result, options) {
612
- const title = options.commerceShield?.title || "AstraSync Agent Verification";
613
- const message = options.commerceShield?.message || result.guidance?.message || "This site verifies AI agents before granting access. We noticed you're visiting without AstraSync credentials.";
614
- const registrationUrl = result.guidance?.registrationUrl || "https://astrasync.ai/register";
615
- const docsUrl = result.guidance?.documentationUrl || "https://astrasync.ai/docs/agent-access";
657
+ const title = escapeHtml(options.commerceShield?.title || "AstraSync Agent Verification");
658
+ const message = escapeHtml(
659
+ options.commerceShield?.message || result.guidance?.message || "This site verifies AI agents before granting access. We noticed you're visiting without AstraSync credentials."
660
+ );
661
+ const registrationUrl = sanitizeUrl(
662
+ result.guidance?.registrationUrl,
663
+ "https://astrasync.ai/register"
664
+ );
665
+ const docsUrl = sanitizeUrl(
666
+ result.guidance?.documentationUrl,
667
+ "https://astrasync.ai/docs/agent-access"
668
+ );
616
669
  const allowGuest = options.commerceShield?.allowGuestAccess ?? true;
617
670
  return `
618
671
  <!DOCTYPE html>
@@ -734,7 +787,7 @@ function generateCommerceShieldHtml(result, options) {
734
787
  <div class="shield-steps">
735
788
  <h3>To get verified access:</h3>
736
789
  <ol>
737
- <li>Register at <a href="${registrationUrl}">astrasync.ai/register</a></li>
790
+ <li>Register at <a href="${registrationUrl}">astrasync.ai/agents/register</a></li>
738
791
  <li>Create and register your agent</li>
739
792
  <li>Add your ASTRA-ID to request headers</li>
740
793
  <li>Refresh this page</li>
@@ -822,7 +875,7 @@ function createMiddleware(options) {
822
875
  denialReasons: preCheckFailures.map((f) => f.message),
823
876
  guidance: {
824
877
  message: "Request exceeds counterparty-defined PDLSS limits.",
825
- registrationUrl: `${config.apiBaseUrl?.replace("/api", "")}/register`,
878
+ registrationUrl: `${config.apiBaseUrl?.replace("/api", "")}/agents/register`,
826
879
  documentationUrl: `${config.apiBaseUrl?.replace("/api", "")}/docs/pdlss`
827
880
  },
828
881
  verifiedAt: /* @__PURE__ */ new Date()