@kya-os/agentshield-nextjs 0.1.18 → 0.1.19

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.
@@ -0,0 +1,348 @@
1
+ # AgentShield WASM Setup for Next.js Edge Runtime
2
+
3
+ ## The Challenge
4
+
5
+ Next.js Edge Runtime (used by middleware) has strict requirements for WebAssembly:
6
+
7
+ - ✅ Supports `WebAssembly.instantiate()`
8
+ - ❌ Cannot use `WebAssembly.compile()` with buffers
9
+ - ❌ Cannot dynamically load WASM from node_modules
10
+ - ✅ Requires static imports with `?module` suffix
11
+
12
+ ## Solution: Manual WASM Setup
13
+
14
+ Since npm packages cannot reliably provide WASM files that work in Edge Runtime, we provide a setup
15
+ process that copies the necessary files to your Next.js project.
16
+
17
+ ## Quick Start
18
+
19
+ ### Step 1: Install AgentShield
20
+
21
+ ```bash
22
+ npm install @kya-os/agentshield-nextjs
23
+ # or
24
+ pnpm add @kya-os/agentshield-nextjs
25
+ ```
26
+
27
+ ### Step 2: Run Setup Script
28
+
29
+ ```bash
30
+ npx agentshield-setup-edge
31
+ ```
32
+
33
+ This will:
34
+
35
+ 1. Copy the WASM file to your project root
36
+ 2. Create TypeScript definitions
37
+ 3. Generate an Edge-compatible loader
38
+
39
+ ### Step 3: Update your middleware.ts
40
+
41
+ ```typescript
42
+ // middleware.ts
43
+ import { NextResponse } from 'next/server';
44
+ import type { NextRequest } from 'next/server';
45
+ import { createAgentShieldMiddleware } from './lib/agentshield-edge';
46
+
47
+ const agentShield = createAgentShieldMiddleware({
48
+ enableWasm: true, // Enable WASM for 95%+ confidence
49
+ onAgentDetected: agent => {
50
+ console.log('AI Agent detected:', agent);
51
+ },
52
+ });
53
+
54
+ export async function middleware(request: NextRequest) {
55
+ // Initialize on first request
56
+ await agentShield.init();
57
+
58
+ // Check for AI agents
59
+ const result = await agentShield.detect(request);
60
+
61
+ if (result.isAgent && result.confidence > 0.85) {
62
+ // Handle AI agent traffic
63
+ console.log(`Detected ${result.agent} with ${result.confidence * 100}% confidence`);
64
+
65
+ // Optional: Block or redirect
66
+ // return NextResponse.redirect(new URL('/api-access-denied', request.url));
67
+ }
68
+
69
+ return NextResponse.next();
70
+ }
71
+
72
+ export const config = {
73
+ matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
74
+ };
75
+ ```
76
+
77
+ ## Manual Setup (Alternative)
78
+
79
+ If you prefer to set up manually or the script doesn't work:
80
+
81
+ ### 1. Copy WASM File
82
+
83
+ ```bash
84
+ # Create wasm directory in your project root
85
+ mkdir -p wasm
86
+
87
+ # Copy the WASM file from node_modules
88
+ cp node_modules/@kya-os/agentshield-nextjs/dist/wasm/agentshield_wasm_bg.wasm ./wasm/
89
+ ```
90
+
91
+ ### 2. Create TypeScript Definitions
92
+
93
+ Create `wasm/agentshield.d.ts`:
94
+
95
+ ```typescript
96
+ // wasm/agentshield.d.ts
97
+ declare module '*.wasm?module' {
98
+ const wasmModule: WebAssembly.Module;
99
+ export default wasmModule;
100
+ }
101
+
102
+ export interface AgentShieldWasm {
103
+ detect_agent(metadata: string): string;
104
+ get_version(): string;
105
+ Memory: WebAssembly.Memory;
106
+ }
107
+ ```
108
+
109
+ ### 3. Create Edge Loader
110
+
111
+ Create `lib/agentshield-edge.ts`:
112
+
113
+ ```typescript
114
+ // lib/agentshield-edge.ts
115
+ import type { NextRequest } from 'next/server';
116
+ import wasmModule from '../wasm/agentshield_wasm_bg.wasm?module';
117
+
118
+ let wasmInstance: WebAssembly.Instance | null = null;
119
+ let wasmMemory: WebAssembly.Memory | null = null;
120
+
121
+ interface WasmExports {
122
+ detect_agent(metadataPtr: number, metadataLen: number): number;
123
+ get_version(): number;
124
+ __wbindgen_malloc(size: number): number;
125
+ __wbindgen_free(ptr: number, size: number): void;
126
+ __wbindgen_realloc(ptr: number, oldSize: number, newSize: number): number;
127
+ memory: WebAssembly.Memory;
128
+ }
129
+
130
+ async function initWasm(): Promise<void> {
131
+ if (wasmInstance) return;
132
+
133
+ // Import the WASM module (Edge Runtime compatible)
134
+ wasmMemory = new WebAssembly.Memory({ initial: 17, maximum: 256 });
135
+
136
+ const imports = {
137
+ wbg: {
138
+ __wbindgen_throw: (ptr: number, len: number) => {
139
+ throw new Error(readString(ptr, len));
140
+ },
141
+ },
142
+ env: {
143
+ memory: wasmMemory,
144
+ },
145
+ };
146
+
147
+ wasmInstance = await WebAssembly.instantiate(wasmModule, imports);
148
+ }
149
+
150
+ function readString(ptr: number, len: number): string {
151
+ if (!wasmInstance || !wasmMemory) throw new Error('WASM not initialized');
152
+ const memory = new Uint8Array(wasmMemory.buffer);
153
+ const bytes = memory.slice(ptr, ptr + len);
154
+ return new TextDecoder().decode(bytes);
155
+ }
156
+
157
+ function writeString(str: string): [number, number] {
158
+ if (!wasmInstance) throw new Error('WASM not initialized');
159
+ const exports = wasmInstance.exports as unknown as WasmExports;
160
+
161
+ const encoded = new TextEncoder().encode(str);
162
+ const ptr = exports.__wbindgen_malloc(encoded.length);
163
+
164
+ const memory = new Uint8Array(exports.memory.buffer);
165
+ memory.set(encoded, ptr);
166
+
167
+ return [ptr, encoded.length];
168
+ }
169
+
170
+ export interface DetectionResult {
171
+ isAgent: boolean;
172
+ confidence: number;
173
+ agent?: string;
174
+ verificationMethod: 'cryptographic' | 'pattern';
175
+ }
176
+
177
+ export function createAgentShieldMiddleware(options: {
178
+ enableWasm?: boolean;
179
+ onAgentDetected?: (result: DetectionResult) => void;
180
+ }) {
181
+ let initialized = false;
182
+
183
+ return {
184
+ async init(): Promise<void> {
185
+ if (initialized) return;
186
+
187
+ if (options.enableWasm !== false) {
188
+ try {
189
+ await initWasm();
190
+ initialized = true;
191
+ console.log('✅ AgentShield WASM initialized in Edge Runtime');
192
+ } catch (error) {
193
+ console.warn('⚠️ WASM initialization failed, falling back to pattern detection:', error);
194
+ initialized = true;
195
+ }
196
+ } else {
197
+ initialized = true;
198
+ }
199
+ },
200
+
201
+ async detect(request: NextRequest): Promise<DetectionResult> {
202
+ const metadata = {
203
+ userAgent: request.headers.get('user-agent') || '',
204
+ ipAddress: request.ip || request.headers.get('x-forwarded-for') || '',
205
+ headers: Object.fromEntries(request.headers.entries()),
206
+ };
207
+
208
+ if (wasmInstance && options.enableWasm !== false) {
209
+ try {
210
+ const exports = wasmInstance.exports as unknown as WasmExports;
211
+ const [ptr, len] = writeString(JSON.stringify(metadata));
212
+
213
+ const resultPtr = exports.detect_agent(ptr, len);
214
+ const resultLen = 1024; // Assume max result size
215
+ const resultStr = readString(resultPtr, resultLen);
216
+
217
+ exports.__wbindgen_free(ptr, len);
218
+ exports.__wbindgen_free(resultPtr, resultLen);
219
+
220
+ const result = JSON.parse(resultStr);
221
+
222
+ if (options.onAgentDetected && result.isAgent) {
223
+ options.onAgentDetected(result);
224
+ }
225
+
226
+ return {
227
+ ...result,
228
+ verificationMethod: 'cryptographic',
229
+ };
230
+ } catch (error) {
231
+ console.error('WASM detection failed:', error);
232
+ // Fall through to pattern detection
233
+ }
234
+ }
235
+
236
+ // Fallback: Pattern-based detection (85% confidence)
237
+ const userAgent = metadata.userAgent.toLowerCase();
238
+ const aiAgentPatterns = [
239
+ { pattern: /chatgpt/i, name: 'ChatGPT' },
240
+ { pattern: /claude/i, name: 'Claude' },
241
+ { pattern: /anthropic/i, name: 'Anthropic' },
242
+ { pattern: /openai/i, name: 'OpenAI' },
243
+ { pattern: /gpt-/i, name: 'GPT' },
244
+ { pattern: /copilot/i, name: 'GitHub Copilot' },
245
+ { pattern: /bard/i, name: 'Google Bard' },
246
+ { pattern: /gemini/i, name: 'Google Gemini' },
247
+ ];
248
+
249
+ for (const { pattern, name } of aiAgentPatterns) {
250
+ if (pattern.test(userAgent)) {
251
+ const result: DetectionResult = {
252
+ isAgent: true,
253
+ confidence: 0.85,
254
+ agent: name,
255
+ verificationMethod: 'pattern',
256
+ };
257
+
258
+ if (options.onAgentDetected) {
259
+ options.onAgentDetected(result);
260
+ }
261
+
262
+ return result;
263
+ }
264
+ }
265
+
266
+ return {
267
+ isAgent: false,
268
+ confidence: 0.95,
269
+ verificationMethod: 'pattern',
270
+ };
271
+ },
272
+ };
273
+ }
274
+ ```
275
+
276
+ ## How It Works
277
+
278
+ 1. **Static Import**: The WASM file is imported at build time using `?module` suffix
279
+ 2. **Edge Compatible**: Uses `WebAssembly.instantiate()` with the imported module
280
+ 3. **Graceful Fallback**: Falls back to pattern detection if WASM fails
281
+ 4. **Type Safety**: Full TypeScript support with proper typing
282
+
283
+ ## Verification Methods
284
+
285
+ - **Cryptographic (95-100% confidence)**: Uses WASM for cryptographic verification
286
+ - **Pattern (85% confidence)**: Fallback pattern matching for known AI agents
287
+
288
+ ## Troubleshooting
289
+
290
+ ### WASM not loading?
291
+
292
+ 1. Ensure the WASM file exists at `wasm/agentshield_wasm_bg.wasm`
293
+ 2. Check Next.js config doesn't exclude `.wasm` files
294
+ 3. Verify the import path is correct
295
+
296
+ ### TypeScript errors?
297
+
298
+ Add to your `tsconfig.json`:
299
+
300
+ ```json
301
+ {
302
+ "compilerOptions": {
303
+ "types": ["@types/node"],
304
+ "moduleResolution": "bundler"
305
+ }
306
+ }
307
+ ```
308
+
309
+ ### Build errors?
310
+
311
+ Update your `next.config.js`:
312
+
313
+ ```javascript
314
+ /** @type {import('next').NextConfig} */
315
+ const nextConfig = {
316
+ webpack: config => {
317
+ // Handle WASM imports
318
+ config.module.rules.push({
319
+ test: /\.wasm$/,
320
+ type: 'asset/resource',
321
+ });
322
+
323
+ return config;
324
+ },
325
+ experimental: {
326
+ // Ensure Edge Runtime can access WASM
327
+ serverComponentsExternalPackages: ['@kya-os/agentshield-nextjs'],
328
+ },
329
+ };
330
+
331
+ module.exports = nextConfig;
332
+ ```
333
+
334
+ ## Why Manual Setup?
335
+
336
+ The Edge Runtime's security model prevents dynamic code evaluation. While this adds a setup step, it
337
+ ensures:
338
+
339
+ 1. **Reliability**: Works consistently across all deployment platforms
340
+ 2. **Security**: No dynamic code evaluation
341
+ 3. **Performance**: WASM is loaded at build time, not runtime
342
+ 4. **Vercel Compatibility**: Works perfectly with Vercel's Edge Runtime
343
+
344
+ ## Support
345
+
346
+ - GitHub Issues:
347
+ [github.com/kya-os/agentshield/issues](https://github.com/kya-os/agentshield/issues)
348
+ - Documentation: [agentshield.ai/docs](https://agentshield.ai/docs)