@astrasyncai/verification-gateway 2.1.0 → 2.2.3

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 (84) hide show
  1. package/README.md +64 -30
  2. package/dist/adapter-interface/interface.d.mts +2 -2
  3. package/dist/adapter-interface/interface.d.ts +2 -2
  4. package/dist/adapters/express.d.mts +2 -2
  5. package/dist/adapters/express.d.ts +2 -2
  6. package/dist/adapters/express.js +74 -95
  7. package/dist/adapters/express.js.map +1 -1
  8. package/dist/adapters/express.mjs +74 -95
  9. package/dist/adapters/express.mjs.map +1 -1
  10. package/dist/adapters/nextjs.d.mts +2 -2
  11. package/dist/adapters/nextjs.d.ts +2 -2
  12. package/dist/adapters/nextjs.js +74 -115
  13. package/dist/adapters/nextjs.js.map +1 -1
  14. package/dist/adapters/nextjs.mjs +74 -115
  15. package/dist/adapters/nextjs.mjs.map +1 -1
  16. package/dist/adapters/sdk.d.mts +2 -2
  17. package/dist/adapters/sdk.d.ts +2 -2
  18. package/dist/adapters/sdk.js +56 -55
  19. package/dist/adapters/sdk.js.map +1 -1
  20. package/dist/adapters/sdk.mjs +56 -55
  21. package/dist/adapters/sdk.mjs.map +1 -1
  22. package/dist/agent/index.d.mts +2 -2
  23. package/dist/agent/index.d.ts +2 -2
  24. package/dist/agent/index.js +68 -2
  25. package/dist/agent/index.js.map +1 -1
  26. package/dist/agent/index.mjs +66 -2
  27. package/dist/agent/index.mjs.map +1 -1
  28. package/dist/browser/background.js +56 -55
  29. package/dist/browser/background.js.map +1 -1
  30. package/dist/browser/background.mjs +56 -55
  31. package/dist/browser/background.mjs.map +1 -1
  32. package/dist/browser/browser-adapter.d.mts +2 -2
  33. package/dist/browser/browser-adapter.d.ts +2 -2
  34. package/dist/cli/index.d.mts +2 -2
  35. package/dist/cli/index.d.ts +2 -2
  36. package/dist/cursor/cursor-adapter.d.mts +2 -2
  37. package/dist/cursor/cursor-adapter.d.ts +2 -2
  38. package/dist/cursor/extension.d.mts +2 -2
  39. package/dist/cursor/extension.d.ts +2 -2
  40. package/dist/cursor/extension.js +56 -55
  41. package/dist/cursor/extension.js.map +1 -1
  42. package/dist/cursor/extension.mjs +56 -55
  43. package/dist/cursor/extension.mjs.map +1 -1
  44. package/dist/{express-Bcl-uBUE.d.ts → express-BtKlLI8U.d.ts} +2 -2
  45. package/dist/{express-CtwDIZyF.d.mts → express-DgwpS8Ha.d.mts} +2 -2
  46. package/dist/gateway/gateway.d.mts +2 -2
  47. package/dist/gateway/gateway.d.ts +2 -2
  48. package/dist/gateway/gateway.js +56 -55
  49. package/dist/gateway/gateway.js.map +1 -1
  50. package/dist/gateway/gateway.mjs +56 -55
  51. package/dist/gateway/gateway.mjs.map +1 -1
  52. package/dist/git-trigger/git-hooks.d.mts +2 -2
  53. package/dist/git-trigger/git-hooks.d.ts +2 -2
  54. package/dist/{index-BY8yQ8N8.d.mts → index-AzhK20t0.d.mts} +46 -3
  55. package/dist/{index-CME6r4uH.d.ts → index-Ba0Lvsjo.d.ts} +1 -1
  56. package/dist/{index-3NRaBNvp.d.mts → index-BaxpmTGA.d.mts} +1 -1
  57. package/dist/{index-CtYSYwn3.d.ts → index-DpJS1JEI.d.ts} +46 -3
  58. package/dist/index.d.mts +7 -7
  59. package/dist/index.d.ts +7 -7
  60. package/dist/index.js +158 -117
  61. package/dist/index.js.map +1 -1
  62. package/dist/index.mjs +158 -117
  63. package/dist/index.mjs.map +1 -1
  64. package/dist/local-evaluator/evaluator.d.mts +2 -2
  65. package/dist/local-evaluator/evaluator.d.ts +2 -2
  66. package/dist/{nextjs-CEldnIJ9.d.ts → nextjs-B2kg19c1.d.ts} +1 -1
  67. package/dist/{nextjs-BQyMCSx_.d.mts → nextjs-ZymQ8jDh.d.mts} +1 -1
  68. package/dist/{sdk-BhvuJSrH.d.mts → sdk-B7id0VFS.d.mts} +2 -2
  69. package/dist/{sdk-BlyVSC_S.d.ts → sdk-Bso0FSI0.d.ts} +2 -2
  70. package/dist/transport/index.d.mts +2 -2
  71. package/dist/transport/index.d.ts +2 -2
  72. package/dist/{types-79qS7aON.d.ts → types-BYKAY6Cc.d.ts} +1 -1
  73. package/dist/{types-jJnPXStc.d.mts → types-CgXPKUwi.d.mts} +1 -1
  74. package/dist/{types-CxQwJKbd.d.mts → types-DOrqNMgy.d.mts} +79 -13
  75. package/dist/{types-CxQwJKbd.d.ts → types-DOrqNMgy.d.ts} +79 -13
  76. package/dist/ui/index.d.mts +1 -1
  77. package/dist/ui/index.d.ts +1 -1
  78. package/dist/webhooks.d.mts +59 -0
  79. package/dist/webhooks.d.ts +59 -0
  80. package/dist/webhooks.js +81 -0
  81. package/dist/webhooks.js.map +1 -0
  82. package/dist/webhooks.mjs +55 -0
  83. package/dist/webhooks.mjs.map +1 -0
  84. package/package.json +8 -3
package/dist/index.js CHANGED
@@ -179,14 +179,36 @@ function getCapabilities(accessLevel) {
179
179
 
180
180
  // src/verify.ts
181
181
  var DEFAULT_CONFIG = {
182
- apiBaseUrl: "https://api.astrasync.ai",
182
+ apiBaseUrl: "https://astrasync.ai/api",
183
183
  defaultAccessLevel: "guidance",
184
- minTrustScore: 40,
185
- minTrustScoreForFull: 70,
184
+ // minTrustScore + minTrustScoreForFull deprecated in v2.3.0 — server decides.
186
185
  cacheTtl: 300,
187
186
  // 5 minutes
188
187
  debug: false
189
188
  };
189
+ var initCheckPerformed = false;
190
+ var deprecationWarningShown = false;
191
+ async function performInitCheck(apiBaseUrl, debug) {
192
+ initCheckPerformed = true;
193
+ try {
194
+ const probeUrl = `${apiBaseUrl}/agents/verify-access`;
195
+ const response = await fetch(probeUrl, { method: "HEAD" });
196
+ const contentType = response.headers.get("content-type") ?? "";
197
+ if (contentType.startsWith("text/html")) {
198
+ console.warn(
199
+ `[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.`
200
+ );
201
+ } else if (debug) {
202
+ console.log(
203
+ `[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
204
+ );
205
+ }
206
+ } catch (err) {
207
+ if (debug) {
208
+ console.log(`[VerificationGateway] init check failed (non-blocking): ${String(err)}`);
209
+ }
210
+ }
211
+ }
190
212
  var verificationCache = /* @__PURE__ */ new Map();
191
213
  function getCacheKey(credentials) {
192
214
  return `${credentials.astraId || ""}-${credentials.apiKey || ""}-${credentials.jwt || ""}`;
@@ -214,7 +236,7 @@ function clearCache() {
214
236
  }
215
237
  function extractCredentials(headers, query) {
216
238
  const credentials = {};
217
- const astraIdHeader = headers["x-astra-id"] || headers["X-Astra-Id"] || headers["X-ASTRA-ID"];
239
+ const astraIdHeader = headers["x-astra-id"] || headers["X-Astra-Id"] || headers["X-ASTRA-ID"] || headers["x-astra-agentid"] || headers["X-Astra-AgentId"] || headers["x-astra-agent-id"] || headers["X-Astra-Agent-Id"] || headers["X-ASTRA-AGENT-ID"];
218
240
  if (astraIdHeader) {
219
241
  credentials.astraId = Array.isArray(astraIdHeader) ? astraIdHeader[0] : astraIdHeader;
220
242
  }
@@ -266,7 +288,7 @@ function createGuidanceResponse(config, reason) {
266
288
  async function callVerifyAccessAPI(config, request) {
267
289
  const { credentials, ...requestData } = request;
268
290
  const body = {
269
- agentId: credentials.astraId,
291
+ ...credentials.astraId && { agentId: credentials.astraId },
270
292
  purpose: requestData.purpose || "general"
271
293
  };
272
294
  if (requestData.action) body.action = requestData.action;
@@ -278,21 +300,34 @@ async function callVerifyAccessAPI(config, request) {
278
300
  if (requestData.isSubAgentRequest) body.isSubAgentRequest = requestData.isSubAgentRequest;
279
301
  if (requestData.parentAgentId) body.parentAgentId = requestData.parentAgentId;
280
302
  if (requestData.subAgentDepth !== void 0) body.subAgentDepth = requestData.subAgentDepth;
281
- if (requestData.enableRuntimeChallenge) body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
303
+ if (requestData.enableRuntimeChallenge)
304
+ body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
282
305
  if (requestData.createSession) body.createSession = requestData.createSession;
283
306
  if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;
284
307
  if (requestData.counterpartyType) body.counterpartyType = requestData.counterpartyType;
285
308
  if (requestData.counterpartyUrl) body.counterpartyUrl = requestData.counterpartyUrl;
286
- if (requestData.runtimeChallengeOptions) body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
309
+ if (config.counterpartyId) body.counterpartyId = config.counterpartyId;
310
+ if (requestData.runtimeChallengeOptions)
311
+ body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
312
+ if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
313
+ const meta = {
314
+ ...requestData.clientIp && { sourceIp: requestData.clientIp },
315
+ ...requestData.userAgent && { userAgent: requestData.userAgent },
316
+ ...requestData.callerMetadata
317
+ };
318
+ if (Object.keys(meta).length > 0) body.callerMetadata = meta;
319
+ }
287
320
  const headers = {
288
321
  "Content-Type": "application/json",
289
322
  ...config.customHeaders
290
323
  };
291
- if (config.apiKey) {
292
- headers["X-API-Key"] = config.apiKey;
293
- }
294
324
  if (credentials.authorizationHeader) {
295
325
  headers["Authorization"] = credentials.authorizationHeader;
326
+ } else if (config.apiKey) {
327
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
328
+ }
329
+ if (config.apiKey) {
330
+ headers["X-API-Key"] = config.apiKey;
296
331
  }
297
332
  try {
298
333
  const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
@@ -318,8 +353,14 @@ async function callVerifyAccessAPI(config, request) {
318
353
  }
319
354
  async function verify(config, request) {
320
355
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
321
- if (!hasCredentials(request.credentials)) {
322
- return createGuidanceResponse(mergedConfig, "No agent credentials provided");
356
+ if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
357
+ void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug);
358
+ }
359
+ if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
360
+ deprecationWarningShown = true;
361
+ console.warn(
362
+ "[VerificationGateway] minTrustScore / minTrustScoreForFull are deprecated in v2.3.0 and have no effect. Server is now the single source of truth for access-level decisions (the SDK reads access.accessLevel from the verify-access response). To gate access to an endpoint, configure the endpoint's trust_score_requirement server-side."
363
+ );
323
364
  }
324
365
  if (mergedConfig.cacheTtl && mergedConfig.cacheTtl > 0) {
325
366
  const cached = getCachedResult(request.credentials);
@@ -391,18 +432,7 @@ async function verify(config, request) {
391
432
  selfInstantiationAllowed: apiResponse.access.pdlss.selfInstantiationAllowed,
392
433
  appliedPolicy: apiResponse.access.appliedPolicy
393
434
  } : void 0;
394
- const trustScore = agent?.trustScore || 0;
395
- const isOrgMember = false;
396
- const accessLevel = determineAccessLevel(
397
- true,
398
- trustScore,
399
- isOrgMember,
400
- {
401
- "read-only": 20,
402
- standard: mergedConfig.minTrustScore || 40,
403
- full: mergedConfig.minTrustScoreForFull || 70
404
- }
405
- );
435
+ const accessLevel = apiResponse.access?.accessLevel ?? "standard";
406
436
  const result = {
407
437
  verified: true,
408
438
  accessLevel,
@@ -424,7 +454,9 @@ async function verify(config, request) {
424
454
  if (result.recommendation === "deny") {
425
455
  result.verified = false;
426
456
  result.accessLevel = "none";
427
- result.denialReasons = result.recommendationReasons || ["Access denied by AstraSync recommendation"];
457
+ result.denialReasons = result.recommendationReasons || [
458
+ "Access denied by AstraSync recommendation"
459
+ ];
428
460
  if (result.runtimeChallenge) {
429
461
  result.guidance = {
430
462
  message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
@@ -446,7 +478,10 @@ async function verify(config, request) {
446
478
  }
447
479
  async function recordDecision(config, sessionId, decision, reason) {
448
480
  const headers = { "Content-Type": "application/json" };
449
- if (config.apiKey) headers["X-API-Key"] = config.apiKey;
481
+ if (config.apiKey) {
482
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
483
+ headers["X-API-Key"] = config.apiKey;
484
+ }
450
485
  await fetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
451
486
  method: "POST",
452
487
  headers,
@@ -454,15 +489,6 @@ async function recordDecision(config, sessionId, decision, reason) {
454
489
  }).catch(() => {
455
490
  });
456
491
  }
457
- async function reportUnregisteredAttempt(config, data) {
458
- const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
459
- await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
460
- method: "POST",
461
- headers: { "Content-Type": "application/json" },
462
- body: JSON.stringify(data)
463
- }).catch(() => {
464
- });
465
- }
466
492
  async function reportCounterpartyPreCheckFailure(config, data) {
467
493
  const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
468
494
  await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
@@ -688,32 +714,6 @@ function createMiddleware(options) {
688
714
  return next();
689
715
  }
690
716
  const credentials = customExtractCredentials ? customExtractCredentials(req) : defaultExtractCredentials(req);
691
- if (!hasCredentials(credentials) && routeConfig.minAccessLevel !== "guidance") {
692
- const counterpartyUrl2 = config.counterpartyUrl || `${req.protocol}://${req.get("host")}`;
693
- reportUnregisteredAttempt(config, {
694
- counterpartyUrl: counterpartyUrl2,
695
- counterpartyType: config.counterpartyType || "api",
696
- sourceIp: req.ip,
697
- userAgent: req.headers["user-agent"],
698
- requestPath: req.path,
699
- requestMethod: req.method
700
- }).catch(() => {
701
- });
702
- const result2 = {
703
- verified: false,
704
- accessLevel: "none",
705
- denialReasons: ["No agent credentials provided"],
706
- guidance: {
707
- message: "This endpoint requires agent verification. Please provide your ASTRA-ID.",
708
- registrationUrl: `${config.apiBaseUrl?.replace("/api", "")}/register`,
709
- documentationUrl: `${config.apiBaseUrl?.replace("/api", "")}/docs/agent-access`
710
- },
711
- verifiedAt: /* @__PURE__ */ new Date()
712
- };
713
- req.agentVerification = result2;
714
- onDenied(result2, req, res);
715
- return;
716
- }
717
717
  const purpose = customExtractPurpose ? customExtractPurpose(req) : defaultExtractPurpose(req);
718
718
  const astraCreds = extractAstraSyncCredentials(req);
719
719
  const counterpartyUrl = config.counterpartyUrl || `${req.protocol}://${req.get("host")}`;
@@ -744,18 +744,28 @@ function createMiddleware(options) {
744
744
  return;
745
745
  }
746
746
  const shouldRecordDecisions = recordDecisions !== false;
747
+ const forwardedFor = req.headers["x-forwarded-for"];
748
+ const forwardedForStr = Array.isArray(forwardedFor) ? forwardedFor.join(", ") : forwardedFor;
749
+ const originalClientIp = forwardedForStr ? forwardedForStr.split(",")[0].trim() : req.ip;
750
+ const agentCardUrl = typeof req.headers["x-astrasync-agent-card"] === "string" ? req.headers["x-astrasync-agent-card"] : void 0;
747
751
  const result = await verify(config, {
748
752
  credentials,
749
753
  purpose,
750
754
  action: req.method.toLowerCase(),
751
755
  resource: req.path,
752
- clientIp: req.ip,
753
- userAgent: req.headers["user-agent"],
754
756
  createSession: shouldRecordDecisions,
755
757
  counterpartyUrl,
756
758
  counterpartyType: config.counterpartyType || "api",
757
759
  enableRuntimeChallenge,
758
- durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration
760
+ durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,
761
+ callerMetadata: {
762
+ sourceIp: originalClientIp,
763
+ userAgent: req.headers["user-agent"],
764
+ referer: req.headers.referer,
765
+ host: req.headers.host,
766
+ forwardedFor: forwardedForStr,
767
+ agentCardUrl
768
+ }
759
769
  });
760
770
  req.agentVerification = result;
761
771
  const sessionId = result.sessionId;
@@ -1027,7 +1037,13 @@ function generateCommerceShieldHtml(result, options) {
1027
1037
  `.trim();
1028
1038
  }
1029
1039
  function createMiddleware2(options) {
1030
- const { routes = [], skipPaths = [], showCommerceShield = true, enableRuntimeChallenge = true, ...config } = options;
1040
+ const {
1041
+ routes = [],
1042
+ skipPaths = [],
1043
+ showCommerceShield = true,
1044
+ enableRuntimeChallenge = true,
1045
+ ...config
1046
+ } = options;
1031
1047
  return async function middleware(request) {
1032
1048
  const { NextResponse } = await import("next/server");
1033
1049
  const pathname = request.nextUrl.pathname;
@@ -1043,53 +1059,6 @@ function createMiddleware2(options) {
1043
1059
  return NextResponse.next();
1044
1060
  }
1045
1061
  const credentials = extractCredentialsFromNextRequest(request);
1046
- if (!hasCredentials(credentials) && routeConfig.minAccessLevel !== "guidance") {
1047
- const counterpartyUrl2 = config.counterpartyUrl || request.nextUrl.origin;
1048
- reportUnregisteredAttempt(config, {
1049
- counterpartyUrl: counterpartyUrl2,
1050
- counterpartyType: config.counterpartyType || "website",
1051
- sourceIp: request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || void 0,
1052
- userAgent: request.headers.get("user-agent") || void 0,
1053
- requestPath: pathname,
1054
- requestMethod: request.method
1055
- }).catch(() => {
1056
- });
1057
- const result2 = {
1058
- verified: false,
1059
- accessLevel: "none",
1060
- denialReasons: ["No agent credentials provided"],
1061
- guidance: {
1062
- message: "This page requires agent verification.",
1063
- registrationUrl: `${config.apiBaseUrl?.replace("/api", "")}/register`,
1064
- documentationUrl: `${config.apiBaseUrl?.replace("/api", "")}/docs/agent-access`
1065
- },
1066
- verifiedAt: /* @__PURE__ */ new Date()
1067
- };
1068
- if (pathname.startsWith("/api/")) {
1069
- return NextResponse.json(
1070
- {
1071
- success: false,
1072
- error: {
1073
- code: "UNAUTHORIZED",
1074
- message: "No agent credentials provided",
1075
- guidance: result2.guidance
1076
- }
1077
- },
1078
- { status: 401 }
1079
- );
1080
- }
1081
- if (showCommerceShield) {
1082
- return new NextResponse(generateCommerceShieldHtml(result2, options), {
1083
- status: 200,
1084
- headers: {
1085
- "Content-Type": "text/html",
1086
- "X-AstraSync-Verification": "commerce-shield"
1087
- }
1088
- });
1089
- }
1090
- const registerUrl = result2.guidance?.registrationUrl || "/register";
1091
- return NextResponse.redirect(new URL(registerUrl, request.url));
1092
- }
1093
1062
  const counterpartyUrl = config.counterpartyUrl || request.nextUrl.origin;
1094
1063
  const purpose = extractPurpose(request);
1095
1064
  const astraCreds = extractAstraSyncCredentialsFromNextRequest(request);
@@ -1139,17 +1108,25 @@ function createMiddleware2(options) {
1139
1108
  }
1140
1109
  return NextResponse.redirect(new URL("/unauthorized", request.url));
1141
1110
  }
1111
+ const forwardedFor = request.headers.get("x-forwarded-for") || void 0;
1112
+ const originalClientIp = forwardedFor?.split(",")[0]?.trim();
1142
1113
  const result = await verify(config, {
1143
1114
  credentials,
1144
1115
  purpose,
1145
1116
  action: request.method.toLowerCase(),
1146
1117
  resource: pathname,
1147
- clientIp: request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || void 0,
1148
- userAgent: request.headers.get("user-agent") || void 0,
1149
1118
  counterpartyUrl,
1150
1119
  counterpartyType: config.counterpartyType || "website",
1151
1120
  enableRuntimeChallenge,
1152
- durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration
1121
+ durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,
1122
+ callerMetadata: {
1123
+ sourceIp: originalClientIp,
1124
+ userAgent: request.headers.get("user-agent") || void 0,
1125
+ referer: request.headers.get("referer") || void 0,
1126
+ host: request.headers.get("host") || void 0,
1127
+ forwardedFor,
1128
+ agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0
1129
+ }
1153
1130
  });
1154
1131
  if (!hasMinimumAccess(result.accessLevel, routeConfig.minAccessLevel)) {
1155
1132
  if (pathname.startsWith("/api/")) {
@@ -3771,21 +3748,85 @@ function extractCredentialsFromProtocol(protocol, context) {
3771
3748
  var agent_exports = {};
3772
3749
  __export(agent_exports, {
3773
3750
  AgentClient: () => AgentClient,
3751
+ AstraSyncSdkError: () => AstraSyncSdkError,
3774
3752
  ChallengeHandler: () => ChallengeHandler,
3753
+ OwnershipMismatchError: () => OwnershipMismatchError,
3775
3754
  formatPDLSSForTransport: () => formatPDLSSForTransport,
3776
3755
  parsePDLSSFromTransport: () => parsePDLSSFromTransport,
3777
3756
  recordDecision: () => recordDecision2
3778
3757
  });
3779
3758
 
3759
+ // src/agent/errors.ts
3760
+ var AstraSyncSdkError = class extends Error {
3761
+ constructor(code, message) {
3762
+ super(message);
3763
+ this.name = "AstraSyncSdkError";
3764
+ this.code = code;
3765
+ }
3766
+ };
3767
+ var OwnershipMismatchError = class extends AstraSyncSdkError {
3768
+ constructor(astraId) {
3769
+ super(
3770
+ "ownership_mismatch",
3771
+ `The configured API key does not own agent ${astraId}. Refusing to initialise.`
3772
+ );
3773
+ this.name = "OwnershipMismatchError";
3774
+ this.astraId = astraId;
3775
+ }
3776
+ };
3777
+
3780
3778
  // src/agent/client.ts
3781
- var AgentClient = class {
3779
+ var AgentClient = class _AgentClient {
3782
3780
  constructor(config) {
3783
3781
  this.credentials = {
3784
3782
  agentId: config.agentId,
3785
- verifyUrl: config.verifyUrl ?? "https://api.astrasync.ai/agents/verify-access",
3783
+ verifyUrl: config.verifyUrl ?? "https://astrasync.ai/api/agents/verify-access",
3786
3784
  challengeUrl: config.challengeUrl,
3787
3785
  pdlss: config.pdlss
3788
3786
  };
3787
+ this.apiBaseUrl = config.apiBaseUrl ?? "https://astrasync.ai/api";
3788
+ this.apiKey = config.apiKey;
3789
+ }
3790
+ /**
3791
+ * Async factory that validates the API key's account owns the configured
3792
+ * ASTRA-id before returning a usable client. Refuses to initialise on
3793
+ * mismatch so a stolen ASTRA-id cannot be paired with a valid (different)
3794
+ * API key.
3795
+ *
3796
+ * Set env `ASTRASYNC_SKIP_OWNERSHIP_CHECK=true` to bypass — intended for
3797
+ * test environments only.
3798
+ */
3799
+ static async create(config) {
3800
+ const client = new _AgentClient(config);
3801
+ const skip = typeof process !== "undefined" && process.env?.ASTRASYNC_SKIP_OWNERSHIP_CHECK === "true";
3802
+ if (skip) return client;
3803
+ if (!config.apiKey) {
3804
+ throw new OwnershipMismatchError(config.agentId);
3805
+ }
3806
+ const owned = await client.verifyOwnership();
3807
+ if (!owned) throw new OwnershipMismatchError(config.agentId);
3808
+ return client;
3809
+ }
3810
+ /**
3811
+ * Calls GET /api/agents/:astraId/ownership with the configured API key.
3812
+ * Returns true only when the backend confirms this API key's account
3813
+ * owns the configured agent.
3814
+ */
3815
+ async verifyOwnership() {
3816
+ if (!this.apiKey) return false;
3817
+ const url = `${this.apiBaseUrl.replace(/\/+$/, "")}/api/agents/${encodeURIComponent(
3818
+ this.credentials.agentId
3819
+ )}/ownership`;
3820
+ const resp = await fetch(url, {
3821
+ method: "GET",
3822
+ headers: {
3823
+ Authorization: `Bearer ${this.apiKey}`,
3824
+ "Content-Type": "application/json"
3825
+ }
3826
+ });
3827
+ if (!resp.ok) return false;
3828
+ const body = await resp.json().catch(() => null);
3829
+ return Boolean(body?.data?.owned);
3789
3830
  }
3790
3831
  /**
3791
3832
  * Make an HTTP request with AstraSync headers automatically injected.