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