@kya-os/agentshield-nextjs 0.1.40 → 0.1.42

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 (79) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/api-client.d.mts +145 -0
  3. package/dist/api-client.d.ts +145 -0
  4. package/dist/api-client.js +130 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/api-client.mjs +126 -0
  7. package/dist/api-client.mjs.map +1 -0
  8. package/dist/api-middleware.d.mts +118 -0
  9. package/dist/api-middleware.d.ts +118 -0
  10. package/dist/api-middleware.js +295 -0
  11. package/dist/api-middleware.js.map +1 -0
  12. package/dist/api-middleware.mjs +292 -0
  13. package/dist/api-middleware.mjs.map +1 -0
  14. package/dist/create-middleware.d.mts +2 -1
  15. package/dist/create-middleware.d.ts +2 -1
  16. package/dist/create-middleware.js +474 -200
  17. package/dist/create-middleware.js.map +1 -1
  18. package/dist/create-middleware.mjs +454 -200
  19. package/dist/create-middleware.mjs.map +1 -1
  20. package/dist/edge/index.d.mts +110 -0
  21. package/dist/edge/index.d.ts +110 -0
  22. package/dist/edge/index.js +253 -0
  23. package/dist/edge/index.js.map +1 -0
  24. package/dist/edge/index.mjs +251 -0
  25. package/dist/edge/index.mjs.map +1 -0
  26. package/dist/edge-detector-wrapper.d.mts +6 -15
  27. package/dist/edge-detector-wrapper.d.ts +6 -15
  28. package/dist/edge-detector-wrapper.js +314 -95
  29. package/dist/edge-detector-wrapper.js.map +1 -1
  30. package/dist/edge-detector-wrapper.mjs +294 -95
  31. package/dist/edge-detector-wrapper.mjs.map +1 -1
  32. package/dist/edge-runtime-loader.d.mts +1 -1
  33. package/dist/edge-runtime-loader.d.ts +1 -1
  34. package/dist/edge-runtime-loader.js +10 -25
  35. package/dist/edge-runtime-loader.js.map +1 -1
  36. package/dist/edge-runtime-loader.mjs +11 -23
  37. package/dist/edge-runtime-loader.mjs.map +1 -1
  38. package/dist/edge-wasm-middleware.js +2 -1
  39. package/dist/edge-wasm-middleware.js.map +1 -1
  40. package/dist/edge-wasm-middleware.mjs +2 -1
  41. package/dist/edge-wasm-middleware.mjs.map +1 -1
  42. package/dist/enhanced-middleware.d.mts +153 -0
  43. package/dist/enhanced-middleware.d.ts +153 -0
  44. package/dist/enhanced-middleware.js +1074 -0
  45. package/dist/enhanced-middleware.js.map +1 -0
  46. package/dist/enhanced-middleware.mjs +1072 -0
  47. package/dist/enhanced-middleware.mjs.map +1 -0
  48. package/dist/index.d.mts +8 -153
  49. package/dist/index.d.ts +8 -153
  50. package/dist/index.js +1390 -680
  51. package/dist/index.js.map +1 -1
  52. package/dist/index.mjs +1370 -685
  53. package/dist/index.mjs.map +1 -1
  54. package/dist/middleware.d.mts +2 -1
  55. package/dist/middleware.d.ts +2 -1
  56. package/dist/middleware.js +474 -200
  57. package/dist/middleware.js.map +1 -1
  58. package/dist/middleware.mjs +454 -200
  59. package/dist/middleware.mjs.map +1 -1
  60. package/dist/session-tracker.d.mts +1 -1
  61. package/dist/session-tracker.d.ts +1 -1
  62. package/dist/session-tracker.js.map +1 -1
  63. package/dist/session-tracker.mjs.map +1 -1
  64. package/dist/signature-verifier.d.mts +1 -0
  65. package/dist/signature-verifier.d.ts +1 -0
  66. package/dist/signature-verifier.js +204 -44
  67. package/dist/signature-verifier.js.map +1 -1
  68. package/dist/signature-verifier.mjs +184 -44
  69. package/dist/signature-verifier.mjs.map +1 -1
  70. package/dist/{types-BJTEUa4T.d.mts → types-DVmy9NE3.d.mts} +19 -2
  71. package/dist/{types-BJTEUa4T.d.ts → types-DVmy9NE3.d.ts} +19 -2
  72. package/dist/wasm-middleware.js +15 -6
  73. package/dist/wasm-middleware.js.map +1 -1
  74. package/dist/wasm-middleware.mjs +15 -6
  75. package/dist/wasm-middleware.mjs.map +1 -1
  76. package/package.json +43 -21
  77. package/wasm/agentshield_wasm.js +209 -152
  78. package/wasm/agentshield_wasm_bg.wasm +0 -0
  79. package/wasm/package.json +30 -0
@@ -1,15 +1,128 @@
1
+ import * as ed25519 from '@noble/ed25519';
2
+ import { sha512 } from '@noble/hashes/sha2';
3
+ import { loadRulesSync } from '@kya-os/agentshield-shared';
4
+
1
5
  // src/signature-verifier.ts
6
+ ed25519.etc.sha512Sync = (...m) => sha512(ed25519.etc.concatBytes(...m));
2
7
  var KNOWN_KEYS = {
3
8
  chatgpt: [
4
9
  {
5
10
  kid: "otMqcjr17mGyruktGvJU8oojQTSMHlVm7uO-lrcqbdg",
6
11
  // ChatGPT's current Ed25519 public key (base64)
12
+ // Source: https://chatgpt.com/.well-known/http-message-signatures-directory
7
13
  publicKey: "7F_3jDlxaquwh291MiACkcS3Opq88NksyHiakzS-Y1g",
8
- validFrom: (/* @__PURE__ */ new Date("2025-01-01")).getTime() / 1e3,
9
- validUntil: (/* @__PURE__ */ new Date("2025-04-11")).getTime() / 1e3
14
+ validFrom: 1735689600,
15
+ // Jan 1, 2025 (from OpenAI's nbf)
16
+ // Extended expiration as fallback safety - API fetch should provide fresh keys
17
+ // Check OpenAI's well-known endpoint for actual expiration dates
18
+ validUntil: 1799625600
19
+ // Jan 1, 2027 (extended for fallback safety)
10
20
  }
11
21
  ]
12
22
  };
23
+ var keyCache = /* @__PURE__ */ new Map();
24
+ var CACHE_TTL_MS = 5 * 60 * 1e3;
25
+ var CACHE_MAX_SIZE = 100;
26
+ function getApiBaseUrl() {
27
+ if (typeof window !== "undefined") {
28
+ return "/api/internal";
29
+ }
30
+ const baseUrl = process.env.NEXT_PUBLIC_APP_URL || process.env.NEXT_PUBLIC_API_URL || process.env.API_URL || (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : null);
31
+ if (baseUrl) {
32
+ return baseUrl.replace(/\/$/, "") + "/api/internal";
33
+ }
34
+ if (process.env.NODE_ENV !== "production") {
35
+ console.warn(
36
+ "[Signature] No base URL configured for server-side fetch. Using localhost fallback."
37
+ );
38
+ return "http://localhost:3000/api/internal";
39
+ }
40
+ console.error(
41
+ "[Signature] CRITICAL: No base URL configured for server-side fetch in production!"
42
+ );
43
+ return "/api/internal";
44
+ }
45
+ function cleanupExpiredCache() {
46
+ const now = Date.now();
47
+ const entriesToDelete = [];
48
+ for (const [agent, cached] of keyCache.entries()) {
49
+ if (now - cached.cachedAt > CACHE_TTL_MS) {
50
+ entriesToDelete.push(agent);
51
+ }
52
+ }
53
+ for (const agent of entriesToDelete) {
54
+ keyCache.delete(agent);
55
+ }
56
+ if (keyCache.size > CACHE_MAX_SIZE) {
57
+ const entries = Array.from(keyCache.entries()).map(([agent, cached]) => ({
58
+ agent,
59
+ cachedAt: cached.cachedAt
60
+ }));
61
+ entries.sort((a, b) => a.cachedAt - b.cachedAt);
62
+ const toRemove = entries.slice(0, keyCache.size - CACHE_MAX_SIZE);
63
+ for (const entry of toRemove) {
64
+ keyCache.delete(entry.agent);
65
+ }
66
+ }
67
+ }
68
+ async function fetchKeysFromApi(agent) {
69
+ if (keyCache.size > CACHE_MAX_SIZE) {
70
+ cleanupExpiredCache();
71
+ }
72
+ const cached = keyCache.get(agent);
73
+ if (cached && Date.now() - cached.cachedAt < CACHE_TTL_MS) {
74
+ return cached.keys;
75
+ }
76
+ if (typeof fetch === "undefined") {
77
+ console.warn("[Signature] fetch() not available in this environment");
78
+ return null;
79
+ }
80
+ try {
81
+ const apiBaseUrl = getApiBaseUrl();
82
+ const url = `${apiBaseUrl}/signature-keys?agent=${encodeURIComponent(agent)}`;
83
+ const response = await fetch(url, {
84
+ method: "GET",
85
+ headers: {
86
+ "Content-Type": "application/json"
87
+ },
88
+ // 5 second timeout
89
+ signal: AbortSignal.timeout(5e3)
90
+ });
91
+ if (!response.ok) {
92
+ console.warn(`[Signature] Failed to fetch keys from API: ${response.status}`);
93
+ return null;
94
+ }
95
+ const data = await response.json();
96
+ if (!data.keys || !Array.isArray(data.keys) || data.keys.length === 0) {
97
+ console.warn(`[Signature] No keys returned from API for agent: ${agent}`);
98
+ return null;
99
+ }
100
+ keyCache.set(agent, {
101
+ keys: data.keys,
102
+ cachedAt: Date.now()
103
+ });
104
+ return data.keys;
105
+ } catch (error) {
106
+ console.warn("[Signature] Error fetching keys from API, using fallback", {
107
+ error: error instanceof Error ? error.message : "Unknown error",
108
+ agent
109
+ });
110
+ return null;
111
+ }
112
+ }
113
+ function isValidAgent(agent) {
114
+ return agent in KNOWN_KEYS;
115
+ }
116
+ async function getKeysForAgent(agent) {
117
+ const apiKeys = await fetchKeysFromApi(agent);
118
+ if (apiKeys && apiKeys.length > 0) {
119
+ return apiKeys;
120
+ }
121
+ if (isValidAgent(agent)) {
122
+ return KNOWN_KEYS[agent];
123
+ }
124
+ return [];
125
+ }
13
126
  function parseSignatureInput(signatureInput) {
14
127
  try {
15
128
  const match = signatureInput.match(/sig1=\((.*?)\);(.+)/);
@@ -45,21 +158,29 @@ function buildSignatureBase(method, path, headers, signedHeaders) {
45
158
  case "@authority":
46
159
  value = headers["host"] || headers["Host"] || "";
47
160
  break;
48
- default:
49
- const key = Object.keys(headers).find(
50
- (k) => k.toLowerCase() === headerName.toLowerCase()
51
- );
161
+ default: {
162
+ const key = Object.keys(headers).find((k) => k.toLowerCase() === headerName.toLowerCase());
52
163
  value = key ? headers[key] || "" : "";
53
164
  break;
165
+ }
54
166
  }
55
167
  components.push(`"${headerName}": ${value}`);
56
168
  }
57
169
  return components.join("\n");
58
170
  }
171
+ function base64ToBytes(base64) {
172
+ let standardBase64 = base64.replace(/-/g, "+").replace(/_/g, "/");
173
+ const padding = standardBase64.length % 4;
174
+ if (padding) {
175
+ standardBase64 += "=".repeat(4 - padding);
176
+ }
177
+ const binaryString = atob(standardBase64);
178
+ return Uint8Array.from(binaryString, (c) => c.charCodeAt(0));
179
+ }
59
180
  async function verifyEd25519Signature(publicKeyBase64, signatureBase64, message) {
60
181
  try {
61
- const publicKeyBytes = Uint8Array.from(atob(publicKeyBase64), (c) => c.charCodeAt(0));
62
- const signatureBytes = Uint8Array.from(atob(signatureBase64), (c) => c.charCodeAt(0));
182
+ const publicKeyBytes = base64ToBytes(publicKeyBase64);
183
+ const signatureBytes = base64ToBytes(signatureBase64);
63
184
  const messageBytes = new TextEncoder().encode(message);
64
185
  if (publicKeyBytes.length !== 32) {
65
186
  console.error("[Signature] Invalid public key length:", publicKeyBytes.length);
@@ -69,34 +190,36 @@ async function verifyEd25519Signature(publicKeyBase64, signatureBase64, message)
69
190
  console.error("[Signature] Invalid signature length:", signatureBytes.length);
70
191
  return false;
71
192
  }
72
- const publicKey = await crypto.subtle.importKey(
73
- "raw",
74
- publicKeyBytes,
75
- {
76
- name: "Ed25519",
77
- namedCurve: "Ed25519"
78
- },
79
- false,
80
- ["verify"]
81
- );
82
- const isValid = await crypto.subtle.verify(
83
- "Ed25519",
84
- publicKey,
85
- signatureBytes,
86
- messageBytes
87
- );
88
- return isValid;
89
- } catch (error) {
90
- console.error("[Signature] Ed25519 verification failed:", error);
91
- if (typeof window === "undefined") {
92
- try {
93
- console.warn("[Signature] Ed25519 not supported in this environment");
94
- return false;
95
- } catch {
96
- return false;
97
- }
193
+ return ed25519.verify(signatureBytes, messageBytes, publicKeyBytes);
194
+ } catch (nobleError) {
195
+ console.warn("[Signature] @noble/ed25519 failed, trying Web Crypto fallback:", nobleError);
196
+ try {
197
+ const publicKeyBytes = base64ToBytes(publicKeyBase64);
198
+ const signatureBytes = base64ToBytes(signatureBase64);
199
+ const messageBytes = new TextEncoder().encode(message);
200
+ const publicKey = await crypto.subtle.importKey(
201
+ "raw",
202
+ publicKeyBytes.buffer,
203
+ {
204
+ name: "Ed25519",
205
+ namedCurve: "Ed25519"
206
+ },
207
+ false,
208
+ ["verify"]
209
+ );
210
+ return await crypto.subtle.verify(
211
+ "Ed25519",
212
+ publicKey,
213
+ signatureBytes.buffer,
214
+ messageBytes
215
+ );
216
+ } catch (cryptoError) {
217
+ console.error("[Signature] Both @noble/ed25519 and Web Crypto failed:", {
218
+ nobleError: nobleError instanceof Error ? nobleError.message : "Unknown",
219
+ cryptoError: cryptoError instanceof Error ? cryptoError.message : "Unknown"
220
+ });
221
+ return false;
98
222
  }
99
- return false;
100
223
  }
101
224
  }
102
225
  async function verifyAgentSignature(method, path, headers) {
@@ -141,12 +264,12 @@ async function verifyAgentSignature(method, path, headers) {
141
264
  }
142
265
  }
143
266
  let agent;
144
- let knownKeys;
267
+ let agentKey;
145
268
  if (signatureAgent === '"https://chatgpt.com"' || signatureAgent?.includes("chatgpt.com")) {
146
269
  agent = "ChatGPT";
147
- knownKeys = KNOWN_KEYS.chatgpt;
270
+ agentKey = "chatgpt";
148
271
  }
149
- if (!agent || !knownKeys) {
272
+ if (!agent || !agentKey) {
150
273
  return {
151
274
  isValid: false,
152
275
  confidence: 0,
@@ -154,6 +277,15 @@ async function verifyAgentSignature(method, path, headers) {
154
277
  verificationMethod: "none"
155
278
  };
156
279
  }
280
+ const knownKeys = await getKeysForAgent(agentKey);
281
+ if (knownKeys.length === 0) {
282
+ return {
283
+ isValid: false,
284
+ confidence: 0,
285
+ reason: "No keys available for agent",
286
+ verificationMethod: "none"
287
+ };
288
+ }
157
289
  const key = knownKeys.find((k) => k.kid === parsed.keyid);
158
290
  if (!key) {
159
291
  return {
@@ -180,11 +312,7 @@ async function verifyAgentSignature(method, path, headers) {
180
312
  if (signatureValue.endsWith(":")) {
181
313
  signatureValue = signatureValue.slice(0, -1);
182
314
  }
183
- const isValid = await verifyEd25519Signature(
184
- key.publicKey,
185
- signatureValue,
186
- signatureBase
187
- );
315
+ const isValid = await verifyEd25519Signature(key.publicKey, signatureValue, signatureBase);
188
316
  if (isValid) {
189
317
  return {
190
318
  isValid: true,
@@ -208,27 +336,27 @@ function hasSignatureHeaders(headers) {
208
336
  }
209
337
  function isChatGPTSignature(headers) {
210
338
  const signatureAgent = headers["signature-agent"] || headers["Signature-Agent"];
211
- return signatureAgent === '"https://chatgpt.com"' || (signatureAgent?.includes("chatgpt.com") || false);
339
+ if (!signatureAgent) {
340
+ return false;
341
+ }
342
+ const agentUrlStr = signatureAgent.replace(/^"+|"+$/g, "");
343
+ if (agentUrlStr === "https://chatgpt.com") {
344
+ return true;
345
+ }
346
+ try {
347
+ const agentUrl = new URL(agentUrlStr);
348
+ const allowedHosts = ["chatgpt.com", "www.chatgpt.com"];
349
+ return allowedHosts.includes(agentUrl.host);
350
+ } catch {
351
+ return false;
352
+ }
212
353
  }
213
-
214
- // src/edge-detector-wrapper.ts
215
- var AI_AGENT_PATTERNS = [
216
- { pattern: /chatgpt-user/i, type: "chatgpt", name: "ChatGPT" },
217
- { pattern: /claude-web/i, type: "claude", name: "Claude" },
218
- { pattern: /perplexitybot/i, type: "perplexity", name: "Perplexity" },
219
- { pattern: /perplexity-user/i, type: "perplexity", name: "Perplexity" },
220
- { pattern: /perplexity-ai/i, type: "perplexity", name: "Perplexity" },
221
- { pattern: /perplexity/i, type: "perplexity", name: "Perplexity" },
222
- // Fallback
223
- { pattern: /bingbot/i, type: "bing", name: "Bing AI" },
224
- { pattern: /anthropic-ai/i, type: "anthropic", name: "Anthropic" }
225
- ];
226
- var CLOUD_PROVIDERS = {
227
- aws: ["54.", "52.", "35.", "18.", "3."],
228
- gcp: ["35.", "34.", "104.", "107.", "108."],
229
- azure: ["13.", "20.", "40.", "52.", "104."]
230
- };
354
+ var rules = loadRulesSync();
231
355
  var EdgeAgentDetector = class {
356
+ rules;
357
+ constructor() {
358
+ this.rules = rules;
359
+ }
232
360
  async analyze(input) {
233
361
  const reasons = [];
234
362
  let detectedAgent;
@@ -247,7 +375,7 @@ var EdgeAgentDetector = class {
247
375
  headers
248
376
  );
249
377
  if (signatureResult.isValid) {
250
- confidence = signatureResult.confidence;
378
+ confidence = signatureResult.confidence * 100;
251
379
  reasons.push(`verified_signature:${signatureResult.agent?.toLowerCase() || "unknown"}`);
252
380
  if (signatureResult.agent) {
253
381
  detectedAgent = {
@@ -260,7 +388,13 @@ var EdgeAgentDetector = class {
260
388
  reasons.push(`keyid:${signatureResult.keyid}`);
261
389
  }
262
390
  } else {
263
- confidence = Math.max(confidence, 0.3);
391
+ console.warn("[EdgeAgentDetector] Signature verification failed:", {
392
+ reason: signatureResult.reason,
393
+ agent: signatureResult.agent,
394
+ hasSignatureAgent: !!headers["signature-agent"] || !!headers["Signature-Agent"],
395
+ signatureAgentValue: headers["signature-agent"] || headers["Signature-Agent"]
396
+ });
397
+ confidence = Math.max(confidence, 30);
264
398
  reasons.push("invalid_signature");
265
399
  if (signatureResult.reason) {
266
400
  reasons.push(`signature_error:${signatureResult.reason}`);
@@ -272,68 +406,133 @@ var EdgeAgentDetector = class {
272
406
  }
273
407
  } catch (error) {
274
408
  console.error("[EdgeAgentDetector] Signature verification error:", error);
275
- confidence = Math.max(confidence, 0.2);
409
+ confidence = Math.max(confidence, 20);
276
410
  reasons.push("signature_verification_error");
277
411
  }
278
412
  }
279
413
  const userAgent = input.userAgent || input.headers?.["user-agent"] || "";
280
414
  if (userAgent) {
281
- for (const { pattern, type, name } of AI_AGENT_PATTERNS) {
282
- if (pattern.test(userAgent)) {
283
- const highConfidenceAgents = [
284
- "chatgpt",
285
- "claude",
286
- "perplexity",
287
- "anthropic"
288
- ];
289
- const patternConfidence = highConfidenceAgents.includes(type) ? 0.85 : 0.5;
290
- confidence = Math.max(confidence, patternConfidence);
291
- reasons.push(`known_pattern:${type}`);
415
+ const userAgentEntries = Object.entries(this.rules.rules.userAgents);
416
+ const genericKeys = ["generic_bot", "dev_tools", "automation_tools"];
417
+ const sortedEntries = userAgentEntries.sort((a, b) => {
418
+ const aIsGeneric = genericKeys.includes(a[0]);
419
+ const bIsGeneric = genericKeys.includes(b[0]);
420
+ if (aIsGeneric && !bIsGeneric) return 1;
421
+ if (!aIsGeneric && bIsGeneric) return -1;
422
+ return 0;
423
+ });
424
+ for (const [agentKey, agentRule] of sortedEntries) {
425
+ const rule = agentRule;
426
+ const matched = rule.patterns.some((pattern) => {
427
+ const regex = new RegExp(pattern, "i");
428
+ return regex.test(userAgent);
429
+ });
430
+ if (matched) {
431
+ const agentType = this.getAgentType(agentKey);
432
+ const agentName = this.getAgentName(agentKey);
433
+ confidence = Math.max(confidence, rule.confidence * 100);
434
+ reasons.push(`known_pattern:${agentType}`);
292
435
  if (!detectedAgent) {
293
- detectedAgent = { type, name };
436
+ detectedAgent = { type: agentType, name: agentName };
294
437
  verificationMethod = "pattern";
295
438
  }
296
439
  break;
297
440
  }
298
441
  }
299
442
  }
300
- const aiHeaders = [
301
- "openai-conversation-id",
302
- "openai-ephemeral-user-id",
303
- "anthropic-client-id",
304
- "x-goog-api-client",
305
- "x-ms-copilot-id"
306
- ];
307
- const foundAiHeaders = aiHeaders.filter(
308
- (header) => normalizedHeaders[header]
443
+ const suspiciousHeaders = this.rules.rules.headers.suspicious;
444
+ const foundAiHeaders = suspiciousHeaders.filter(
445
+ (headerRule) => normalizedHeaders[headerRule.name.toLowerCase()]
309
446
  );
310
447
  if (foundAiHeaders.length > 0) {
311
- confidence = Math.max(confidence, 0.6);
448
+ const maxConfidence = Math.max(...foundAiHeaders.map((h) => h.confidence * 100));
449
+ confidence = Math.max(confidence, maxConfidence);
312
450
  reasons.push(`ai_headers:${foundAiHeaders.length}`);
313
451
  }
314
452
  const ip = input.ip || input.ipAddress;
315
453
  if (ip && !normalizedHeaders["x-forwarded-for"] && !normalizedHeaders["x-real-ip"]) {
316
- for (const [provider, prefixes] of Object.entries(CLOUD_PROVIDERS)) {
317
- if (prefixes.some((prefix) => ip.startsWith(prefix))) {
318
- confidence = Math.max(confidence, 0.4);
454
+ const ipRanges = "providers" in this.rules.rules.ipRanges ? this.rules.rules.ipRanges.providers : this.rules.rules.ipRanges;
455
+ for (const [provider, ipRule] of Object.entries(ipRanges)) {
456
+ if (!ipRule || typeof ipRule !== "object" || !("ranges" in ipRule) || !Array.isArray(ipRule.ranges))
457
+ continue;
458
+ const matched = ipRule.ranges.some((range) => {
459
+ const prefix = range.split("/")[0];
460
+ const prefixParts = prefix.split(".");
461
+ const ipParts = ip.split(".");
462
+ for (let i = 0; i < Math.min(prefixParts.length - 1, 2); i++) {
463
+ if (prefixParts[i] !== ipParts[i] && prefixParts[i] !== "0") {
464
+ return false;
465
+ }
466
+ }
467
+ return true;
468
+ });
469
+ if (matched) {
470
+ const rule = ipRule;
471
+ confidence = Math.max(confidence, rule.confidence * 40);
319
472
  reasons.push(`cloud_provider:${provider}`);
320
473
  break;
321
474
  }
322
475
  }
323
476
  }
324
- if (reasons.length > 2 && confidence < 1) {
325
- confidence = Math.min(confidence * 1.2, 0.95);
477
+ if (reasons.length > 2 && confidence < 100) {
478
+ confidence = Math.min(confidence * 1.2, 95);
326
479
  }
480
+ confidence = Math.min(Math.max(confidence, 0), 100);
327
481
  return {
328
- isAgent: confidence > 0.3,
482
+ isAgent: confidence > 30,
483
+ // Updated to 0-100 scale (was 0.3)
329
484
  confidence,
485
+ detectionClass: confidence > 30 && detectedAgent ? { type: "AiAgent", agentType: detectedAgent.name } : confidence > 30 ? { type: "Unknown" } : { type: "Human" },
486
+ signals: [],
487
+ // Will be populated by enhanced detection engine in future tasks
330
488
  ...detectedAgent && { detectedAgent },
331
489
  reasons,
332
- ...verificationMethod && { verificationMethod },
333
- forgeabilityRisk: verificationMethod === "signature" ? "low" : confidence > 0.8 ? "medium" : "high",
490
+ ...verificationMethod && {
491
+ verificationMethod
492
+ },
493
+ forgeabilityRisk: verificationMethod === "signature" ? "low" : confidence > 80 ? "medium" : "high",
494
+ // Updated to 0-100 scale
334
495
  timestamp: /* @__PURE__ */ new Date()
335
496
  };
336
497
  }
498
+ /**
499
+ * Get agent type from rule key
500
+ */
501
+ getAgentType(agentKey) {
502
+ const typeMap = {
503
+ openai_gptbot: "openai",
504
+ anthropic_claude: "anthropic",
505
+ perplexity_bot: "perplexity",
506
+ google_ai: "google",
507
+ microsoft_ai: "microsoft",
508
+ meta_ai: "meta",
509
+ cohere_bot: "cohere",
510
+ huggingface_bot: "huggingface",
511
+ generic_bot: "generic",
512
+ dev_tools: "dev",
513
+ automation_tools: "automation"
514
+ };
515
+ return typeMap[agentKey] || agentKey;
516
+ }
517
+ /**
518
+ * Get agent name from rule key
519
+ */
520
+ getAgentName(agentKey) {
521
+ const nameMap = {
522
+ openai_gptbot: "ChatGPT/GPTBot",
523
+ anthropic_claude: "Claude",
524
+ perplexity_bot: "Perplexity",
525
+ google_ai: "Google AI",
526
+ microsoft_ai: "Microsoft Copilot",
527
+ meta_ai: "Meta AI",
528
+ cohere_bot: "Cohere",
529
+ huggingface_bot: "HuggingFace",
530
+ generic_bot: "Generic Bot",
531
+ dev_tools: "Development Tool",
532
+ automation_tools: "Automation Tool"
533
+ };
534
+ return nameMap[agentKey] || agentKey;
535
+ }
337
536
  };
338
537
  var EdgeAgentDetectorWrapper = class {
339
538
  detector;