@kya-os/agentshield-nextjs 0.2.13 → 0.3.1

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.
Files changed (73) hide show
  1. package/dist/api-client.d.mts +6 -1
  2. package/dist/api-client.d.ts +6 -1
  3. package/dist/api-client.js.map +1 -1
  4. package/dist/api-client.mjs.map +1 -1
  5. package/dist/api-middleware.d.mts +13 -0
  6. package/dist/api-middleware.d.ts +13 -0
  7. package/dist/api-middleware.js +149 -19
  8. package/dist/api-middleware.js.map +1 -1
  9. package/dist/api-middleware.mjs +149 -19
  10. package/dist/api-middleware.mjs.map +1 -1
  11. package/dist/create-middleware.js +565 -487
  12. package/dist/create-middleware.js.map +1 -1
  13. package/dist/create-middleware.mjs +565 -487
  14. package/dist/create-middleware.mjs.map +1 -1
  15. package/dist/edge/index.js +69 -46
  16. package/dist/edge/index.js.map +1 -1
  17. package/dist/edge/index.mjs +69 -46
  18. package/dist/edge/index.mjs.map +1 -1
  19. package/dist/edge-detector-wrapper.js +9 -1
  20. package/dist/edge-detector-wrapper.js.map +1 -1
  21. package/dist/edge-detector-wrapper.mjs +9 -1
  22. package/dist/edge-detector-wrapper.mjs.map +1 -1
  23. package/dist/edge-runtime-loader.d.mts +1 -0
  24. package/dist/edge-runtime-loader.d.ts +1 -0
  25. package/dist/edge-runtime-loader.js +19 -3
  26. package/dist/edge-runtime-loader.js.map +1 -1
  27. package/dist/edge-runtime-loader.mjs +19 -3
  28. package/dist/edge-runtime-loader.mjs.map +1 -1
  29. package/dist/edge-wasm-middleware.d.mts +1 -0
  30. package/dist/edge-wasm-middleware.d.ts +1 -0
  31. package/dist/edge-wasm-middleware.js +10 -2
  32. package/dist/edge-wasm-middleware.js.map +1 -1
  33. package/dist/edge-wasm-middleware.mjs +11 -3
  34. package/dist/edge-wasm-middleware.mjs.map +1 -1
  35. package/dist/enhanced-middleware.js +48 -20
  36. package/dist/enhanced-middleware.js.map +1 -1
  37. package/dist/enhanced-middleware.mjs +49 -21
  38. package/dist/enhanced-middleware.mjs.map +1 -1
  39. package/dist/index.d.mts +1 -1
  40. package/dist/index.d.ts +1 -1
  41. package/dist/index.js +263 -102
  42. package/dist/index.js.map +1 -1
  43. package/dist/index.mjs +264 -103
  44. package/dist/index.mjs.map +1 -1
  45. package/dist/middleware.js +565 -487
  46. package/dist/middleware.js.map +1 -1
  47. package/dist/middleware.mjs +565 -487
  48. package/dist/middleware.mjs.map +1 -1
  49. package/dist/policy.d.mts +16 -4
  50. package/dist/policy.d.ts +16 -4
  51. package/dist/policy.js +14 -10
  52. package/dist/policy.js.map +1 -1
  53. package/dist/policy.mjs +14 -10
  54. package/dist/policy.mjs.map +1 -1
  55. package/dist/session-tracker.js +13 -19
  56. package/dist/session-tracker.js.map +1 -1
  57. package/dist/session-tracker.mjs +13 -19
  58. package/dist/session-tracker.mjs.map +1 -1
  59. package/dist/signature-verifier.js +9 -1
  60. package/dist/signature-verifier.js.map +1 -1
  61. package/dist/signature-verifier.mjs +9 -1
  62. package/dist/signature-verifier.mjs.map +1 -1
  63. package/dist/wasm-middleware.d.mts +1 -0
  64. package/dist/wasm-middleware.d.ts +1 -0
  65. package/dist/wasm-middleware.js +15 -15
  66. package/dist/wasm-middleware.js.map +1 -1
  67. package/dist/wasm-middleware.mjs +15 -15
  68. package/dist/wasm-middleware.mjs.map +1 -1
  69. package/package.json +3 -3
  70. package/wasm/agentshield_wasm.d.ts +379 -21
  71. package/wasm/agentshield_wasm.js +1409 -506
  72. package/wasm/agentshield_wasm_bg.wasm +0 -0
  73. package/dist/.tsbuildinfo +0 -1
@@ -1,9 +1,457 @@
1
+ import { loadRulesSync, evaluateEnforcement, shouldEnforce, mapVerificationMethod } from '@kya-os/agentshield-shared';
1
2
  import { NextResponse } from 'next/server';
2
3
  import * as ed25519 from '@noble/ed25519';
3
4
  import { sha512 } from '@noble/hashes/sha2.js';
4
- import { loadRulesSync, mapVerificationMethod } from '@kya-os/agentshield-shared';
5
5
 
6
- // src/create-middleware.ts
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+
16
+ // src/wasm-loader.ts
17
+ function setWasmBaseUrl(url) {
18
+ baseUrl = url;
19
+ }
20
+ function getWasmUrl() {
21
+ if (baseUrl) {
22
+ try {
23
+ const url = new URL(baseUrl);
24
+ return `${url.origin}${WASM_PATH}`;
25
+ } catch {
26
+ return WASM_PATH;
27
+ }
28
+ }
29
+ return WASM_PATH;
30
+ }
31
+ async function initWasm() {
32
+ if (wasmExports) return true;
33
+ if (initPromise) {
34
+ await initPromise;
35
+ return !!wasmExports;
36
+ }
37
+ initPromise = (async () => {
38
+ try {
39
+ const controller = new AbortController();
40
+ const timeout = setTimeout(() => controller.abort(), 3e3);
41
+ try {
42
+ const wasmUrl = getWasmUrl();
43
+ if (typeof WebAssembly.instantiateStreaming === "function") {
44
+ try {
45
+ const response2 = await fetch(wasmUrl, { signal: controller.signal });
46
+ clearTimeout(timeout);
47
+ if (!response2.ok) {
48
+ throw new Error(`Failed to fetch WASM: ${response2.status}`);
49
+ }
50
+ const streamResponse = response2.clone();
51
+ const { instance } = await WebAssembly.instantiateStreaming(streamResponse, {
52
+ wbg: {
53
+ __wbg_log_1d3ae13c3d5e6b8e: (ptr, len) => {
54
+ if (process.env.NODE_ENV !== "production") {
55
+ console.debug("WASM:", ptr, len);
56
+ }
57
+ },
58
+ __wbindgen_throw: (ptr, len) => {
59
+ throw new Error(`WASM Error at ${ptr}, length ${len}`);
60
+ }
61
+ }
62
+ });
63
+ wasmInstance = instance;
64
+ wasmExports = instance.exports;
65
+ if (process.env.NODE_ENV !== "production") {
66
+ console.debug("[AgentShield] \u2705 WASM module initialized with streaming");
67
+ }
68
+ return;
69
+ } catch (streamError) {
70
+ if (!controller.signal.aborted) {
71
+ if (process.env.NODE_ENV !== "production") {
72
+ console.debug(
73
+ "[AgentShield] Streaming compilation failed, falling back to standard compilation"
74
+ );
75
+ }
76
+ } else {
77
+ throw streamError;
78
+ }
79
+ }
80
+ }
81
+ const response = await fetch(wasmUrl, { signal: controller.signal });
82
+ clearTimeout(timeout);
83
+ if (!response.ok) {
84
+ throw new Error(`Failed to fetch WASM: ${response.status}`);
85
+ }
86
+ const wasmArrayBuffer = await response.arrayBuffer();
87
+ const compiledModule = await WebAssembly.compile(wasmArrayBuffer);
88
+ const imports = {
89
+ wbg: {
90
+ __wbg_log_1d3ae13c3d5e6b8e: (ptr, len) => {
91
+ if (process.env.NODE_ENV !== "production") {
92
+ console.debug("WASM:", ptr, len);
93
+ }
94
+ },
95
+ __wbindgen_throw: (ptr, len) => {
96
+ throw new Error(`WASM Error at ${ptr}, length ${len}`);
97
+ }
98
+ }
99
+ };
100
+ wasmInstance = await WebAssembly.instantiate(compiledModule, imports);
101
+ wasmExports = wasmInstance.exports;
102
+ if (process.env.NODE_ENV !== "production") {
103
+ console.debug("[AgentShield] \u2705 WASM module initialized via fallback");
104
+ }
105
+ } catch (fetchError) {
106
+ const error = fetchError;
107
+ if (error.name === "AbortError") {
108
+ console.warn(
109
+ "[AgentShield] WASM fetch timed out after 3 seconds - using pattern detection"
110
+ );
111
+ } else {
112
+ console.warn(
113
+ "[AgentShield] Failed to fetch WASM file:",
114
+ error.message || "Unknown error"
115
+ );
116
+ }
117
+ wasmExports = null;
118
+ }
119
+ } catch (error) {
120
+ console.error("[AgentShield] Failed to initialize WASM:", error);
121
+ wasmExports = null;
122
+ }
123
+ })();
124
+ await initPromise;
125
+ return !!wasmExports;
126
+ }
127
+ async function detectAgentWithWasm(_userAgent, _headers, _ipAddress) {
128
+ return null;
129
+ }
130
+ async function getWasmVersion() {
131
+ const initialized = await initWasm();
132
+ if (!initialized || !wasmExports) {
133
+ return null;
134
+ }
135
+ if (typeof wasmExports.version === "function") {
136
+ return wasmExports.version();
137
+ }
138
+ return "unknown";
139
+ }
140
+ async function isWasmAvailable() {
141
+ try {
142
+ const initialized = await initWasm();
143
+ if (!initialized) return false;
144
+ const version = await getWasmVersion();
145
+ return version !== null;
146
+ } catch {
147
+ return false;
148
+ }
149
+ }
150
+ var wasmInstance, wasmExports, initPromise, WASM_PATH, baseUrl;
151
+ var init_wasm_loader = __esm({
152
+ "src/wasm-loader.ts"() {
153
+ wasmInstance = null;
154
+ wasmExports = null;
155
+ initPromise = null;
156
+ WASM_PATH = "/wasm/agentshield_wasm_bg.wasm";
157
+ baseUrl = null;
158
+ }
159
+ });
160
+
161
+ // src/edge-detector-with-wasm.ts
162
+ var edge_detector_with_wasm_exports = {};
163
+ __export(edge_detector_with_wasm_exports, {
164
+ EdgeAgentDetectorWithWasm: () => EdgeAgentDetectorWithWasm,
165
+ EdgeAgentDetectorWrapperWithWasm: () => EdgeAgentDetectorWrapperWithWasm
166
+ });
167
+ var rules2, EdgeAgentDetectorWithWasm, EdgeAgentDetectorWrapperWithWasm;
168
+ var init_edge_detector_with_wasm = __esm({
169
+ "src/edge-detector-with-wasm.ts"() {
170
+ init_wasm_loader();
171
+ rules2 = loadRulesSync();
172
+ EdgeAgentDetectorWithWasm = class {
173
+ constructor(enableWasm = true) {
174
+ this.enableWasm = enableWasm;
175
+ this.rules = rules2;
176
+ }
177
+ wasmEnabled = false;
178
+ initPromise = null;
179
+ baseUrl = null;
180
+ rules;
181
+ /**
182
+ * Set the base URL for WASM loading in Edge Runtime
183
+ */
184
+ setBaseUrl(url) {
185
+ this.baseUrl = url;
186
+ setWasmBaseUrl(url);
187
+ }
188
+ /**
189
+ * Initialize the detector (including WASM if enabled)
190
+ */
191
+ async init() {
192
+ if (!this.enableWasm) {
193
+ this.wasmEnabled = false;
194
+ return;
195
+ }
196
+ if (this.initPromise) {
197
+ await this.initPromise;
198
+ return;
199
+ }
200
+ this.initPromise = (async () => {
201
+ try {
202
+ const wasmAvailable = await isWasmAvailable();
203
+ if (wasmAvailable) {
204
+ if (this.baseUrl) {
205
+ setWasmBaseUrl(this.baseUrl);
206
+ }
207
+ await initWasm();
208
+ this.wasmEnabled = true;
209
+ } else {
210
+ this.wasmEnabled = false;
211
+ }
212
+ } catch (error) {
213
+ console.error("[AgentShield] Failed to initialize WASM:", error);
214
+ this.wasmEnabled = false;
215
+ }
216
+ })();
217
+ await this.initPromise;
218
+ }
219
+ /**
220
+ * Pattern-based detection (fallback)
221
+ */
222
+ async patternDetection(input) {
223
+ const reasons = [];
224
+ let detectedAgent;
225
+ let verificationMethod;
226
+ let confidence = 0;
227
+ const headers = input.headers || {};
228
+ const normalizedHeaders = {};
229
+ for (const [key, value] of Object.entries(headers)) {
230
+ normalizedHeaders[key.toLowerCase()] = value;
231
+ }
232
+ const signaturePresent = !!(normalizedHeaders["signature"] || normalizedHeaders["signature-input"]);
233
+ const signatureAgent = normalizedHeaders["signature-agent"];
234
+ const isChatGPT = (() => {
235
+ try {
236
+ const url = new URL(signatureAgent?.replace(/^"|"$/g, "") || "");
237
+ return url.hostname === "chatgpt.com" || url.hostname.endsWith(".chatgpt.com");
238
+ } catch {
239
+ return false;
240
+ }
241
+ })();
242
+ if (isChatGPT) {
243
+ confidence = 85;
244
+ reasons.push("signature_agent:chatgpt");
245
+ detectedAgent = { type: "chatgpt", name: "ChatGPT" };
246
+ verificationMethod = "signature";
247
+ } else if (signaturePresent) {
248
+ confidence = Math.max(confidence, 40);
249
+ reasons.push("signature_present");
250
+ }
251
+ const userAgent = input.userAgent || input.headers?.["user-agent"] || "";
252
+ if (userAgent) {
253
+ for (const [agentKey, agentRule] of Object.entries(this.rules.rules.userAgents)) {
254
+ const matched = agentRule.patterns.some((pattern) => {
255
+ const regex = new RegExp(pattern, "i");
256
+ return regex.test(userAgent);
257
+ });
258
+ if (matched) {
259
+ const agentType = this.getAgentType(agentKey);
260
+ const agentName = this.getAgentName(agentKey);
261
+ confidence = Math.max(confidence, Math.round(agentRule.confidence * 0.85 * 100));
262
+ reasons.push(`known_pattern:${agentType}`);
263
+ if (!detectedAgent) {
264
+ detectedAgent = { type: agentType, name: agentName };
265
+ verificationMethod = "pattern";
266
+ }
267
+ break;
268
+ }
269
+ }
270
+ }
271
+ const suspiciousHeaders = this.rules.rules.headers.suspicious;
272
+ const foundAiHeaders = suspiciousHeaders.filter(
273
+ (headerRule) => normalizedHeaders[headerRule.name.toLowerCase()]
274
+ );
275
+ if (foundAiHeaders.length > 0) {
276
+ const maxConfidence = Math.max(...foundAiHeaders.map((h) => h.confidence));
277
+ confidence = Math.max(confidence, maxConfidence);
278
+ reasons.push(`ai_headers:${foundAiHeaders.length}`);
279
+ }
280
+ const ip = input.ip || input.ipAddress;
281
+ if (ip && !normalizedHeaders["x-forwarded-for"] && !normalizedHeaders["x-real-ip"]) {
282
+ const ipRanges = "providers" in this.rules.rules.ipRanges ? this.rules.rules.ipRanges.providers : this.rules.rules.ipRanges;
283
+ for (const [provider, ipRule] of Object.entries(ipRanges)) {
284
+ if (!ipRule || typeof ipRule !== "object" || !("ranges" in ipRule) || !Array.isArray(ipRule.ranges))
285
+ continue;
286
+ const matched = ipRule.ranges.some((range) => {
287
+ const prefix = range.split("/")[0];
288
+ const prefixParts = prefix.split(".");
289
+ const ipParts = ip.split(".");
290
+ for (let i = 0; i < Math.min(prefixParts.length - 1, 2); i++) {
291
+ if (prefixParts[i] !== ipParts[i] && prefixParts[i] !== "0") {
292
+ return false;
293
+ }
294
+ }
295
+ return true;
296
+ });
297
+ if (matched) {
298
+ confidence = Math.max(confidence, Math.round(ipRule.confidence * 0.4 * 100));
299
+ reasons.push(`cloud_provider:${provider}`);
300
+ break;
301
+ }
302
+ }
303
+ }
304
+ if (reasons.length > 2) {
305
+ confidence = Math.min(Math.round(confidence * 1.2), 95);
306
+ }
307
+ confidence = Math.min(Math.max(confidence, 0), 100);
308
+ return {
309
+ isAgent: confidence > 30,
310
+ // 30% threshold
311
+ confidence,
312
+ detectionClass: confidence > 30 && detectedAgent ? { type: "AiAgent", agentType: detectedAgent.name } : confidence > 30 ? { type: "Unknown" } : { type: "Human" },
313
+ signals: [],
314
+ // Will be populated by enhanced detection engine in future tasks
315
+ ...detectedAgent && { detectedAgent },
316
+ reasons,
317
+ ...verificationMethod && {
318
+ verificationMethod: mapVerificationMethod(verificationMethod)
319
+ },
320
+ forgeabilityRisk: confidence > 80 ? "medium" : "high",
321
+ timestamp: /* @__PURE__ */ new Date()
322
+ };
323
+ }
324
+ /**
325
+ * Analyze request with WASM enhancement when available
326
+ */
327
+ async analyze(input) {
328
+ await this.init();
329
+ if (this.wasmEnabled) {
330
+ try {
331
+ const wasmResult = await detectAgentWithWasm(
332
+ input.userAgent || input.headers?.["user-agent"],
333
+ input.headers || {},
334
+ input.ip || input.ipAddress
335
+ );
336
+ if (wasmResult) {
337
+ const detectedAgent = wasmResult.agent ? this.mapAgentName(wasmResult.agent) : void 0;
338
+ return {
339
+ isAgent: wasmResult.isAgent,
340
+ confidence: wasmResult.confidence,
341
+ detectionClass: wasmResult.isAgent && detectedAgent ? { type: "AiAgent", agentType: detectedAgent.name } : wasmResult.isAgent ? { type: "Unknown" } : { type: "Human" },
342
+ signals: [],
343
+ // Will be populated by enhanced detection engine in future tasks
344
+ ...detectedAgent && { detectedAgent },
345
+ reasons: [`wasm:${wasmResult.verificationMethod}`],
346
+ verificationMethod: mapVerificationMethod(wasmResult.verificationMethod),
347
+ forgeabilityRisk: wasmResult.verificationMethod === "signature" ? "low" : wasmResult.confidence > 90 ? "medium" : "high",
348
+ timestamp: /* @__PURE__ */ new Date()
349
+ };
350
+ }
351
+ } catch (error) {
352
+ console.error("[AgentShield] WASM detection error:", error);
353
+ }
354
+ }
355
+ const patternResult = await this.patternDetection(input);
356
+ if (this.wasmEnabled && patternResult.confidence >= 85) {
357
+ patternResult.confidence = Math.min(95, patternResult.confidence + 10);
358
+ patternResult.reasons.push("wasm_enhanced");
359
+ }
360
+ return patternResult;
361
+ }
362
+ /**
363
+ * Get agent type from rule key
364
+ */
365
+ getAgentType(agentKey) {
366
+ const typeMap = {
367
+ openai_gptbot: "openai",
368
+ anthropic_claude: "anthropic",
369
+ perplexity_bot: "perplexity",
370
+ google_ai: "google",
371
+ microsoft_ai: "microsoft",
372
+ meta_ai: "meta",
373
+ cohere_bot: "cohere",
374
+ huggingface_bot: "huggingface",
375
+ generic_bot: "generic",
376
+ dev_tools: "dev",
377
+ automation_tools: "automation"
378
+ };
379
+ return typeMap[agentKey] || agentKey;
380
+ }
381
+ /**
382
+ * Get agent name from rule key
383
+ */
384
+ getAgentName(agentKey) {
385
+ const nameMap = {
386
+ openai_gptbot: "ChatGPT/GPTBot",
387
+ anthropic_claude: "Claude",
388
+ perplexity_bot: "Perplexity",
389
+ google_ai: "Google AI",
390
+ microsoft_ai: "Microsoft Copilot",
391
+ meta_ai: "Meta AI",
392
+ cohere_bot: "Cohere",
393
+ huggingface_bot: "HuggingFace",
394
+ generic_bot: "Generic Bot",
395
+ dev_tools: "Development Tool",
396
+ automation_tools: "Automation Tool"
397
+ };
398
+ return nameMap[agentKey] || agentKey;
399
+ }
400
+ /**
401
+ * Map agent names from WASM to consistent format
402
+ */
403
+ mapAgentName(agent) {
404
+ const lowerAgent = agent.toLowerCase();
405
+ if (lowerAgent.includes("chatgpt")) {
406
+ return { type: "chatgpt", name: "ChatGPT" };
407
+ } else if (lowerAgent.includes("claude")) {
408
+ return { type: "claude", name: "Claude" };
409
+ } else if (lowerAgent.includes("perplexity")) {
410
+ return { type: "perplexity", name: "Perplexity" };
411
+ } else if (lowerAgent.includes("bing")) {
412
+ return { type: "bing", name: "Bing AI" };
413
+ } else if (lowerAgent.includes("anthropic")) {
414
+ return { type: "anthropic", name: "Anthropic" };
415
+ }
416
+ return { type: "unknown", name: agent };
417
+ }
418
+ };
419
+ EdgeAgentDetectorWrapperWithWasm = class {
420
+ detector;
421
+ events = /* @__PURE__ */ new Map();
422
+ constructor(config) {
423
+ this.detector = new EdgeAgentDetectorWithWasm(config?.enableWasm ?? true);
424
+ if (config?.baseUrl) {
425
+ this.detector.setBaseUrl(config.baseUrl);
426
+ }
427
+ }
428
+ setBaseUrl(url) {
429
+ this.detector.setBaseUrl(url);
430
+ }
431
+ async analyze(input) {
432
+ const result = await this.detector.analyze(input);
433
+ if (result.isAgent && this.events.has("agent.detected")) {
434
+ const handlers = this.events.get("agent.detected") || [];
435
+ handlers.forEach((handler) => handler(result, input));
436
+ }
437
+ return result;
438
+ }
439
+ on(event, handler) {
440
+ if (!this.events.has(event)) {
441
+ this.events.set(event, []);
442
+ }
443
+ this.events.get(event).push(handler);
444
+ }
445
+ emit(event, ...args) {
446
+ const handlers = this.events.get(event) || [];
447
+ handlers.forEach((handler) => handler(...args));
448
+ }
449
+ async init() {
450
+ await this.detector.init();
451
+ }
452
+ };
453
+ }
454
+ });
7
455
  ed25519.etc.sha512Sync = (...m) => sha512(ed25519.etc.concatBytes(...m));
8
456
  var KNOWN_KEYS = {
9
457
  chatgpt: [
@@ -264,7 +712,15 @@ async function verifyAgentSignature(method, path, headers) {
264
712
  }
265
713
  let agent;
266
714
  let agentKey;
267
- if (signatureAgent === '"https://chatgpt.com"' || signatureAgent?.includes("chatgpt.com")) {
715
+ const isChatGPT = signatureAgent === '"https://chatgpt.com"' || (() => {
716
+ try {
717
+ const url = new URL(signatureAgent?.replace(/^"|"$/g, "") || "");
718
+ return url.hostname === "chatgpt.com" || url.hostname.endsWith(".chatgpt.com");
719
+ } catch {
720
+ return false;
721
+ }
722
+ })();
723
+ if (isChatGPT) {
268
724
  agent = "ChatGPT";
269
725
  agentKey = "chatgpt";
270
726
  }
@@ -561,462 +1017,46 @@ var EdgeAgentDetectorWrapper = class {
561
1017
  return;
562
1018
  }
563
1019
  };
564
-
565
- // src/wasm-loader.ts
566
- var wasmInstance = null;
567
- var wasmExports = null;
568
- var initPromise = null;
569
- var WASM_PATH = "/wasm/agentshield_wasm_bg.wasm";
570
- var baseUrl = null;
571
- function setWasmBaseUrl(url) {
572
- baseUrl = url;
573
- }
574
- function getWasmUrl() {
575
- if (baseUrl) {
1020
+ var EdgeSessionTracker = class {
1021
+ config;
1022
+ constructor(config) {
1023
+ this.config = {
1024
+ enabled: config.enabled,
1025
+ cookieName: config.cookieName || "__agentshield_session",
1026
+ cookieMaxAge: config.cookieMaxAge || 3600,
1027
+ // 1 hour default
1028
+ encryptionKey: config.encryptionKey || process.env.AGENTSHIELD_SECRET || "agentshield-default-key"
1029
+ };
1030
+ }
1031
+ /**
1032
+ * Track a new AI agent session
1033
+ */
1034
+ async track(_request, response, result) {
576
1035
  try {
577
- const url = new URL(baseUrl);
578
- return `${url.origin}${WASM_PATH}`;
579
- } catch {
580
- return WASM_PATH;
581
- }
582
- }
583
- return WASM_PATH;
584
- }
585
- async function initWasm() {
586
- if (wasmExports) return true;
587
- if (initPromise) {
588
- await initPromise;
589
- return !!wasmExports;
590
- }
591
- initPromise = (async () => {
592
- try {
593
- const controller = new AbortController();
594
- const timeout = setTimeout(() => controller.abort(), 3e3);
595
- try {
596
- const wasmUrl = getWasmUrl();
597
- if (typeof WebAssembly.instantiateStreaming === "function") {
598
- try {
599
- const response2 = await fetch(wasmUrl, { signal: controller.signal });
600
- clearTimeout(timeout);
601
- if (!response2.ok) {
602
- throw new Error(`Failed to fetch WASM: ${response2.status}`);
603
- }
604
- const streamResponse = response2.clone();
605
- const { instance } = await WebAssembly.instantiateStreaming(streamResponse, {
606
- wbg: {
607
- __wbg_log_1d3ae13c3d5e6b8e: (ptr, len) => {
608
- if (process.env.NODE_ENV !== "production") {
609
- console.debug("WASM:", ptr, len);
610
- }
611
- },
612
- __wbindgen_throw: (ptr, len) => {
613
- throw new Error(`WASM Error at ${ptr}, length ${len}`);
614
- }
615
- }
616
- });
617
- wasmInstance = instance;
618
- wasmExports = instance.exports;
619
- if (process.env.NODE_ENV !== "production") {
620
- console.debug("[AgentShield] \u2705 WASM module initialized with streaming");
621
- }
622
- return;
623
- } catch (streamError) {
624
- if (!controller.signal.aborted) {
625
- if (process.env.NODE_ENV !== "production") {
626
- console.debug(
627
- "[AgentShield] Streaming compilation failed, falling back to standard compilation"
628
- );
629
- }
630
- } else {
631
- throw streamError;
632
- }
633
- }
634
- }
635
- const response = await fetch(wasmUrl, { signal: controller.signal });
636
- clearTimeout(timeout);
637
- if (!response.ok) {
638
- throw new Error(`Failed to fetch WASM: ${response.status}`);
639
- }
640
- const wasmArrayBuffer = await response.arrayBuffer();
641
- const compiledModule = await WebAssembly.compile(wasmArrayBuffer);
642
- const imports = {
643
- wbg: {
644
- __wbg_log_1d3ae13c3d5e6b8e: (ptr, len) => {
645
- if (process.env.NODE_ENV !== "production") {
646
- console.debug("WASM:", ptr, len);
647
- }
648
- },
649
- __wbindgen_throw: (ptr, len) => {
650
- throw new Error(`WASM Error at ${ptr}, length ${len}`);
651
- }
652
- }
653
- };
654
- wasmInstance = await WebAssembly.instantiate(compiledModule, imports);
655
- wasmExports = wasmInstance.exports;
656
- if (process.env.NODE_ENV !== "production") {
657
- console.debug("[AgentShield] \u2705 WASM module initialized via fallback");
658
- }
659
- } catch (fetchError) {
660
- const error = fetchError;
661
- if (error.name === "AbortError") {
662
- console.warn(
663
- "[AgentShield] WASM fetch timed out after 3 seconds - using pattern detection"
664
- );
665
- } else {
666
- console.warn(
667
- "[AgentShield] Failed to fetch WASM file:",
668
- error.message || "Unknown error"
669
- );
670
- }
671
- wasmExports = null;
672
- }
673
- } catch (error) {
674
- console.error("[AgentShield] Failed to initialize WASM:", error);
675
- wasmExports = null;
676
- }
677
- })();
678
- await initPromise;
679
- return !!wasmExports;
680
- }
681
- async function detectAgentWithWasm(_userAgent, _headers, _ipAddress) {
682
- return null;
683
- }
684
- async function getWasmVersion() {
685
- const initialized = await initWasm();
686
- if (!initialized || !wasmExports) {
687
- return null;
688
- }
689
- if (typeof wasmExports.version === "function") {
690
- return wasmExports.version();
691
- }
692
- return "unknown";
693
- }
694
- async function isWasmAvailable() {
695
- try {
696
- const initialized = await initWasm();
697
- if (!initialized) return false;
698
- const version = await getWasmVersion();
699
- return version !== null;
700
- } catch {
701
- return false;
702
- }
703
- }
704
- var rules2 = loadRulesSync();
705
- var EdgeAgentDetectorWithWasm = class {
706
- constructor(enableWasm = true) {
707
- this.enableWasm = enableWasm;
708
- this.rules = rules2;
709
- }
710
- wasmEnabled = false;
711
- initPromise = null;
712
- baseUrl = null;
713
- rules;
714
- /**
715
- * Set the base URL for WASM loading in Edge Runtime
716
- */
717
- setBaseUrl(url) {
718
- this.baseUrl = url;
719
- setWasmBaseUrl(url);
720
- }
721
- /**
722
- * Initialize the detector (including WASM if enabled)
723
- */
724
- async init() {
725
- if (!this.enableWasm) {
726
- this.wasmEnabled = false;
727
- return;
728
- }
729
- if (this.initPromise) {
730
- await this.initPromise;
731
- return;
732
- }
733
- this.initPromise = (async () => {
734
- try {
735
- const wasmAvailable = await isWasmAvailable();
736
- if (wasmAvailable) {
737
- if (this.baseUrl) {
738
- setWasmBaseUrl(this.baseUrl);
739
- }
740
- await initWasm();
741
- this.wasmEnabled = true;
742
- } else {
743
- this.wasmEnabled = false;
744
- }
745
- } catch (error) {
746
- console.error("[AgentShield] Failed to initialize WASM:", error);
747
- this.wasmEnabled = false;
748
- }
749
- })();
750
- await this.initPromise;
751
- }
752
- /**
753
- * Pattern-based detection (fallback)
754
- */
755
- async patternDetection(input) {
756
- const reasons = [];
757
- let detectedAgent;
758
- let verificationMethod;
759
- let confidence = 0;
760
- const headers = input.headers || {};
761
- const normalizedHeaders = {};
762
- for (const [key, value] of Object.entries(headers)) {
763
- normalizedHeaders[key.toLowerCase()] = value;
764
- }
765
- const signaturePresent = !!(normalizedHeaders["signature"] || normalizedHeaders["signature-input"]);
766
- const signatureAgent = normalizedHeaders["signature-agent"];
767
- if (signatureAgent?.includes("chatgpt.com")) {
768
- confidence = 85;
769
- reasons.push("signature_agent:chatgpt");
770
- detectedAgent = { type: "chatgpt", name: "ChatGPT" };
771
- verificationMethod = "signature";
772
- } else if (signaturePresent) {
773
- confidence = Math.max(confidence, 40);
774
- reasons.push("signature_present");
775
- }
776
- const userAgent = input.userAgent || input.headers?.["user-agent"] || "";
777
- if (userAgent) {
778
- for (const [agentKey, agentRule] of Object.entries(this.rules.rules.userAgents)) {
779
- const matched = agentRule.patterns.some((pattern) => {
780
- const regex = new RegExp(pattern, "i");
781
- return regex.test(userAgent);
782
- });
783
- if (matched) {
784
- const agentType = this.getAgentType(agentKey);
785
- const agentName = this.getAgentName(agentKey);
786
- confidence = Math.max(confidence, Math.round(agentRule.confidence * 0.85 * 100));
787
- reasons.push(`known_pattern:${agentType}`);
788
- if (!detectedAgent) {
789
- detectedAgent = { type: agentType, name: agentName };
790
- verificationMethod = "pattern";
791
- }
792
- break;
793
- }
794
- }
795
- }
796
- const suspiciousHeaders = this.rules.rules.headers.suspicious;
797
- const foundAiHeaders = suspiciousHeaders.filter(
798
- (headerRule) => normalizedHeaders[headerRule.name.toLowerCase()]
799
- );
800
- if (foundAiHeaders.length > 0) {
801
- const maxConfidence = Math.max(...foundAiHeaders.map((h) => h.confidence));
802
- confidence = Math.max(confidence, maxConfidence);
803
- reasons.push(`ai_headers:${foundAiHeaders.length}`);
804
- }
805
- const ip = input.ip || input.ipAddress;
806
- if (ip && !normalizedHeaders["x-forwarded-for"] && !normalizedHeaders["x-real-ip"]) {
807
- const ipRanges = "providers" in this.rules.rules.ipRanges ? this.rules.rules.ipRanges.providers : this.rules.rules.ipRanges;
808
- for (const [provider, ipRule] of Object.entries(ipRanges)) {
809
- if (!ipRule || typeof ipRule !== "object" || !("ranges" in ipRule) || !Array.isArray(ipRule.ranges))
810
- continue;
811
- const matched = ipRule.ranges.some((range) => {
812
- const prefix = range.split("/")[0];
813
- const prefixParts = prefix.split(".");
814
- const ipParts = ip.split(".");
815
- for (let i = 0; i < Math.min(prefixParts.length - 1, 2); i++) {
816
- if (prefixParts[i] !== ipParts[i] && prefixParts[i] !== "0") {
817
- return false;
818
- }
819
- }
820
- return true;
821
- });
822
- if (matched) {
823
- confidence = Math.max(confidence, Math.round(ipRule.confidence * 0.4 * 100));
824
- reasons.push(`cloud_provider:${provider}`);
825
- break;
826
- }
827
- }
828
- }
829
- if (reasons.length > 2) {
830
- confidence = Math.min(Math.round(confidence * 1.2), 95);
831
- }
832
- confidence = Math.min(Math.max(confidence, 0), 100);
833
- return {
834
- isAgent: confidence > 30,
835
- // 30% threshold
836
- confidence,
837
- detectionClass: confidence > 30 && detectedAgent ? { type: "AiAgent", agentType: detectedAgent.name } : confidence > 30 ? { type: "Unknown" } : { type: "Human" },
838
- signals: [],
839
- // Will be populated by enhanced detection engine in future tasks
840
- ...detectedAgent && { detectedAgent },
841
- reasons,
842
- ...verificationMethod && {
843
- verificationMethod: mapVerificationMethod(verificationMethod)
844
- },
845
- forgeabilityRisk: confidence > 80 ? "medium" : "high",
846
- timestamp: /* @__PURE__ */ new Date()
847
- };
848
- }
849
- /**
850
- * Analyze request with WASM enhancement when available
851
- */
852
- async analyze(input) {
853
- await this.init();
854
- if (this.wasmEnabled) {
855
- try {
856
- const wasmResult = await detectAgentWithWasm(
857
- input.userAgent || input.headers?.["user-agent"],
858
- input.headers || {},
859
- input.ip || input.ipAddress
860
- );
861
- if (wasmResult) {
862
- const detectedAgent = wasmResult.agent ? this.mapAgentName(wasmResult.agent) : void 0;
863
- return {
864
- isAgent: wasmResult.isAgent,
865
- confidence: wasmResult.confidence,
866
- detectionClass: wasmResult.isAgent && detectedAgent ? { type: "AiAgent", agentType: detectedAgent.name } : wasmResult.isAgent ? { type: "Unknown" } : { type: "Human" },
867
- signals: [],
868
- // Will be populated by enhanced detection engine in future tasks
869
- ...detectedAgent && { detectedAgent },
870
- reasons: [`wasm:${wasmResult.verificationMethod}`],
871
- verificationMethod: mapVerificationMethod(wasmResult.verificationMethod),
872
- forgeabilityRisk: wasmResult.verificationMethod === "signature" ? "low" : wasmResult.confidence > 90 ? "medium" : "high",
873
- timestamp: /* @__PURE__ */ new Date()
874
- };
875
- }
876
- } catch (error) {
877
- console.error("[AgentShield] WASM detection error:", error);
878
- }
879
- }
880
- const patternResult = await this.patternDetection(input);
881
- if (this.wasmEnabled && patternResult.confidence >= 85) {
882
- patternResult.confidence = Math.min(95, patternResult.confidence + 10);
883
- patternResult.reasons.push("wasm_enhanced");
884
- }
885
- return patternResult;
886
- }
887
- /**
888
- * Get agent type from rule key
889
- */
890
- getAgentType(agentKey) {
891
- const typeMap = {
892
- openai_gptbot: "openai",
893
- anthropic_claude: "anthropic",
894
- perplexity_bot: "perplexity",
895
- google_ai: "google",
896
- microsoft_ai: "microsoft",
897
- meta_ai: "meta",
898
- cohere_bot: "cohere",
899
- huggingface_bot: "huggingface",
900
- generic_bot: "generic",
901
- dev_tools: "dev",
902
- automation_tools: "automation"
903
- };
904
- return typeMap[agentKey] || agentKey;
905
- }
906
- /**
907
- * Get agent name from rule key
908
- */
909
- getAgentName(agentKey) {
910
- const nameMap = {
911
- openai_gptbot: "ChatGPT/GPTBot",
912
- anthropic_claude: "Claude",
913
- perplexity_bot: "Perplexity",
914
- google_ai: "Google AI",
915
- microsoft_ai: "Microsoft Copilot",
916
- meta_ai: "Meta AI",
917
- cohere_bot: "Cohere",
918
- huggingface_bot: "HuggingFace",
919
- generic_bot: "Generic Bot",
920
- dev_tools: "Development Tool",
921
- automation_tools: "Automation Tool"
922
- };
923
- return nameMap[agentKey] || agentKey;
924
- }
925
- /**
926
- * Map agent names from WASM to consistent format
927
- */
928
- mapAgentName(agent) {
929
- const lowerAgent = agent.toLowerCase();
930
- if (lowerAgent.includes("chatgpt")) {
931
- return { type: "chatgpt", name: "ChatGPT" };
932
- } else if (lowerAgent.includes("claude")) {
933
- return { type: "claude", name: "Claude" };
934
- } else if (lowerAgent.includes("perplexity")) {
935
- return { type: "perplexity", name: "Perplexity" };
936
- } else if (lowerAgent.includes("bing")) {
937
- return { type: "bing", name: "Bing AI" };
938
- } else if (lowerAgent.includes("anthropic")) {
939
- return { type: "anthropic", name: "Anthropic" };
940
- }
941
- return { type: "unknown", name: agent };
942
- }
943
- };
944
- var EdgeAgentDetectorWrapperWithWasm = class {
945
- detector;
946
- events = /* @__PURE__ */ new Map();
947
- constructor(config) {
948
- this.detector = new EdgeAgentDetectorWithWasm(config?.enableWasm ?? true);
949
- if (config?.baseUrl) {
950
- this.detector.setBaseUrl(config.baseUrl);
951
- }
952
- }
953
- setBaseUrl(url) {
954
- this.detector.setBaseUrl(url);
955
- }
956
- async analyze(input) {
957
- const result = await this.detector.analyze(input);
958
- if (result.isAgent && this.events.has("agent.detected")) {
959
- const handlers = this.events.get("agent.detected") || [];
960
- handlers.forEach((handler) => handler(result, input));
961
- }
962
- return result;
963
- }
964
- on(event, handler) {
965
- if (!this.events.has(event)) {
966
- this.events.set(event, []);
967
- }
968
- this.events.get(event).push(handler);
969
- }
970
- emit(event, ...args) {
971
- const handlers = this.events.get(event) || [];
972
- handlers.forEach((handler) => handler(...args));
973
- }
974
- async init() {
975
- await this.detector.init();
976
- }
977
- };
978
-
979
- // src/session-tracker.ts
980
- var EdgeSessionTracker = class {
981
- config;
982
- constructor(config) {
983
- this.config = {
984
- enabled: config.enabled,
985
- cookieName: config.cookieName || "__agentshield_session",
986
- cookieMaxAge: config.cookieMaxAge || 3600,
987
- // 1 hour default
988
- encryptionKey: config.encryptionKey || process.env.AGENTSHIELD_SECRET || "agentshield-default-key"
989
- };
990
- }
991
- /**
992
- * Track a new AI agent session
993
- */
994
- async track(_request, response, result) {
995
- try {
996
- if (!this.config.enabled || !result.isAgent) {
997
- return response;
998
- }
999
- const sessionData = {
1000
- id: crypto.randomUUID(),
1001
- agent: result.detectedAgent?.name || "unknown",
1002
- confidence: result.confidence,
1003
- detectedAt: Date.now(),
1004
- expires: Date.now() + this.config.cookieMaxAge * 1e3
1005
- };
1006
- const encrypted = await this.encrypt(JSON.stringify(sessionData));
1007
- response.cookies.set(this.config.cookieName, encrypted, {
1008
- httpOnly: true,
1009
- secure: process.env.NODE_ENV === "production",
1010
- sameSite: "lax",
1011
- maxAge: this.config.cookieMaxAge,
1012
- path: "/"
1013
- });
1014
- return response;
1015
- } catch (error) {
1016
- if (process.env.DEBUG_AGENTSHIELD) {
1017
- console.warn("AgentShield: Failed to track session:", error);
1018
- }
1019
- return response;
1036
+ if (!this.config.enabled || !shouldEnforce(result)) {
1037
+ return response;
1038
+ }
1039
+ const sessionData = {
1040
+ id: crypto.randomUUID(),
1041
+ agent: result.detectedAgent?.name || "unknown",
1042
+ confidence: result.confidence,
1043
+ detectedAt: Date.now(),
1044
+ expires: Date.now() + this.config.cookieMaxAge * 1e3
1045
+ };
1046
+ const encrypted = await this.encrypt(JSON.stringify(sessionData));
1047
+ response.cookies.set(this.config.cookieName, encrypted, {
1048
+ httpOnly: true,
1049
+ secure: process.env.NODE_ENV === "production",
1050
+ sameSite: "lax",
1051
+ maxAge: this.config.cookieMaxAge,
1052
+ path: "/"
1053
+ });
1054
+ return response;
1055
+ } catch (error) {
1056
+ if (process.env.DEBUG_AGENTSHIELD) {
1057
+ console.warn("AgentShield: Failed to track session:", error);
1058
+ }
1059
+ return response;
1020
1060
  }
1021
1061
  }
1022
1062
  /**
@@ -1068,9 +1108,7 @@ var EdgeSessionTracker = class {
1068
1108
  for (let i = 0; i < encoded.length; i++) {
1069
1109
  obfuscated[i] = (encoded[i] || 0) ^ key.charCodeAt(i % key.length);
1070
1110
  }
1071
- return btoa(
1072
- Array.from(obfuscated, (byte) => String.fromCharCode(byte)).join("")
1073
- );
1111
+ return btoa(Array.from(obfuscated, (byte) => String.fromCharCode(byte)).join(""));
1074
1112
  } catch (error) {
1075
1113
  return btoa(data);
1076
1114
  }
@@ -1093,14 +1131,29 @@ var EdgeSessionTracker = class {
1093
1131
  }
1094
1132
  };
1095
1133
 
1096
- // src/middleware.ts
1134
+ // src/utils.ts
1135
+ function getClientIp(request) {
1136
+ const forwardedFor = request.headers.get("x-forwarded-for");
1137
+ if (forwardedFor) {
1138
+ const ip = forwardedFor.split(",")[0]?.trim();
1139
+ if (ip) return ip;
1140
+ }
1141
+ const realIp = request.headers.get("x-real-ip");
1142
+ if (realIp) return realIp;
1143
+ const cfIp = request.headers.get("cf-connecting-ip");
1144
+ if (cfIp) return cfIp;
1145
+ const clientIp = request.headers.get("x-client-ip");
1146
+ if (clientIp) return clientIp;
1147
+ return void 0;
1148
+ }
1097
1149
  function createAgentShieldMiddleware(config = {}) {
1098
- const detector = config.enableWasm ? new EdgeAgentDetectorWrapperWithWasm({ enableWasm: true }) : new EdgeAgentDetectorWrapper(config);
1150
+ let detector = config.enableWasm ? null : new EdgeAgentDetectorWrapper(config);
1151
+ let detectorInitPromise = null;
1099
1152
  const sessionTracker = config.sessionTracking?.enabled || config.enableWasm ? new EdgeSessionTracker({
1100
1153
  enabled: true,
1101
1154
  ...config.sessionTracking
1102
1155
  }) : null;
1103
- if (config.events) {
1156
+ if (detector && config.events) {
1104
1157
  Object.entries(config.events).forEach(([event, handler]) => {
1105
1158
  if (handler) {
1106
1159
  detector.on(event, handler);
@@ -1121,6 +1174,23 @@ function createAgentShieldMiddleware(config = {}) {
1121
1174
  } = config;
1122
1175
  return async (request) => {
1123
1176
  try {
1177
+ if (!detector) {
1178
+ if (!detectorInitPromise) {
1179
+ detectorInitPromise = (async () => {
1180
+ const { EdgeAgentDetectorWrapperWithWasm: EdgeAgentDetectorWrapperWithWasm2 } = await Promise.resolve().then(() => (init_edge_detector_with_wasm(), edge_detector_with_wasm_exports));
1181
+ detector = new EdgeAgentDetectorWrapperWithWasm2({ enableWasm: true });
1182
+ if (config.events) {
1183
+ Object.entries(config.events).forEach(([event, handler]) => {
1184
+ if (handler) {
1185
+ detector.on(event, handler);
1186
+ }
1187
+ });
1188
+ }
1189
+ })();
1190
+ }
1191
+ await detectorInitPromise;
1192
+ }
1193
+ const activeDetector = detector;
1124
1194
  const shouldSkip = skipPaths.some((pattern) => {
1125
1195
  if (typeof pattern === "string") {
1126
1196
  return request.nextUrl.pathname.startsWith(pattern);
@@ -1134,11 +1204,11 @@ function createAgentShieldMiddleware(config = {}) {
1134
1204
  const existingSession = sessionTracker ? await sessionTracker.check(request) : null;
1135
1205
  if (existingSession) {
1136
1206
  const response2 = NextResponse.next();
1137
- response2.headers.set("x-agentshield-detected", "true");
1138
- response2.headers.set("x-agentshield-agent", existingSession.agent);
1139
- response2.headers.set("x-agentshield-confidence", existingSession.confidence.toString());
1140
- response2.headers.set("x-agentshield-session", "continued");
1141
- response2.headers.set("x-agentshield-session-id", existingSession.id);
1207
+ response2.headers.set("kya-detected", "true");
1208
+ response2.headers.set("kya-agent", existingSession.agent);
1209
+ response2.headers.set("kya-confidence", existingSession.confidence.toString());
1210
+ response2.headers.set("kya-session", "continued");
1211
+ response2.headers.set("kya-session-id", existingSession.id);
1142
1212
  request.agentShield = {
1143
1213
  result: {
1144
1214
  isAgent: true,
@@ -1158,17 +1228,17 @@ function createAgentShieldMiddleware(config = {}) {
1158
1228
  };
1159
1229
  const context2 = {
1160
1230
  userAgent: request.headers.get("user-agent") || "",
1161
- ipAddress: (request.ip ?? request.headers.get("x-forwarded-for")) || "",
1231
+ ipAddress: getClientIp(request) || "",
1162
1232
  headers: Object.fromEntries(request.headers.entries()),
1163
1233
  url: request.url,
1164
1234
  method: request.method,
1165
1235
  timestamp: /* @__PURE__ */ new Date()
1166
1236
  };
1167
- detector.emit("agent.session.continued", existingSession, context2);
1237
+ activeDetector.emit("agent.session.continued", existingSession, context2);
1168
1238
  return response2;
1169
1239
  }
1170
1240
  const userAgent = request.headers.get("user-agent");
1171
- const ipAddress = request.ip ?? request.headers.get("x-forwarded-for");
1241
+ const ipAddress = getClientIp(request);
1172
1242
  const url = new URL(request.url);
1173
1243
  const pathWithQuery = url.pathname + url.search;
1174
1244
  const context = {
@@ -1180,15 +1250,19 @@ function createAgentShieldMiddleware(config = {}) {
1180
1250
  method: request.method,
1181
1251
  timestamp: /* @__PURE__ */ new Date()
1182
1252
  };
1183
- const result = await detector.analyze(context);
1184
- if (result.isAgent && result.confidence >= (config.confidenceThreshold ?? 70)) {
1253
+ const result = await activeDetector.analyze(context);
1254
+ const decision = evaluateEnforcement(result, {
1255
+ confidenceThreshold: config.confidenceThreshold,
1256
+ defaultAction: onAgentDetected
1257
+ });
1258
+ if (decision.shouldNotify) {
1185
1259
  if (onDetection) {
1186
1260
  const customResponse = await onDetection(request, result);
1187
1261
  if (customResponse) {
1188
1262
  return customResponse;
1189
1263
  }
1190
1264
  }
1191
- switch (onAgentDetected) {
1265
+ switch (decision.action) {
1192
1266
  case "block": {
1193
1267
  const response2 = NextResponse.json(
1194
1268
  {
@@ -1204,11 +1278,17 @@ function createAgentShieldMiddleware(config = {}) {
1204
1278
  response2.headers.set(key, value);
1205
1279
  });
1206
1280
  }
1207
- detector.emit("agent.blocked", result, context);
1281
+ activeDetector.emit("agent.blocked", result, context);
1208
1282
  return response2;
1209
1283
  }
1210
- case "redirect":
1211
- return NextResponse.redirect(new URL(redirectUrl, request.url));
1284
+ case "redirect": {
1285
+ const redirectTarget = new URL(redirectUrl, request.url);
1286
+ const agentName = result.detectedAgent?.name;
1287
+ if (agentName && !redirectTarget.searchParams.has("agent")) {
1288
+ redirectTarget.searchParams.set("agent", agentName.toLowerCase());
1289
+ }
1290
+ return NextResponse.redirect(redirectTarget);
1291
+ }
1212
1292
  case "rewrite":
1213
1293
  return NextResponse.rewrite(new URL(rewriteUrl, request.url));
1214
1294
  case "log":
@@ -1224,9 +1304,7 @@ function createAgentShieldMiddleware(config = {}) {
1224
1304
  break;
1225
1305
  case "allow":
1226
1306
  default:
1227
- if (result.isAgent && result.confidence >= (config.confidenceThreshold ?? 70)) {
1228
- detector.emit("agent.allowed", result, context);
1229
- }
1307
+ activeDetector.emit("agent.allowed", result, context);
1230
1308
  break;
1231
1309
  }
1232
1310
  }
@@ -1235,15 +1313,15 @@ function createAgentShieldMiddleware(config = {}) {
1235
1313
  skipped: false
1236
1314
  };
1237
1315
  let response = NextResponse.next();
1238
- response.headers.set("x-agentshield-detected", result.isAgent.toString());
1239
- response.headers.set("x-agentshield-confidence", result.confidence.toString());
1316
+ response.headers.set("kya-detected", result.isAgent.toString());
1317
+ response.headers.set("kya-confidence", result.confidence.toString());
1240
1318
  if (result.detectedAgent?.name) {
1241
- response.headers.set("x-agentshield-agent", result.detectedAgent.name);
1319
+ response.headers.set("kya-agent", result.detectedAgent.name);
1242
1320
  }
1243
- if (sessionTracker && result.isAgent && result.confidence >= (config.confidenceThreshold ?? 70)) {
1321
+ if (sessionTracker && decision.shouldNotify) {
1244
1322
  response = await sessionTracker.track(request, response, result);
1245
- response.headers.set("x-agentshield-session", "new");
1246
- detector.emit("agent.session.started", result, context);
1323
+ response.headers.set("kya-session", "new");
1324
+ activeDetector.emit("agent.session.started", result, context);
1247
1325
  }
1248
1326
  return response;
1249
1327
  } catch (error) {