@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
|
@@ -0,0 +1,624 @@
|
|
|
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/adapters/nextjs.ts
|
|
31
|
+
var nextjs_exports = {};
|
|
32
|
+
__export(nextjs_exports, {
|
|
33
|
+
createMatcherConfig: () => createMatcherConfig,
|
|
34
|
+
createMiddleware: () => createMiddleware
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(nextjs_exports);
|
|
37
|
+
|
|
38
|
+
// src/access-levels.ts
|
|
39
|
+
var ACCESS_LEVEL_HIERARCHY = {
|
|
40
|
+
none: 0,
|
|
41
|
+
guidance: 1,
|
|
42
|
+
"read-only": 2,
|
|
43
|
+
standard: 3,
|
|
44
|
+
full: 4,
|
|
45
|
+
internal: 5
|
|
46
|
+
};
|
|
47
|
+
var DEFAULT_TRUST_THRESHOLDS = {
|
|
48
|
+
none: 0,
|
|
49
|
+
guidance: 0,
|
|
50
|
+
"read-only": 20,
|
|
51
|
+
standard: 40,
|
|
52
|
+
full: 70,
|
|
53
|
+
internal: 0
|
|
54
|
+
// Internal is based on org membership, not score
|
|
55
|
+
};
|
|
56
|
+
function getTrustLevel(score) {
|
|
57
|
+
if (score >= 80) return "PLATINUM";
|
|
58
|
+
if (score >= 60) return "GOLD";
|
|
59
|
+
if (score >= 40) return "SILVER";
|
|
60
|
+
return "BRONZE";
|
|
61
|
+
}
|
|
62
|
+
function hasMinimumAccess(actual, required) {
|
|
63
|
+
return ACCESS_LEVEL_HIERARCHY[actual] >= ACCESS_LEVEL_HIERARCHY[required];
|
|
64
|
+
}
|
|
65
|
+
function getAccessLevelForScore(trustScore, thresholds = DEFAULT_TRUST_THRESHOLDS) {
|
|
66
|
+
if (trustScore >= thresholds.full) return "full";
|
|
67
|
+
if (trustScore >= thresholds.standard) return "standard";
|
|
68
|
+
if (trustScore >= thresholds["read-only"]) return "read-only";
|
|
69
|
+
return "guidance";
|
|
70
|
+
}
|
|
71
|
+
function determineAccessLevel(verified, trustScore, isOrgMember, customThresholds) {
|
|
72
|
+
if (!verified) {
|
|
73
|
+
return "guidance";
|
|
74
|
+
}
|
|
75
|
+
if (isOrgMember) {
|
|
76
|
+
return "internal";
|
|
77
|
+
}
|
|
78
|
+
const thresholds = {
|
|
79
|
+
...DEFAULT_TRUST_THRESHOLDS,
|
|
80
|
+
...customThresholds
|
|
81
|
+
};
|
|
82
|
+
return getAccessLevelForScore(trustScore, thresholds);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/verify.ts
|
|
86
|
+
var DEFAULT_CONFIG = {
|
|
87
|
+
apiBaseUrl: "https://api.astrasync.ai",
|
|
88
|
+
defaultAccessLevel: "guidance",
|
|
89
|
+
minTrustScore: 40,
|
|
90
|
+
minTrustScoreForFull: 70,
|
|
91
|
+
cacheTtl: 300,
|
|
92
|
+
// 5 minutes
|
|
93
|
+
debug: false
|
|
94
|
+
};
|
|
95
|
+
var verificationCache = /* @__PURE__ */ new Map();
|
|
96
|
+
function getCacheKey(credentials) {
|
|
97
|
+
return `${credentials.astraId || ""}-${credentials.apiKey || ""}-${credentials.jwt || ""}`;
|
|
98
|
+
}
|
|
99
|
+
function getCachedResult(credentials) {
|
|
100
|
+
const key = getCacheKey(credentials);
|
|
101
|
+
const cached = verificationCache.get(key);
|
|
102
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
103
|
+
return cached.result;
|
|
104
|
+
}
|
|
105
|
+
if (cached) {
|
|
106
|
+
verificationCache.delete(key);
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
function cacheResult(credentials, result, ttlSeconds) {
|
|
111
|
+
const key = getCacheKey(credentials);
|
|
112
|
+
verificationCache.set(key, {
|
|
113
|
+
result,
|
|
114
|
+
expiresAt: Date.now() + ttlSeconds * 1e3
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function hasCredentials(credentials) {
|
|
118
|
+
return !!(credentials.astraId || credentials.apiKey || credentials.jwt);
|
|
119
|
+
}
|
|
120
|
+
function createGuidanceResponse(config, reason) {
|
|
121
|
+
const guidance = {
|
|
122
|
+
message: "This service verifies AI agents before granting access. Please register your agent with AstraSync.",
|
|
123
|
+
registrationUrl: `${config.apiBaseUrl.replace("/api", "")}/register`,
|
|
124
|
+
documentationUrl: `${config.apiBaseUrl.replace("/api", "")}/docs/agent-access`,
|
|
125
|
+
steps: [
|
|
126
|
+
"Register for an AstraSync account",
|
|
127
|
+
"Create and register your agent",
|
|
128
|
+
"Add your ASTRA-ID to request headers",
|
|
129
|
+
"Retry your request"
|
|
130
|
+
]
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
verified: false,
|
|
134
|
+
accessLevel: "guidance",
|
|
135
|
+
guidance,
|
|
136
|
+
denialReasons: reason ? [reason] : ["No valid agent credentials provided"],
|
|
137
|
+
verifiedAt: /* @__PURE__ */ new Date()
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
async function callVerifyAccessAPI(config, request) {
|
|
141
|
+
const { credentials, ...requestData } = request;
|
|
142
|
+
const body = {
|
|
143
|
+
agentId: credentials.astraId,
|
|
144
|
+
purpose: requestData.purpose || "general"
|
|
145
|
+
};
|
|
146
|
+
if (requestData.action) body.action = requestData.action;
|
|
147
|
+
if (requestData.resourceType) body.resourceType = requestData.resourceType;
|
|
148
|
+
if (requestData.resource) body.resource = requestData.resource;
|
|
149
|
+
if (requestData.jurisdiction) body.jurisdiction = requestData.jurisdiction;
|
|
150
|
+
if (requestData.transactionValue) body.transactionValue = requestData.transactionValue;
|
|
151
|
+
if (requestData.currency) body.currency = requestData.currency;
|
|
152
|
+
if (requestData.isSubAgentRequest) body.isSubAgentRequest = requestData.isSubAgentRequest;
|
|
153
|
+
if (requestData.parentAgentId) body.parentAgentId = requestData.parentAgentId;
|
|
154
|
+
if (requestData.subAgentDepth !== void 0) body.subAgentDepth = requestData.subAgentDepth;
|
|
155
|
+
if (requestData.enableRuntimeChallenge) body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
|
|
156
|
+
if (requestData.createSession) body.createSession = requestData.createSession;
|
|
157
|
+
if (requestData.counterpartyType) body.counterpartyType = requestData.counterpartyType;
|
|
158
|
+
if (requestData.runtimeChallengeOptions) body.runtimeChallengeOptions = requestData.runtimeChallengeOptions;
|
|
159
|
+
const headers = {
|
|
160
|
+
"Content-Type": "application/json",
|
|
161
|
+
...config.customHeaders
|
|
162
|
+
};
|
|
163
|
+
if (config.apiKey) {
|
|
164
|
+
headers["X-API-Key"] = config.apiKey;
|
|
165
|
+
}
|
|
166
|
+
if (credentials.authorizationHeader) {
|
|
167
|
+
headers["Authorization"] = credentials.authorizationHeader;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const response = await fetch(`${config.apiBaseUrl}/agents/verify-access`, {
|
|
171
|
+
method: "POST",
|
|
172
|
+
headers,
|
|
173
|
+
body: JSON.stringify(body)
|
|
174
|
+
});
|
|
175
|
+
const data = await response.json();
|
|
176
|
+
if (!response.ok) {
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
error: data.message || data.error || `API returned ${response.status}`
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
return data;
|
|
183
|
+
} catch (error) {
|
|
184
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
185
|
+
return {
|
|
186
|
+
success: false,
|
|
187
|
+
error: `Failed to call verify-access API: ${message}`
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async function verify(config, request) {
|
|
192
|
+
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
193
|
+
if (!hasCredentials(request.credentials)) {
|
|
194
|
+
return createGuidanceResponse(mergedConfig, "No agent credentials provided");
|
|
195
|
+
}
|
|
196
|
+
if (mergedConfig.cacheTtl && mergedConfig.cacheTtl > 0) {
|
|
197
|
+
const cached = getCachedResult(request.credentials);
|
|
198
|
+
if (cached) {
|
|
199
|
+
if (mergedConfig.debug) {
|
|
200
|
+
console.log("[VerificationGateway] Returning cached result");
|
|
201
|
+
}
|
|
202
|
+
return cached;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (mergedConfig.debug) {
|
|
206
|
+
console.log("[VerificationGateway] Calling verify-access API");
|
|
207
|
+
}
|
|
208
|
+
const apiResponse = await callVerifyAccessAPI(mergedConfig, request);
|
|
209
|
+
if (!apiResponse.success) {
|
|
210
|
+
return createGuidanceResponse(mergedConfig, apiResponse.error);
|
|
211
|
+
}
|
|
212
|
+
if (!apiResponse.access?.allowed) {
|
|
213
|
+
const result2 = {
|
|
214
|
+
verified: false,
|
|
215
|
+
accessLevel: "guidance",
|
|
216
|
+
denialReasons: apiResponse.access?.reason ? [apiResponse.access.reason] : ["Access denied"],
|
|
217
|
+
requiresStepUp: apiResponse.access?.requiresStepUp,
|
|
218
|
+
requiresApproval: apiResponse.access?.requiresApproval,
|
|
219
|
+
guidance: {
|
|
220
|
+
message: apiResponse.access?.reason || "Access denied by PDLSS policy",
|
|
221
|
+
registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/register`,
|
|
222
|
+
documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/pdlss`
|
|
223
|
+
},
|
|
224
|
+
verifiedAt: /* @__PURE__ */ new Date()
|
|
225
|
+
};
|
|
226
|
+
return result2;
|
|
227
|
+
}
|
|
228
|
+
const agent = apiResponse.agent ? {
|
|
229
|
+
astraId: apiResponse.agent.astraId,
|
|
230
|
+
name: apiResponse.agent.name,
|
|
231
|
+
trustScore: apiResponse.agent.trustScore,
|
|
232
|
+
trustLevel: getTrustLevel(apiResponse.agent.trustScore),
|
|
233
|
+
blockchainVerified: apiResponse.agent.blockchainStatus === "verified",
|
|
234
|
+
status: apiResponse.agent.agentStatus
|
|
235
|
+
} : void 0;
|
|
236
|
+
const developer = apiResponse.developer ? {
|
|
237
|
+
astradId: apiResponse.developer.kyaOwnerId,
|
|
238
|
+
name: apiResponse.developer.fullName,
|
|
239
|
+
trustScore: apiResponse.developer.trustScore || 0,
|
|
240
|
+
verified: apiResponse.developer.identityVerified
|
|
241
|
+
} : void 0;
|
|
242
|
+
const organization = apiResponse.organization ? {
|
|
243
|
+
name: apiResponse.organization.name,
|
|
244
|
+
verified: apiResponse.organization.verified,
|
|
245
|
+
trustScore: apiResponse.organization.trustScore
|
|
246
|
+
} : void 0;
|
|
247
|
+
const pdlss = apiResponse.access?.pdlss ? {
|
|
248
|
+
purposeAllowed: apiResponse.access.pdlss.purposeAllowed,
|
|
249
|
+
withinDuration: apiResponse.access.pdlss.withinDuration,
|
|
250
|
+
withinLimits: apiResponse.access.pdlss.withinLimits,
|
|
251
|
+
scopeAllowed: apiResponse.access.pdlss.scopeAllowed,
|
|
252
|
+
selfInstantiationAllowed: apiResponse.access.pdlss.selfInstantiationAllowed,
|
|
253
|
+
appliedPolicy: apiResponse.access.appliedPolicy
|
|
254
|
+
} : void 0;
|
|
255
|
+
const trustScore = agent?.trustScore || 0;
|
|
256
|
+
const isOrgMember = false;
|
|
257
|
+
const accessLevel = determineAccessLevel(
|
|
258
|
+
true,
|
|
259
|
+
trustScore,
|
|
260
|
+
isOrgMember,
|
|
261
|
+
{
|
|
262
|
+
"read-only": 20,
|
|
263
|
+
standard: mergedConfig.minTrustScore || 40,
|
|
264
|
+
full: mergedConfig.minTrustScoreForFull || 70
|
|
265
|
+
}
|
|
266
|
+
);
|
|
267
|
+
const result = {
|
|
268
|
+
verified: true,
|
|
269
|
+
accessLevel,
|
|
270
|
+
agent,
|
|
271
|
+
developer,
|
|
272
|
+
organization,
|
|
273
|
+
pdlss,
|
|
274
|
+
requiresStepUp: apiResponse.access?.requiresStepUp,
|
|
275
|
+
requiresApproval: apiResponse.access?.requiresApproval,
|
|
276
|
+
verifiedAt: /* @__PURE__ */ new Date(),
|
|
277
|
+
cacheTtl: mergedConfig.cacheTtl,
|
|
278
|
+
// Handshake Protocol v10 enhanced fields (present when backend returns them)
|
|
279
|
+
sessionId: apiResponse.sessionId,
|
|
280
|
+
runtimeChallenge: apiResponse.runtimeChallenge,
|
|
281
|
+
tokenGuidance: apiResponse.tokenGuidance,
|
|
282
|
+
recommendation: apiResponse.recommendation,
|
|
283
|
+
recommendationReasons: apiResponse.recommendationReasons
|
|
284
|
+
};
|
|
285
|
+
if (result.recommendation === "deny") {
|
|
286
|
+
result.verified = false;
|
|
287
|
+
result.accessLevel = "none";
|
|
288
|
+
result.denialReasons = result.recommendationReasons || ["Access denied by AstraSync recommendation"];
|
|
289
|
+
if (result.runtimeChallenge) {
|
|
290
|
+
result.guidance = {
|
|
291
|
+
message: `Verification failed: ${result.runtimeChallenge.reason || "runtime challenge failed"}`,
|
|
292
|
+
registrationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/register`,
|
|
293
|
+
documentationUrl: `${mergedConfig.apiBaseUrl?.replace("/api", "")}/docs/runtime-challenge`
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
} else if (result.recommendation === "step_up_required") {
|
|
297
|
+
result.requiresStepUp = true;
|
|
298
|
+
if (ACCESS_LEVEL_HIERARCHY[result.accessLevel] > ACCESS_LEVEL_HIERARCHY["read-only"]) {
|
|
299
|
+
result.accessLevel = "read-only";
|
|
300
|
+
}
|
|
301
|
+
result.denialReasons = result.recommendationReasons || ["Step-up verification required"];
|
|
302
|
+
}
|
|
303
|
+
if (mergedConfig.cacheTtl && mergedConfig.cacheTtl > 0 && result.recommendation !== "deny") {
|
|
304
|
+
cacheResult(request.credentials, result, mergedConfig.cacheTtl);
|
|
305
|
+
}
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// src/adapters/nextjs.ts
|
|
310
|
+
function extractCredentialsFromNextRequest(request) {
|
|
311
|
+
const credentials = {};
|
|
312
|
+
const astraId = request.headers.get("x-astra-id") || request.headers.get("X-Astra-Id");
|
|
313
|
+
if (astraId) {
|
|
314
|
+
credentials.astraId = astraId;
|
|
315
|
+
}
|
|
316
|
+
const apiKey = request.headers.get("x-api-key") || request.headers.get("X-Api-Key");
|
|
317
|
+
if (apiKey) {
|
|
318
|
+
credentials.apiKey = apiKey;
|
|
319
|
+
}
|
|
320
|
+
const authHeader = request.headers.get("authorization");
|
|
321
|
+
if (authHeader) {
|
|
322
|
+
credentials.authorizationHeader = authHeader;
|
|
323
|
+
if (authHeader.startsWith("Bearer ")) {
|
|
324
|
+
credentials.jwt = authHeader.slice(7);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const url = new URL(request.url);
|
|
328
|
+
const astraIdParam = url.searchParams.get("astraId");
|
|
329
|
+
const apiKeyParam = url.searchParams.get("apiKey");
|
|
330
|
+
if (astraIdParam && !credentials.astraId) {
|
|
331
|
+
credentials.astraId = astraIdParam;
|
|
332
|
+
}
|
|
333
|
+
if (apiKeyParam && !credentials.apiKey) {
|
|
334
|
+
credentials.apiKey = apiKeyParam;
|
|
335
|
+
}
|
|
336
|
+
return credentials;
|
|
337
|
+
}
|
|
338
|
+
function matchRoute(pattern, path) {
|
|
339
|
+
const regexPattern = pattern.replace(/\*/g, ".*").replace(/\//g, "\\/");
|
|
340
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
341
|
+
return regex.test(path);
|
|
342
|
+
}
|
|
343
|
+
function findRouteConfig(routes, path, method) {
|
|
344
|
+
return routes.find((route) => {
|
|
345
|
+
const methodMatches = route.method === "*" || route.method.toUpperCase() === method.toUpperCase();
|
|
346
|
+
const pathMatches = matchRoute(route.pattern, path);
|
|
347
|
+
return methodMatches && pathMatches;
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
function inferPurpose(method) {
|
|
351
|
+
switch (method.toUpperCase()) {
|
|
352
|
+
case "GET":
|
|
353
|
+
return "read";
|
|
354
|
+
case "POST":
|
|
355
|
+
return "create";
|
|
356
|
+
case "PUT":
|
|
357
|
+
case "PATCH":
|
|
358
|
+
return "update";
|
|
359
|
+
case "DELETE":
|
|
360
|
+
return "delete";
|
|
361
|
+
default:
|
|
362
|
+
return "general";
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function generateCommerceShieldHtml(result, options) {
|
|
366
|
+
const title = options.commerceShield?.title || "AstraSync Agent Verification";
|
|
367
|
+
const message = options.commerceShield?.message || result.guidance?.message || "This site verifies AI agents before granting access. We noticed you're visiting without AstraSync credentials.";
|
|
368
|
+
const registrationUrl = result.guidance?.registrationUrl || "https://astrasync.ai/register";
|
|
369
|
+
const docsUrl = result.guidance?.documentationUrl || "https://astrasync.ai/docs/agent-access";
|
|
370
|
+
const allowGuest = options.commerceShield?.allowGuestAccess ?? true;
|
|
371
|
+
return `
|
|
372
|
+
<!DOCTYPE html>
|
|
373
|
+
<html lang="en">
|
|
374
|
+
<head>
|
|
375
|
+
<meta charset="UTF-8">
|
|
376
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
377
|
+
<title>${title}</title>
|
|
378
|
+
<style>
|
|
379
|
+
* {
|
|
380
|
+
box-sizing: border-box;
|
|
381
|
+
margin: 0;
|
|
382
|
+
padding: 0;
|
|
383
|
+
}
|
|
384
|
+
body {
|
|
385
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
|
386
|
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
387
|
+
min-height: 100vh;
|
|
388
|
+
display: flex;
|
|
389
|
+
align-items: center;
|
|
390
|
+
justify-content: center;
|
|
391
|
+
padding: 20px;
|
|
392
|
+
}
|
|
393
|
+
.shield-container {
|
|
394
|
+
background: rgba(255, 255, 255, 0.95);
|
|
395
|
+
border-radius: 16px;
|
|
396
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
|
397
|
+
max-width: 480px;
|
|
398
|
+
width: 100%;
|
|
399
|
+
padding: 40px;
|
|
400
|
+
text-align: center;
|
|
401
|
+
}
|
|
402
|
+
.shield-icon {
|
|
403
|
+
font-size: 48px;
|
|
404
|
+
margin-bottom: 20px;
|
|
405
|
+
}
|
|
406
|
+
.shield-title {
|
|
407
|
+
font-size: 24px;
|
|
408
|
+
font-weight: 700;
|
|
409
|
+
color: #1a1a2e;
|
|
410
|
+
margin-bottom: 16px;
|
|
411
|
+
}
|
|
412
|
+
.shield-message {
|
|
413
|
+
color: #4a5568;
|
|
414
|
+
line-height: 1.6;
|
|
415
|
+
margin-bottom: 24px;
|
|
416
|
+
}
|
|
417
|
+
.shield-steps {
|
|
418
|
+
text-align: left;
|
|
419
|
+
background: #f7fafc;
|
|
420
|
+
border-radius: 8px;
|
|
421
|
+
padding: 20px;
|
|
422
|
+
margin-bottom: 24px;
|
|
423
|
+
}
|
|
424
|
+
.shield-steps h3 {
|
|
425
|
+
font-size: 14px;
|
|
426
|
+
font-weight: 600;
|
|
427
|
+
color: #2d3748;
|
|
428
|
+
margin-bottom: 12px;
|
|
429
|
+
}
|
|
430
|
+
.shield-steps ol {
|
|
431
|
+
padding-left: 20px;
|
|
432
|
+
color: #4a5568;
|
|
433
|
+
}
|
|
434
|
+
.shield-steps li {
|
|
435
|
+
margin-bottom: 8px;
|
|
436
|
+
}
|
|
437
|
+
.shield-buttons {
|
|
438
|
+
display: flex;
|
|
439
|
+
flex-direction: column;
|
|
440
|
+
gap: 12px;
|
|
441
|
+
}
|
|
442
|
+
.btn {
|
|
443
|
+
display: inline-block;
|
|
444
|
+
padding: 14px 24px;
|
|
445
|
+
border-radius: 8px;
|
|
446
|
+
font-weight: 600;
|
|
447
|
+
text-decoration: none;
|
|
448
|
+
transition: all 0.2s;
|
|
449
|
+
cursor: pointer;
|
|
450
|
+
border: none;
|
|
451
|
+
font-size: 16px;
|
|
452
|
+
}
|
|
453
|
+
.btn-primary {
|
|
454
|
+
background: linear-gradient(135deg, #6366f1 0%, #4f46e5 100%);
|
|
455
|
+
color: white;
|
|
456
|
+
}
|
|
457
|
+
.btn-primary:hover {
|
|
458
|
+
transform: translateY(-2px);
|
|
459
|
+
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.4);
|
|
460
|
+
}
|
|
461
|
+
.btn-secondary {
|
|
462
|
+
background: #e2e8f0;
|
|
463
|
+
color: #4a5568;
|
|
464
|
+
}
|
|
465
|
+
.btn-secondary:hover {
|
|
466
|
+
background: #cbd5e0;
|
|
467
|
+
}
|
|
468
|
+
.shield-footer {
|
|
469
|
+
margin-top: 24px;
|
|
470
|
+
font-size: 14px;
|
|
471
|
+
color: #718096;
|
|
472
|
+
}
|
|
473
|
+
.shield-footer a {
|
|
474
|
+
color: #6366f1;
|
|
475
|
+
text-decoration: none;
|
|
476
|
+
}
|
|
477
|
+
.shield-footer a:hover {
|
|
478
|
+
text-decoration: underline;
|
|
479
|
+
}
|
|
480
|
+
</style>
|
|
481
|
+
</head>
|
|
482
|
+
<body>
|
|
483
|
+
<div class="shield-container">
|
|
484
|
+
<div class="shield-icon">\u{1F6E1}\uFE0F</div>
|
|
485
|
+
<h1 class="shield-title">${title}</h1>
|
|
486
|
+
<p class="shield-message">${message}</p>
|
|
487
|
+
|
|
488
|
+
<div class="shield-steps">
|
|
489
|
+
<h3>To get verified access:</h3>
|
|
490
|
+
<ol>
|
|
491
|
+
<li>Register at <a href="${registrationUrl}">astrasync.ai/register</a></li>
|
|
492
|
+
<li>Create and register your agent</li>
|
|
493
|
+
<li>Add your ASTRA-ID to request headers</li>
|
|
494
|
+
<li>Refresh this page</li>
|
|
495
|
+
</ol>
|
|
496
|
+
</div>
|
|
497
|
+
|
|
498
|
+
<div class="shield-buttons">
|
|
499
|
+
<a href="${registrationUrl}" class="btn btn-primary">Register Now</a>
|
|
500
|
+
${allowGuest ? '<button onclick="window.location.reload()" class="btn btn-secondary">Continue as Guest (Limited)</button>' : ""}
|
|
501
|
+
</div>
|
|
502
|
+
|
|
503
|
+
<p class="shield-footer">
|
|
504
|
+
Learn more: <a href="${docsUrl}">Agent Access Documentation</a>
|
|
505
|
+
</p>
|
|
506
|
+
</div>
|
|
507
|
+
</body>
|
|
508
|
+
</html>
|
|
509
|
+
`.trim();
|
|
510
|
+
}
|
|
511
|
+
function createMiddleware(options) {
|
|
512
|
+
const {
|
|
513
|
+
routes = [],
|
|
514
|
+
skipPaths = [],
|
|
515
|
+
showCommerceShield = true,
|
|
516
|
+
...config
|
|
517
|
+
} = options;
|
|
518
|
+
return async function middleware(request) {
|
|
519
|
+
const { NextResponse } = await import("next/server");
|
|
520
|
+
const pathname = request.nextUrl.pathname;
|
|
521
|
+
const shouldSkip = skipPaths.some((pattern) => matchRoute(pattern, pathname));
|
|
522
|
+
if (shouldSkip) {
|
|
523
|
+
return NextResponse.next();
|
|
524
|
+
}
|
|
525
|
+
const routeConfig = findRouteConfig(routes, pathname, request.method);
|
|
526
|
+
if (!routeConfig) {
|
|
527
|
+
return NextResponse.next();
|
|
528
|
+
}
|
|
529
|
+
if (routeConfig.minAccessLevel === "none") {
|
|
530
|
+
return NextResponse.next();
|
|
531
|
+
}
|
|
532
|
+
const credentials = extractCredentialsFromNextRequest(request);
|
|
533
|
+
if (!hasCredentials(credentials) && routeConfig.minAccessLevel !== "guidance") {
|
|
534
|
+
const result2 = {
|
|
535
|
+
verified: false,
|
|
536
|
+
accessLevel: "none",
|
|
537
|
+
denialReasons: ["No agent credentials provided"],
|
|
538
|
+
guidance: {
|
|
539
|
+
message: "This page requires agent verification.",
|
|
540
|
+
registrationUrl: `${config.apiBaseUrl?.replace("/api", "")}/register`,
|
|
541
|
+
documentationUrl: `${config.apiBaseUrl?.replace("/api", "")}/docs/agent-access`
|
|
542
|
+
},
|
|
543
|
+
verifiedAt: /* @__PURE__ */ new Date()
|
|
544
|
+
};
|
|
545
|
+
if (pathname.startsWith("/api/")) {
|
|
546
|
+
return NextResponse.json(
|
|
547
|
+
{
|
|
548
|
+
success: false,
|
|
549
|
+
error: {
|
|
550
|
+
code: "UNAUTHORIZED",
|
|
551
|
+
message: "No agent credentials provided",
|
|
552
|
+
guidance: result2.guidance
|
|
553
|
+
}
|
|
554
|
+
},
|
|
555
|
+
{ status: 401 }
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
if (showCommerceShield) {
|
|
559
|
+
return new NextResponse(generateCommerceShieldHtml(result2, options), {
|
|
560
|
+
status: 200,
|
|
561
|
+
headers: {
|
|
562
|
+
"Content-Type": "text/html",
|
|
563
|
+
"X-AstraSync-Verification": "commerce-shield"
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
const registerUrl = result2.guidance?.registrationUrl || "/register";
|
|
568
|
+
return NextResponse.redirect(new URL(registerUrl, request.url));
|
|
569
|
+
}
|
|
570
|
+
const purpose = request.headers.get("x-purpose") || inferPurpose(request.method);
|
|
571
|
+
const result = await verify(config, {
|
|
572
|
+
credentials,
|
|
573
|
+
purpose,
|
|
574
|
+
action: request.method.toLowerCase(),
|
|
575
|
+
resource: pathname,
|
|
576
|
+
clientIp: request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || void 0,
|
|
577
|
+
userAgent: request.headers.get("user-agent") || void 0
|
|
578
|
+
});
|
|
579
|
+
if (!hasMinimumAccess(result.accessLevel, routeConfig.minAccessLevel)) {
|
|
580
|
+
if (pathname.startsWith("/api/")) {
|
|
581
|
+
return NextResponse.json(
|
|
582
|
+
{
|
|
583
|
+
success: false,
|
|
584
|
+
error: {
|
|
585
|
+
code: result.verified ? "INSUFFICIENT_ACCESS" : "UNAUTHORIZED",
|
|
586
|
+
message: result.denialReasons?.[0] || "Access denied",
|
|
587
|
+
accessLevel: result.accessLevel,
|
|
588
|
+
required: routeConfig.minAccessLevel,
|
|
589
|
+
guidance: result.guidance
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
{ status: result.verified ? 403 : 401 }
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
if (showCommerceShield) {
|
|
596
|
+
return new NextResponse(generateCommerceShieldHtml(result, options), {
|
|
597
|
+
status: 200,
|
|
598
|
+
headers: {
|
|
599
|
+
"Content-Type": "text/html",
|
|
600
|
+
"X-AstraSync-Verification": "commerce-shield"
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
return NextResponse.redirect(new URL("/unauthorized", request.url));
|
|
605
|
+
}
|
|
606
|
+
const response = NextResponse.next();
|
|
607
|
+
response.headers.set("X-AstraSync-Verified", result.verified.toString());
|
|
608
|
+
response.headers.set("X-AstraSync-Access-Level", result.accessLevel);
|
|
609
|
+
if (result.agent) {
|
|
610
|
+
response.headers.set("X-AstraSync-Agent-Id", result.agent.astraId);
|
|
611
|
+
response.headers.set("X-AstraSync-Trust-Score", result.agent.trustScore.toString());
|
|
612
|
+
}
|
|
613
|
+
return response;
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
function createMatcherConfig(paths) {
|
|
617
|
+
return { matcher: paths };
|
|
618
|
+
}
|
|
619
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
620
|
+
0 && (module.exports = {
|
|
621
|
+
createMatcherConfig,
|
|
622
|
+
createMiddleware
|
|
623
|
+
});
|
|
624
|
+
//# sourceMappingURL=nextjs.js.map
|