@astrasyncai/verification-gateway 1.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.
- package/README.md +213 -0
- package/dist/adapters/express.d.mts +3 -0
- package/dist/adapters/express.d.ts +3 -0
- package/dist/adapters/express.js +516 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/express.mjs +486 -0
- package/dist/adapters/express.mjs.map +1 -0
- package/dist/adapters/nextjs.d.mts +3 -0
- package/dist/adapters/nextjs.d.ts +3 -0
- package/dist/adapters/nextjs.js +624 -0
- package/dist/adapters/nextjs.js.map +1 -0
- package/dist/adapters/nextjs.mjs +586 -0
- package/dist/adapters/nextjs.mjs.map +1 -0
- package/dist/adapters/sdk.d.mts +2 -0
- package/dist/adapters/sdk.d.ts +2 -0
- package/dist/adapters/sdk.js +505 -0
- package/dist/adapters/sdk.js.map +1 -0
- package/dist/adapters/sdk.mjs +473 -0
- package/dist/adapters/sdk.mjs.map +1 -0
- package/dist/express-BhD3mWsL.d.ts +64 -0
- package/dist/express-DUDYpvNZ.d.mts +64 -0
- package/dist/index.d.mts +353 -0
- package/dist/index.d.ts +353 -0
- package/dist/index.js +1499 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1446 -0
- package/dist/index.mjs.map +1 -0
- package/dist/nextjs-BtqyLSVQ.d.mts +22 -0
- package/dist/nextjs-C9FPOjSh.d.ts +22 -0
- package/dist/sdk-BkVigGjF.d.ts +190 -0
- package/dist/sdk-xCbZgeZx.d.mts +190 -0
- package/dist/types-CS6v75-d.d.mts +359 -0
- package/dist/types-CS6v75-d.d.ts +359 -0
- package/dist/ui/index.d.mts +140 -0
- package/dist/ui/index.d.ts +140 -0
- package/dist/ui/index.js +826 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/index.mjs +782 -0
- package/dist/ui/index.mjs.map +1 -0
- package/package.json +89 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1499 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
ACCESS_LEVEL_DESCRIPTIONS: () => ACCESS_LEVEL_DESCRIPTIONS,
|
|
34
|
+
ACCESS_LEVEL_HIERARCHY: () => ACCESS_LEVEL_HIERARCHY,
|
|
35
|
+
AgentClient: () => AgentClient,
|
|
36
|
+
ChallengeHandler: () => ChallengeHandler,
|
|
37
|
+
DEFAULT_TRUST_THRESHOLDS: () => DEFAULT_TRUST_THRESHOLDS,
|
|
38
|
+
TRUST_LEVEL_RANGES: () => TRUST_LEVEL_RANGES,
|
|
39
|
+
VERSION: () => VERSION,
|
|
40
|
+
agent: () => agent_exports,
|
|
41
|
+
clearCache: () => clearCache,
|
|
42
|
+
determineAccessLevel: () => determineAccessLevel,
|
|
43
|
+
express: () => express_exports,
|
|
44
|
+
extractCredentials: () => extractCredentials,
|
|
45
|
+
getAccessLevelForScore: () => getAccessLevelForScore,
|
|
46
|
+
getCapabilities: () => getCapabilities,
|
|
47
|
+
getTrustLevel: () => getTrustLevel,
|
|
48
|
+
hasCredentials: () => hasCredentials,
|
|
49
|
+
hasMinimumAccess: () => hasMinimumAccess,
|
|
50
|
+
nextjs: () => nextjs_exports,
|
|
51
|
+
quickVerify: () => quickVerify,
|
|
52
|
+
recordDecision: () => recordDecision,
|
|
53
|
+
sdk: () => sdk_exports,
|
|
54
|
+
transport: () => transport_exports,
|
|
55
|
+
verify: () => verify
|
|
56
|
+
});
|
|
57
|
+
module.exports = __toCommonJS(src_exports);
|
|
58
|
+
|
|
59
|
+
// src/access-levels.ts
|
|
60
|
+
var ACCESS_LEVEL_HIERARCHY = {
|
|
61
|
+
none: 0,
|
|
62
|
+
guidance: 1,
|
|
63
|
+
"read-only": 2,
|
|
64
|
+
standard: 3,
|
|
65
|
+
full: 4,
|
|
66
|
+
internal: 5
|
|
67
|
+
};
|
|
68
|
+
var ACCESS_LEVEL_DESCRIPTIONS = {
|
|
69
|
+
none: "No access - credentials required",
|
|
70
|
+
guidance: "Guidance mode - registration information provided",
|
|
71
|
+
"read-only": "Read-only access - can browse but not modify",
|
|
72
|
+
standard: "Standard access - normal operations per PDLSS policy",
|
|
73
|
+
full: "Full access - all operations for high-trust agents",
|
|
74
|
+
internal: "Internal access - organization member privileges"
|
|
75
|
+
};
|
|
76
|
+
var DEFAULT_TRUST_THRESHOLDS = {
|
|
77
|
+
none: 0,
|
|
78
|
+
guidance: 0,
|
|
79
|
+
"read-only": 20,
|
|
80
|
+
standard: 40,
|
|
81
|
+
full: 70,
|
|
82
|
+
internal: 0
|
|
83
|
+
// Internal is based on org membership, not score
|
|
84
|
+
};
|
|
85
|
+
var TRUST_LEVEL_RANGES = {
|
|
86
|
+
BRONZE: { min: 0, max: 39 },
|
|
87
|
+
SILVER: { min: 40, max: 59 },
|
|
88
|
+
GOLD: { min: 60, max: 79 },
|
|
89
|
+
PLATINUM: { min: 80, max: 100 }
|
|
90
|
+
};
|
|
91
|
+
function getTrustLevel(score) {
|
|
92
|
+
if (score >= 80) return "PLATINUM";
|
|
93
|
+
if (score >= 60) return "GOLD";
|
|
94
|
+
if (score >= 40) return "SILVER";
|
|
95
|
+
return "BRONZE";
|
|
96
|
+
}
|
|
97
|
+
function hasMinimumAccess(actual, required) {
|
|
98
|
+
return ACCESS_LEVEL_HIERARCHY[actual] >= ACCESS_LEVEL_HIERARCHY[required];
|
|
99
|
+
}
|
|
100
|
+
function getAccessLevelForScore(trustScore, thresholds = DEFAULT_TRUST_THRESHOLDS) {
|
|
101
|
+
if (trustScore >= thresholds.full) return "full";
|
|
102
|
+
if (trustScore >= thresholds.standard) return "standard";
|
|
103
|
+
if (trustScore >= thresholds["read-only"]) return "read-only";
|
|
104
|
+
return "guidance";
|
|
105
|
+
}
|
|
106
|
+
function determineAccessLevel(verified, trustScore, isOrgMember, customThresholds) {
|
|
107
|
+
if (!verified) {
|
|
108
|
+
return "guidance";
|
|
109
|
+
}
|
|
110
|
+
if (isOrgMember) {
|
|
111
|
+
return "internal";
|
|
112
|
+
}
|
|
113
|
+
const thresholds = {
|
|
114
|
+
...DEFAULT_TRUST_THRESHOLDS,
|
|
115
|
+
...customThresholds
|
|
116
|
+
};
|
|
117
|
+
return getAccessLevelForScore(trustScore, thresholds);
|
|
118
|
+
}
|
|
119
|
+
function getCapabilities(accessLevel) {
|
|
120
|
+
switch (accessLevel) {
|
|
121
|
+
case "none":
|
|
122
|
+
return {
|
|
123
|
+
canRead: false,
|
|
124
|
+
canWrite: false,
|
|
125
|
+
canDelete: false,
|
|
126
|
+
canAdmin: false,
|
|
127
|
+
canAccessInternal: false
|
|
128
|
+
};
|
|
129
|
+
case "guidance":
|
|
130
|
+
return {
|
|
131
|
+
canRead: false,
|
|
132
|
+
canWrite: false,
|
|
133
|
+
canDelete: false,
|
|
134
|
+
canAdmin: false,
|
|
135
|
+
canAccessInternal: false
|
|
136
|
+
};
|
|
137
|
+
case "read-only":
|
|
138
|
+
return {
|
|
139
|
+
canRead: true,
|
|
140
|
+
canWrite: false,
|
|
141
|
+
canDelete: false,
|
|
142
|
+
canAdmin: false,
|
|
143
|
+
canAccessInternal: false
|
|
144
|
+
};
|
|
145
|
+
case "standard":
|
|
146
|
+
return {
|
|
147
|
+
canRead: true,
|
|
148
|
+
canWrite: true,
|
|
149
|
+
canDelete: false,
|
|
150
|
+
canAdmin: false,
|
|
151
|
+
canAccessInternal: false
|
|
152
|
+
};
|
|
153
|
+
case "full":
|
|
154
|
+
return {
|
|
155
|
+
canRead: true,
|
|
156
|
+
canWrite: true,
|
|
157
|
+
canDelete: true,
|
|
158
|
+
canAdmin: false,
|
|
159
|
+
canAccessInternal: false
|
|
160
|
+
};
|
|
161
|
+
case "internal":
|
|
162
|
+
return {
|
|
163
|
+
canRead: true,
|
|
164
|
+
canWrite: true,
|
|
165
|
+
canDelete: true,
|
|
166
|
+
canAdmin: true,
|
|
167
|
+
canAccessInternal: true
|
|
168
|
+
};
|
|
169
|
+
default:
|
|
170
|
+
return {
|
|
171
|
+
canRead: false,
|
|
172
|
+
canWrite: false,
|
|
173
|
+
canDelete: false,
|
|
174
|
+
canAdmin: false,
|
|
175
|
+
canAccessInternal: false
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/verify.ts
|
|
181
|
+
var DEFAULT_CONFIG = {
|
|
182
|
+
apiBaseUrl: "https://api.astrasync.ai",
|
|
183
|
+
defaultAccessLevel: "guidance",
|
|
184
|
+
minTrustScore: 40,
|
|
185
|
+
minTrustScoreForFull: 70,
|
|
186
|
+
cacheTtl: 300,
|
|
187
|
+
// 5 minutes
|
|
188
|
+
debug: false
|
|
189
|
+
};
|
|
190
|
+
var verificationCache = /* @__PURE__ */ new Map();
|
|
191
|
+
function getCacheKey(credentials) {
|
|
192
|
+
return `${credentials.astraId || ""}-${credentials.apiKey || ""}-${credentials.jwt || ""}`;
|
|
193
|
+
}
|
|
194
|
+
function getCachedResult(credentials) {
|
|
195
|
+
const key = getCacheKey(credentials);
|
|
196
|
+
const cached = verificationCache.get(key);
|
|
197
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
198
|
+
return cached.result;
|
|
199
|
+
}
|
|
200
|
+
if (cached) {
|
|
201
|
+
verificationCache.delete(key);
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
function cacheResult(credentials, result, ttlSeconds) {
|
|
206
|
+
const key = getCacheKey(credentials);
|
|
207
|
+
verificationCache.set(key, {
|
|
208
|
+
result,
|
|
209
|
+
expiresAt: Date.now() + ttlSeconds * 1e3
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function clearCache() {
|
|
213
|
+
verificationCache.clear();
|
|
214
|
+
}
|
|
215
|
+
function extractCredentials(headers, query) {
|
|
216
|
+
const credentials = {};
|
|
217
|
+
const astraIdHeader = headers["x-astra-id"] || headers["X-Astra-Id"] || headers["X-ASTRA-ID"];
|
|
218
|
+
if (astraIdHeader) {
|
|
219
|
+
credentials.astraId = Array.isArray(astraIdHeader) ? astraIdHeader[0] : astraIdHeader;
|
|
220
|
+
}
|
|
221
|
+
const apiKeyHeader = headers["x-api-key"] || headers["X-Api-Key"] || headers["X-API-KEY"];
|
|
222
|
+
if (apiKeyHeader) {
|
|
223
|
+
credentials.apiKey = Array.isArray(apiKeyHeader) ? apiKeyHeader[0] : apiKeyHeader;
|
|
224
|
+
}
|
|
225
|
+
const authHeader = headers["authorization"] || headers["Authorization"];
|
|
226
|
+
if (authHeader) {
|
|
227
|
+
const authValue = Array.isArray(authHeader) ? authHeader[0] : authHeader;
|
|
228
|
+
credentials.authorizationHeader = authValue;
|
|
229
|
+
if (authValue.startsWith("Bearer ")) {
|
|
230
|
+
credentials.jwt = authValue.slice(7);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (query) {
|
|
234
|
+
if (query.astraId && !credentials.astraId) {
|
|
235
|
+
credentials.astraId = query.astraId;
|
|
236
|
+
}
|
|
237
|
+
if (query.apiKey && !credentials.apiKey) {
|
|
238
|
+
credentials.apiKey = query.apiKey;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return credentials;
|
|
242
|
+
}
|
|
243
|
+
function hasCredentials(credentials) {
|
|
244
|
+
return !!(credentials.astraId || credentials.apiKey || credentials.jwt);
|
|
245
|
+
}
|
|
246
|
+
function createGuidanceResponse(config, reason) {
|
|
247
|
+
const guidance = {
|
|
248
|
+
message: "This service verifies AI agents before granting access. Please register your agent with AstraSync.",
|
|
249
|
+
registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/register`,
|
|
250
|
+
documentationUrl: `${config.apiBaseUrl.replace("/api", "")}/docs/agent-access`,
|
|
251
|
+
steps: [
|
|
252
|
+
"Register for an AstraSync account",
|
|
253
|
+
"Create and register your agent",
|
|
254
|
+
"Add your ASTRA-ID to request headers",
|
|
255
|
+
"Retry your request"
|
|
256
|
+
]
|
|
257
|
+
};
|
|
258
|
+
return {
|
|
259
|
+
verified: false,
|
|
260
|
+
accessLevel: "guidance",
|
|
261
|
+
guidance,
|
|
262
|
+
denialReasons: reason ? [reason] : ["No valid agent credentials provided"],
|
|
263
|
+
verifiedAt: /* @__PURE__ */ new Date()
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
async function callVerifyAccessAPI(config, request) {
|
|
267
|
+
const { credentials, ...requestData } = request;
|
|
268
|
+
const body = {
|
|
269
|
+
agentId: credentials.astraId,
|
|
270
|
+
purpose: requestData.purpose || "general"
|
|
271
|
+
};
|
|
272
|
+
if (requestData.action) body.action = requestData.action;
|
|
273
|
+
if (requestData.resourceType) body.resourceType = requestData.resourceType;
|
|
274
|
+
if (requestData.resource) body.resource = requestData.resource;
|
|
275
|
+
if (requestData.jurisdiction) body.jurisdiction = requestData.jurisdiction;
|
|
276
|
+
if (requestData.transactionValue) body.transactionValue = requestData.transactionValue;
|
|
277
|
+
if (requestData.currency) body.currency = requestData.currency;
|
|
278
|
+
if (requestData.isSubAgentRequest) body.isSubAgentRequest = requestData.isSubAgentRequest;
|
|
279
|
+
if (requestData.parentAgentId) body.parentAgentId = requestData.parentAgentId;
|
|
280
|
+
if (requestData.subAgentDepth !== void 0) body.subAgentDepth = requestData.subAgentDepth;
|
|
281
|
+
if (requestData.enableRuntimeChallenge) body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
|
|
282
|
+
if (requestData.createSession) body.createSession = requestData.createSession;
|
|
283
|
+
if (requestData.counterpartyType) body.counterpartyType = requestData.counterpartyType;
|
|
284
|
+
if (requestData.runtimeChallengeOptions) body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
|
|
285
|
+
const headers = {
|
|
286
|
+
"Content-Type": "application/json",
|
|
287
|
+
...config.customHeaders
|
|
288
|
+
};
|
|
289
|
+
if (config.apiKey) {
|
|
290
|
+
headers["X-API-Key"] = config.apiKey;
|
|
291
|
+
}
|
|
292
|
+
if (credentials.authorizationHeader) {
|
|
293
|
+
headers["Authorization"] = credentials.authorizationHeader;
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
297
|
+
method: "POST",
|
|
298
|
+
headers,
|
|
299
|
+
body: JSON.stringify(body)
|
|
300
|
+
});
|
|
301
|
+
const data = await response.json();
|
|
302
|
+
if (!response.ok) {
|
|
303
|
+
return {
|
|
304
|
+
success: false,
|
|
305
|
+
error: data.message || data.error || `API returned ${response.status}`
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
return data;
|
|
309
|
+
} catch (error) {
|
|
310
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
311
|
+
return {
|
|
312
|
+
success: false,
|
|
313
|
+
error: `Failed to call verify-access API: ${message}`
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
async function verify(config, request) {
|
|
318
|
+
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
319
|
+
if (!hasCredentials(request.credentials)) {
|
|
320
|
+
return createGuidanceResponse(mergedConfig, "No agent credentials provided");
|
|
321
|
+
}
|
|
322
|
+
if (mergedConfig.cacheTtl && mergedConfig.cacheTtl > 0) {
|
|
323
|
+
const cached = getCachedResult(request.credentials);
|
|
324
|
+
if (cached) {
|
|
325
|
+
if (mergedConfig.debug) {
|
|
326
|
+
console.log("[VerificationGateway] Returning cached result");
|
|
327
|
+
}
|
|
328
|
+
return cached;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (mergedConfig.debug) {
|
|
332
|
+
console.log("[VerificationGateway] Calling verify-access API");
|
|
333
|
+
}
|
|
334
|
+
const apiResponse = await callVerifyAccessAPI(mergedConfig, request);
|
|
335
|
+
if (!apiResponse.success) {
|
|
336
|
+
return createGuidanceResponse(mergedConfig, apiResponse.error);
|
|
337
|
+
}
|
|
338
|
+
if (!apiResponse.access?.allowed) {
|
|
339
|
+
const result2 = {
|
|
340
|
+
verified: false,
|
|
341
|
+
accessLevel: "guidance",
|
|
342
|
+
denialReasons: apiResponse.access?.reason ? [apiResponse.access.reason] : ["Access denied"],
|
|
343
|
+
requiresStepUp: apiResponse.access?.requiresStepUp,
|
|
344
|
+
requiresApproval: apiResponse.access?.requiresApproval,
|
|
345
|
+
guidance: {
|
|
346
|
+
message: apiResponse.access?.reason || "Access denied by PDLSS policy",
|
|
347
|
+
registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/register`,
|
|
348
|
+
documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/pdlss`
|
|
349
|
+
},
|
|
350
|
+
verifiedAt: /* @__PURE__ */ new Date()
|
|
351
|
+
};
|
|
352
|
+
return result2;
|
|
353
|
+
}
|
|
354
|
+
const agent = apiResponse.agent ? {
|
|
355
|
+
astraId: apiResponse.agent.astraId,
|
|
356
|
+
name: apiResponse.agent.name,
|
|
357
|
+
trustScore: apiResponse.agent.trustScore,
|
|
358
|
+
trustLevel: getTrustLevel(apiResponse.agent.trustScore),
|
|
359
|
+
blockchainVerified: apiResponse.agent.blockchainStatus === "verified",
|
|
360
|
+
status: apiResponse.agent.agentStatus
|
|
361
|
+
} : void 0;
|
|
362
|
+
const developer = apiResponse.developer ? {
|
|
363
|
+
astradId: apiResponse.developer.kyaOwnerId,
|
|
364
|
+
name: apiResponse.developer.fullName,
|
|
365
|
+
trustScore: apiResponse.developer.trustScore || 0,
|
|
366
|
+
verified: apiResponse.developer.identityVerified
|
|
367
|
+
} : void 0;
|
|
368
|
+
const organization = apiResponse.organization ? {
|
|
369
|
+
name: apiResponse.organization.name,
|
|
370
|
+
verified: apiResponse.organization.verified,
|
|
371
|
+
trustScore: apiResponse.organization.trustScore
|
|
372
|
+
} : void 0;
|
|
373
|
+
const pdlss = apiResponse.access?.pdlss ? {
|
|
374
|
+
purposeAllowed: apiResponse.access.pdlss.purposeAllowed,
|
|
375
|
+
withinDuration: apiResponse.access.pdlss.withinDuration,
|
|
376
|
+
withinLimits: apiResponse.access.pdlss.withinLimits,
|
|
377
|
+
scopeAllowed: apiResponse.access.pdlss.scopeAllowed,
|
|
378
|
+
selfInstantiationAllowed: apiResponse.access.pdlss.selfInstantiationAllowed,
|
|
379
|
+
appliedPolicy: apiResponse.access.appliedPolicy
|
|
380
|
+
} : void 0;
|
|
381
|
+
const trustScore = agent?.trustScore || 0;
|
|
382
|
+
const isOrgMember = false;
|
|
383
|
+
const accessLevel = determineAccessLevel(
|
|
384
|
+
true,
|
|
385
|
+
trustScore,
|
|
386
|
+
isOrgMember,
|
|
387
|
+
{
|
|
388
|
+
"read-only": 20,
|
|
389
|
+
standard: mergedConfig.minTrustScore || 40,
|
|
390
|
+
full: mergedConfig.minTrustScoreForFull || 70
|
|
391
|
+
}
|
|
392
|
+
);
|
|
393
|
+
const result = {
|
|
394
|
+
verified: true,
|
|
395
|
+
accessLevel,
|
|
396
|
+
agent,
|
|
397
|
+
developer,
|
|
398
|
+
organization,
|
|
399
|
+
pdlss,
|
|
400
|
+
requiresStepUp: apiResponse.access?.requiresStepUp,
|
|
401
|
+
requiresApproval: apiResponse.access?.requiresApproval,
|
|
402
|
+
verifiedAt: /* @__PURE__ */ new Date(),
|
|
403
|
+
cacheTtl: mergedConfig.cacheTtl,
|
|
404
|
+
// Handshake Protocol v10 enhanced fields (present when backend returns them)
|
|
405
|
+
sessionId: apiResponse.sessionId,
|
|
406
|
+
runtimeChallenge: apiResponse.runtimeChallenge,
|
|
407
|
+
tokenGuidance: apiResponse.tokenGuidance,
|
|
408
|
+
recommendation: apiResponse.recommendation,
|
|
409
|
+
recommendationReasons: apiResponse.recommendationReasons
|
|
410
|
+
};
|
|
411
|
+
if (result.recommendation === "deny") {
|
|
412
|
+
result.verified = false;
|
|
413
|
+
result.accessLevel = "none";
|
|
414
|
+
result.denialReasons = result.recommendationReasons || ["Access denied by AstraSync recommendation"];
|
|
415
|
+
if (result.runtimeChallenge) {
|
|
416
|
+
result.guidance = {
|
|
417
|
+
message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
|
|
418
|
+
registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/register`,
|
|
419
|
+
documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/runtime-challenge`
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
} else if (result.recommendation === "step_up_required") {
|
|
423
|
+
result.requiresStepUp = true;
|
|
424
|
+
if (ACCESS_LEVEL_HIERARCHY[result.accessLevel] > ACCESS_LEVEL_HIERARCHY["read-only"]) {
|
|
425
|
+
result.accessLevel = "read-only";
|
|
426
|
+
}
|
|
427
|
+
result.denialReasons = result.recommendationReasons || ["Step-up verification required"];
|
|
428
|
+
}
|
|
429
|
+
if (mergedConfig.cacheTtl && mergedConfig.cacheTtl > 0 && result.recommendation !== "deny") {
|
|
430
|
+
cacheResult(request.credentials, result, mergedConfig.cacheTtl);
|
|
431
|
+
}
|
|
432
|
+
return result;
|
|
433
|
+
}
|
|
434
|
+
async function quickVerify(config, credentials) {
|
|
435
|
+
const result = await verify(config, {
|
|
436
|
+
credentials,
|
|
437
|
+
purpose: "verification"
|
|
438
|
+
});
|
|
439
|
+
return {
|
|
440
|
+
verified: result.verified,
|
|
441
|
+
accessLevel: result.accessLevel,
|
|
442
|
+
reason: result.denialReasons?.[0]
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// src/adapters/express.ts
|
|
447
|
+
var express_exports = {};
|
|
448
|
+
__export(express_exports, {
|
|
449
|
+
createMiddleware: () => createMiddleware,
|
|
450
|
+
extractAstraSyncCredentials: () => extractAstraSyncCredentials,
|
|
451
|
+
requireAccess: () => requireAccess,
|
|
452
|
+
verifyOnly: () => verifyOnly
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// src/transport/http.ts
|
|
456
|
+
var HEADER_PREFIX = "X-Astra-";
|
|
457
|
+
function setHttpHeaders(headers, credentials) {
|
|
458
|
+
const result = { ...headers };
|
|
459
|
+
result[`${HEADER_PREFIX}ID`] = credentials.agentId;
|
|
460
|
+
if (credentials.verifyUrl) {
|
|
461
|
+
result[`${HEADER_PREFIX}Verify`] = credentials.verifyUrl;
|
|
462
|
+
}
|
|
463
|
+
if (credentials.challengeUrl) {
|
|
464
|
+
result[`${HEADER_PREFIX}Challenge`] = credentials.challengeUrl;
|
|
465
|
+
}
|
|
466
|
+
if (credentials.pdlss?.purpose) {
|
|
467
|
+
const purposeValue = credentials.pdlss.purpose.action ? `${credentials.pdlss.purpose.category}:${credentials.pdlss.purpose.action}` : credentials.pdlss.purpose.category;
|
|
468
|
+
result[`${HEADER_PREFIX}Purpose`] = purposeValue;
|
|
469
|
+
}
|
|
470
|
+
if (credentials.pdlss?.duration?.maxSessionDuration) {
|
|
471
|
+
result[`${HEADER_PREFIX}Duration`] = String(credentials.pdlss.duration.maxSessionDuration);
|
|
472
|
+
}
|
|
473
|
+
if (credentials.pdlss?.scope?.jurisdiction) {
|
|
474
|
+
result[`${HEADER_PREFIX}Scope`] = credentials.pdlss.scope.jurisdiction;
|
|
475
|
+
}
|
|
476
|
+
return result;
|
|
477
|
+
}
|
|
478
|
+
function extractHttpCredentials(headers) {
|
|
479
|
+
const getValue = (key) => {
|
|
480
|
+
const v = headers[key] ?? headers[key.toLowerCase()];
|
|
481
|
+
return Array.isArray(v) ? v[0] : v;
|
|
482
|
+
};
|
|
483
|
+
const agentId = getValue(`${HEADER_PREFIX}ID`) ?? getValue("x-astra-id");
|
|
484
|
+
if (!agentId) return null;
|
|
485
|
+
const credentials = { agentId };
|
|
486
|
+
const verifyUrl = getValue(`${HEADER_PREFIX}Verify`) ?? getValue("x-astra-verify");
|
|
487
|
+
if (verifyUrl) credentials.verifyUrl = verifyUrl;
|
|
488
|
+
const challengeUrl = getValue(`${HEADER_PREFIX}Challenge`) ?? getValue("x-astra-challenge");
|
|
489
|
+
if (challengeUrl) credentials.challengeUrl = challengeUrl;
|
|
490
|
+
const purpose = getValue(`${HEADER_PREFIX}Purpose`) ?? getValue("x-astra-purpose");
|
|
491
|
+
if (purpose) {
|
|
492
|
+
const [category, action] = purpose.split(":");
|
|
493
|
+
credentials.pdlss = {
|
|
494
|
+
...credentials.pdlss,
|
|
495
|
+
purpose: { category, action }
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
const duration = getValue(`${HEADER_PREFIX}Duration`) ?? getValue("x-astra-duration");
|
|
499
|
+
if (duration) {
|
|
500
|
+
credentials.pdlss = {
|
|
501
|
+
...credentials.pdlss,
|
|
502
|
+
duration: { maxSessionDuration: parseInt(duration, 10) }
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
const scope = getValue(`${HEADER_PREFIX}Scope`) ?? getValue("x-astra-scope");
|
|
506
|
+
if (scope) {
|
|
507
|
+
credentials.pdlss = {
|
|
508
|
+
...credentials.pdlss,
|
|
509
|
+
scope: { jurisdiction: scope }
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
return credentials;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// src/adapters/express.ts
|
|
516
|
+
function defaultExtractCredentials(req) {
|
|
517
|
+
return extractCredentials(
|
|
518
|
+
req.headers,
|
|
519
|
+
req.query
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
function extractAstraSyncCredentials(req) {
|
|
523
|
+
return extractHttpCredentials(req.headers);
|
|
524
|
+
}
|
|
525
|
+
function defaultExtractPurpose(req) {
|
|
526
|
+
const purposeHeader = req.headers["x-purpose"] || req.headers["X-Purpose"];
|
|
527
|
+
if (purposeHeader) {
|
|
528
|
+
return Array.isArray(purposeHeader) ? purposeHeader[0] : purposeHeader;
|
|
529
|
+
}
|
|
530
|
+
if (req.query.purpose && typeof req.query.purpose === "string") {
|
|
531
|
+
return req.query.purpose;
|
|
532
|
+
}
|
|
533
|
+
switch (req.method) {
|
|
534
|
+
case "GET":
|
|
535
|
+
return "read";
|
|
536
|
+
case "POST":
|
|
537
|
+
return "create";
|
|
538
|
+
case "PUT":
|
|
539
|
+
case "PATCH":
|
|
540
|
+
return "update";
|
|
541
|
+
case "DELETE":
|
|
542
|
+
return "delete";
|
|
543
|
+
default:
|
|
544
|
+
return "general";
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
function matchRoute(pattern, path) {
|
|
548
|
+
const regexPattern = pattern.replace(/\*/g, ".*").replace(/\//g, "\\/");
|
|
549
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
550
|
+
return regex.test(path);
|
|
551
|
+
}
|
|
552
|
+
function findRouteConfig(routes, path, method) {
|
|
553
|
+
return routes.find((route) => {
|
|
554
|
+
const methodMatches = route.method === "*" || route.method.toUpperCase() === method.toUpperCase();
|
|
555
|
+
const pathMatches = matchRoute(route.pattern, path);
|
|
556
|
+
return methodMatches && pathMatches;
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
function defaultOnDenied(result, _req, res) {
|
|
560
|
+
const statusCode = result.verified ? 403 : 401;
|
|
561
|
+
res.status(statusCode).json({
|
|
562
|
+
success: false,
|
|
563
|
+
error: {
|
|
564
|
+
code: result.verified ? "INSUFFICIENT_ACCESS" : "UNAUTHORIZED",
|
|
565
|
+
message: result.denialReasons?.[0] || "Access denied",
|
|
566
|
+
accessLevel: result.accessLevel,
|
|
567
|
+
guidance: result.guidance
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
function createMiddleware(options) {
|
|
572
|
+
const {
|
|
573
|
+
routes = [],
|
|
574
|
+
extractCredentials: customExtractCredentials,
|
|
575
|
+
extractPurpose: customExtractPurpose,
|
|
576
|
+
skipPaths = [],
|
|
577
|
+
onDenied = defaultOnDenied,
|
|
578
|
+
...config
|
|
579
|
+
} = options;
|
|
580
|
+
return async (req, res, next) => {
|
|
581
|
+
try {
|
|
582
|
+
const shouldSkip = skipPaths.some((pattern) => matchRoute(pattern, req.path));
|
|
583
|
+
if (shouldSkip) {
|
|
584
|
+
return next();
|
|
585
|
+
}
|
|
586
|
+
const routeConfig = findRouteConfig(routes, req.path, req.method);
|
|
587
|
+
if (!routeConfig) {
|
|
588
|
+
return next();
|
|
589
|
+
}
|
|
590
|
+
if (routeConfig.minAccessLevel === "none") {
|
|
591
|
+
return next();
|
|
592
|
+
}
|
|
593
|
+
const credentials = customExtractCredentials ? customExtractCredentials(req) : defaultExtractCredentials(req);
|
|
594
|
+
if (!hasCredentials(credentials) && routeConfig.minAccessLevel !== "guidance") {
|
|
595
|
+
const result2 = {
|
|
596
|
+
verified: false,
|
|
597
|
+
accessLevel: "none",
|
|
598
|
+
denialReasons: ["No agent credentials provided"],
|
|
599
|
+
guidance: {
|
|
600
|
+
message: "This endpoint requires agent verification. Please provide your ASTRA-ID.",
|
|
601
|
+
registrationUrl: `${config.apiBaseUrl?.replace("/api", "")}/register`,
|
|
602
|
+
documentationUrl: `${config.apiBaseUrl?.replace("/api", "")}/docs/agent-access`
|
|
603
|
+
},
|
|
604
|
+
verifiedAt: /* @__PURE__ */ new Date()
|
|
605
|
+
};
|
|
606
|
+
req.agentVerification = result2;
|
|
607
|
+
onDenied(result2, req, res);
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const purpose = customExtractPurpose ? customExtractPurpose(req) : defaultExtractPurpose(req);
|
|
611
|
+
const result = await verify(config, {
|
|
612
|
+
credentials,
|
|
613
|
+
purpose,
|
|
614
|
+
action: req.method.toLowerCase(),
|
|
615
|
+
resource: req.path,
|
|
616
|
+
clientIp: req.ip,
|
|
617
|
+
userAgent: req.headers["user-agent"]
|
|
618
|
+
});
|
|
619
|
+
req.agentVerification = result;
|
|
620
|
+
if (!hasMinimumAccess(result.accessLevel, routeConfig.minAccessLevel)) {
|
|
621
|
+
onDenied(result, req, res);
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
if (routeConfig.minTrustScore && result.agent) {
|
|
625
|
+
if (result.agent.trustScore < routeConfig.minTrustScore) {
|
|
626
|
+
result.denialReasons = [
|
|
627
|
+
`Trust score ${result.agent.trustScore} is below required ${routeConfig.minTrustScore}`
|
|
628
|
+
];
|
|
629
|
+
onDenied(result, req, res);
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
next();
|
|
634
|
+
} catch (error) {
|
|
635
|
+
console.error("[VerificationGateway] Middleware error:", error);
|
|
636
|
+
next();
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
function requireAccess(minAccessLevel, options) {
|
|
641
|
+
return createMiddleware({
|
|
642
|
+
...options,
|
|
643
|
+
routes: [
|
|
644
|
+
{ pattern: "*", method: "*", minAccessLevel }
|
|
645
|
+
]
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
function verifyOnly(options) {
|
|
649
|
+
return createMiddleware({
|
|
650
|
+
...options,
|
|
651
|
+
routes: [
|
|
652
|
+
{ pattern: "*", method: "*", minAccessLevel: "none" }
|
|
653
|
+
]
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// src/adapters/nextjs.ts
|
|
658
|
+
var nextjs_exports = {};
|
|
659
|
+
__export(nextjs_exports, {
|
|
660
|
+
createMatcherConfig: () => createMatcherConfig,
|
|
661
|
+
createMiddleware: () => createMiddleware2
|
|
662
|
+
});
|
|
663
|
+
function extractCredentialsFromNextRequest(request) {
|
|
664
|
+
const credentials = {};
|
|
665
|
+
const astraId = request.headers.get("x-astra-id") || request.headers.get("X-Astra-Id");
|
|
666
|
+
if (astraId) {
|
|
667
|
+
credentials.astraId = astraId;
|
|
668
|
+
}
|
|
669
|
+
const apiKey = request.headers.get("x-api-key") || request.headers.get("X-Api-Key");
|
|
670
|
+
if (apiKey) {
|
|
671
|
+
credentials.apiKey = apiKey;
|
|
672
|
+
}
|
|
673
|
+
const authHeader = request.headers.get("authorization");
|
|
674
|
+
if (authHeader) {
|
|
675
|
+
credentials.authorizationHeader = authHeader;
|
|
676
|
+
if (authHeader.startsWith("Bearer ")) {
|
|
677
|
+
credentials.jwt = authHeader.slice(7);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
const url = new URL(request.url);
|
|
681
|
+
const astraIdParam = url.searchParams.get("astraId");
|
|
682
|
+
const apiKeyParam = url.searchParams.get("apiKey");
|
|
683
|
+
if (astraIdParam && !credentials.astraId) {
|
|
684
|
+
credentials.astraId = astraIdParam;
|
|
685
|
+
}
|
|
686
|
+
if (apiKeyParam && !credentials.apiKey) {
|
|
687
|
+
credentials.apiKey = apiKeyParam;
|
|
688
|
+
}
|
|
689
|
+
return credentials;
|
|
690
|
+
}
|
|
691
|
+
function matchRoute2(pattern, path) {
|
|
692
|
+
const regexPattern = pattern.replace(/\*/g, ".*").replace(/\//g, "\\/");
|
|
693
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
694
|
+
return regex.test(path);
|
|
695
|
+
}
|
|
696
|
+
function findRouteConfig2(routes, path, method) {
|
|
697
|
+
return routes.find((route) => {
|
|
698
|
+
const methodMatches = route.method === "*" || route.method.toUpperCase() === method.toUpperCase();
|
|
699
|
+
const pathMatches = matchRoute2(route.pattern, path);
|
|
700
|
+
return methodMatches && pathMatches;
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
function inferPurpose(method) {
|
|
704
|
+
switch (method.toUpperCase()) {
|
|
705
|
+
case "GET":
|
|
706
|
+
return "read";
|
|
707
|
+
case "POST":
|
|
708
|
+
return "create";
|
|
709
|
+
case "PUT":
|
|
710
|
+
case "PATCH":
|
|
711
|
+
return "update";
|
|
712
|
+
case "DELETE":
|
|
713
|
+
return "delete";
|
|
714
|
+
default:
|
|
715
|
+
return "general";
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
function generateCommerceShieldHtml(result, options) {
|
|
719
|
+
const title = options.commerceShield?.title || "AstraSync Agent Verification";
|
|
720
|
+
const message = options.commerceShield?.message || result.guidance?.message || "This site verifies AI agents before granting access. We noticed you're visiting without AstraSync credentials.";
|
|
721
|
+
const registrationUrl = result.guidance?.registrationUrl || "https://astrasync.ai/register";
|
|
722
|
+
const docsUrl = result.guidance?.documentationUrl || "https://astrasync.ai/docs/agent-access";
|
|
723
|
+
const allowGuest = options.commerceShield?.allowGuestAccess ?? true;
|
|
724
|
+
return `
|
|
725
|
+
<!DOCTYPE html>
|
|
726
|
+
<html lang="en">
|
|
727
|
+
<head>
|
|
728
|
+
<meta charset="UTF-8">
|
|
729
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
730
|
+
<title>${title}</title>
|
|
731
|
+
<style>
|
|
732
|
+
* {
|
|
733
|
+
box-sizing: border-box;
|
|
734
|
+
margin: 0;
|
|
735
|
+
padding: 0;
|
|
736
|
+
}
|
|
737
|
+
body {
|
|
738
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
|
739
|
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
740
|
+
min-height: 100vh;
|
|
741
|
+
display: flex;
|
|
742
|
+
align-items: center;
|
|
743
|
+
justify-content: center;
|
|
744
|
+
padding: 20px;
|
|
745
|
+
}
|
|
746
|
+
.shield-container {
|
|
747
|
+
background: rgba(255, 255, 255, 0.95);
|
|
748
|
+
border-radius: 16px;
|
|
749
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
|
750
|
+
max-width: 480px;
|
|
751
|
+
width: 100%;
|
|
752
|
+
padding: 40px;
|
|
753
|
+
text-align: center;
|
|
754
|
+
}
|
|
755
|
+
.shield-icon {
|
|
756
|
+
font-size: 48px;
|
|
757
|
+
margin-bottom: 20px;
|
|
758
|
+
}
|
|
759
|
+
.shield-title {
|
|
760
|
+
font-size: 24px;
|
|
761
|
+
font-weight: 700;
|
|
762
|
+
color: #1a1a2e;
|
|
763
|
+
margin-bottom: 16px;
|
|
764
|
+
}
|
|
765
|
+
.shield-message {
|
|
766
|
+
color: #4a5568;
|
|
767
|
+
line-height: 1.6;
|
|
768
|
+
margin-bottom: 24px;
|
|
769
|
+
}
|
|
770
|
+
.shield-steps {
|
|
771
|
+
text-align: left;
|
|
772
|
+
background: #f7fafc;
|
|
773
|
+
border-radius: 8px;
|
|
774
|
+
padding: 20px;
|
|
775
|
+
margin-bottom: 24px;
|
|
776
|
+
}
|
|
777
|
+
.shield-steps h3 {
|
|
778
|
+
font-size: 14px;
|
|
779
|
+
font-weight: 600;
|
|
780
|
+
color: #2d3748;
|
|
781
|
+
margin-bottom: 12px;
|
|
782
|
+
}
|
|
783
|
+
.shield-steps ol {
|
|
784
|
+
padding-left: 20px;
|
|
785
|
+
color: #4a5568;
|
|
786
|
+
}
|
|
787
|
+
.shield-steps li {
|
|
788
|
+
margin-bottom: 8px;
|
|
789
|
+
}
|
|
790
|
+
.shield-buttons {
|
|
791
|
+
display: flex;
|
|
792
|
+
flex-direction: column;
|
|
793
|
+
gap: 12px;
|
|
794
|
+
}
|
|
795
|
+
.btn {
|
|
796
|
+
display: inline-block;
|
|
797
|
+
padding: 14px 24px;
|
|
798
|
+
border-radius: 8px;
|
|
799
|
+
font-weight: 600;
|
|
800
|
+
text-decoration: none;
|
|
801
|
+
transition: all 0.2s;
|
|
802
|
+
cursor: pointer;
|
|
803
|
+
border: none;
|
|
804
|
+
font-size: 16px;
|
|
805
|
+
}
|
|
806
|
+
.btn-primary {
|
|
807
|
+
background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);
|
|
808
|
+
color: white;
|
|
809
|
+
}
|
|
810
|
+
.btn-primary:hover {
|
|
811
|
+
transform: translateY(-2px);
|
|
812
|
+
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);
|
|
813
|
+
}
|
|
814
|
+
.btn-secondary {
|
|
815
|
+
background: #e2e8f0;
|
|
816
|
+
color: #4a5568;
|
|
817
|
+
}
|
|
818
|
+
.btn-secondary:hover {
|
|
819
|
+
background: #cbd5e0;
|
|
820
|
+
}
|
|
821
|
+
.shield-footer {
|
|
822
|
+
margin-top: 24px;
|
|
823
|
+
font-size: 14px;
|
|
824
|
+
color: #718096;
|
|
825
|
+
}
|
|
826
|
+
.shield-footer a {
|
|
827
|
+
color: #6366f1;
|
|
828
|
+
text-decoration: none;
|
|
829
|
+
}
|
|
830
|
+
.shield-footer a:hover {
|
|
831
|
+
text-decoration: underline;
|
|
832
|
+
}
|
|
833
|
+
</style>
|
|
834
|
+
</head>
|
|
835
|
+
<body>
|
|
836
|
+
<div class="shield-container">
|
|
837
|
+
<div class="shield-icon">\u{1F6E1}\uFE0F</div>
|
|
838
|
+
<h1 class="shield-title">${title}</h1>
|
|
839
|
+
<p class="shield-message">${message}</p>
|
|
840
|
+
|
|
841
|
+
<div class="shield-steps">
|
|
842
|
+
<h3>To get verified access:</h3>
|
|
843
|
+
<ol>
|
|
844
|
+
<li>Register at <a href="${registrationUrl}">astrasync.ai/register</a></li>
|
|
845
|
+
<li>Create and register your agent</li>
|
|
846
|
+
<li>Add your ASTRA-ID to request headers</li>
|
|
847
|
+
<li>Refresh this page</li>
|
|
848
|
+
</ol>
|
|
849
|
+
</div>
|
|
850
|
+
|
|
851
|
+
<div class="shield-buttons">
|
|
852
|
+
<a href="${registrationUrl}" class="btn btn-primary">Register Now</a>
|
|
853
|
+
${allowGuest ? '<button onclick="window.location.reload()" class="btn btn-secondary">Continue as Guest (Limited)</button>' : ""}
|
|
854
|
+
</div>
|
|
855
|
+
|
|
856
|
+
<p class="shield-footer">
|
|
857
|
+
Learn more: <a href="${docsUrl}">Agent Access Documentation</a>
|
|
858
|
+
</p>
|
|
859
|
+
</div>
|
|
860
|
+
</body>
|
|
861
|
+
</html>
|
|
862
|
+
`.trim();
|
|
863
|
+
}
|
|
864
|
+
function createMiddleware2(options) {
|
|
865
|
+
const {
|
|
866
|
+
routes = [],
|
|
867
|
+
skipPaths = [],
|
|
868
|
+
showCommerceShield = true,
|
|
869
|
+
...config
|
|
870
|
+
} = options;
|
|
871
|
+
return async function middleware(request) {
|
|
872
|
+
const { NextResponse } = await import("next/server");
|
|
873
|
+
const pathname = request.nextUrl.pathname;
|
|
874
|
+
const shouldSkip = skipPaths.some((pattern) => matchRoute2(pattern, pathname));
|
|
875
|
+
if (shouldSkip) {
|
|
876
|
+
return NextResponse.next();
|
|
877
|
+
}
|
|
878
|
+
const routeConfig = findRouteConfig2(routes, pathname, request.method);
|
|
879
|
+
if (!routeConfig) {
|
|
880
|
+
return NextResponse.next();
|
|
881
|
+
}
|
|
882
|
+
if (routeConfig.minAccessLevel === "none") {
|
|
883
|
+
return NextResponse.next();
|
|
884
|
+
}
|
|
885
|
+
const credentials = extractCredentialsFromNextRequest(request);
|
|
886
|
+
if (!hasCredentials(credentials) && routeConfig.minAccessLevel !== "guidance") {
|
|
887
|
+
const result2 = {
|
|
888
|
+
verified: false,
|
|
889
|
+
accessLevel: "none",
|
|
890
|
+
denialReasons: ["No agent credentials provided"],
|
|
891
|
+
guidance: {
|
|
892
|
+
message: "This page requires agent verification.",
|
|
893
|
+
registrationUrl: `${config.apiBaseUrl?.replace("/api", "")}/register`,
|
|
894
|
+
documentationUrl: `${config.apiBaseUrl?.replace("/api", "")}/docs/agent-access`
|
|
895
|
+
},
|
|
896
|
+
verifiedAt: /* @__PURE__ */ new Date()
|
|
897
|
+
};
|
|
898
|
+
if (pathname.startsWith("/api/")) {
|
|
899
|
+
return NextResponse.json(
|
|
900
|
+
{
|
|
901
|
+
success: false,
|
|
902
|
+
error: {
|
|
903
|
+
code: "UNAUTHORIZED",
|
|
904
|
+
message: "No agent credentials provided",
|
|
905
|
+
guidance: result2.guidance
|
|
906
|
+
}
|
|
907
|
+
},
|
|
908
|
+
{ status: 401 }
|
|
909
|
+
);
|
|
910
|
+
}
|
|
911
|
+
if (showCommerceShield) {
|
|
912
|
+
return new NextResponse(generateCommerceShieldHtml(result2, options), {
|
|
913
|
+
status: 200,
|
|
914
|
+
headers: {
|
|
915
|
+
"Content-Type": "text/html",
|
|
916
|
+
"X-AstraSync-Verification": "commerce-shield"
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
const registerUrl = result2.guidance?.registrationUrl || "/register";
|
|
921
|
+
return NextResponse.redirect(new URL(registerUrl, request.url));
|
|
922
|
+
}
|
|
923
|
+
const purpose = request.headers.get("x-purpose") || inferPurpose(request.method);
|
|
924
|
+
const result = await verify(config, {
|
|
925
|
+
credentials,
|
|
926
|
+
purpose,
|
|
927
|
+
action: request.method.toLowerCase(),
|
|
928
|
+
resource: pathname,
|
|
929
|
+
clientIp: request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || void 0,
|
|
930
|
+
userAgent: request.headers.get("user-agent") || void 0
|
|
931
|
+
});
|
|
932
|
+
if (!hasMinimumAccess(result.accessLevel, routeConfig.minAccessLevel)) {
|
|
933
|
+
if (pathname.startsWith("/api/")) {
|
|
934
|
+
return NextResponse.json(
|
|
935
|
+
{
|
|
936
|
+
success: false,
|
|
937
|
+
error: {
|
|
938
|
+
code: result.verified ? "INSUFFICIENT_ACCESS" : "UNAUTHORIZED",
|
|
939
|
+
message: result.denialReasons?.[0] || "Access denied",
|
|
940
|
+
accessLevel: result.accessLevel,
|
|
941
|
+
required: routeConfig.minAccessLevel,
|
|
942
|
+
guidance: result.guidance
|
|
943
|
+
}
|
|
944
|
+
},
|
|
945
|
+
{ status: result.verified ? 403 : 401 }
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
if (showCommerceShield) {
|
|
949
|
+
return new NextResponse(generateCommerceShieldHtml(result, options), {
|
|
950
|
+
status: 200,
|
|
951
|
+
headers: {
|
|
952
|
+
"Content-Type": "text/html",
|
|
953
|
+
"X-AstraSync-Verification": "commerce-shield"
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
return NextResponse.redirect(new URL("/unauthorized", request.url));
|
|
958
|
+
}
|
|
959
|
+
const response = NextResponse.next();
|
|
960
|
+
response.headers.set("X-AstraSync-Verified", result.verified.toString());
|
|
961
|
+
response.headers.set("X-AstraSync-Access-Level", result.accessLevel);
|
|
962
|
+
if (result.agent) {
|
|
963
|
+
response.headers.set("X-AstraSync-Agent-Id", result.agent.astraId);
|
|
964
|
+
response.headers.set("X-AstraSync-Trust-Score", result.agent.trustScore.toString());
|
|
965
|
+
}
|
|
966
|
+
return response;
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
function createMatcherConfig(paths) {
|
|
970
|
+
return { matcher: paths };
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
// src/adapters/sdk.ts
|
|
974
|
+
var sdk_exports = {};
|
|
975
|
+
__export(sdk_exports, {
|
|
976
|
+
VerificationGatewayClient: () => VerificationGatewayClient,
|
|
977
|
+
createClient: () => createClient,
|
|
978
|
+
getCapabilities: () => getCapabilities,
|
|
979
|
+
getTrustLevel: () => getTrustLevel,
|
|
980
|
+
hasMinimumAccess: () => hasMinimumAccess,
|
|
981
|
+
verifyOnce: () => verifyOnce
|
|
982
|
+
});
|
|
983
|
+
var VerificationGatewayClient = class {
|
|
984
|
+
constructor(options) {
|
|
985
|
+
this.config = {
|
|
986
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
987
|
+
apiKey: options.apiKey,
|
|
988
|
+
defaultAccessLevel: options.defaultAccessLevel,
|
|
989
|
+
minTrustScore: options.minTrustScore,
|
|
990
|
+
minTrustScoreForFull: options.minTrustScoreForFull,
|
|
991
|
+
cacheTtl: options.cacheTtl,
|
|
992
|
+
debug: options.debug,
|
|
993
|
+
customHeaders: options.customHeaders
|
|
994
|
+
};
|
|
995
|
+
this.timeout = options.timeout || 1e4;
|
|
996
|
+
this.retryConfig = options.retry || { maxRetries: 3, backoffMs: 1e3 };
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Full verification with all details
|
|
1000
|
+
*/
|
|
1001
|
+
async verify(options) {
|
|
1002
|
+
const credentials = {
|
|
1003
|
+
astraId: options.astraId,
|
|
1004
|
+
apiKey: options.apiKey,
|
|
1005
|
+
jwt: options.jwt
|
|
1006
|
+
};
|
|
1007
|
+
return this.executeWithRetry(
|
|
1008
|
+
() => verify(this.config, {
|
|
1009
|
+
credentials,
|
|
1010
|
+
purpose: options.purpose,
|
|
1011
|
+
action: options.action,
|
|
1012
|
+
resourceType: options.resourceType,
|
|
1013
|
+
resource: options.resource,
|
|
1014
|
+
jurisdiction: options.jurisdiction,
|
|
1015
|
+
transactionValue: options.transactionValue,
|
|
1016
|
+
currency: options.currency,
|
|
1017
|
+
isSubAgentRequest: options.isSubAgentRequest,
|
|
1018
|
+
parentAgentId: options.parentAgentId,
|
|
1019
|
+
subAgentDepth: options.subAgentDepth
|
|
1020
|
+
})
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Quick verification - just check if credentials are valid
|
|
1025
|
+
*/
|
|
1026
|
+
async quickVerify(credentials) {
|
|
1027
|
+
return this.executeWithRetry(() => quickVerify(this.config, credentials));
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Check if an agent has a specific access level
|
|
1031
|
+
*/
|
|
1032
|
+
async hasAccess(credentials, requiredLevel) {
|
|
1033
|
+
const result = await this.quickVerify(credentials);
|
|
1034
|
+
return hasMinimumAccess(result.accessLevel, requiredLevel);
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* Get capabilities for a verified agent
|
|
1038
|
+
*/
|
|
1039
|
+
async getCapabilities(credentials) {
|
|
1040
|
+
const result = await this.quickVerify(credentials);
|
|
1041
|
+
return getCapabilities(result.accessLevel);
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Verify a specific ASTRA-ID
|
|
1045
|
+
*/
|
|
1046
|
+
async verifyAstraId(astraId, options) {
|
|
1047
|
+
return this.verify({
|
|
1048
|
+
astraId,
|
|
1049
|
+
purpose: options?.purpose,
|
|
1050
|
+
action: options?.action
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Verify using an API key
|
|
1055
|
+
*/
|
|
1056
|
+
async verifyApiKey(apiKey, options) {
|
|
1057
|
+
return this.verify({
|
|
1058
|
+
apiKey,
|
|
1059
|
+
purpose: options?.purpose,
|
|
1060
|
+
action: options?.action
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Clear the verification cache
|
|
1065
|
+
*/
|
|
1066
|
+
clearCache() {
|
|
1067
|
+
clearCache();
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* Execute a function with retry logic
|
|
1071
|
+
*/
|
|
1072
|
+
async executeWithRetry(fn) {
|
|
1073
|
+
let lastError = null;
|
|
1074
|
+
for (let attempt = 0; attempt <= this.retryConfig.maxRetries; attempt++) {
|
|
1075
|
+
try {
|
|
1076
|
+
const result = await Promise.race([
|
|
1077
|
+
fn(),
|
|
1078
|
+
new Promise(
|
|
1079
|
+
(_, reject) => setTimeout(() => reject(new Error("Request timeout")), this.timeout)
|
|
1080
|
+
)
|
|
1081
|
+
]);
|
|
1082
|
+
return result;
|
|
1083
|
+
} catch (error) {
|
|
1084
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
1085
|
+
if (attempt < this.retryConfig.maxRetries) {
|
|
1086
|
+
const backoff = this.retryConfig.backoffMs * Math.pow(2, attempt);
|
|
1087
|
+
await new Promise((resolve) => setTimeout(resolve, backoff));
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
throw lastError || new Error("Verification failed after retries");
|
|
1092
|
+
}
|
|
1093
|
+
};
|
|
1094
|
+
function createClient(options) {
|
|
1095
|
+
return new VerificationGatewayClient(options);
|
|
1096
|
+
}
|
|
1097
|
+
async function verifyOnce(options) {
|
|
1098
|
+
const client = createClient(options);
|
|
1099
|
+
return client.verify(options);
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
// src/transport/index.ts
|
|
1103
|
+
var transport_exports = {};
|
|
1104
|
+
__export(transport_exports, {
|
|
1105
|
+
applyCredentials: () => applyCredentials,
|
|
1106
|
+
detectProtocol: () => detectProtocol,
|
|
1107
|
+
extractA2ACredentials: () => extractA2ACredentials,
|
|
1108
|
+
extractCredentialsFromProtocol: () => extractCredentialsFromProtocol,
|
|
1109
|
+
extractHttpCredentials: () => extractHttpCredentials,
|
|
1110
|
+
extractMcpCredentials: () => extractMcpCredentials,
|
|
1111
|
+
setA2AMetadata: () => setA2AMetadata,
|
|
1112
|
+
setHttpHeaders: () => setHttpHeaders,
|
|
1113
|
+
setMcpMeta: () => setMcpMeta
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
// src/transport/a2a.ts
|
|
1117
|
+
function setA2AMetadata(task, credentials) {
|
|
1118
|
+
const astrasync = {
|
|
1119
|
+
agentId: credentials.agentId
|
|
1120
|
+
};
|
|
1121
|
+
if (credentials.verifyUrl) astrasync.verifyUrl = credentials.verifyUrl;
|
|
1122
|
+
if (credentials.challengeUrl) astrasync.challengeUrl = credentials.challengeUrl;
|
|
1123
|
+
if (credentials.pdlss?.purpose) astrasync.purpose = credentials.pdlss.purpose;
|
|
1124
|
+
if (credentials.pdlss?.duration) astrasync.duration = credentials.pdlss.duration;
|
|
1125
|
+
if (credentials.pdlss?.scope) astrasync.scope = credentials.pdlss.scope;
|
|
1126
|
+
return {
|
|
1127
|
+
...task,
|
|
1128
|
+
metadata: {
|
|
1129
|
+
...task.metadata,
|
|
1130
|
+
astrasync
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
function extractA2ACredentials(task) {
|
|
1135
|
+
const meta = task.metadata?.astrasync;
|
|
1136
|
+
if (!meta?.agentId) return null;
|
|
1137
|
+
const credentials = {
|
|
1138
|
+
agentId: meta.agentId
|
|
1139
|
+
};
|
|
1140
|
+
if (meta.verifyUrl) credentials.verifyUrl = meta.verifyUrl;
|
|
1141
|
+
if (meta.challengeUrl) credentials.challengeUrl = meta.challengeUrl;
|
|
1142
|
+
if (meta.purpose || meta.duration || meta.scope) {
|
|
1143
|
+
credentials.pdlss = {};
|
|
1144
|
+
if (meta.purpose) credentials.pdlss.purpose = meta.purpose;
|
|
1145
|
+
if (meta.duration) credentials.pdlss.duration = meta.duration;
|
|
1146
|
+
if (meta.scope) credentials.pdlss.scope = meta.scope;
|
|
1147
|
+
}
|
|
1148
|
+
return credentials;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
// src/transport/mcp.ts
|
|
1152
|
+
function setMcpMeta(params, credentials) {
|
|
1153
|
+
const astrasync = {
|
|
1154
|
+
agentId: credentials.agentId
|
|
1155
|
+
};
|
|
1156
|
+
if (credentials.verifyUrl) astrasync.verifyUrl = credentials.verifyUrl;
|
|
1157
|
+
if (credentials.challengeUrl) astrasync.challengeUrl = credentials.challengeUrl;
|
|
1158
|
+
if (credentials.pdlss?.purpose) astrasync.purpose = credentials.pdlss.purpose;
|
|
1159
|
+
if (credentials.pdlss?.duration) astrasync.duration = credentials.pdlss.duration;
|
|
1160
|
+
if (credentials.pdlss?.scope) astrasync.scope = credentials.pdlss.scope;
|
|
1161
|
+
return {
|
|
1162
|
+
...params,
|
|
1163
|
+
_meta: {
|
|
1164
|
+
...params._meta,
|
|
1165
|
+
astrasync
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
function extractMcpCredentials(params) {
|
|
1170
|
+
const meta = params._meta?.astrasync;
|
|
1171
|
+
if (!meta?.agentId) return null;
|
|
1172
|
+
const credentials = {
|
|
1173
|
+
agentId: meta.agentId
|
|
1174
|
+
};
|
|
1175
|
+
if (meta.verifyUrl) credentials.verifyUrl = meta.verifyUrl;
|
|
1176
|
+
if (meta.challengeUrl) credentials.challengeUrl = meta.challengeUrl;
|
|
1177
|
+
if (meta.purpose || meta.duration || meta.scope) {
|
|
1178
|
+
credentials.pdlss = {};
|
|
1179
|
+
if (meta.purpose) credentials.pdlss.purpose = meta.purpose;
|
|
1180
|
+
if (meta.duration) credentials.pdlss.duration = meta.duration;
|
|
1181
|
+
if (meta.scope) credentials.pdlss.scope = meta.scope;
|
|
1182
|
+
}
|
|
1183
|
+
return credentials;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// src/transport/index.ts
|
|
1187
|
+
function detectProtocol(context) {
|
|
1188
|
+
if (context.metadata && typeof context.metadata === "object") {
|
|
1189
|
+
return "a2a";
|
|
1190
|
+
}
|
|
1191
|
+
if (context._meta && typeof context._meta === "object") {
|
|
1192
|
+
return "mcp";
|
|
1193
|
+
}
|
|
1194
|
+
return "http";
|
|
1195
|
+
}
|
|
1196
|
+
function applyCredentials(protocol, target, credentials) {
|
|
1197
|
+
switch (protocol) {
|
|
1198
|
+
case "http":
|
|
1199
|
+
return setHttpHeaders(target, credentials);
|
|
1200
|
+
case "a2a":
|
|
1201
|
+
return setA2AMetadata(target, credentials);
|
|
1202
|
+
case "mcp":
|
|
1203
|
+
return setMcpMeta(target, credentials);
|
|
1204
|
+
default:
|
|
1205
|
+
return target;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
function extractCredentialsFromProtocol(protocol, context) {
|
|
1209
|
+
switch (protocol) {
|
|
1210
|
+
case "http":
|
|
1211
|
+
return extractHttpCredentials(context);
|
|
1212
|
+
case "a2a":
|
|
1213
|
+
return extractA2ACredentials(context);
|
|
1214
|
+
case "mcp":
|
|
1215
|
+
return extractMcpCredentials(context);
|
|
1216
|
+
default:
|
|
1217
|
+
return null;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
// src/agent/index.ts
|
|
1222
|
+
var agent_exports = {};
|
|
1223
|
+
__export(agent_exports, {
|
|
1224
|
+
AgentClient: () => AgentClient,
|
|
1225
|
+
ChallengeHandler: () => ChallengeHandler,
|
|
1226
|
+
formatPDLSSForTransport: () => formatPDLSSForTransport,
|
|
1227
|
+
parsePDLSSFromTransport: () => parsePDLSSFromTransport,
|
|
1228
|
+
recordDecision: () => recordDecision
|
|
1229
|
+
});
|
|
1230
|
+
|
|
1231
|
+
// src/agent/client.ts
|
|
1232
|
+
var AgentClient = class {
|
|
1233
|
+
constructor(config) {
|
|
1234
|
+
this.credentials = {
|
|
1235
|
+
agentId: config.agentId,
|
|
1236
|
+
verifyUrl: config.verifyUrl ?? "https://api.astrasync.ai/agents/verify-access",
|
|
1237
|
+
challengeUrl: config.challengeUrl,
|
|
1238
|
+
pdlss: config.pdlss
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Make an HTTP request with AstraSync headers automatically injected.
|
|
1243
|
+
*/
|
|
1244
|
+
async fetch(url, options) {
|
|
1245
|
+
const { purpose, action, ...fetchOptions } = options ?? {};
|
|
1246
|
+
const creds = { ...this.credentials };
|
|
1247
|
+
if (purpose) {
|
|
1248
|
+
creds.pdlss = {
|
|
1249
|
+
...creds.pdlss,
|
|
1250
|
+
purpose: { category: purpose, action }
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
const existingHeaders = {};
|
|
1254
|
+
if (fetchOptions.headers) {
|
|
1255
|
+
if (fetchOptions.headers instanceof Headers) {
|
|
1256
|
+
fetchOptions.headers.forEach((value, key) => {
|
|
1257
|
+
existingHeaders[key] = value;
|
|
1258
|
+
});
|
|
1259
|
+
} else if (Array.isArray(fetchOptions.headers)) {
|
|
1260
|
+
for (const [key, value] of fetchOptions.headers) {
|
|
1261
|
+
existingHeaders[key] = value;
|
|
1262
|
+
}
|
|
1263
|
+
} else {
|
|
1264
|
+
Object.assign(existingHeaders, fetchOptions.headers);
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
const enrichedHeaders = setHttpHeaders(existingHeaders, creds);
|
|
1268
|
+
return fetch(url, {
|
|
1269
|
+
...fetchOptions,
|
|
1270
|
+
headers: enrichedHeaders
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Prepare A2A task metadata with AstraSync credentials.
|
|
1275
|
+
*/
|
|
1276
|
+
prepareA2AMetadata(task, overrides) {
|
|
1277
|
+
const creds = this.buildCredentials(overrides);
|
|
1278
|
+
return setA2AMetadata(task, creds);
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Prepare MCP params with AstraSync _meta.
|
|
1282
|
+
*/
|
|
1283
|
+
prepareMcpMeta(params, overrides) {
|
|
1284
|
+
const creds = this.buildCredentials(overrides);
|
|
1285
|
+
return setMcpMeta(params, creds);
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* Generic: apply credentials to any protocol.
|
|
1289
|
+
*/
|
|
1290
|
+
applyCredentials(protocol, target, overrides) {
|
|
1291
|
+
const creds = this.buildCredentials(overrides);
|
|
1292
|
+
return applyCredentials(protocol, target, creds);
|
|
1293
|
+
}
|
|
1294
|
+
buildCredentials(overrides) {
|
|
1295
|
+
if (!overrides?.purpose) return this.credentials;
|
|
1296
|
+
return {
|
|
1297
|
+
...this.credentials,
|
|
1298
|
+
pdlss: {
|
|
1299
|
+
...this.credentials.pdlss,
|
|
1300
|
+
purpose: { category: overrides.purpose, action: overrides.action }
|
|
1301
|
+
}
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
};
|
|
1305
|
+
|
|
1306
|
+
// src/agent/challenge-handler.ts
|
|
1307
|
+
var ChallengeHandler = class {
|
|
1308
|
+
constructor(config) {
|
|
1309
|
+
this.pendingCounterparties = /* @__PURE__ */ new Set();
|
|
1310
|
+
this.agentId = config.agentId;
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* Register a counterparty as pending (before initiating contact).
|
|
1314
|
+
*/
|
|
1315
|
+
registerPending(counterpartyId) {
|
|
1316
|
+
this.pendingCounterparties.add(counterpartyId);
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Remove a counterparty from pending list (after interaction complete).
|
|
1320
|
+
*/
|
|
1321
|
+
removePending(counterpartyId) {
|
|
1322
|
+
this.pendingCounterparties.delete(counterpartyId);
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* Get current pending counterparties list.
|
|
1326
|
+
*/
|
|
1327
|
+
getPendingList() {
|
|
1328
|
+
return [...this.pendingCounterparties];
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* Express middleware for the challenge endpoint.
|
|
1332
|
+
* Mount at: app.post('/astrasync/challenge', handler.expressMiddleware())
|
|
1333
|
+
*/
|
|
1334
|
+
expressMiddleware() {
|
|
1335
|
+
return (req, res) => {
|
|
1336
|
+
const result = this.handleChallenge(req.body);
|
|
1337
|
+
res.status(result.status).json(result.body);
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Generic handler (framework-agnostic).
|
|
1342
|
+
* Returns { status, body } for the caller to send.
|
|
1343
|
+
*/
|
|
1344
|
+
handleChallenge(body) {
|
|
1345
|
+
if (!body || typeof body !== "object") {
|
|
1346
|
+
return {
|
|
1347
|
+
status: 400,
|
|
1348
|
+
body: {
|
|
1349
|
+
challengeId: "",
|
|
1350
|
+
acknowledged: false,
|
|
1351
|
+
pendingCounterparties: [],
|
|
1352
|
+
respondedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1353
|
+
error: "Invalid challenge payload"
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
const payload = body;
|
|
1358
|
+
if (!payload.challengeId || !payload.issuedAt || !payload.expiresAt) {
|
|
1359
|
+
return {
|
|
1360
|
+
status: 400,
|
|
1361
|
+
body: {
|
|
1362
|
+
challengeId: payload.challengeId ?? "",
|
|
1363
|
+
acknowledged: false,
|
|
1364
|
+
pendingCounterparties: [],
|
|
1365
|
+
respondedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1366
|
+
error: "Missing required challenge fields"
|
|
1367
|
+
}
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
const now = /* @__PURE__ */ new Date();
|
|
1371
|
+
const expiresAt = new Date(payload.expiresAt);
|
|
1372
|
+
if (now > expiresAt) {
|
|
1373
|
+
return {
|
|
1374
|
+
status: 410,
|
|
1375
|
+
body: {
|
|
1376
|
+
challengeId: payload.challengeId,
|
|
1377
|
+
acknowledged: false,
|
|
1378
|
+
pendingCounterparties: [],
|
|
1379
|
+
respondedAt: now.toISOString(),
|
|
1380
|
+
error: "Challenge has expired"
|
|
1381
|
+
}
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
return {
|
|
1385
|
+
status: 200,
|
|
1386
|
+
body: {
|
|
1387
|
+
challengeId: payload.challengeId,
|
|
1388
|
+
acknowledged: true,
|
|
1389
|
+
pendingCounterparties: this.getPendingList(),
|
|
1390
|
+
respondedAt: now.toISOString()
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
};
|
|
1395
|
+
|
|
1396
|
+
// src/agent/pdlss-formatter.ts
|
|
1397
|
+
function formatPDLSSForTransport(pdlss) {
|
|
1398
|
+
const transport = {};
|
|
1399
|
+
if (pdlss.purpose?.categories?.length) {
|
|
1400
|
+
transport.purpose = {
|
|
1401
|
+
category: pdlss.purpose.categories[0],
|
|
1402
|
+
action: pdlss.purpose.allowedActions?.[0]
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
if (pdlss.duration) {
|
|
1406
|
+
const candidates = [];
|
|
1407
|
+
if (pdlss.duration.maxSessionDuration) candidates.push(pdlss.duration.maxSessionDuration);
|
|
1408
|
+
if (pdlss.duration.ttl) candidates.push(pdlss.duration.ttl);
|
|
1409
|
+
if (candidates.length > 0) {
|
|
1410
|
+
transport.duration = { maxSessionDuration: Math.min(...candidates) };
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
if (pdlss.scope?.jurisdictions?.length) {
|
|
1414
|
+
transport.scope = { jurisdiction: pdlss.scope.jurisdictions[0] };
|
|
1415
|
+
}
|
|
1416
|
+
return transport;
|
|
1417
|
+
}
|
|
1418
|
+
function parsePDLSSFromTransport(transport) {
|
|
1419
|
+
const pdlss = {};
|
|
1420
|
+
if (transport.purpose) {
|
|
1421
|
+
pdlss.purpose = {
|
|
1422
|
+
categories: [transport.purpose.category],
|
|
1423
|
+
allowedActions: transport.purpose.action ? [transport.purpose.action] : void 0
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
if (transport.duration) {
|
|
1427
|
+
pdlss.duration = {
|
|
1428
|
+
maxSessionDuration: transport.duration.maxSessionDuration
|
|
1429
|
+
};
|
|
1430
|
+
}
|
|
1431
|
+
if (transport.scope) {
|
|
1432
|
+
pdlss.scope = {
|
|
1433
|
+
jurisdictions: transport.scope.jurisdiction ? [transport.scope.jurisdiction] : void 0
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
return pdlss;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
// src/agent/decision-client.ts
|
|
1440
|
+
async function recordDecision(config, params) {
|
|
1441
|
+
const { sessionId, ...body } = params;
|
|
1442
|
+
const baseUrl = config.apiBaseUrl.replace(/\/$/, "");
|
|
1443
|
+
const url = `${baseUrl}/agents/verify-access/${encodeURIComponent(sessionId)}/decision`;
|
|
1444
|
+
const headers = {
|
|
1445
|
+
"Content-Type": "application/json"
|
|
1446
|
+
};
|
|
1447
|
+
if (config.apiKey) {
|
|
1448
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
1449
|
+
}
|
|
1450
|
+
if (config.customHeaders) {
|
|
1451
|
+
Object.assign(headers, config.customHeaders);
|
|
1452
|
+
}
|
|
1453
|
+
const response = await fetch(url, {
|
|
1454
|
+
method: "POST",
|
|
1455
|
+
headers,
|
|
1456
|
+
body: JSON.stringify(body)
|
|
1457
|
+
});
|
|
1458
|
+
if (!response.ok) {
|
|
1459
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
1460
|
+
throw new Error(
|
|
1461
|
+
`Failed to record decision for session ${sessionId}: ${response.status} ${errorText}`
|
|
1462
|
+
);
|
|
1463
|
+
}
|
|
1464
|
+
const result = await response.json();
|
|
1465
|
+
return {
|
|
1466
|
+
recorded: result.recorded ?? true,
|
|
1467
|
+
blockchainTxHash: result.blockchainTxHash
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
// src/index.ts
|
|
1472
|
+
var VERSION = "2.0.0";
|
|
1473
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1474
|
+
0 && (module.exports = {
|
|
1475
|
+
ACCESS_LEVEL_DESCRIPTIONS,
|
|
1476
|
+
ACCESS_LEVEL_HIERARCHY,
|
|
1477
|
+
AgentClient,
|
|
1478
|
+
ChallengeHandler,
|
|
1479
|
+
DEFAULT_TRUST_THRESHOLDS,
|
|
1480
|
+
TRUST_LEVEL_RANGES,
|
|
1481
|
+
VERSION,
|
|
1482
|
+
agent,
|
|
1483
|
+
clearCache,
|
|
1484
|
+
determineAccessLevel,
|
|
1485
|
+
express,
|
|
1486
|
+
extractCredentials,
|
|
1487
|
+
getAccessLevelForScore,
|
|
1488
|
+
getCapabilities,
|
|
1489
|
+
getTrustLevel,
|
|
1490
|
+
hasCredentials,
|
|
1491
|
+
hasMinimumAccess,
|
|
1492
|
+
nextjs,
|
|
1493
|
+
quickVerify,
|
|
1494
|
+
recordDecision,
|
|
1495
|
+
sdk,
|
|
1496
|
+
transport,
|
|
1497
|
+
verify
|
|
1498
|
+
});
|
|
1499
|
+
//# sourceMappingURL=index.js.map
|