@kya-os/agentshield-nextjs 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +392 -0
- package/dist/index.d.mts +87 -0
- package/dist/index.d.ts +87 -0
- package/dist/index.js +198 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +192 -0
- package/dist/index.mjs.map +1 -0
- package/dist/middleware-OvcbG6s2.d.mts +73 -0
- package/dist/middleware-OvcbG6s2.d.ts +73 -0
- package/dist/middleware.d.mts +3 -0
- package/dist/middleware.d.ts +3 -0
- package/dist/middleware.js +120 -0
- package/dist/middleware.js.map +1 -0
- package/dist/middleware.mjs +117 -0
- package/dist/middleware.mjs.map +1 -0
- package/package.json +90 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var server = require('next/server');
|
|
4
|
+
var agentshield = require('@kya-os/agentshield');
|
|
5
|
+
var react = require('react');
|
|
6
|
+
|
|
7
|
+
// src/middleware.ts
|
|
8
|
+
function createAgentShieldMiddleware(config = {}) {
|
|
9
|
+
const detector = new agentshield.AgentDetector(config);
|
|
10
|
+
if (config.events) {
|
|
11
|
+
Object.entries(config.events).forEach(([event, handler]) => {
|
|
12
|
+
detector.on(event, handler);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
const {
|
|
16
|
+
onAgentDetected = "log",
|
|
17
|
+
onDetection,
|
|
18
|
+
skipPaths = [],
|
|
19
|
+
blockedResponse = {
|
|
20
|
+
status: 403,
|
|
21
|
+
message: "Access denied: Automated agent detected",
|
|
22
|
+
headers: { "Content-Type": "application/json" }
|
|
23
|
+
},
|
|
24
|
+
redirectUrl = "/blocked",
|
|
25
|
+
rewriteUrl = "/blocked"
|
|
26
|
+
} = config;
|
|
27
|
+
return async (request) => {
|
|
28
|
+
try {
|
|
29
|
+
const shouldSkip = skipPaths.some((pattern) => {
|
|
30
|
+
if (typeof pattern === "string") {
|
|
31
|
+
return request.nextUrl.pathname.startsWith(pattern);
|
|
32
|
+
}
|
|
33
|
+
return pattern.test(request.nextUrl.pathname);
|
|
34
|
+
});
|
|
35
|
+
if (shouldSkip) {
|
|
36
|
+
request.agentShield = { skipped: true };
|
|
37
|
+
return server.NextResponse.next();
|
|
38
|
+
}
|
|
39
|
+
const context = {
|
|
40
|
+
userAgent: request.headers.get("user-agent") ?? void 0,
|
|
41
|
+
ipAddress: request.ip ?? request.headers.get("x-forwarded-for") ?? void 0,
|
|
42
|
+
headers: Object.fromEntries(request.headers.entries()),
|
|
43
|
+
url: request.url,
|
|
44
|
+
method: request.method,
|
|
45
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
46
|
+
};
|
|
47
|
+
const result = await detector.analyze(context);
|
|
48
|
+
if (result.isAgent && result.confidence >= (config.confidenceThreshold ?? 0.7)) {
|
|
49
|
+
if (onDetection) {
|
|
50
|
+
const customResponse = await onDetection(request, result);
|
|
51
|
+
if (customResponse) {
|
|
52
|
+
return customResponse;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
switch (onAgentDetected) {
|
|
56
|
+
case "block": {
|
|
57
|
+
const response2 = server.NextResponse.json(
|
|
58
|
+
{
|
|
59
|
+
error: blockedResponse.message,
|
|
60
|
+
detected: true,
|
|
61
|
+
confidence: result.confidence,
|
|
62
|
+
timestamp: result.timestamp
|
|
63
|
+
},
|
|
64
|
+
{ status: blockedResponse.status }
|
|
65
|
+
);
|
|
66
|
+
if (blockedResponse.headers) {
|
|
67
|
+
Object.entries(blockedResponse.headers).forEach(
|
|
68
|
+
([key, value]) => {
|
|
69
|
+
response2.headers.set(key, value);
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
detector.emit("agent.blocked", result, context);
|
|
74
|
+
return response2;
|
|
75
|
+
}
|
|
76
|
+
case "redirect":
|
|
77
|
+
return server.NextResponse.redirect(new URL(redirectUrl, request.url));
|
|
78
|
+
case "rewrite":
|
|
79
|
+
return server.NextResponse.rewrite(new URL(rewriteUrl, request.url));
|
|
80
|
+
case "log":
|
|
81
|
+
console.warn("AgentShield: Agent detected", {
|
|
82
|
+
ipAddress: context.ipAddress,
|
|
83
|
+
userAgent: context.userAgent,
|
|
84
|
+
confidence: result.confidence,
|
|
85
|
+
reasons: result.reasons,
|
|
86
|
+
pathname: request.nextUrl.pathname
|
|
87
|
+
});
|
|
88
|
+
break;
|
|
89
|
+
case "allow":
|
|
90
|
+
default:
|
|
91
|
+
if (result.isAgent && result.confidence >= (config.confidenceThreshold ?? 0.7)) {
|
|
92
|
+
detector.emit("agent.allowed", result, context);
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
request.agentShield = {
|
|
98
|
+
result,
|
|
99
|
+
skipped: false
|
|
100
|
+
};
|
|
101
|
+
const response = server.NextResponse.next();
|
|
102
|
+
response.headers.set("x-agentshield-detected", result.isAgent.toString());
|
|
103
|
+
response.headers.set(
|
|
104
|
+
"x-agentshield-confidence",
|
|
105
|
+
result.confidence.toString()
|
|
106
|
+
);
|
|
107
|
+
return response;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error("AgentShield middleware error:", error);
|
|
110
|
+
return server.NextResponse.next();
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function agentShield(config = {}) {
|
|
115
|
+
return createAgentShieldMiddleware(config);
|
|
116
|
+
}
|
|
117
|
+
function useAgentDetection(config = {}) {
|
|
118
|
+
const [detector] = react.useState(() => new agentshield.AgentDetector(config));
|
|
119
|
+
const [isDetecting, setIsDetecting] = react.useState(false);
|
|
120
|
+
const [lastResult, setLastResult] = react.useState(null);
|
|
121
|
+
const detect = react.useCallback(async () => {
|
|
122
|
+
setIsDetecting(true);
|
|
123
|
+
try {
|
|
124
|
+
const context = {
|
|
125
|
+
userAgent: navigator.userAgent,
|
|
126
|
+
headers: {},
|
|
127
|
+
// Client-side headers are limited
|
|
128
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
129
|
+
};
|
|
130
|
+
const result = await detector.analyze(context);
|
|
131
|
+
setLastResult(result);
|
|
132
|
+
return result;
|
|
133
|
+
} finally {
|
|
134
|
+
setIsDetecting(false);
|
|
135
|
+
}
|
|
136
|
+
}, [detector]);
|
|
137
|
+
return {
|
|
138
|
+
detect,
|
|
139
|
+
isDetecting,
|
|
140
|
+
lastResult,
|
|
141
|
+
detector
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function useDetectionMonitor(onDetection) {
|
|
145
|
+
const [detectionHistory, setDetectionHistory] = react.useState(
|
|
146
|
+
[]
|
|
147
|
+
);
|
|
148
|
+
const addDetection = react.useCallback(
|
|
149
|
+
(result, request) => {
|
|
150
|
+
setDetectionHistory((prev) => [...prev, result].slice(-100));
|
|
151
|
+
if (onDetection && request) {
|
|
152
|
+
onDetection({
|
|
153
|
+
result,
|
|
154
|
+
request,
|
|
155
|
+
userAgent: request.headers?.get?.("user-agent"),
|
|
156
|
+
ip: request.ip
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
[onDetection]
|
|
161
|
+
);
|
|
162
|
+
const clearHistory = react.useCallback(() => {
|
|
163
|
+
setDetectionHistory([]);
|
|
164
|
+
}, []);
|
|
165
|
+
const getStats = react.useCallback(() => {
|
|
166
|
+
const total = detectionHistory.length;
|
|
167
|
+
const detected = detectionHistory.filter((r) => r.isAgent).length;
|
|
168
|
+
const avgConfidence = total > 0 ? detectionHistory.reduce((sum, r) => sum + r.confidence, 0) / total : 0;
|
|
169
|
+
return {
|
|
170
|
+
total,
|
|
171
|
+
detected,
|
|
172
|
+
avgConfidence,
|
|
173
|
+
detectionRate: total > 0 ? detected / total : 0
|
|
174
|
+
};
|
|
175
|
+
}, [detectionHistory]);
|
|
176
|
+
return {
|
|
177
|
+
detectionHistory,
|
|
178
|
+
addDetection,
|
|
179
|
+
clearHistory,
|
|
180
|
+
getStats
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/index.ts
|
|
185
|
+
var VERSION = "0.1.0";
|
|
186
|
+
/**
|
|
187
|
+
* @fileoverview AgentShield Next.js Integration
|
|
188
|
+
* @version 0.1.0
|
|
189
|
+
* @license MIT OR Apache-2.0
|
|
190
|
+
*/
|
|
191
|
+
|
|
192
|
+
exports.VERSION = VERSION;
|
|
193
|
+
exports.agentShield = agentShield;
|
|
194
|
+
exports.createAgentShieldMiddleware = createAgentShieldMiddleware;
|
|
195
|
+
exports.useAgentDetection = useAgentDetection;
|
|
196
|
+
exports.useDetectionMonitor = useDetectionMonitor;
|
|
197
|
+
//# sourceMappingURL=index.js.map
|
|
198
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/middleware.ts","../src/hooks.ts","../src/index.ts"],"names":["AgentDetector","NextResponse","response","useState","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Next.js middleware for AgentShield\n */\n\nimport { NextRequest, NextResponse } from 'next/server';\nimport { AgentDetector } from '@kya-os/agentshield';\nimport type { NextJSMiddlewareConfig } from './types';\n\n/**\n * Create AgentShield middleware for Next.js\n */\nexport function createAgentShieldMiddleware(\n config: Partial<NextJSMiddlewareConfig> = {}\n) {\n const detector = new AgentDetector(config);\n \n // Wire up event handlers if provided\n if (config.events) {\n Object.entries(config.events).forEach(([event, handler]) => {\n detector.on(event as any, handler as any);\n });\n }\n\n const {\n onAgentDetected = 'log',\n onDetection,\n skipPaths = [],\n blockedResponse = {\n status: 403,\n message: 'Access denied: Automated agent detected',\n headers: { 'Content-Type': 'application/json' },\n },\n redirectUrl = '/blocked',\n rewriteUrl = '/blocked',\n } = config;\n\n return async (request: NextRequest): Promise<NextResponse> => {\n try {\n // Check if path should be skipped\n const shouldSkip = skipPaths.some(pattern => {\n if (typeof pattern === 'string') {\n return request.nextUrl.pathname.startsWith(pattern);\n }\n return pattern.test(request.nextUrl.pathname);\n });\n\n if (shouldSkip) {\n // Mark as skipped in request\n (request as any).agentShield = { skipped: true };\n return NextResponse.next();\n }\n\n // Prepare request context\n const context = {\n userAgent: request.headers.get('user-agent') ?? undefined,\n ipAddress: request.ip ?? request.headers.get('x-forwarded-for') ?? undefined,\n headers: Object.fromEntries(request.headers.entries()),\n url: request.url,\n method: request.method,\n timestamp: new Date(),\n };\n\n // Analyze request\n const result = await detector.analyze(context);\n\n // Handle detection result\n if (\n result.isAgent &&\n result.confidence >= (config.confidenceThreshold ?? 0.7)\n ) {\n // Call custom detection handler if provided\n if (onDetection) {\n const customResponse = await onDetection(request, result);\n if (customResponse) {\n return customResponse;\n }\n }\n\n // Handle based on configuration\n switch (onAgentDetected) {\n case 'block': {\n const response = NextResponse.json(\n {\n error: blockedResponse.message,\n detected: true,\n confidence: result.confidence,\n timestamp: result.timestamp,\n },\n { status: blockedResponse.status }\n );\n\n if (blockedResponse.headers) {\n Object.entries(blockedResponse.headers).forEach(\n ([key, value]) => {\n response.headers.set(key, value);\n }\n );\n }\n \n // Emit blocked event\n detector.emit('agent.blocked', result, context);\n\n return response;\n }\n\n case 'redirect':\n return NextResponse.redirect(new URL(redirectUrl, request.url));\n\n case 'rewrite':\n return NextResponse.rewrite(new URL(rewriteUrl, request.url));\n\n case 'log':\n console.warn('AgentShield: Agent detected', {\n ipAddress: context.ipAddress,\n userAgent: context.userAgent,\n confidence: result.confidence,\n reasons: result.reasons,\n pathname: request.nextUrl.pathname,\n });\n break;\n\n case 'allow':\n default:\n // Emit allowed event for high-confidence agents\n if (result.isAgent && result.confidence >= (config.confidenceThreshold ?? 0.7)) {\n detector.emit('agent.allowed', result, context);\n }\n // Continue processing\n break;\n }\n }\n\n // Add detection result to request for API routes\n (request as any).agentShield = {\n result,\n skipped: false,\n };\n\n // Add detection result to response headers for debugging\n const response = NextResponse.next();\n response.headers.set('x-agentshield-detected', result.isAgent.toString());\n response.headers.set(\n 'x-agentshield-confidence',\n result.confidence.toString()\n );\n\n return response;\n } catch (error) {\n console.error('AgentShield middleware error:', error);\n return NextResponse.next(); // Continue on error\n }\n };\n}\n\n/**\n * Convenience function for basic setup\n */\nexport function agentShield(config: Partial<NextJSMiddlewareConfig> = {}) {\n return createAgentShieldMiddleware(config);\n}\n","/**\n * React hooks for AgentShield in Next.js applications\n */\n\nimport { useState, useCallback } from 'react';\nimport { AgentDetector } from '@kya-os/agentshield';\nimport type { DetectionResult, AgentShieldConfig } from '@kya-os/agentshield';\nimport type { DetectionContext } from './types';\n\n/**\n * Hook for client-side agent detection\n */\nexport function useAgentDetection(config: Partial<AgentShieldConfig> = {}) {\n const [detector] = useState(() => new AgentDetector(config));\n const [isDetecting, setIsDetecting] = useState(false);\n const [lastResult, setLastResult] = useState<DetectionResult | null>(null);\n\n const detect = useCallback(async () => {\n setIsDetecting(true);\n try {\n const context = {\n userAgent: navigator.userAgent,\n headers: {}, // Client-side headers are limited\n timestamp: new Date(),\n };\n\n const result = await detector.analyze(context);\n setLastResult(result);\n return result;\n } finally {\n setIsDetecting(false);\n }\n }, [detector]);\n\n return {\n detect,\n isDetecting,\n lastResult,\n detector,\n };\n}\n\n/**\n * Hook for monitoring detection results\n */\nexport function useDetectionMonitor(\n onDetection?: (context: DetectionContext) => void\n) {\n const [detectionHistory, setDetectionHistory] = useState<DetectionResult[]>(\n []\n );\n\n const addDetection = useCallback(\n (result: DetectionResult, request?: any) => {\n setDetectionHistory(prev => [...prev, result].slice(-100)); // Keep last 100\n\n if (onDetection && request) {\n onDetection({\n result,\n request,\n userAgent: request.headers?.get?.('user-agent'),\n ip: request.ip,\n });\n }\n },\n [onDetection]\n );\n\n const clearHistory = useCallback(() => {\n setDetectionHistory([]);\n }, []);\n\n const getStats = useCallback(() => {\n const total = detectionHistory.length;\n const detected = detectionHistory.filter(r => r.isAgent).length;\n const avgConfidence =\n total > 0\n ? detectionHistory.reduce((sum, r) => sum + r.confidence, 0) / total\n : 0;\n\n return {\n total,\n detected,\n avgConfidence,\n detectionRate: total > 0 ? detected / total : 0,\n };\n }, [detectionHistory]);\n\n return {\n detectionHistory,\n addDetection,\n clearHistory,\n getStats,\n };\n}\n","/**\n * @fileoverview AgentShield Next.js Integration\n * @version 0.1.0\n * @license MIT OR Apache-2.0\n */\n\nexport * from './middleware';\nexport * from './types';\nexport * from './hooks';\n\n/**\n * Library version\n */\nexport const VERSION = '0.1.0';\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { AgentDetector } from '@kya-os/agentshield';
|
|
3
|
+
import { useState, useCallback } from 'react';
|
|
4
|
+
|
|
5
|
+
// src/middleware.ts
|
|
6
|
+
function createAgentShieldMiddleware(config = {}) {
|
|
7
|
+
const detector = new AgentDetector(config);
|
|
8
|
+
if (config.events) {
|
|
9
|
+
Object.entries(config.events).forEach(([event, handler]) => {
|
|
10
|
+
detector.on(event, handler);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
const {
|
|
14
|
+
onAgentDetected = "log",
|
|
15
|
+
onDetection,
|
|
16
|
+
skipPaths = [],
|
|
17
|
+
blockedResponse = {
|
|
18
|
+
status: 403,
|
|
19
|
+
message: "Access denied: Automated agent detected",
|
|
20
|
+
headers: { "Content-Type": "application/json" }
|
|
21
|
+
},
|
|
22
|
+
redirectUrl = "/blocked",
|
|
23
|
+
rewriteUrl = "/blocked"
|
|
24
|
+
} = config;
|
|
25
|
+
return async (request) => {
|
|
26
|
+
try {
|
|
27
|
+
const shouldSkip = skipPaths.some((pattern) => {
|
|
28
|
+
if (typeof pattern === "string") {
|
|
29
|
+
return request.nextUrl.pathname.startsWith(pattern);
|
|
30
|
+
}
|
|
31
|
+
return pattern.test(request.nextUrl.pathname);
|
|
32
|
+
});
|
|
33
|
+
if (shouldSkip) {
|
|
34
|
+
request.agentShield = { skipped: true };
|
|
35
|
+
return NextResponse.next();
|
|
36
|
+
}
|
|
37
|
+
const context = {
|
|
38
|
+
userAgent: request.headers.get("user-agent") ?? void 0,
|
|
39
|
+
ipAddress: request.ip ?? request.headers.get("x-forwarded-for") ?? void 0,
|
|
40
|
+
headers: Object.fromEntries(request.headers.entries()),
|
|
41
|
+
url: request.url,
|
|
42
|
+
method: request.method,
|
|
43
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
44
|
+
};
|
|
45
|
+
const result = await detector.analyze(context);
|
|
46
|
+
if (result.isAgent && result.confidence >= (config.confidenceThreshold ?? 0.7)) {
|
|
47
|
+
if (onDetection) {
|
|
48
|
+
const customResponse = await onDetection(request, result);
|
|
49
|
+
if (customResponse) {
|
|
50
|
+
return customResponse;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
switch (onAgentDetected) {
|
|
54
|
+
case "block": {
|
|
55
|
+
const response2 = NextResponse.json(
|
|
56
|
+
{
|
|
57
|
+
error: blockedResponse.message,
|
|
58
|
+
detected: true,
|
|
59
|
+
confidence: result.confidence,
|
|
60
|
+
timestamp: result.timestamp
|
|
61
|
+
},
|
|
62
|
+
{ status: blockedResponse.status }
|
|
63
|
+
);
|
|
64
|
+
if (blockedResponse.headers) {
|
|
65
|
+
Object.entries(blockedResponse.headers).forEach(
|
|
66
|
+
([key, value]) => {
|
|
67
|
+
response2.headers.set(key, value);
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
detector.emit("agent.blocked", result, context);
|
|
72
|
+
return response2;
|
|
73
|
+
}
|
|
74
|
+
case "redirect":
|
|
75
|
+
return NextResponse.redirect(new URL(redirectUrl, request.url));
|
|
76
|
+
case "rewrite":
|
|
77
|
+
return NextResponse.rewrite(new URL(rewriteUrl, request.url));
|
|
78
|
+
case "log":
|
|
79
|
+
console.warn("AgentShield: Agent detected", {
|
|
80
|
+
ipAddress: context.ipAddress,
|
|
81
|
+
userAgent: context.userAgent,
|
|
82
|
+
confidence: result.confidence,
|
|
83
|
+
reasons: result.reasons,
|
|
84
|
+
pathname: request.nextUrl.pathname
|
|
85
|
+
});
|
|
86
|
+
break;
|
|
87
|
+
case "allow":
|
|
88
|
+
default:
|
|
89
|
+
if (result.isAgent && result.confidence >= (config.confidenceThreshold ?? 0.7)) {
|
|
90
|
+
detector.emit("agent.allowed", result, context);
|
|
91
|
+
}
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
request.agentShield = {
|
|
96
|
+
result,
|
|
97
|
+
skipped: false
|
|
98
|
+
};
|
|
99
|
+
const response = NextResponse.next();
|
|
100
|
+
response.headers.set("x-agentshield-detected", result.isAgent.toString());
|
|
101
|
+
response.headers.set(
|
|
102
|
+
"x-agentshield-confidence",
|
|
103
|
+
result.confidence.toString()
|
|
104
|
+
);
|
|
105
|
+
return response;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error("AgentShield middleware error:", error);
|
|
108
|
+
return NextResponse.next();
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function agentShield(config = {}) {
|
|
113
|
+
return createAgentShieldMiddleware(config);
|
|
114
|
+
}
|
|
115
|
+
function useAgentDetection(config = {}) {
|
|
116
|
+
const [detector] = useState(() => new AgentDetector(config));
|
|
117
|
+
const [isDetecting, setIsDetecting] = useState(false);
|
|
118
|
+
const [lastResult, setLastResult] = useState(null);
|
|
119
|
+
const detect = useCallback(async () => {
|
|
120
|
+
setIsDetecting(true);
|
|
121
|
+
try {
|
|
122
|
+
const context = {
|
|
123
|
+
userAgent: navigator.userAgent,
|
|
124
|
+
headers: {},
|
|
125
|
+
// Client-side headers are limited
|
|
126
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
127
|
+
};
|
|
128
|
+
const result = await detector.analyze(context);
|
|
129
|
+
setLastResult(result);
|
|
130
|
+
return result;
|
|
131
|
+
} finally {
|
|
132
|
+
setIsDetecting(false);
|
|
133
|
+
}
|
|
134
|
+
}, [detector]);
|
|
135
|
+
return {
|
|
136
|
+
detect,
|
|
137
|
+
isDetecting,
|
|
138
|
+
lastResult,
|
|
139
|
+
detector
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function useDetectionMonitor(onDetection) {
|
|
143
|
+
const [detectionHistory, setDetectionHistory] = useState(
|
|
144
|
+
[]
|
|
145
|
+
);
|
|
146
|
+
const addDetection = useCallback(
|
|
147
|
+
(result, request) => {
|
|
148
|
+
setDetectionHistory((prev) => [...prev, result].slice(-100));
|
|
149
|
+
if (onDetection && request) {
|
|
150
|
+
onDetection({
|
|
151
|
+
result,
|
|
152
|
+
request,
|
|
153
|
+
userAgent: request.headers?.get?.("user-agent"),
|
|
154
|
+
ip: request.ip
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
[onDetection]
|
|
159
|
+
);
|
|
160
|
+
const clearHistory = useCallback(() => {
|
|
161
|
+
setDetectionHistory([]);
|
|
162
|
+
}, []);
|
|
163
|
+
const getStats = useCallback(() => {
|
|
164
|
+
const total = detectionHistory.length;
|
|
165
|
+
const detected = detectionHistory.filter((r) => r.isAgent).length;
|
|
166
|
+
const avgConfidence = total > 0 ? detectionHistory.reduce((sum, r) => sum + r.confidence, 0) / total : 0;
|
|
167
|
+
return {
|
|
168
|
+
total,
|
|
169
|
+
detected,
|
|
170
|
+
avgConfidence,
|
|
171
|
+
detectionRate: total > 0 ? detected / total : 0
|
|
172
|
+
};
|
|
173
|
+
}, [detectionHistory]);
|
|
174
|
+
return {
|
|
175
|
+
detectionHistory,
|
|
176
|
+
addDetection,
|
|
177
|
+
clearHistory,
|
|
178
|
+
getStats
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/index.ts
|
|
183
|
+
var VERSION = "0.1.0";
|
|
184
|
+
/**
|
|
185
|
+
* @fileoverview AgentShield Next.js Integration
|
|
186
|
+
* @version 0.1.0
|
|
187
|
+
* @license MIT OR Apache-2.0
|
|
188
|
+
*/
|
|
189
|
+
|
|
190
|
+
export { VERSION, agentShield, createAgentShieldMiddleware, useAgentDetection, useDetectionMonitor };
|
|
191
|
+
//# sourceMappingURL=index.mjs.map
|
|
192
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/middleware.ts","../src/hooks.ts","../src/index.ts"],"names":["response","AgentDetector"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Next.js middleware for AgentShield\n */\n\nimport { NextRequest, NextResponse } from 'next/server';\nimport { AgentDetector } from '@kya-os/agentshield';\nimport type { NextJSMiddlewareConfig } from './types';\n\n/**\n * Create AgentShield middleware for Next.js\n */\nexport function createAgentShieldMiddleware(\n config: Partial<NextJSMiddlewareConfig> = {}\n) {\n const detector = new AgentDetector(config);\n \n // Wire up event handlers if provided\n if (config.events) {\n Object.entries(config.events).forEach(([event, handler]) => {\n detector.on(event as any, handler as any);\n });\n }\n\n const {\n onAgentDetected = 'log',\n onDetection,\n skipPaths = [],\n blockedResponse = {\n status: 403,\n message: 'Access denied: Automated agent detected',\n headers: { 'Content-Type': 'application/json' },\n },\n redirectUrl = '/blocked',\n rewriteUrl = '/blocked',\n } = config;\n\n return async (request: NextRequest): Promise<NextResponse> => {\n try {\n // Check if path should be skipped\n const shouldSkip = skipPaths.some(pattern => {\n if (typeof pattern === 'string') {\n return request.nextUrl.pathname.startsWith(pattern);\n }\n return pattern.test(request.nextUrl.pathname);\n });\n\n if (shouldSkip) {\n // Mark as skipped in request\n (request as any).agentShield = { skipped: true };\n return NextResponse.next();\n }\n\n // Prepare request context\n const context = {\n userAgent: request.headers.get('user-agent') ?? undefined,\n ipAddress: request.ip ?? request.headers.get('x-forwarded-for') ?? undefined,\n headers: Object.fromEntries(request.headers.entries()),\n url: request.url,\n method: request.method,\n timestamp: new Date(),\n };\n\n // Analyze request\n const result = await detector.analyze(context);\n\n // Handle detection result\n if (\n result.isAgent &&\n result.confidence >= (config.confidenceThreshold ?? 0.7)\n ) {\n // Call custom detection handler if provided\n if (onDetection) {\n const customResponse = await onDetection(request, result);\n if (customResponse) {\n return customResponse;\n }\n }\n\n // Handle based on configuration\n switch (onAgentDetected) {\n case 'block': {\n const response = NextResponse.json(\n {\n error: blockedResponse.message,\n detected: true,\n confidence: result.confidence,\n timestamp: result.timestamp,\n },\n { status: blockedResponse.status }\n );\n\n if (blockedResponse.headers) {\n Object.entries(blockedResponse.headers).forEach(\n ([key, value]) => {\n response.headers.set(key, value);\n }\n );\n }\n \n // Emit blocked event\n detector.emit('agent.blocked', result, context);\n\n return response;\n }\n\n case 'redirect':\n return NextResponse.redirect(new URL(redirectUrl, request.url));\n\n case 'rewrite':\n return NextResponse.rewrite(new URL(rewriteUrl, request.url));\n\n case 'log':\n console.warn('AgentShield: Agent detected', {\n ipAddress: context.ipAddress,\n userAgent: context.userAgent,\n confidence: result.confidence,\n reasons: result.reasons,\n pathname: request.nextUrl.pathname,\n });\n break;\n\n case 'allow':\n default:\n // Emit allowed event for high-confidence agents\n if (result.isAgent && result.confidence >= (config.confidenceThreshold ?? 0.7)) {\n detector.emit('agent.allowed', result, context);\n }\n // Continue processing\n break;\n }\n }\n\n // Add detection result to request for API routes\n (request as any).agentShield = {\n result,\n skipped: false,\n };\n\n // Add detection result to response headers for debugging\n const response = NextResponse.next();\n response.headers.set('x-agentshield-detected', result.isAgent.toString());\n response.headers.set(\n 'x-agentshield-confidence',\n result.confidence.toString()\n );\n\n return response;\n } catch (error) {\n console.error('AgentShield middleware error:', error);\n return NextResponse.next(); // Continue on error\n }\n };\n}\n\n/**\n * Convenience function for basic setup\n */\nexport function agentShield(config: Partial<NextJSMiddlewareConfig> = {}) {\n return createAgentShieldMiddleware(config);\n}\n","/**\n * React hooks for AgentShield in Next.js applications\n */\n\nimport { useState, useCallback } from 'react';\nimport { AgentDetector } from '@kya-os/agentshield';\nimport type { DetectionResult, AgentShieldConfig } from '@kya-os/agentshield';\nimport type { DetectionContext } from './types';\n\n/**\n * Hook for client-side agent detection\n */\nexport function useAgentDetection(config: Partial<AgentShieldConfig> = {}) {\n const [detector] = useState(() => new AgentDetector(config));\n const [isDetecting, setIsDetecting] = useState(false);\n const [lastResult, setLastResult] = useState<DetectionResult | null>(null);\n\n const detect = useCallback(async () => {\n setIsDetecting(true);\n try {\n const context = {\n userAgent: navigator.userAgent,\n headers: {}, // Client-side headers are limited\n timestamp: new Date(),\n };\n\n const result = await detector.analyze(context);\n setLastResult(result);\n return result;\n } finally {\n setIsDetecting(false);\n }\n }, [detector]);\n\n return {\n detect,\n isDetecting,\n lastResult,\n detector,\n };\n}\n\n/**\n * Hook for monitoring detection results\n */\nexport function useDetectionMonitor(\n onDetection?: (context: DetectionContext) => void\n) {\n const [detectionHistory, setDetectionHistory] = useState<DetectionResult[]>(\n []\n );\n\n const addDetection = useCallback(\n (result: DetectionResult, request?: any) => {\n setDetectionHistory(prev => [...prev, result].slice(-100)); // Keep last 100\n\n if (onDetection && request) {\n onDetection({\n result,\n request,\n userAgent: request.headers?.get?.('user-agent'),\n ip: request.ip,\n });\n }\n },\n [onDetection]\n );\n\n const clearHistory = useCallback(() => {\n setDetectionHistory([]);\n }, []);\n\n const getStats = useCallback(() => {\n const total = detectionHistory.length;\n const detected = detectionHistory.filter(r => r.isAgent).length;\n const avgConfidence =\n total > 0\n ? detectionHistory.reduce((sum, r) => sum + r.confidence, 0) / total\n : 0;\n\n return {\n total,\n detected,\n avgConfidence,\n detectionRate: total > 0 ? detected / total : 0,\n };\n }, [detectionHistory]);\n\n return {\n detectionHistory,\n addDetection,\n clearHistory,\n getStats,\n };\n}\n","/**\n * @fileoverview AgentShield Next.js Integration\n * @version 0.1.0\n * @license MIT OR Apache-2.0\n */\n\nexport * from './middleware';\nexport * from './types';\nexport * from './hooks';\n\n/**\n * Library version\n */\nexport const VERSION = '0.1.0';\n"]}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { AgentShieldConfig, DetectionResult, AgentShieldEvents } from '@kya-os/agentshield';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Next.js-specific type definitions
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Next.js middleware configuration
|
|
10
|
+
*/
|
|
11
|
+
interface NextJSMiddlewareConfig extends Partial<AgentShieldConfig> {
|
|
12
|
+
/**
|
|
13
|
+
* Action to take when an agent is detected
|
|
14
|
+
*/
|
|
15
|
+
onAgentDetected?: 'block' | 'redirect' | 'rewrite' | 'allow' | 'log';
|
|
16
|
+
/**
|
|
17
|
+
* Custom handler for agent detection
|
|
18
|
+
* @deprecated Use 'events' instead. Will be removed in v1.0.0
|
|
19
|
+
*/
|
|
20
|
+
onDetection?: (req: NextRequest, result: DetectionResult) => NextResponse | Promise<NextResponse> | void | Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Event handlers for detection events
|
|
23
|
+
*/
|
|
24
|
+
events?: Partial<AgentShieldEvents>;
|
|
25
|
+
/**
|
|
26
|
+
* Path patterns to skip detection
|
|
27
|
+
*/
|
|
28
|
+
skipPaths?: string[] | RegExp[];
|
|
29
|
+
/**
|
|
30
|
+
* Response when blocking agents
|
|
31
|
+
*/
|
|
32
|
+
blockedResponse?: {
|
|
33
|
+
status: number;
|
|
34
|
+
message: string;
|
|
35
|
+
headers?: Record<string, string>;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Redirect URL when redirecting detected agents
|
|
39
|
+
*/
|
|
40
|
+
redirectUrl?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Rewrite URL when rewriting requests from detected agents
|
|
43
|
+
*/
|
|
44
|
+
rewriteUrl?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Confidence threshold for agent detection
|
|
47
|
+
*/
|
|
48
|
+
confidenceThreshold?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Detection context for hooks
|
|
52
|
+
*/
|
|
53
|
+
interface DetectionContext {
|
|
54
|
+
result: DetectionResult;
|
|
55
|
+
request: NextRequest;
|
|
56
|
+
userAgent?: string;
|
|
57
|
+
ip?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Next.js middleware for AgentShield
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create AgentShield middleware for Next.js
|
|
66
|
+
*/
|
|
67
|
+
declare function createAgentShieldMiddleware(config?: Partial<NextJSMiddlewareConfig>): (request: NextRequest) => Promise<NextResponse>;
|
|
68
|
+
/**
|
|
69
|
+
* Convenience function for basic setup
|
|
70
|
+
*/
|
|
71
|
+
declare function agentShield(config?: Partial<NextJSMiddlewareConfig>): (request: NextRequest) => Promise<NextResponse>;
|
|
72
|
+
|
|
73
|
+
export { type DetectionContext as D, type NextJSMiddlewareConfig as N, agentShield as a, createAgentShieldMiddleware as c };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { AgentShieldConfig, DetectionResult, AgentShieldEvents } from '@kya-os/agentshield';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Next.js-specific type definitions
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Next.js middleware configuration
|
|
10
|
+
*/
|
|
11
|
+
interface NextJSMiddlewareConfig extends Partial<AgentShieldConfig> {
|
|
12
|
+
/**
|
|
13
|
+
* Action to take when an agent is detected
|
|
14
|
+
*/
|
|
15
|
+
onAgentDetected?: 'block' | 'redirect' | 'rewrite' | 'allow' | 'log';
|
|
16
|
+
/**
|
|
17
|
+
* Custom handler for agent detection
|
|
18
|
+
* @deprecated Use 'events' instead. Will be removed in v1.0.0
|
|
19
|
+
*/
|
|
20
|
+
onDetection?: (req: NextRequest, result: DetectionResult) => NextResponse | Promise<NextResponse> | void | Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Event handlers for detection events
|
|
23
|
+
*/
|
|
24
|
+
events?: Partial<AgentShieldEvents>;
|
|
25
|
+
/**
|
|
26
|
+
* Path patterns to skip detection
|
|
27
|
+
*/
|
|
28
|
+
skipPaths?: string[] | RegExp[];
|
|
29
|
+
/**
|
|
30
|
+
* Response when blocking agents
|
|
31
|
+
*/
|
|
32
|
+
blockedResponse?: {
|
|
33
|
+
status: number;
|
|
34
|
+
message: string;
|
|
35
|
+
headers?: Record<string, string>;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Redirect URL when redirecting detected agents
|
|
39
|
+
*/
|
|
40
|
+
redirectUrl?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Rewrite URL when rewriting requests from detected agents
|
|
43
|
+
*/
|
|
44
|
+
rewriteUrl?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Confidence threshold for agent detection
|
|
47
|
+
*/
|
|
48
|
+
confidenceThreshold?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Detection context for hooks
|
|
52
|
+
*/
|
|
53
|
+
interface DetectionContext {
|
|
54
|
+
result: DetectionResult;
|
|
55
|
+
request: NextRequest;
|
|
56
|
+
userAgent?: string;
|
|
57
|
+
ip?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Next.js middleware for AgentShield
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create AgentShield middleware for Next.js
|
|
66
|
+
*/
|
|
67
|
+
declare function createAgentShieldMiddleware(config?: Partial<NextJSMiddlewareConfig>): (request: NextRequest) => Promise<NextResponse>;
|
|
68
|
+
/**
|
|
69
|
+
* Convenience function for basic setup
|
|
70
|
+
*/
|
|
71
|
+
declare function agentShield(config?: Partial<NextJSMiddlewareConfig>): (request: NextRequest) => Promise<NextResponse>;
|
|
72
|
+
|
|
73
|
+
export { type DetectionContext as D, type NextJSMiddlewareConfig as N, agentShield as a, createAgentShieldMiddleware as c };
|