@kya-os/agentshield-nextjs 0.1.33 → 0.1.34
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/dist/index.d.mts +152 -3
- package/dist/index.d.ts +152 -3
- package/dist/index.js +461 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +461 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -18
package/dist/index.mjs
CHANGED
|
@@ -1055,6 +1055,466 @@ function createAgentShieldMiddleware2(config) {
|
|
|
1055
1055
|
};
|
|
1056
1056
|
}
|
|
1057
1057
|
|
|
1058
|
+
// src/wasm-confidence.ts
|
|
1059
|
+
async function checkWasmAvailability() {
|
|
1060
|
+
try {
|
|
1061
|
+
if (typeof WebAssembly === "undefined") {
|
|
1062
|
+
return false;
|
|
1063
|
+
}
|
|
1064
|
+
const wasmCode = new Uint8Array([
|
|
1065
|
+
0,
|
|
1066
|
+
97,
|
|
1067
|
+
115,
|
|
1068
|
+
109,
|
|
1069
|
+
1,
|
|
1070
|
+
0,
|
|
1071
|
+
0,
|
|
1072
|
+
0
|
|
1073
|
+
]);
|
|
1074
|
+
const module = await WebAssembly.compile(wasmCode);
|
|
1075
|
+
await WebAssembly.instantiate(module);
|
|
1076
|
+
return true;
|
|
1077
|
+
} catch {
|
|
1078
|
+
return false;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
function shouldIndicateWasmVerification(confidence) {
|
|
1082
|
+
return confidence >= 0.85 && confidence < 1;
|
|
1083
|
+
}
|
|
1084
|
+
function getWasmConfidenceBoost(baseConfidence, reasons = []) {
|
|
1085
|
+
if (reasons.some(
|
|
1086
|
+
(r) => r.includes("signature_agent") && !r.includes("signature_headers_present")
|
|
1087
|
+
)) {
|
|
1088
|
+
return 1;
|
|
1089
|
+
}
|
|
1090
|
+
if (baseConfidence >= 0.85) {
|
|
1091
|
+
return 0.95;
|
|
1092
|
+
}
|
|
1093
|
+
if (baseConfidence >= 0.7) {
|
|
1094
|
+
return Math.min(baseConfidence * 1.1, 0.9);
|
|
1095
|
+
}
|
|
1096
|
+
return baseConfidence;
|
|
1097
|
+
}
|
|
1098
|
+
function getVerificationMethod(confidence, reasons = []) {
|
|
1099
|
+
if (reasons.some(
|
|
1100
|
+
(r) => r.includes("signature_agent") && !r.includes("signature_headers_present")
|
|
1101
|
+
)) {
|
|
1102
|
+
return "signature";
|
|
1103
|
+
}
|
|
1104
|
+
if (shouldIndicateWasmVerification(confidence)) {
|
|
1105
|
+
return "wasm-enhanced";
|
|
1106
|
+
}
|
|
1107
|
+
return "pattern";
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// src/storage/memory-adapter.ts
|
|
1111
|
+
var MemoryStorageAdapter = class {
|
|
1112
|
+
events = /* @__PURE__ */ new Map();
|
|
1113
|
+
sessions = /* @__PURE__ */ new Map();
|
|
1114
|
+
eventTimeline = [];
|
|
1115
|
+
maxEvents = 1e3;
|
|
1116
|
+
maxSessions = 100;
|
|
1117
|
+
async storeEvent(event) {
|
|
1118
|
+
const eventKey = `${event.timestamp}:${event.eventId}`;
|
|
1119
|
+
this.events.set(eventKey, event);
|
|
1120
|
+
this.eventTimeline.push({
|
|
1121
|
+
timestamp: Date.parse(event.timestamp),
|
|
1122
|
+
eventId: eventKey
|
|
1123
|
+
});
|
|
1124
|
+
this.eventTimeline.sort((a, b) => b.timestamp - a.timestamp);
|
|
1125
|
+
if (this.eventTimeline.length > this.maxEvents) {
|
|
1126
|
+
const removed = this.eventTimeline.splice(this.maxEvents);
|
|
1127
|
+
removed.forEach((item) => this.events.delete(item.eventId));
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
async getRecentEvents(limit = 100) {
|
|
1131
|
+
const recent = this.eventTimeline.slice(0, limit);
|
|
1132
|
+
return recent.map((item) => this.events.get(item.eventId)).filter((event) => event !== void 0);
|
|
1133
|
+
}
|
|
1134
|
+
async getSessionEvents(sessionId) {
|
|
1135
|
+
const events = [];
|
|
1136
|
+
for (const event of this.events.values()) {
|
|
1137
|
+
if (event.sessionId === sessionId) {
|
|
1138
|
+
events.push(event);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
return events.sort(
|
|
1142
|
+
(a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp)
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
1145
|
+
async storeSession(session) {
|
|
1146
|
+
this.sessions.set(session.sessionId, session);
|
|
1147
|
+
if (this.sessions.size > this.maxSessions) {
|
|
1148
|
+
const sortedSessions = Array.from(this.sessions.entries()).sort((a, b) => Date.parse(b[1].lastSeen) - Date.parse(a[1].lastSeen));
|
|
1149
|
+
const toRemove = sortedSessions.slice(this.maxSessions);
|
|
1150
|
+
toRemove.forEach(([id]) => this.sessions.delete(id));
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
async getSession(sessionId) {
|
|
1154
|
+
return this.sessions.get(sessionId) || null;
|
|
1155
|
+
}
|
|
1156
|
+
async getRecentSessions(limit = 10) {
|
|
1157
|
+
const sorted = Array.from(this.sessions.values()).sort((a, b) => Date.parse(b.lastSeen) - Date.parse(a.lastSeen));
|
|
1158
|
+
return sorted.slice(0, limit);
|
|
1159
|
+
}
|
|
1160
|
+
async cleanup(olderThan) {
|
|
1161
|
+
const cutoff = olderThan.getTime();
|
|
1162
|
+
this.eventTimeline = this.eventTimeline.filter((item) => {
|
|
1163
|
+
if (item.timestamp < cutoff) {
|
|
1164
|
+
this.events.delete(item.eventId);
|
|
1165
|
+
return false;
|
|
1166
|
+
}
|
|
1167
|
+
return true;
|
|
1168
|
+
});
|
|
1169
|
+
for (const [id, session] of this.sessions.entries()) {
|
|
1170
|
+
if (Date.parse(session.lastSeen) < cutoff) {
|
|
1171
|
+
this.sessions.delete(id);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1176
|
+
|
|
1177
|
+
// src/storage/redis-adapter.ts
|
|
1178
|
+
var RedisStorageAdapter = class {
|
|
1179
|
+
redis;
|
|
1180
|
+
ttl;
|
|
1181
|
+
keyPrefix = "agent-shield";
|
|
1182
|
+
constructor(redis, ttl = 86400) {
|
|
1183
|
+
this.redis = redis;
|
|
1184
|
+
this.ttl = ttl;
|
|
1185
|
+
}
|
|
1186
|
+
eventKey(timestamp, eventId) {
|
|
1187
|
+
return `${this.keyPrefix}:events:${timestamp}:${eventId}`;
|
|
1188
|
+
}
|
|
1189
|
+
sessionKey(sessionId) {
|
|
1190
|
+
return `${this.keyPrefix}:sessions:${sessionId}`;
|
|
1191
|
+
}
|
|
1192
|
+
timelineKey() {
|
|
1193
|
+
return `${this.keyPrefix}:events:timeline`;
|
|
1194
|
+
}
|
|
1195
|
+
async storeEvent(event) {
|
|
1196
|
+
const key = this.eventKey(event.timestamp, event.eventId);
|
|
1197
|
+
await this.redis.setex(key, this.ttl, JSON.stringify(event));
|
|
1198
|
+
await this.redis.zadd(this.timelineKey(), {
|
|
1199
|
+
score: Date.parse(event.timestamp),
|
|
1200
|
+
member: key
|
|
1201
|
+
});
|
|
1202
|
+
const count = await this.redis.zcard(this.timelineKey());
|
|
1203
|
+
if (count && count > 1e3) {
|
|
1204
|
+
await this.redis.zremrangebyrank(this.timelineKey(), 0, -1001);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
async getRecentEvents(limit = 100) {
|
|
1208
|
+
const keys = await this.redis.zrevrange(this.timelineKey(), 0, limit - 1);
|
|
1209
|
+
if (!keys || keys.length === 0) {
|
|
1210
|
+
return [];
|
|
1211
|
+
}
|
|
1212
|
+
const events = [];
|
|
1213
|
+
for (const key of keys) {
|
|
1214
|
+
const data = await this.redis.get(key);
|
|
1215
|
+
if (data) {
|
|
1216
|
+
try {
|
|
1217
|
+
const event = typeof data === "string" ? JSON.parse(data) : data;
|
|
1218
|
+
events.push(event);
|
|
1219
|
+
} catch (e) {
|
|
1220
|
+
console.error(`Failed to parse event ${key}:`, e);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
return events;
|
|
1225
|
+
}
|
|
1226
|
+
async getSessionEvents(sessionId) {
|
|
1227
|
+
const keys = await this.redis.zrevrange(this.timelineKey(), 0, -1);
|
|
1228
|
+
if (!keys || keys.length === 0) {
|
|
1229
|
+
return [];
|
|
1230
|
+
}
|
|
1231
|
+
const events = [];
|
|
1232
|
+
for (const key of keys) {
|
|
1233
|
+
const data = await this.redis.get(key);
|
|
1234
|
+
if (data) {
|
|
1235
|
+
try {
|
|
1236
|
+
const event = typeof data === "string" ? JSON.parse(data) : data;
|
|
1237
|
+
if (event.sessionId === sessionId) {
|
|
1238
|
+
events.push(event);
|
|
1239
|
+
}
|
|
1240
|
+
} catch (e) {
|
|
1241
|
+
console.error(`Failed to parse event ${key}:`, e);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
return events;
|
|
1246
|
+
}
|
|
1247
|
+
async storeSession(session) {
|
|
1248
|
+
const key = this.sessionKey(session.sessionId);
|
|
1249
|
+
const existing = await this.redis.get(key);
|
|
1250
|
+
if (existing) {
|
|
1251
|
+
const existingSession = typeof existing === "string" ? JSON.parse(existing) : existing;
|
|
1252
|
+
const methods = /* @__PURE__ */ new Set([
|
|
1253
|
+
...existingSession.verificationMethods || [],
|
|
1254
|
+
...session.verificationMethods
|
|
1255
|
+
]);
|
|
1256
|
+
const updatedSession = {
|
|
1257
|
+
...existingSession,
|
|
1258
|
+
lastSeen: session.lastSeen,
|
|
1259
|
+
eventCount: session.eventCount,
|
|
1260
|
+
paths: Array.from(/* @__PURE__ */ new Set([...existingSession.paths, ...session.paths])),
|
|
1261
|
+
averageConfidence: session.averageConfidence,
|
|
1262
|
+
verificationMethods: Array.from(methods)
|
|
1263
|
+
};
|
|
1264
|
+
await this.redis.setex(key, this.ttl, JSON.stringify(updatedSession));
|
|
1265
|
+
} else {
|
|
1266
|
+
await this.redis.setex(key, this.ttl, JSON.stringify(session));
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
async getSession(sessionId) {
|
|
1270
|
+
const key = this.sessionKey(sessionId);
|
|
1271
|
+
const data = await this.redis.get(key);
|
|
1272
|
+
if (!data) {
|
|
1273
|
+
return null;
|
|
1274
|
+
}
|
|
1275
|
+
try {
|
|
1276
|
+
return typeof data === "string" ? JSON.parse(data) : data;
|
|
1277
|
+
} catch (e) {
|
|
1278
|
+
console.error(`Failed to parse session ${sessionId}:`, e);
|
|
1279
|
+
return null;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
async getRecentSessions(limit = 10) {
|
|
1283
|
+
const pattern = `${this.keyPrefix}:sessions:*`;
|
|
1284
|
+
const sessions = [];
|
|
1285
|
+
let cursor = 0;
|
|
1286
|
+
do {
|
|
1287
|
+
const [nextCursor, keys] = await this.redis.scan(cursor, {
|
|
1288
|
+
match: pattern,
|
|
1289
|
+
count: 100
|
|
1290
|
+
});
|
|
1291
|
+
cursor = parseInt(nextCursor);
|
|
1292
|
+
for (const key of keys) {
|
|
1293
|
+
const data = await this.redis.get(key);
|
|
1294
|
+
if (data) {
|
|
1295
|
+
try {
|
|
1296
|
+
const session = typeof data === "string" ? JSON.parse(data) : data;
|
|
1297
|
+
sessions.push(session);
|
|
1298
|
+
} catch (e) {
|
|
1299
|
+
console.error(`Failed to parse session from ${key}:`, e);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
} while (cursor !== 0 && sessions.length < limit * 2);
|
|
1304
|
+
return sessions.sort((a, b) => Date.parse(b.lastSeen) - Date.parse(a.lastSeen)).slice(0, limit);
|
|
1305
|
+
}
|
|
1306
|
+
async cleanup(olderThan) {
|
|
1307
|
+
const cutoff = olderThan.getTime();
|
|
1308
|
+
await this.redis.zremrangebyrank(
|
|
1309
|
+
this.timelineKey(),
|
|
1310
|
+
0,
|
|
1311
|
+
Math.floor(cutoff / 1e3)
|
|
1312
|
+
);
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
|
|
1316
|
+
// src/storage/index.ts
|
|
1317
|
+
async function createStorageAdapter(config) {
|
|
1318
|
+
if (!config || config.type === "memory") {
|
|
1319
|
+
return new MemoryStorageAdapter();
|
|
1320
|
+
}
|
|
1321
|
+
if (config.type === "custom" && config.custom) {
|
|
1322
|
+
return config.custom;
|
|
1323
|
+
}
|
|
1324
|
+
if (config.type === "redis" && config.redis) {
|
|
1325
|
+
try {
|
|
1326
|
+
const { Redis } = await import('@upstash/redis');
|
|
1327
|
+
const redis = new Redis({
|
|
1328
|
+
url: config.redis.url,
|
|
1329
|
+
token: config.redis.token
|
|
1330
|
+
});
|
|
1331
|
+
return new RedisStorageAdapter(redis, config.ttl);
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
console.warn("[AgentShield] Failed to initialize Redis storage, falling back to memory:", error);
|
|
1334
|
+
return new MemoryStorageAdapter();
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
return new MemoryStorageAdapter();
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// src/enhanced-middleware.ts
|
|
1341
|
+
var SessionManager = class {
|
|
1342
|
+
sessionLastActivity = /* @__PURE__ */ new Map();
|
|
1343
|
+
generateSessionId(ipAddress, userAgent) {
|
|
1344
|
+
const now = Date.now();
|
|
1345
|
+
const timeWindow = Math.floor(now / (5 * 60 * 1e3));
|
|
1346
|
+
const baseKey = `${ipAddress || "unknown"}:${userAgent || "unknown"}`;
|
|
1347
|
+
const windowKey = `${baseKey}:${timeWindow}`;
|
|
1348
|
+
const lastActivity = this.sessionLastActivity.get(windowKey);
|
|
1349
|
+
const shouldCreateNewSession = !lastActivity || now - lastActivity > 3e4;
|
|
1350
|
+
this.sessionLastActivity.set(windowKey, now);
|
|
1351
|
+
if (this.sessionLastActivity.size > 100) {
|
|
1352
|
+
const cutoff = now - 6e5;
|
|
1353
|
+
for (const [key, time] of this.sessionLastActivity.entries()) {
|
|
1354
|
+
if (time < cutoff) {
|
|
1355
|
+
this.sessionLastActivity.delete(key);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
const data = shouldCreateNewSession ? `${windowKey}:${now}` : `${windowKey}:${lastActivity}`;
|
|
1360
|
+
let hash = 0;
|
|
1361
|
+
for (let i = 0; i < data.length; i++) {
|
|
1362
|
+
const char = data.charCodeAt(i);
|
|
1363
|
+
hash = (hash << 5) - hash + char;
|
|
1364
|
+
hash = hash & hash;
|
|
1365
|
+
}
|
|
1366
|
+
return Math.abs(hash).toString(16).padStart(12, "0").substring(0, 12);
|
|
1367
|
+
}
|
|
1368
|
+
};
|
|
1369
|
+
function createEnhancedAgentShieldMiddleware(config = {}) {
|
|
1370
|
+
let storageAdapter = null;
|
|
1371
|
+
let storageInitPromise = null;
|
|
1372
|
+
const getStorage = async () => {
|
|
1373
|
+
if (storageAdapter) return storageAdapter;
|
|
1374
|
+
if (storageInitPromise) return storageInitPromise;
|
|
1375
|
+
storageInitPromise = createStorageAdapter(config.storage).then((adapter) => {
|
|
1376
|
+
storageAdapter = adapter;
|
|
1377
|
+
return adapter;
|
|
1378
|
+
});
|
|
1379
|
+
return storageInitPromise;
|
|
1380
|
+
};
|
|
1381
|
+
let wasmAvailable = false;
|
|
1382
|
+
checkWasmAvailability().then((available) => {
|
|
1383
|
+
wasmAvailable = available;
|
|
1384
|
+
if (available) {
|
|
1385
|
+
console.log("[AgentShield] \u2705 WASM support detected - enhanced detection enabled");
|
|
1386
|
+
}
|
|
1387
|
+
});
|
|
1388
|
+
const detector = wasmAvailable ? new EdgeAgentDetectorWrapperWithWasm({ enableWasm: true }) : new EdgeAgentDetectorWrapper({});
|
|
1389
|
+
const sessionManager = new SessionManager();
|
|
1390
|
+
const sessionTrackingEnabled = config.sessionTracking?.enabled !== false;
|
|
1391
|
+
return async (request) => {
|
|
1392
|
+
const { pathname } = request.nextUrl;
|
|
1393
|
+
if (config.skipPaths?.some((path) => pathname.startsWith(path))) {
|
|
1394
|
+
return NextResponse.next();
|
|
1395
|
+
}
|
|
1396
|
+
const userAgent = request.headers.get("user-agent");
|
|
1397
|
+
const ipAddress = request.ip ?? request.headers.get("x-forwarded-for");
|
|
1398
|
+
const url = new URL(request.url);
|
|
1399
|
+
const pathWithQuery = url.pathname + url.search;
|
|
1400
|
+
const context = {
|
|
1401
|
+
userAgent: userAgent || "",
|
|
1402
|
+
ipAddress: ipAddress || "",
|
|
1403
|
+
headers: Object.fromEntries(request.headers.entries()),
|
|
1404
|
+
url: pathWithQuery,
|
|
1405
|
+
method: request.method,
|
|
1406
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
1407
|
+
};
|
|
1408
|
+
const result = await detector.analyze(context);
|
|
1409
|
+
let finalConfidence = result.confidence;
|
|
1410
|
+
let verificationMethod = result.verificationMethod || "pattern";
|
|
1411
|
+
if (result.isAgent) {
|
|
1412
|
+
const reasons = result.reasons || [];
|
|
1413
|
+
if (shouldIndicateWasmVerification(result.confidence)) {
|
|
1414
|
+
finalConfidence = getWasmConfidenceBoost(result.confidence, reasons);
|
|
1415
|
+
verificationMethod = getVerificationMethod(finalConfidence, reasons);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
if (result.isAgent && finalConfidence >= (config.confidenceThreshold ?? 0.7)) {
|
|
1419
|
+
if (sessionTrackingEnabled) {
|
|
1420
|
+
const storage = await getStorage();
|
|
1421
|
+
const sessionId = sessionManager.generateSessionId(ipAddress || void 0, userAgent || void 0);
|
|
1422
|
+
const event = {
|
|
1423
|
+
eventId: `agent_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`,
|
|
1424
|
+
sessionId,
|
|
1425
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1426
|
+
agentType: result.detectedAgent?.type || "unknown",
|
|
1427
|
+
agentName: result.detectedAgent?.name || "Unknown",
|
|
1428
|
+
confidence: finalConfidence,
|
|
1429
|
+
path: pathWithQuery,
|
|
1430
|
+
...userAgent && { userAgent },
|
|
1431
|
+
...ipAddress && { ipAddress },
|
|
1432
|
+
method: request.method,
|
|
1433
|
+
detectionReasons: result.reasons || [],
|
|
1434
|
+
verificationMethod,
|
|
1435
|
+
detectionDetails: {
|
|
1436
|
+
patterns: result.detectedAgent?.patterns,
|
|
1437
|
+
behaviors: result.detectedAgent?.behaviors,
|
|
1438
|
+
fingerprintMatches: result.detectedAgent?.fingerprints
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
try {
|
|
1442
|
+
await storage.storeEvent(event);
|
|
1443
|
+
let session = await storage.getSession(sessionId);
|
|
1444
|
+
if (session) {
|
|
1445
|
+
session.lastSeen = event.timestamp;
|
|
1446
|
+
session.eventCount++;
|
|
1447
|
+
if (!session.paths.includes(pathWithQuery)) {
|
|
1448
|
+
session.paths.push(pathWithQuery);
|
|
1449
|
+
}
|
|
1450
|
+
session.averageConfidence = (session.averageConfidence * (session.eventCount - 1) + finalConfidence) / session.eventCount;
|
|
1451
|
+
if (!session.verificationMethods.includes(verificationMethod)) {
|
|
1452
|
+
session.verificationMethods.push(verificationMethod);
|
|
1453
|
+
}
|
|
1454
|
+
} else {
|
|
1455
|
+
session = {
|
|
1456
|
+
sessionId,
|
|
1457
|
+
...ipAddress && { ipAddress },
|
|
1458
|
+
...userAgent && { userAgent },
|
|
1459
|
+
agentType: result.detectedAgent?.type || "unknown",
|
|
1460
|
+
agentName: result.detectedAgent?.name || "Unknown",
|
|
1461
|
+
firstSeen: event.timestamp,
|
|
1462
|
+
lastSeen: event.timestamp,
|
|
1463
|
+
eventCount: 1,
|
|
1464
|
+
paths: [pathWithQuery],
|
|
1465
|
+
averageConfidence: finalConfidence,
|
|
1466
|
+
verificationMethods: [verificationMethod]
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
if (session) {
|
|
1470
|
+
await storage.storeSession(session);
|
|
1471
|
+
}
|
|
1472
|
+
} catch (error) {
|
|
1473
|
+
console.error("[AgentShield] Failed to store event:", error);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
if (config.onDetection) {
|
|
1477
|
+
await config.onDetection(result, context);
|
|
1478
|
+
}
|
|
1479
|
+
switch (config.onAgentDetected) {
|
|
1480
|
+
case "block": {
|
|
1481
|
+
const { status = 403, message = "Access denied: AI agent detected" } = config.blockedResponse || {};
|
|
1482
|
+
const response2 = NextResponse.json(
|
|
1483
|
+
{ error: message, detected: true, confidence: finalConfidence },
|
|
1484
|
+
{ status }
|
|
1485
|
+
);
|
|
1486
|
+
response2.headers.set("x-agentshield-detected", "true");
|
|
1487
|
+
response2.headers.set("x-agentshield-confidence", String(Math.round(finalConfidence * 100)));
|
|
1488
|
+
response2.headers.set("x-agentshield-agent", result.detectedAgent?.name || "Unknown");
|
|
1489
|
+
response2.headers.set("x-agentshield-verification", verificationMethod);
|
|
1490
|
+
return response2;
|
|
1491
|
+
}
|
|
1492
|
+
case "log":
|
|
1493
|
+
console.log(`[AgentShield] \u{1F916} AI Agent detected (${verificationMethod}):`, {
|
|
1494
|
+
agent: result.detectedAgent?.name,
|
|
1495
|
+
confidence: `${(finalConfidence * 100).toFixed(0)}%`,
|
|
1496
|
+
path: pathWithQuery,
|
|
1497
|
+
verification: verificationMethod
|
|
1498
|
+
});
|
|
1499
|
+
break;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
const response = NextResponse.next();
|
|
1503
|
+
if (result.isAgent) {
|
|
1504
|
+
response.headers.set("x-agentshield-detected", "true");
|
|
1505
|
+
response.headers.set("x-agentshield-confidence", String(Math.round(finalConfidence * 100)));
|
|
1506
|
+
response.headers.set("x-agentshield-agent", result.detectedAgent?.name || "Unknown");
|
|
1507
|
+
response.headers.set("x-agentshield-verification", verificationMethod);
|
|
1508
|
+
if (finalConfidence > 0.9) {
|
|
1509
|
+
response.headers.set("x-ai-visitor", "true");
|
|
1510
|
+
response.headers.set("x-ai-confidence", finalConfidence.toString());
|
|
1511
|
+
response.headers.set("x-ai-verification", verificationMethod);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
return response;
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1058
1518
|
// src/index.ts
|
|
1059
1519
|
var VERSION = "0.1.0";
|
|
1060
1520
|
/**
|
|
@@ -1063,6 +1523,6 @@ var VERSION = "0.1.0";
|
|
|
1063
1523
|
* @license MIT OR Apache-2.0
|
|
1064
1524
|
*/
|
|
1065
1525
|
|
|
1066
|
-
export { EdgeSessionTracker, StatelessSessionChecker, VERSION, createAgentShieldMiddleware2 as createAgentShieldMiddleware, createAgentShieldMiddleware as createAgentShieldMiddlewareBase, createAgentShieldMiddleware2 as createMiddleware };
|
|
1526
|
+
export { EdgeSessionTracker, StatelessSessionChecker, VERSION, createAgentShieldMiddleware2 as createAgentShieldMiddleware, createAgentShieldMiddleware as createAgentShieldMiddlewareBase, createEnhancedAgentShieldMiddleware, createAgentShieldMiddleware2 as createMiddleware };
|
|
1067
1527
|
//# sourceMappingURL=index.mjs.map
|
|
1068
1528
|
//# sourceMappingURL=index.mjs.map
|