@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.
- package/README.md +64 -30
- package/dist/adapter-interface/interface.d.mts +2 -2
- package/dist/adapter-interface/interface.d.ts +2 -2
- package/dist/adapters/express.d.mts +2 -2
- package/dist/adapters/express.d.ts +2 -2
- package/dist/adapters/express.js +74 -95
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +74 -95
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +2 -2
- package/dist/adapters/nextjs.d.ts +2 -2
- package/dist/adapters/nextjs.js +74 -115
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +74 -115
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +2 -2
- package/dist/adapters/sdk.d.ts +2 -2
- package/dist/adapters/sdk.js +56 -55
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +56 -55
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +2 -2
- package/dist/agent/index.d.ts +2 -2
- package/dist/agent/index.js +68 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +66 -2
- package/dist/agent/index.mjs.map +1 -1
- package/dist/browser/background.js +56 -55
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +56 -55
- package/dist/browser/background.mjs.map +1 -1
- package/dist/browser/browser-adapter.d.mts +2 -2
- package/dist/browser/browser-adapter.d.ts +2 -2
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.d.ts +2 -2
- package/dist/cursor/cursor-adapter.d.mts +2 -2
- package/dist/cursor/cursor-adapter.d.ts +2 -2
- package/dist/cursor/extension.d.mts +2 -2
- package/dist/cursor/extension.d.ts +2 -2
- package/dist/cursor/extension.js +56 -55
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +56 -55
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/{express-Bcl-uBUE.d.ts → express-BtKlLI8U.d.ts} +2 -2
- package/dist/{express-CtwDIZyF.d.mts → express-DgwpS8Ha.d.mts} +2 -2
- package/dist/gateway/gateway.d.mts +2 -2
- package/dist/gateway/gateway.d.ts +2 -2
- package/dist/gateway/gateway.js +56 -55
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +56 -55
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +2 -2
- package/dist/git-trigger/git-hooks.d.ts +2 -2
- package/dist/{index-BY8yQ8N8.d.mts → index-AzhK20t0.d.mts} +46 -3
- package/dist/{index-CME6r4uH.d.ts → index-Ba0Lvsjo.d.ts} +1 -1
- package/dist/{index-3NRaBNvp.d.mts → index-BaxpmTGA.d.mts} +1 -1
- package/dist/{index-CtYSYwn3.d.ts → index-DpJS1JEI.d.ts} +46 -3
- package/dist/index.d.mts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +158 -117
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +158 -117
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.d.mts +2 -2
- package/dist/local-evaluator/evaluator.d.ts +2 -2
- package/dist/{nextjs-CEldnIJ9.d.ts → nextjs-B2kg19c1.d.ts} +1 -1
- package/dist/{nextjs-BQyMCSx_.d.mts → nextjs-ZymQ8jDh.d.mts} +1 -1
- package/dist/{sdk-BhvuJSrH.d.mts → sdk-B7id0VFS.d.mts} +2 -2
- package/dist/{sdk-BlyVSC_S.d.ts → sdk-Bso0FSI0.d.ts} +2 -2
- package/dist/transport/index.d.mts +2 -2
- package/dist/transport/index.d.ts +2 -2
- package/dist/{types-79qS7aON.d.ts → types-BYKAY6Cc.d.ts} +1 -1
- package/dist/{types-jJnPXStc.d.mts → types-CgXPKUwi.d.mts} +1 -1
- package/dist/{types-CxQwJKbd.d.mts → types-DOrqNMgy.d.mts} +79 -13
- package/dist/{types-CxQwJKbd.d.ts → types-DOrqNMgy.d.ts} +79 -13
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/webhooks.d.mts +59 -0
- package/dist/webhooks.d.ts +59 -0
- package/dist/webhooks.js +81 -0
- package/dist/webhooks.js.map +1 -0
- package/dist/webhooks.mjs +55 -0
- package/dist/webhooks.mjs.map +1 -0
- 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://
|
|
130
|
+
apiBaseUrl: "https://astrasync.ai/api",
|
|
131
131
|
defaultAccessLevel: "guidance",
|
|
132
|
-
minTrustScore
|
|
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)
|
|
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 (
|
|
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 (!
|
|
270
|
-
|
|
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
|
|
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 || [
|
|
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)
|
|
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 {
|
|
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://
|
|
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.
|