@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.mjs CHANGED
@@ -127,14 +127,36 @@ function getCapabilities(accessLevel) {
127
127
 
128
128
  // src/verify.ts
129
129
  var DEFAULT_CONFIG = {
130
- apiBaseUrl: "https://api.astrasync.ai",
130
+ apiBaseUrl: "https://astrasync.ai/api",
131
131
  defaultAccessLevel: "guidance",
132
- minTrustScore: 40,
133
- minTrustScoreForFull: 70,
132
+ // minTrustScore + minTrustScoreForFull deprecated in v2.3.0 — server decides.
134
133
  cacheTtl: 300,
135
134
  // 5 minutes
136
135
  debug: false
137
136
  };
137
+ var initCheckPerformed = false;
138
+ var deprecationWarningShown = false;
139
+ async function performInitCheck(apiBaseUrl, debug) {
140
+ initCheckPerformed = true;
141
+ try {
142
+ const probeUrl = `${apiBaseUrl}/agents/verify-access`;
143
+ const response = await fetch(probeUrl, { method: "HEAD" });
144
+ const contentType = response.headers.get("content-type") ?? "";
145
+ if (contentType.startsWith("text/html")) {
146
+ console.warn(
147
+ `[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.`
148
+ );
149
+ } else if (debug) {
150
+ console.log(
151
+ `[VerificationGateway] init check passed for ${apiBaseUrl} (content-type: ${contentType})`
152
+ );
153
+ }
154
+ } catch (err) {
155
+ if (debug) {
156
+ console.log(`[VerificationGateway] init check failed (non-blocking): ${String(err)}`);
157
+ }
158
+ }
159
+ }
138
160
  var verificationCache = /* @__PURE__ */ new Map();
139
161
  function getCacheKey(credentials) {
140
162
  return `${credentials.astraId || ""}-${credentials.apiKey || ""}-${credentials.jwt || ""}`;
@@ -162,7 +184,7 @@ function clearCache() {
162
184
  }
163
185
  function extractCredentials(headers, query) {
164
186
  const credentials = {};
165
- const astraIdHeader = headers["x-astra-id"] || headers["X-Astra-Id"] || headers["X-ASTRA-ID"];
187
+ 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"];
166
188
  if (astraIdHeader) {
167
189
  credentials.astraId = Array.isArray(astraIdHeader) ? astraIdHeader[0] : astraIdHeader;
168
190
  }
@@ -214,7 +236,7 @@ function createGuidanceResponse(config, reason) {
214
236
  async function callVerifyAccessAPI(config, request) {
215
237
  const { credentials, ...requestData } = request;
216
238
  const body = {
217
- agentId: credentials.astraId,
239
+ ...credentials.astraId && { agentId: credentials.astraId },
218
240
  purpose: requestData.purpose || "general"
219
241
  };
220
242
  if (requestData.action) body.action = requestData.action;
@@ -226,21 +248,34 @@ async function callVerifyAccessAPI(config, request) {
226
248
  if (requestData.isSubAgentRequest) body.isSubAgentRequest = requestData.isSubAgentRequest;
227
249
  if (requestData.parentAgentId) body.parentAgentId = requestData.parentAgentId;
228
250
  if (requestData.subAgentDepth !== void 0) body.subAgentDepth = requestData.subAgentDepth;
229
- if (requestData.enableRuntimeChallenge) body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
251
+ if (requestData.enableRuntimeChallenge)
252
+ body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
230
253
  if (requestData.createSession) body.createSession = requestData.createSession;
231
254
  if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;
232
255
  if (requestData.counterpartyType) body.counterpartyType = requestData.counterpartyType;
233
256
  if (requestData.counterpartyUrl) body.counterpartyUrl = requestData.counterpartyUrl;
234
- if (requestData.runtimeChallengeOptions) body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
257
+ if (config.counterpartyId) body.counterpartyId = config.counterpartyId;
258
+ if (requestData.runtimeChallengeOptions)
259
+ body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
260
+ if (requestData.callerMetadata || requestData.clientIp || requestData.userAgent) {
261
+ const meta = {
262
+ ...requestData.clientIp && { sourceIp: requestData.clientIp },
263
+ ...requestData.userAgent && { userAgent: requestData.userAgent },
264
+ ...requestData.callerMetadata
265
+ };
266
+ if (Object.keys(meta).length > 0) body.callerMetadata = meta;
267
+ }
235
268
  const headers = {
236
269
  "Content-Type": "application/json",
237
270
  ...config.customHeaders
238
271
  };
239
- if (config.apiKey) {
240
- headers["X-API-Key"] = config.apiKey;
241
- }
242
272
  if (credentials.authorizationHeader) {
243
273
  headers["Authorization"] = credentials.authorizationHeader;
274
+ } else if (config.apiKey) {
275
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
276
+ }
277
+ if (config.apiKey) {
278
+ headers["X-API-Key"] = config.apiKey;
244
279
  }
245
280
  try {
246
281
  const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
@@ -266,8 +301,14 @@ async function callVerifyAccessAPI(config, request) {
266
301
  }
267
302
  async function verify(config, request) {
268
303
  const mergedConfig = { ...DEFAULT_CONFIG, ...config };
269
- if (!hasCredentials(request.credentials)) {
270
- return createGuidanceResponse(mergedConfig, "No agent credentials provided");
304
+ if (!initCheckPerformed && !mergedConfig.disableInitChecks && mergedConfig.apiBaseUrl) {
305
+ void performInitCheck(mergedConfig.apiBaseUrl, mergedConfig.debug);
306
+ }
307
+ if (!deprecationWarningShown && (config.minTrustScore !== void 0 || config.minTrustScoreForFull !== void 0)) {
308
+ deprecationWarningShown = true;
309
+ console.warn(
310
+ "[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."
311
+ );
271
312
  }
272
313
  if (mergedConfig.cacheTtl && mergedConfig.cacheTtl > 0) {
273
314
  const cached = getCachedResult(request.credentials);
@@ -339,18 +380,7 @@ async function verify(config, request) {
339
380
  selfInstantiationAllowed: apiResponse.access.pdlss.selfInstantiationAllowed,
340
381
  appliedPolicy: apiResponse.access.appliedPolicy
341
382
  } : void 0;
342
- const trustScore = agent?.trustScore || 0;
343
- const isOrgMember = false;
344
- const accessLevel = determineAccessLevel(
345
- true,
346
- trustScore,
347
- isOrgMember,
348
- {
349
- "read-only": 20,
350
- standard: mergedConfig.minTrustScore || 40,
351
- full: mergedConfig.minTrustScoreForFull || 70
352
- }
353
- );
383
+ const accessLevel = apiResponse.access?.accessLevel ?? "standard";
354
384
  const result = {
355
385
  verified: true,
356
386
  accessLevel,
@@ -372,7 +402,9 @@ async function verify(config, request) {
372
402
  if (result.recommendation === "deny") {
373
403
  result.verified = false;
374
404
  result.accessLevel = "none";
375
- result.denialReasons = result.recommendationReasons || ["Access denied by AstraSync recommendation"];
405
+ result.denialReasons = result.recommendationReasons || [
406
+ "Access denied by AstraSync recommendation"
407
+ ];
376
408
  if (result.runtimeChallenge) {
377
409
  result.guidance = {
378
410
  message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
@@ -394,7 +426,10 @@ async function verify(config, request) {
394
426
  }
395
427
  async function recordDecision(config, sessionId, decision, reason) {
396
428
  const headers = { "Content-Type": "application/json" };
397
- if (config.apiKey) headers["X-API-Key"] = config.apiKey;
429
+ if (config.apiKey) {
430
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
431
+ headers["X-API-Key"] = config.apiKey;
432
+ }
398
433
  await fetch(`${config.apiBaseUrl}/agents/verify-access/${sessionId}/decision`, {
399
434
  method: "POST",
400
435
  headers,
@@ -402,15 +437,6 @@ async function recordDecision(config, sessionId, decision, reason) {
402
437
  }).catch(() => {
403
438
  });
404
439
  }
405
- async function reportUnregisteredAttempt(config, data) {
406
- const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
407
- await fetch(`${apiBaseUrl}/verification-activity/unregistered-attempt`, {
408
- method: "POST",
409
- headers: { "Content-Type": "application/json" },
410
- body: JSON.stringify(data)
411
- }).catch(() => {
412
- });
413
- }
414
440
  async function reportCounterpartyPreCheckFailure(config, data) {
415
441
  const apiBaseUrl = config.apiBaseUrl || DEFAULT_CONFIG.apiBaseUrl;
416
442
  await fetch(`${apiBaseUrl}/verification-activity/counterparty-pre-check-failure`, {
@@ -636,32 +662,6 @@ function createMiddleware(options) {
636
662
  return next();
637
663
  }
638
664
  const credentials = customExtractCredentials ? customExtractCredentials(req) : defaultExtractCredentials(req);
639
- if (!hasCredentials(credentials) && routeConfig.minAccessLevel !== "guidance") {
640
- const counterpartyUrl2 = config.counterpartyUrl || `${req.protocol}://${req.get("host")}`;
641
- reportUnregisteredAttempt(config, {
642
- counterpartyUrl: counterpartyUrl2,
643
- counterpartyType: config.counterpartyType || "api",
644
- sourceIp: req.ip,
645
- userAgent: req.headers["user-agent"],
646
- requestPath: req.path,
647
- requestMethod: req.method
648
- }).catch(() => {
649
- });
650
- const result2 = {
651
- verified: false,
652
- accessLevel: "none",
653
- denialReasons: ["No agent credentials provided"],
654
- guidance: {
655
- message: "This endpoint requires agent verification. Please provide your ASTRA-ID.",
656
- registrationUrl: `${config.apiBaseUrl?.replace("/api", "")}/register`,
657
- documentationUrl: `${config.apiBaseUrl?.replace("/api", "")}/docs/agent-access`
658
- },
659
- verifiedAt: /* @__PURE__ */ new Date()
660
- };
661
- req.agentVerification = result2;
662
- onDenied(result2, req, res);
663
- return;
664
- }
665
665
  const purpose = customExtractPurpose ? customExtractPurpose(req) : defaultExtractPurpose(req);
666
666
  const astraCreds = extractAstraSyncCredentials(req);
667
667
  const counterpartyUrl = config.counterpartyUrl || `${req.protocol}://${req.get("host")}`;
@@ -692,18 +692,28 @@ function createMiddleware(options) {
692
692
  return;
693
693
  }
694
694
  const shouldRecordDecisions = recordDecisions !== false;
695
+ const forwardedFor = req.headers["x-forwarded-for"];
696
+ const forwardedForStr = Array.isArray(forwardedFor) ? forwardedFor.join(", ") : forwardedFor;
697
+ const originalClientIp = forwardedForStr ? forwardedForStr.split(",")[0].trim() : req.ip;
698
+ const agentCardUrl = typeof req.headers["x-astrasync-agent-card"] === "string" ? req.headers["x-astrasync-agent-card"] : void 0;
695
699
  const result = await verify(config, {
696
700
  credentials,
697
701
  purpose,
698
702
  action: req.method.toLowerCase(),
699
703
  resource: req.path,
700
- clientIp: req.ip,
701
- userAgent: req.headers["user-agent"],
702
704
  createSession: shouldRecordDecisions,
703
705
  counterpartyUrl,
704
706
  counterpartyType: config.counterpartyType || "api",
705
707
  enableRuntimeChallenge,
706
- durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration
708
+ durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,
709
+ callerMetadata: {
710
+ sourceIp: originalClientIp,
711
+ userAgent: req.headers["user-agent"],
712
+ referer: req.headers.referer,
713
+ host: req.headers.host,
714
+ forwardedFor: forwardedForStr,
715
+ agentCardUrl
716
+ }
707
717
  });
708
718
  req.agentVerification = result;
709
719
  const sessionId = result.sessionId;
@@ -975,7 +985,13 @@ function generateCommerceShieldHtml(result, options) {
975
985
  `.trim();
976
986
  }
977
987
  function createMiddleware2(options) {
978
- const { routes = [], skipPaths = [], showCommerceShield = true, enableRuntimeChallenge = true, ...config } = options;
988
+ const {
989
+ routes = [],
990
+ skipPaths = [],
991
+ showCommerceShield = true,
992
+ enableRuntimeChallenge = true,
993
+ ...config
994
+ } = options;
979
995
  return async function middleware(request) {
980
996
  const { NextResponse } = await import("next/server");
981
997
  const pathname = request.nextUrl.pathname;
@@ -991,53 +1007,6 @@ function createMiddleware2(options) {
991
1007
  return NextResponse.next();
992
1008
  }
993
1009
  const credentials = extractCredentialsFromNextRequest(request);
994
- if (!hasCredentials(credentials) && routeConfig.minAccessLevel !== "guidance") {
995
- const counterpartyUrl2 = config.counterpartyUrl || request.nextUrl.origin;
996
- reportUnregisteredAttempt(config, {
997
- counterpartyUrl: counterpartyUrl2,
998
- counterpartyType: config.counterpartyType || "website",
999
- sourceIp: request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || void 0,
1000
- userAgent: request.headers.get("user-agent") || void 0,
1001
- requestPath: pathname,
1002
- requestMethod: request.method
1003
- }).catch(() => {
1004
- });
1005
- const result2 = {
1006
- verified: false,
1007
- accessLevel: "none",
1008
- denialReasons: ["No agent credentials provided"],
1009
- guidance: {
1010
- message: "This page requires agent verification.",
1011
- registrationUrl: `${config.apiBaseUrl?.replace("/api", "")}/register`,
1012
- documentationUrl: `${config.apiBaseUrl?.replace("/api", "")}/docs/agent-access`
1013
- },
1014
- verifiedAt: /* @__PURE__ */ new Date()
1015
- };
1016
- if (pathname.startsWith("/api/")) {
1017
- return NextResponse.json(
1018
- {
1019
- success: false,
1020
- error: {
1021
- code: "UNAUTHORIZED",
1022
- message: "No agent credentials provided",
1023
- guidance: result2.guidance
1024
- }
1025
- },
1026
- { status: 401 }
1027
- );
1028
- }
1029
- if (showCommerceShield) {
1030
- return new NextResponse(generateCommerceShieldHtml(result2, options), {
1031
- status: 200,
1032
- headers: {
1033
- "Content-Type": "text/html",
1034
- "X-AstraSync-Verification": "commerce-shield"
1035
- }
1036
- });
1037
- }
1038
- const registerUrl = result2.guidance?.registrationUrl || "/register";
1039
- return NextResponse.redirect(new URL(registerUrl, request.url));
1040
- }
1041
1010
  const counterpartyUrl = config.counterpartyUrl || request.nextUrl.origin;
1042
1011
  const purpose = extractPurpose(request);
1043
1012
  const astraCreds = extractAstraSyncCredentialsFromNextRequest(request);
@@ -1087,17 +1056,25 @@ function createMiddleware2(options) {
1087
1056
  }
1088
1057
  return NextResponse.redirect(new URL("/unauthorized", request.url));
1089
1058
  }
1059
+ const forwardedFor = request.headers.get("x-forwarded-for") || void 0;
1060
+ const originalClientIp = forwardedFor?.split(",")[0]?.trim();
1090
1061
  const result = await verify(config, {
1091
1062
  credentials,
1092
1063
  purpose,
1093
1064
  action: request.method.toLowerCase(),
1094
1065
  resource: pathname,
1095
- clientIp: request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || void 0,
1096
- userAgent: request.headers.get("user-agent") || void 0,
1097
1066
  counterpartyUrl,
1098
1067
  counterpartyType: config.counterpartyType || "website",
1099
1068
  enableRuntimeChallenge,
1100
- durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration
1069
+ durationRequired: astraCreds?.pdlss?.duration?.maxSessionDuration,
1070
+ callerMetadata: {
1071
+ sourceIp: originalClientIp,
1072
+ userAgent: request.headers.get("user-agent") || void 0,
1073
+ referer: request.headers.get("referer") || void 0,
1074
+ host: request.headers.get("host") || void 0,
1075
+ forwardedFor,
1076
+ agentCardUrl: request.headers.get("x-astrasync-agent-card") || void 0
1077
+ }
1101
1078
  });
1102
1079
  if (!hasMinimumAccess(result.accessLevel, routeConfig.minAccessLevel)) {
1103
1080
  if (pathname.startsWith("/api/")) {
@@ -3722,21 +3699,85 @@ function extractCredentialsFromProtocol(protocol, context) {
3722
3699
  var agent_exports = {};
3723
3700
  __export(agent_exports, {
3724
3701
  AgentClient: () => AgentClient,
3702
+ AstraSyncSdkError: () => AstraSyncSdkError,
3725
3703
  ChallengeHandler: () => ChallengeHandler,
3704
+ OwnershipMismatchError: () => OwnershipMismatchError,
3726
3705
  formatPDLSSForTransport: () => formatPDLSSForTransport,
3727
3706
  parsePDLSSFromTransport: () => parsePDLSSFromTransport,
3728
3707
  recordDecision: () => recordDecision2
3729
3708
  });
3730
3709
 
3710
+ // src/agent/errors.ts
3711
+ var AstraSyncSdkError = class extends Error {
3712
+ constructor(code, message) {
3713
+ super(message);
3714
+ this.name = "AstraSyncSdkError";
3715
+ this.code = code;
3716
+ }
3717
+ };
3718
+ var OwnershipMismatchError = class extends AstraSyncSdkError {
3719
+ constructor(astraId) {
3720
+ super(
3721
+ "ownership_mismatch",
3722
+ `The configured API key does not own agent ${astraId}. Refusing to initialise.`
3723
+ );
3724
+ this.name = "OwnershipMismatchError";
3725
+ this.astraId = astraId;
3726
+ }
3727
+ };
3728
+
3731
3729
  // src/agent/client.ts
3732
- var AgentClient = class {
3730
+ var AgentClient = class _AgentClient {
3733
3731
  constructor(config) {
3734
3732
  this.credentials = {
3735
3733
  agentId: config.agentId,
3736
- verifyUrl: config.verifyUrl ?? "https://api.astrasync.ai/agents/verify-access",
3734
+ verifyUrl: config.verifyUrl ?? "https://astrasync.ai/api/agents/verify-access",
3737
3735
  challengeUrl: config.challengeUrl,
3738
3736
  pdlss: config.pdlss
3739
3737
  };
3738
+ this.apiBaseUrl = config.apiBaseUrl ?? "https://astrasync.ai/api";
3739
+ this.apiKey = config.apiKey;
3740
+ }
3741
+ /**
3742
+ * Async factory that validates the API key's account owns the configured
3743
+ * ASTRA-id before returning a usable client. Refuses to initialise on
3744
+ * mismatch so a stolen ASTRA-id cannot be paired with a valid (different)
3745
+ * API key.
3746
+ *
3747
+ * Set env `ASTRASYNC_SKIP_OWNERSHIP_CHECK=true` to bypass — intended for
3748
+ * test environments only.
3749
+ */
3750
+ static async create(config) {
3751
+ const client = new _AgentClient(config);
3752
+ const skip = typeof process !== "undefined" && process.env?.ASTRASYNC_SKIP_OWNERSHIP_CHECK === "true";
3753
+ if (skip) return client;
3754
+ if (!config.apiKey) {
3755
+ throw new OwnershipMismatchError(config.agentId);
3756
+ }
3757
+ const owned = await client.verifyOwnership();
3758
+ if (!owned) throw new OwnershipMismatchError(config.agentId);
3759
+ return client;
3760
+ }
3761
+ /**
3762
+ * Calls GET /api/agents/:astraId/ownership with the configured API key.
3763
+ * Returns true only when the backend confirms this API key's account
3764
+ * owns the configured agent.
3765
+ */
3766
+ async verifyOwnership() {
3767
+ if (!this.apiKey) return false;
3768
+ const url = `${this.apiBaseUrl.replace(/\/+$/, "")}/api/agents/${encodeURIComponent(
3769
+ this.credentials.agentId
3770
+ )}/ownership`;
3771
+ const resp = await fetch(url, {
3772
+ method: "GET",
3773
+ headers: {
3774
+ Authorization: `Bearer ${this.apiKey}`,
3775
+ "Content-Type": "application/json"
3776
+ }
3777
+ });
3778
+ if (!resp.ok) return false;
3779
+ const body = await resp.json().catch(() => null);
3780
+ return Boolean(body?.data?.owned);
3740
3781
  }
3741
3782
  /**
3742
3783
  * Make an HTTP request with AstraSync headers automatically injected.