@kya-os/agentshield-nextjs 0.3.3 → 0.3.5

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 (110) hide show
  1. package/README.md +21 -369
  2. package/index.js +9 -0
  3. package/package.json +7 -141
  4. package/EDGE_RUNTIME_WASM_SETUP.md +0 -348
  5. package/bin/setup-edge-wasm.js +0 -525
  6. package/dist/.tsbuildinfo +0 -1
  7. package/dist/api-client.d.mts +0 -196
  8. package/dist/api-client.d.ts +0 -196
  9. package/dist/api-client.js +0 -200
  10. package/dist/api-client.js.map +0 -1
  11. package/dist/api-client.mjs +0 -196
  12. package/dist/api-client.mjs.map +0 -1
  13. package/dist/api-middleware.d.mts +0 -140
  14. package/dist/api-middleware.d.ts +0 -140
  15. package/dist/api-middleware.js +0 -511
  16. package/dist/api-middleware.js.map +0 -1
  17. package/dist/api-middleware.mjs +0 -508
  18. package/dist/api-middleware.mjs.map +0 -1
  19. package/dist/create-middleware.d.mts +0 -17
  20. package/dist/create-middleware.d.ts +0 -17
  21. package/dist/create-middleware.js +0 -1381
  22. package/dist/create-middleware.js.map +0 -1
  23. package/dist/create-middleware.mjs +0 -1358
  24. package/dist/create-middleware.mjs.map +0 -1
  25. package/dist/edge/index.d.mts +0 -110
  26. package/dist/edge/index.d.ts +0 -110
  27. package/dist/edge/index.js +0 -277
  28. package/dist/edge/index.js.map +0 -1
  29. package/dist/edge/index.mjs +0 -275
  30. package/dist/edge/index.mjs.map +0 -1
  31. package/dist/edge-detector-wrapper.d.mts +0 -34
  32. package/dist/edge-detector-wrapper.d.ts +0 -34
  33. package/dist/edge-detector-wrapper.js +0 -596
  34. package/dist/edge-detector-wrapper.js.map +0 -1
  35. package/dist/edge-detector-wrapper.mjs +0 -574
  36. package/dist/edge-detector-wrapper.mjs.map +0 -1
  37. package/dist/edge-runtime-loader.d.mts +0 -50
  38. package/dist/edge-runtime-loader.d.ts +0 -50
  39. package/dist/edge-runtime-loader.js +0 -204
  40. package/dist/edge-runtime-loader.js.map +0 -1
  41. package/dist/edge-runtime-loader.mjs +0 -201
  42. package/dist/edge-runtime-loader.mjs.map +0 -1
  43. package/dist/edge-wasm-middleware.d.mts +0 -68
  44. package/dist/edge-wasm-middleware.d.ts +0 -68
  45. package/dist/edge-wasm-middleware.js +0 -318
  46. package/dist/edge-wasm-middleware.js.map +0 -1
  47. package/dist/edge-wasm-middleware.mjs +0 -315
  48. package/dist/edge-wasm-middleware.mjs.map +0 -1
  49. package/dist/enhanced-middleware.d.mts +0 -153
  50. package/dist/enhanced-middleware.d.ts +0 -153
  51. package/dist/enhanced-middleware.js +0 -1082
  52. package/dist/enhanced-middleware.js.map +0 -1
  53. package/dist/enhanced-middleware.mjs +0 -1080
  54. package/dist/enhanced-middleware.mjs.map +0 -1
  55. package/dist/index.d.mts +0 -24
  56. package/dist/index.d.ts +0 -24
  57. package/dist/index.js +0 -2717
  58. package/dist/index.js.map +0 -1
  59. package/dist/index.mjs +0 -2662
  60. package/dist/index.mjs.map +0 -1
  61. package/dist/middleware.d.mts +0 -21
  62. package/dist/middleware.d.ts +0 -21
  63. package/dist/middleware.js +0 -1362
  64. package/dist/middleware.js.map +0 -1
  65. package/dist/middleware.mjs +0 -1339
  66. package/dist/middleware.mjs.map +0 -1
  67. package/dist/nodejs-wasm-loader.d.mts +0 -25
  68. package/dist/nodejs-wasm-loader.d.ts +0 -25
  69. package/dist/nodejs-wasm-loader.js +0 -78
  70. package/dist/nodejs-wasm-loader.js.map +0 -1
  71. package/dist/nodejs-wasm-loader.mjs +0 -68
  72. package/dist/nodejs-wasm-loader.mjs.map +0 -1
  73. package/dist/policy.d.mts +0 -162
  74. package/dist/policy.d.ts +0 -162
  75. package/dist/policy.js +0 -189
  76. package/dist/policy.js.map +0 -1
  77. package/dist/policy.mjs +0 -165
  78. package/dist/policy.mjs.map +0 -1
  79. package/dist/session-tracker.d.mts +0 -55
  80. package/dist/session-tracker.d.ts +0 -55
  81. package/dist/session-tracker.js +0 -170
  82. package/dist/session-tracker.js.map +0 -1
  83. package/dist/session-tracker.mjs +0 -167
  84. package/dist/session-tracker.mjs.map +0 -1
  85. package/dist/signature-verifier.d.mts +0 -33
  86. package/dist/signature-verifier.d.ts +0 -33
  87. package/dist/signature-verifier.js +0 -386
  88. package/dist/signature-verifier.js.map +0 -1
  89. package/dist/signature-verifier.mjs +0 -362
  90. package/dist/signature-verifier.mjs.map +0 -1
  91. package/dist/types-DVmy9NE3.d.mts +0 -105
  92. package/dist/types-DVmy9NE3.d.ts +0 -105
  93. package/dist/wasm-middleware.d.mts +0 -63
  94. package/dist/wasm-middleware.d.ts +0 -63
  95. package/dist/wasm-middleware.js +0 -98
  96. package/dist/wasm-middleware.js.map +0 -1
  97. package/dist/wasm-middleware.mjs +0 -95
  98. package/dist/wasm-middleware.mjs.map +0 -1
  99. package/dist/wasm-setup.d.mts +0 -46
  100. package/dist/wasm-setup.d.ts +0 -46
  101. package/dist/wasm-setup.js +0 -157
  102. package/dist/wasm-setup.js.map +0 -1
  103. package/dist/wasm-setup.mjs +0 -148
  104. package/dist/wasm-setup.mjs.map +0 -1
  105. package/templates/middleware-wasm-100.ts +0 -151
  106. package/wasm/agentshield_wasm.d.ts +0 -479
  107. package/wasm/agentshield_wasm.js +0 -1536
  108. package/wasm/agentshield_wasm_bg.wasm +0 -0
  109. package/wasm/package.json +0 -30
  110. package/wasm.d.ts +0 -21
@@ -1,511 +0,0 @@
1
- 'use strict';
2
-
3
- var server = require('next/server');
4
-
5
- // src/api-middleware.ts
6
-
7
- // src/api-client.ts
8
- var DEFAULT_BASE_URL = "https://kya.vouched.id";
9
- var EDGE_DETECT_URL = "https://detect.checkpoint-gateway.ai";
10
- var DEFAULT_TIMEOUT = 5e3;
11
- var AgentShieldClient = class {
12
- apiKey;
13
- baseUrl;
14
- useEdge;
15
- timeout;
16
- debug;
17
- constructor(config) {
18
- if (!config.apiKey) {
19
- throw new Error("AgentShield API key is required");
20
- }
21
- this.apiKey = config.apiKey;
22
- this.useEdge = config.useEdge !== false;
23
- this.baseUrl = config.baseUrl || (this.useEdge ? EDGE_DETECT_URL : DEFAULT_BASE_URL);
24
- this.timeout = config.timeout || DEFAULT_TIMEOUT;
25
- this.debug = config.debug || false;
26
- }
27
- /**
28
- * Call the enforce API to check if a request should be allowed
29
- */
30
- async enforce(input) {
31
- const startTime = Date.now();
32
- try {
33
- const controller = new AbortController();
34
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
35
- try {
36
- const endpoint = this.useEdge ? `${this.baseUrl}/__detect/enforce` : `${this.baseUrl}/api/v1/enforce`;
37
- const response = await fetch(endpoint, {
38
- method: "POST",
39
- headers: {
40
- "Content-Type": "application/json",
41
- Authorization: `Bearer ${this.apiKey}`,
42
- "X-Request-ID": input.requestId || crypto.randomUUID()
43
- },
44
- body: JSON.stringify(input),
45
- signal: controller.signal
46
- });
47
- clearTimeout(timeoutId);
48
- const data = await response.json();
49
- if (this.debug) {
50
- console.log("[AgentShield] Enforce response:", {
51
- status: response.status,
52
- action: data.data?.decision.action,
53
- processingTimeMs: Date.now() - startTime
54
- });
55
- }
56
- if (!response.ok) {
57
- return {
58
- success: false,
59
- error: {
60
- code: `HTTP_${response.status}`,
61
- message: data.error?.message || `HTTP error: ${response.status}`
62
- }
63
- };
64
- }
65
- return data;
66
- } catch (error) {
67
- clearTimeout(timeoutId);
68
- throw error;
69
- }
70
- } catch (error) {
71
- if (error instanceof Error && error.name === "AbortError") {
72
- if (this.debug) {
73
- console.warn("[AgentShield] Request timed out");
74
- }
75
- return {
76
- success: false,
77
- error: {
78
- code: "TIMEOUT",
79
- message: `Request timed out after ${this.timeout}ms`
80
- }
81
- };
82
- }
83
- if (this.debug) {
84
- console.error("[AgentShield] Request failed:", error);
85
- }
86
- return {
87
- success: false,
88
- error: {
89
- code: "NETWORK_ERROR",
90
- message: error instanceof Error ? error.message : "Network request failed"
91
- }
92
- };
93
- }
94
- }
95
- /**
96
- * Quick check - returns just the action without full response parsing
97
- * Useful for very fast middleware that just needs allow/block
98
- */
99
- async quickCheck(input) {
100
- const result = await this.enforce(input);
101
- if (!result.success || !result.data) {
102
- return {
103
- action: "allow",
104
- error: result.error?.message
105
- };
106
- }
107
- return {
108
- action: result.data.decision.action
109
- };
110
- }
111
- /**
112
- * Check if this client is using edge detection (Gateway Worker)
113
- */
114
- isUsingEdge() {
115
- return this.useEdge;
116
- }
117
- /**
118
- * Log a detection result to AgentShield database.
119
- * Use after Gateway Worker detection to persist results.
120
- * Fire-and-forget - returns immediately without waiting for DB write.
121
- *
122
- * @example
123
- * ```typescript
124
- * // After receiving Gateway response
125
- * if (client.isUsingEdge() && response.data?.detection) {
126
- * client.logDetection({
127
- * detection: response.data.detection,
128
- * context: { userAgent, ipAddress, path, url, method }
129
- * }).catch(err => console.error('Log failed:', err));
130
- * }
131
- * ```
132
- */
133
- async logDetection(input) {
134
- const logEndpoint = this.useEdge ? `${DEFAULT_BASE_URL}/api/v1/log-detection` : `${this.baseUrl}/api/v1/log-detection`;
135
- try {
136
- const controller = new AbortController();
137
- const timeoutId = setTimeout(() => controller.abort(), this.timeout);
138
- try {
139
- const response = await fetch(logEndpoint, {
140
- method: "POST",
141
- headers: {
142
- "Content-Type": "application/json",
143
- Authorization: `Bearer ${this.apiKey}`
144
- },
145
- body: JSON.stringify({
146
- detection: {
147
- isAgent: input.detection.isAgent,
148
- confidence: input.detection.confidence,
149
- agentName: input.detection.agentName,
150
- agentType: input.detection.agentType,
151
- detectionClass: input.detection.detectionClass,
152
- verificationMethod: input.detection.verificationMethod,
153
- reasons: input.detection.reasons
154
- },
155
- context: input.context,
156
- source: input.source || "gateway"
157
- }),
158
- signal: controller.signal
159
- });
160
- clearTimeout(timeoutId);
161
- if (!response.ok && this.debug) {
162
- console.warn("[AgentShield] Log detection returned non-2xx:", response.status);
163
- }
164
- } catch (error) {
165
- clearTimeout(timeoutId);
166
- throw error;
167
- }
168
- } catch (error) {
169
- if (this.debug) {
170
- console.error("[AgentShield] Log detection failed:", error);
171
- }
172
- throw error;
173
- }
174
- }
175
- };
176
- var clientInstance = null;
177
- function getAgentShieldClient(config) {
178
- if (!clientInstance) {
179
- const apiKey = config?.apiKey || process.env.AGENTSHIELD_API_KEY;
180
- if (!apiKey) {
181
- throw new Error(
182
- "AgentShield API key is required. Set AGENTSHIELD_API_KEY environment variable or pass apiKey in config."
183
- );
184
- }
185
- clientInstance = new AgentShieldClient({
186
- apiKey,
187
- baseUrl: config?.baseUrl || process.env.AGENTSHIELD_API_URL,
188
- // Default to edge detection unless explicitly disabled
189
- useEdge: config?.useEdge ?? process.env.AGENTSHIELD_USE_EDGE !== "false",
190
- timeout: config?.timeout,
191
- debug: config?.debug || process.env.AGENTSHIELD_DEBUG === "true"
192
- });
193
- }
194
- return clientInstance;
195
- }
196
-
197
- // src/utils.ts
198
- function getClientIp(request) {
199
- const forwardedFor = request.headers.get("x-forwarded-for");
200
- if (forwardedFor) {
201
- const ip = forwardedFor.split(",")[0]?.trim();
202
- if (ip) return ip;
203
- }
204
- const realIp = request.headers.get("x-real-ip");
205
- if (realIp) return realIp;
206
- const cfIp = request.headers.get("cf-connecting-ip");
207
- if (cfIp) return cfIp;
208
- const clientIp = request.headers.get("x-client-ip");
209
- if (clientIp) return clientIp;
210
- return void 0;
211
- }
212
- function safeHostname(url) {
213
- try {
214
- return new URL(url).hostname;
215
- } catch {
216
- return "this site";
217
- }
218
- }
219
-
220
- // src/responses/agent-instruction.ts
221
- var MCP_I_DOCS_URL = "https://docs.knowthat.ai/mcp-i/getting-started";
222
- var DEFAULT_CONNECT_PATH = "/connect";
223
- function buildAgentInstructionResponse(request, decision, redirectUrl) {
224
- const resolved = resolveUrl(redirectUrl ?? DEFAULT_CONNECT_PATH, request.url);
225
- const agentName = decision.agentName || decision.agentType || "unknown";
226
- if (!resolved.searchParams.has("agent")) {
227
- resolved.searchParams.set("agent", agentName.toLowerCase());
228
- }
229
- const authUrl = resolved.toString();
230
- const hostname = safeHostname(request.url);
231
- const body = {
232
- // Markdown-formatted so clients that render markdown (Claude Desktop,
233
- // ChatGPT web) surface the URL as a clickable link. Tone mirrors the
234
- // gateway response so messaging stays consistent across platforms.
235
- message: `I can't access ${hostname} yet \u2014 this site checks AI assistants at the front door.
236
-
237
- **To give me access, open this link:**
238
- [Connect securely to ${hostname}](${authUrl})
239
-
240
- It only takes a moment and you won't need to do it again. Once you're done, ask me to try again and I'll connect through the verified channel automatically.`,
241
- user_action_required: {
242
- action: `Connect securely to ${hostname}`,
243
- url: authUrl,
244
- reason: `${hostname} checks AI assistants before they connect. Open the link to give your assistant a verified key.`
245
- },
246
- mcp_i: {
247
- version: "1.0",
248
- action: "authenticate",
249
- authorization_url: authUrl,
250
- flow: {
251
- type: "oauth2_delegation",
252
- steps: [
253
- "1. Direct your user to the authorization_url",
254
- "2. User reviews requested scopes and grants consent",
255
- "3. Receive delegation credential (JWT)",
256
- "4. Include credential in KYA-Delegation header",
257
- "5. Retry this request with the proof"
258
- ]
259
- },
260
- retry_instructions: {
261
- header: "KYA-Delegation",
262
- format: "JWT delegation credential from authorization flow"
263
- },
264
- documentation: MCP_I_DOCS_URL
265
- },
266
- error: "mcp_authentication_required",
267
- code: "AGENT_REQUIRES_DELEGATION",
268
- detection: {
269
- agent_type: decision.agentType || "ai_agent",
270
- agent_name: decision.agentName || "Unknown Agent",
271
- confidence: decision.confidence
272
- }
273
- };
274
- const response = server.NextResponse.json(body, { status: 401 });
275
- response.headers.set("WWW-Authenticate", `KYA realm="api", authorization_uri="${authUrl}"`);
276
- response.headers.set(
277
- "Link",
278
- `<${authUrl}>; rel="kya-authorize", <${MCP_I_DOCS_URL}>; rel="help"`
279
- );
280
- response.headers.set("KYA-Auth-Required", "true");
281
- response.headers.set("KYA-Auth-Url", authUrl);
282
- response.headers.set("KYA-Action", "instruct");
283
- response.headers.set("KYA-Detected-Agent", agentName);
284
- response.headers.set("KYA-Confidence", decision.confidence.toString());
285
- response.headers.set("Cache-Control", "no-store");
286
- return response;
287
- }
288
- function resolveUrl(target, baseUrl) {
289
- try {
290
- return new URL(target, baseUrl);
291
- } catch {
292
- return new URL(DEFAULT_CONNECT_PATH, baseUrl);
293
- }
294
- }
295
-
296
- // src/api-middleware.ts
297
- function matchPath(path, pattern) {
298
- if (pattern === path) return true;
299
- if (pattern.includes("*")) {
300
- const regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
301
- return new RegExp(`^${regexPattern}$`).test(path);
302
- }
303
- if (pattern.endsWith("/")) {
304
- return path.startsWith(pattern) || path === pattern.slice(0, -1);
305
- }
306
- return path.startsWith(pattern);
307
- }
308
- function shouldSkipPath(path, skipPaths) {
309
- return skipPaths.some((pattern) => matchPath(path, pattern));
310
- }
311
- function shouldIncludePath(path, includePaths) {
312
- if (!includePaths || includePaths.length === 0) return true;
313
- return includePaths.some((pattern) => matchPath(path, pattern));
314
- }
315
- function buildBlockedResponse(request, decision, config) {
316
- const status = config.blockedResponse?.status ?? 403;
317
- const message = config.blockedResponse?.message ?? decision.message ?? "Access denied";
318
- const recoveryUrl = resolveRecoveryUrl(request, config.redirectUrl || decision.redirectUrl);
319
- const body = {
320
- error: message,
321
- code: "AGENT_BLOCKED",
322
- reason: decision.reason,
323
- agentType: decision.agentType
324
- };
325
- if (recoveryUrl) {
326
- const hostname = safeHostname(request.url);
327
- body.user_action_required = {
328
- action: `Connect securely to ${hostname}`,
329
- url: recoveryUrl,
330
- reason: `${hostname} blocks unverified AI assistants. Open the link to give your assistant a verified key and try again.`
331
- };
332
- body.message = `I can't access ${hostname} \u2014 this site blocks unverified AI assistants.
333
-
334
- **To give me access, open this link:**
335
- [Connect securely to ${hostname}](${recoveryUrl})
336
-
337
- Once you're done, ask me to try again.`;
338
- }
339
- const response = server.NextResponse.json(body, { status });
340
- if (config.blockedResponse?.headers) {
341
- for (const [key, value] of Object.entries(config.blockedResponse.headers)) {
342
- response.headers.set(key, value);
343
- }
344
- }
345
- if (recoveryUrl) {
346
- response.headers.set("Link", `<${recoveryUrl}>; rel="kya-authorize"`);
347
- response.headers.set("KYA-Auth-Url", recoveryUrl);
348
- }
349
- response.headers.set("KYA-Action", decision.action);
350
- response.headers.set("KYA-Reason", decision.reason);
351
- return response;
352
- }
353
- function resolveRecoveryUrl(request, target) {
354
- if (!target) return void 0;
355
- try {
356
- return new URL(target, request.url).toString();
357
- } catch {
358
- return void 0;
359
- }
360
- }
361
- function buildRedirectResponse(request, decision, config) {
362
- const redirectUrl = config.redirectUrl || decision.redirectUrl || "/blocked";
363
- const url = new URL(redirectUrl, request.url);
364
- url.searchParams.set("reason", decision.reason);
365
- if (decision.agentType) {
366
- url.searchParams.set("agent", decision.agentType);
367
- }
368
- return server.NextResponse.redirect(url);
369
- }
370
- function withAgentShield(config = {}) {
371
- let client = null;
372
- const getClient = () => {
373
- if (!client) {
374
- client = getAgentShieldClient({
375
- apiKey: config.apiKey,
376
- baseUrl: config.apiUrl,
377
- useEdge: config.useEdge,
378
- timeout: config.timeout,
379
- debug: config.debug
380
- });
381
- }
382
- return client;
383
- };
384
- const defaultSkipPaths = [
385
- "/_next/static/*",
386
- "/_next/image/*",
387
- "/favicon.ico",
388
- "/robots.txt",
389
- "/sitemap.xml"
390
- ];
391
- const skipPaths = [...defaultSkipPaths, ...config.skipPaths || []];
392
- const failOpen = config.failOpen ?? true;
393
- return async function middleware(request) {
394
- const path = request.nextUrl.pathname;
395
- const startTime = Date.now();
396
- if (shouldSkipPath(path, skipPaths)) {
397
- return server.NextResponse.next();
398
- }
399
- if (!shouldIncludePath(path, config.includePaths)) {
400
- return server.NextResponse.next();
401
- }
402
- try {
403
- const client2 = getClient();
404
- const userAgent = request.headers.get("user-agent") || void 0;
405
- const ipAddress = getClientIp(request);
406
- const result = await client2.enforce({
407
- headers: Object.fromEntries(request.headers.entries()),
408
- userAgent,
409
- ipAddress,
410
- path,
411
- url: request.url,
412
- method: request.method,
413
- requestId: request.headers.get("x-request-id") || void 0,
414
- options: {
415
- // Always include detection results for logging (needed when using edge)
416
- includeDetectionResult: true
417
- }
418
- });
419
- if (!result.success || !result.data) {
420
- if (config.debug) {
421
- console.warn("[AgentShield] API error:", result.error);
422
- }
423
- if (failOpen) {
424
- return server.NextResponse.next();
425
- }
426
- return server.NextResponse.json(
427
- { error: "Security check failed", code: "API_ERROR" },
428
- { status: 503 }
429
- );
430
- }
431
- const decision = result.data.decision;
432
- if (config.debug) {
433
- console.log("[AgentShield] Decision:", {
434
- path,
435
- action: decision.action,
436
- isAgent: decision.isAgent,
437
- confidence: decision.confidence,
438
- agentName: decision.agentName,
439
- detectionMethod: result.data.detection?.detectionMethod || "not-included",
440
- processingTimeMs: Date.now() - startTime
441
- });
442
- }
443
- if (client2.isUsingEdge() && result.data.detection) {
444
- client2.logDetection({
445
- detection: result.data.detection,
446
- context: { userAgent, ipAddress, path, url: request.url, method: request.method }
447
- }).catch((err) => {
448
- if (config.debug) {
449
- console.error("[AgentShield] Log detection failed:", err);
450
- }
451
- });
452
- }
453
- if (decision.isAgent && config.onAgentDetected) {
454
- await config.onAgentDetected(request, decision);
455
- }
456
- const redirectMode = config.redirectMode ?? "instruct";
457
- switch (decision.action) {
458
- case "block": {
459
- if (config.customBlockedResponse) {
460
- return config.customBlockedResponse(request, decision);
461
- }
462
- if (config.onBlock === "redirect") {
463
- return buildRedirectResponse(request, decision, config);
464
- }
465
- return buildBlockedResponse(request, decision, config);
466
- }
467
- case "redirect":
468
- case "instruct": {
469
- if (redirectMode === "http" && decision.action === "redirect") {
470
- return buildRedirectResponse(request, decision, config);
471
- }
472
- const targetUrl = config.redirectUrl || decision.redirectUrl;
473
- return buildAgentInstructionResponse(request, decision, targetUrl);
474
- }
475
- case "challenge": {
476
- return buildRedirectResponse(request, decision, config);
477
- }
478
- case "log":
479
- case "allow":
480
- default: {
481
- const response = server.NextResponse.next();
482
- if (decision.isAgent) {
483
- response.headers.set("KYA-Detected", "true");
484
- response.headers.set("KYA-Confidence", decision.confidence.toString());
485
- if (decision.agentName) {
486
- response.headers.set("KYA-Agent", decision.agentName);
487
- }
488
- }
489
- return response;
490
- }
491
- }
492
- } catch (error) {
493
- if (config.debug) {
494
- console.error("[AgentShield] Middleware error:", error);
495
- }
496
- if (failOpen) {
497
- return server.NextResponse.next();
498
- }
499
- return server.NextResponse.json(
500
- { error: "Security check failed", code: "MIDDLEWARE_ERROR" },
501
- { status: 503 }
502
- );
503
- }
504
- };
505
- }
506
- var agentShieldMiddleware = withAgentShield();
507
-
508
- exports.agentShieldMiddleware = agentShieldMiddleware;
509
- exports.withAgentShield = withAgentShield;
510
- //# sourceMappingURL=api-middleware.js.map
511
- //# sourceMappingURL=api-middleware.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api-client.ts","../src/utils.ts","../src/responses/agent-instruction.ts","../src/api-middleware.ts"],"names":["NextResponse","client"],"mappings":";;;;;;;AAsJA,IAAM,gBAAA,GAAmB,wBAAA;AACzB,IAAM,eAAA,GAAkB,sCAAA;AACxB,IAAM,eAAA,GAAkB,GAAA;AAsBjB,IAAM,oBAAN,MAAwB;AAAA,EACrB,MAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EAER,YAAY,MAAA,EAAiC;AAC3C,IAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAClB,MAAA,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAAA,IACnD;AAEA,IAAA,IAAA,CAAK,SAAS,MAAA,CAAO,MAAA;AAErB,IAAA,IAAA,CAAK,OAAA,GAAU,OAAO,OAAA,KAAY,KAAA;AAClC,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA,CAAO,OAAA,KAAY,IAAA,CAAK,UAAU,eAAA,GAAkB,gBAAA,CAAA;AACnE,IAAA,IAAA,CAAK,OAAA,GAAU,OAAO,OAAA,IAAW,eAAA;AACjC,IAAA,IAAA,CAAK,KAAA,GAAQ,OAAO,KAAA,IAAS,KAAA;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,KAAA,EAA+C;AAC3D,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,IAAA,IAAI;AAEF,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,MAAM,YAAY,UAAA,CAAW,MAAM,WAAW,KAAA,EAAM,EAAG,KAAK,OAAO,CAAA;AAEnE,MAAA,IAAI;AAEF,QAAA,MAAM,QAAA,GAAW,KAAK,OAAA,GAClB,CAAA,EAAG,KAAK,OAAO,CAAA,iBAAA,CAAA,GACf,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,eAAA,CAAA;AAEnB,QAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,QAAA,EAAU;AAAA,UACrC,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,kBAAA;AAAA,YAChB,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,YACpC,cAAA,EAAgB,KAAA,CAAM,SAAA,IAAa,MAAA,CAAO,UAAA;AAAW,WACvD;AAAA,UACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AAAA,UAC1B,QAAQ,UAAA,CAAW;AAAA,SACpB,CAAA;AAED,QAAA,YAAA,CAAa,SAAS,CAAA;AAGtB,QAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAElC,QAAA,IAAI,KAAK,KAAA,EAAO;AACd,UAAA,OAAA,CAAQ,IAAI,iCAAA,EAAmC;AAAA,YAC7C,QAAQ,QAAA,CAAS,MAAA;AAAA,YACjB,MAAA,EAAQ,IAAA,CAAK,IAAA,EAAM,QAAA,CAAS,MAAA;AAAA,YAC5B,gBAAA,EAAkB,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,WAChC,CAAA;AAAA,QACH;AAGA,QAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,UAAA,OAAO;AAAA,YACL,OAAA,EAAS,KAAA;AAAA,YACT,KAAA,EAAO;AAAA,cACL,IAAA,EAAM,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAA;AAAA,cAC7B,SAAS,IAAA,CAAK,KAAA,EAAO,OAAA,IAAW,CAAA,YAAA,EAAe,SAAS,MAAM,CAAA;AAAA;AAChE,WACF;AAAA,QACF;AAEA,QAAA,OAAO,IAAA;AAAA,MACT,SAAS,KAAA,EAAO;AACd,QAAA,YAAA,CAAa,SAAS,CAAA;AACtB,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF,SAAS,KAAA,EAAO;AAEd,MAAA,IAAI,KAAA,YAAiB,KAAA,IAAS,KAAA,CAAM,IAAA,KAAS,YAAA,EAAc;AACzD,QAAA,IAAI,KAAK,KAAA,EAAO;AACd,UAAA,OAAA,CAAQ,KAAK,iCAAiC,CAAA;AAAA,QAChD;AACA,QAAA,OAAO;AAAA,UACL,OAAA,EAAS,KAAA;AAAA,UACT,KAAA,EAAO;AAAA,YACL,IAAA,EAAM,SAAA;AAAA,YACN,OAAA,EAAS,CAAA,wBAAA,EAA2B,IAAA,CAAK,OAAO,CAAA,EAAA;AAAA;AAClD,SACF;AAAA,MACF;AAGA,MAAA,IAAI,KAAK,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,iCAAiC,KAAK,CAAA;AAAA,MACtD;AAEA,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,KAAA;AAAA,QACT,KAAA,EAAO;AAAA,UACL,IAAA,EAAM,eAAA;AAAA,UACN,OAAA,EAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA;AACpD,OACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,KAAA,EAGd;AACD,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA;AAEvC,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,IAAW,CAAC,OAAO,IAAA,EAAM;AAEnC,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,OAAA;AAAA,QACR,KAAA,EAAO,OAAO,KAAA,EAAO;AAAA,OACvB;AAAA,IACF;AAEA,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS;AAAA,KAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAAA,GAAuB;AACrB,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,aAAa,KAAA,EAAyC;AAG1D,IAAA,MAAM,WAAA,GAAc,KAAK,OAAA,GACrB,CAAA,EAAG,gBAAgB,CAAA,qBAAA,CAAA,GACnB,CAAA,EAAG,KAAK,OAAO,CAAA,qBAAA,CAAA;AAEnB,IAAA,IAAI;AACF,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,MAAM,YAAY,UAAA,CAAW,MAAM,WAAW,KAAA,EAAM,EAAG,KAAK,OAAO,CAAA;AAEnE,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,WAAA,EAAa;AAAA,UACxC,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,kBAAA;AAAA,YAChB,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA;AAAA,WACtC;AAAA,UACA,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,YACnB,SAAA,EAAW;AAAA,cACT,OAAA,EAAS,MAAM,SAAA,CAAU,OAAA;AAAA,cACzB,UAAA,EAAY,MAAM,SAAA,CAAU,UAAA;AAAA,cAC5B,SAAA,EAAW,MAAM,SAAA,CAAU,SAAA;AAAA,cAC3B,SAAA,EAAW,MAAM,SAAA,CAAU,SAAA;AAAA,cAC3B,cAAA,EAAgB,MAAM,SAAA,CAAU,cAAA;AAAA,cAChC,kBAAA,EAAoB,MAAM,SAAA,CAAU,kBAAA;AAAA,cACpC,OAAA,EAAS,MAAM,SAAA,CAAU;AAAA,aAC3B;AAAA,YACA,SAAS,KAAA,CAAM,OAAA;AAAA,YACf,MAAA,EAAQ,MAAM,MAAA,IAAU;AAAA,WACzB,CAAA;AAAA,UACD,QAAQ,UAAA,CAAW;AAAA,SACpB,CAAA;AAED,QAAA,YAAA,CAAa,SAAS,CAAA;AAEtB,QAAA,IAAI,CAAC,QAAA,CAAS,EAAA,IAAM,IAAA,CAAK,KAAA,EAAO;AAC9B,UAAA,OAAA,CAAQ,IAAA,CAAK,+CAAA,EAAiD,QAAA,CAAS,MAAM,CAAA;AAAA,QAC/E;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAA,YAAA,CAAa,SAAS,CAAA;AACtB,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF,SAAS,KAAA,EAAO;AAEd,MAAA,IAAI,KAAK,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,uCAAuC,KAAK,CAAA;AAAA,MAC5D;AAEA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AACF,CAAA;AAaA,IAAI,cAAA,GAA2C,IAAA;AAExC,SAAS,qBAAqB,MAAA,EAA8D;AACjG,EAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,IAAA,MAAM,MAAA,GAAS,MAAA,EAAQ,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI,mBAAA;AAE7C,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AAEA,IAAA,cAAA,GAAiB,IAAI,iBAAA,CAAkB;AAAA,MACrC,MAAA;AAAA,MACA,OAAA,EAAS,MAAA,EAAQ,OAAA,IAAW,OAAA,CAAQ,GAAA,CAAI,mBAAA;AAAA;AAAA,MAExC,OAAA,EAAS,MAAA,EAAQ,OAAA,IAAW,OAAA,CAAQ,IAAI,oBAAA,KAAyB,OAAA;AAAA,MACjE,SAAS,MAAA,EAAQ,OAAA;AAAA,MACjB,KAAA,EAAO,MAAA,EAAQ,KAAA,IAAS,OAAA,CAAQ,IAAI,iBAAA,KAAsB;AAAA,KAC3D,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,cAAA;AACT;;;ACjZO,SAAS,YAAY,OAAA,EAA0C;AAEpE,EAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,iBAAiB,CAAA;AAC1D,EAAA,IAAI,YAAA,EAAc;AAEhB,IAAA,MAAM,KAAK,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,GAAG,IAAA,EAAK;AAC5C,IAAA,IAAI,IAAI,OAAO,EAAA;AAAA,EACjB;AAGA,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,WAAW,CAAA;AAC9C,EAAA,IAAI,QAAQ,OAAO,MAAA;AAGnB,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,kBAAkB,CAAA;AACnD,EAAA,IAAI,MAAM,OAAO,IAAA;AAGjB,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAA;AAClD,EAAA,IAAI,UAAU,OAAO,QAAA;AAErB,EAAA,OAAO,MAAA;AACT;AAOO,SAAS,aAAa,GAAA,EAAqB;AAChD,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,GAAA,CAAI,GAAG,CAAA,CAAE,QAAA;AAAA,EACtB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,WAAA;AAAA,EACT;AACF;;;AC3BA,IAAM,cAAA,GAAiB,gDAAA;AACvB,IAAM,oBAAA,GAAuB,UAAA;AAStB,SAAS,6BAAA,CACd,OAAA,EACA,QAAA,EACA,WAAA,EACc;AAId,EAAA,MAAM,QAAA,GAAW,UAAA,CAAW,WAAA,IAAe,oBAAA,EAAsB,QAAQ,GAAG,CAAA;AAI5E,EAAA,MAAM,SAAA,GAAY,QAAA,CAAS,SAAA,IAAa,QAAA,CAAS,SAAA,IAAa,SAAA;AAC9D,EAAA,IAAI,CAAC,QAAA,CAAS,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA,EAAG;AACvC,IAAA,QAAA,CAAS,YAAA,CAAa,GAAA,CAAI,OAAA,EAAS,SAAA,CAAU,aAAa,CAAA;AAAA,EAC5D;AAEA,EAAA,MAAM,OAAA,GAAU,SAAS,QAAA,EAAS;AAClC,EAAA,MAAM,QAAA,GAAW,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AAEzC,EAAA,MAAM,IAAA,GAAO;AAAA;AAAA;AAAA;AAAA,IAIX,OAAA,EACE,kBAAkB,QAAQ,CAAA;;AAAA;AAAA,qBAAA,EAEF,QAAQ,KAAK,OAAO,CAAA;;AAAA,4JAAA,CAAA;AAAA,IAI9C,oBAAA,EAAsB;AAAA,MACpB,MAAA,EAAQ,uBAAuB,QAAQ,CAAA,CAAA;AAAA,MACvC,GAAA,EAAK,OAAA;AAAA,MACL,MAAA,EAAQ,GAAG,QAAQ,CAAA,+FAAA;AAAA,KACrB;AAAA,IAEA,KAAA,EAAO;AAAA,MACL,OAAA,EAAS,KAAA;AAAA,MACT,MAAA,EAAQ,cAAA;AAAA,MACR,iBAAA,EAAmB,OAAA;AAAA,MACnB,IAAA,EAAM;AAAA,QACJ,IAAA,EAAM,mBAAA;AAAA,QACN,KAAA,EAAO;AAAA,UACL,8CAAA;AAAA,UACA,qDAAA;AAAA,UACA,wCAAA;AAAA,UACA,gDAAA;AAAA,UACA;AAAA;AACF,OACF;AAAA,MACA,kBAAA,EAAoB;AAAA,QAClB,MAAA,EAAQ,gBAAA;AAAA,QACR,MAAA,EAAQ;AAAA,OACV;AAAA,MACA,aAAA,EAAe;AAAA,KACjB;AAAA,IAEA,KAAA,EAAO,6BAAA;AAAA,IACP,IAAA,EAAM,2BAAA;AAAA,IAEN,SAAA,EAAW;AAAA,MACT,UAAA,EAAY,SAAS,SAAA,IAAa,UAAA;AAAA,MAClC,UAAA,EAAY,SAAS,SAAA,IAAa,eAAA;AAAA,MAClC,YAAY,QAAA,CAAS;AAAA;AACvB,GACF;AAEA,EAAA,MAAM,WAAWA,mBAAA,CAAa,IAAA,CAAK,MAAM,EAAE,MAAA,EAAQ,KAAK,CAAA;AAGxD,EAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,kBAAA,EAAoB,CAAA,oCAAA,EAAuC,OAAO,CAAA,CAAA,CAAG,CAAA;AAI1F,EAAA,QAAA,CAAS,OAAA,CAAQ,GAAA;AAAA,IACf,MAAA;AAAA,IACA,CAAA,CAAA,EAAI,OAAO,CAAA,yBAAA,EAA4B,cAAc,CAAA,aAAA;AAAA,GACvD;AAGA,EAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,mBAAA,EAAqB,MAAM,CAAA;AAChD,EAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,cAAA,EAAgB,OAAO,CAAA;AAC5C,EAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,YAAA,EAAc,UAAU,CAAA;AAC7C,EAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,oBAAA,EAAsB,SAAS,CAAA;AACpD,EAAA,QAAA,CAAS,QAAQ,GAAA,CAAI,gBAAA,EAAkB,QAAA,CAAS,UAAA,CAAW,UAAU,CAAA;AACrE,EAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,eAAA,EAAiB,UAAU,CAAA;AAEhD,EAAA,OAAO,QAAA;AACT;AAMA,SAAS,UAAA,CAAW,QAAgB,OAAA,EAAsB;AACxD,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,GAAA,CAAI,MAAA,EAAQ,OAAO,CAAA;AAAA,EAChC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAI,GAAA,CAAI,oBAAA,EAAsB,OAAO,CAAA;AAAA,EAC9C;AACF;;;ACMA,SAAS,SAAA,CAAU,MAAc,OAAA,EAA0B;AAEzD,EAAA,IAAI,OAAA,KAAY,MAAM,OAAO,IAAA;AAG7B,EAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAAG;AACzB,IAAA,MAAM,YAAA,GAAe,QAClB,OAAA,CAAQ,oBAAA,EAAsB,MAAM,CAAA,CACpC,OAAA,CAAQ,OAAO,IAAI,CAAA;AACtB,IAAA,OAAO,IAAI,MAAA,CAAO,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA,CAAG,CAAA,CAAE,KAAK,IAAI,CAAA;AAAA,EAClD;AAGA,EAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAAG;AACzB,IAAA,OAAO,IAAA,CAAK,WAAW,OAAO,CAAA,IAAK,SAAS,OAAA,CAAQ,KAAA,CAAM,GAAG,EAAE,CAAA;AAAA,EACjE;AAEA,EAAA,OAAO,IAAA,CAAK,WAAW,OAAO,CAAA;AAChC;AAKA,SAAS,cAAA,CAAe,MAAc,SAAA,EAA8B;AAClE,EAAA,OAAO,UAAU,IAAA,CAAK,CAAC,YAAY,SAAA,CAAU,IAAA,EAAM,OAAO,CAAC,CAAA;AAC7D;AAKA,SAAS,iBAAA,CAAkB,MAAc,YAAA,EAAkC;AACzE,EAAA,IAAI,CAAC,YAAA,IAAgB,YAAA,CAAa,MAAA,KAAW,GAAG,OAAO,IAAA;AACvD,EAAA,OAAO,aAAa,IAAA,CAAK,CAAC,YAAY,SAAA,CAAU,IAAA,EAAM,OAAO,CAAC,CAAA;AAChE;AAeA,SAAS,oBAAA,CACP,OAAA,EACA,QAAA,EACA,MAAA,EACc;AACd,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,eAAA,EAAiB,MAAA,IAAU,GAAA;AACjD,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,eAAA,EAAiB,OAAA,IAAW,SAAS,OAAA,IAAW,eAAA;AAEvE,EAAA,MAAM,cAAc,kBAAA,CAAmB,OAAA,EAAS,MAAA,CAAO,WAAA,IAAe,SAAS,WAAW,CAAA;AAE1F,EAAA,MAAM,IAAA,GAAgC;AAAA,IACpC,KAAA,EAAO,OAAA;AAAA,IACP,IAAA,EAAM,eAAA;AAAA,IACN,QAAQ,QAAA,CAAS,MAAA;AAAA,IACjB,WAAW,QAAA,CAAS;AAAA,GACtB;AAEA,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,MAAM,QAAA,GAAW,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AACzC,IAAA,IAAA,CAAK,oBAAA,GAAuB;AAAA,MAC1B,MAAA,EAAQ,uBAAuB,QAAQ,CAAA,CAAA;AAAA,MACvC,GAAA,EAAK,WAAA;AAAA,MACL,MAAA,EAAQ,GAAG,QAAQ,CAAA,oGAAA;AAAA,KACrB;AACA,IAAA,IAAA,CAAK,OAAA,GACH,kBAAkB,QAAQ,CAAA;;AAAA;AAAA,qBAAA,EAEF,QAAQ,KAAK,WAAW,CAAA;;AAAA,sCAAA,CAAA;AAAA,EAEpD;AAEA,EAAA,MAAM,WAAWA,mBAAAA,CAAa,IAAA,CAAK,IAAA,EAAM,EAAE,QAAQ,CAAA;AAGnD,EAAA,IAAI,MAAA,CAAO,iBAAiB,OAAA,EAAS;AACnC,IAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,MAAA,CAAO,eAAA,CAAgB,OAAO,CAAA,EAAG;AACzE,MAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,IACjC;AAAA,EACF;AAEA,EAAA,IAAI,WAAA,EAAa;AAGf,IAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,CAAA,CAAA,EAAI,WAAW,CAAA,sBAAA,CAAwB,CAAA;AACpE,IAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,cAAA,EAAgB,WAAW,CAAA;AAAA,EAClD;AAGA,EAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,YAAA,EAAc,QAAA,CAAS,MAAM,CAAA;AAClD,EAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,YAAA,EAAc,QAAA,CAAS,MAAM,CAAA;AAElD,EAAA,OAAO,QAAA;AACT;AAEA,SAAS,kBAAA,CAAmB,SAAsB,MAAA,EAAgD;AAChG,EAAA,IAAI,CAAC,QAAQ,OAAO,MAAA;AACpB,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,GAAA,CAAI,MAAA,EAAQ,OAAA,CAAQ,GAAG,EAAE,QAAA,EAAS;AAAA,EAC/C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAKA,SAAS,qBAAA,CACP,OAAA,EACA,QAAA,EACA,MAAA,EACc;AACd,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,WAAA,IAAe,QAAA,CAAS,WAAA,IAAe,UAAA;AAClE,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,WAAA,EAAa,QAAQ,GAAG,CAAA;AAG5C,EAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,QAAA,EAAU,QAAA,CAAS,MAAM,CAAA;AAC9C,EAAA,IAAI,SAAS,SAAA,EAAW;AACtB,IAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,OAAA,EAAS,QAAA,CAAS,SAAS,CAAA;AAAA,EAClD;AAEA,EAAA,OAAOA,mBAAAA,CAAa,SAAS,GAAG,CAAA;AAClC;AAoBO,SAAS,eAAA,CAAgB,MAAA,GAAsC,EAAC,EAAG;AAExE,EAAA,IAAI,MAAA,GAAmC,IAAA;AAEvC,EAAA,MAAM,YAAY,MAAM;AACtB,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAA,GAAS,oBAAA,CAAqB;AAAA,QAC5B,QAAQ,MAAA,CAAO,MAAA;AAAA,QACf,SAAS,MAAA,CAAO,MAAA;AAAA,QAChB,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,OAAO,MAAA,CAAO;AAAA,OACf,CAAA;AAAA,IACH;AACA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AAGA,EAAA,MAAM,gBAAA,GAAmB;AAAA,IACvB,iBAAA;AAAA,IACA,gBAAA;AAAA,IACA,cAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,SAAA,GAAY,CAAC,GAAG,gBAAA,EAAkB,GAAI,MAAA,CAAO,SAAA,IAAa,EAAG,CAAA;AACnE,EAAA,MAAM,QAAA,GAAW,OAAO,QAAA,IAAY,IAAA;AAEpC,EAAA,OAAO,eAAe,WAAW,OAAA,EAA6C;AAC5E,IAAA,MAAM,IAAA,GAAO,QAAQ,OAAA,CAAQ,QAAA;AAC7B,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAG3B,IAAA,IAAI,cAAA,CAAe,IAAA,EAAM,SAAS,CAAA,EAAG;AACnC,MAAA,OAAOA,oBAAa,IAAA,EAAK;AAAA,IAC3B;AAGA,IAAA,IAAI,CAAC,iBAAA,CAAkB,IAAA,EAAM,MAAA,CAAO,YAAY,CAAA,EAAG;AACjD,MAAA,OAAOA,oBAAa,IAAA,EAAK;AAAA,IAC3B;AAEA,IAAA,IAAI;AACF,MAAA,MAAMC,UAAS,SAAA,EAAU;AAGzB,MAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,YAAY,CAAA,IAAK,KAAA,CAAA;AACvD,MAAA,MAAM,SAAA,GAAY,YAAY,OAAO,CAAA;AAGrC,MAAA,MAAM,MAAA,GAAS,MAAMA,OAAAA,CAAO,OAAA,CAAQ;AAAA,QAClC,SAAS,MAAA,CAAO,WAAA,CAAY,OAAA,CAAQ,OAAA,CAAQ,SAAS,CAAA;AAAA,QACrD,SAAA;AAAA,QACA,SAAA;AAAA,QACA,IAAA;AAAA,QACA,KAAK,OAAA,CAAQ,GAAA;AAAA,QACb,QAAQ,OAAA,CAAQ,MAAA;AAAA,QAChB,SAAA,EAAW,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,KAAA,CAAA;AAAA,QAClD,OAAA,EAAS;AAAA;AAAA,UAEP,sBAAA,EAAwB;AAAA;AAC1B,OACD,CAAA;AAGD,MAAA,IAAI,CAAC,MAAA,CAAO,OAAA,IAAW,CAAC,OAAO,IAAA,EAAM;AACnC,QAAA,IAAI,OAAO,KAAA,EAAO;AAChB,UAAA,OAAA,CAAQ,IAAA,CAAK,0BAAA,EAA4B,MAAA,CAAO,KAAK,CAAA;AAAA,QACvD;AAEA,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,OAAOD,oBAAa,IAAA,EAAK;AAAA,QAC3B;AAGA,QAAA,OAAOA,mBAAAA,CAAa,IAAA;AAAA,UAClB,EAAE,KAAA,EAAO,uBAAA,EAAyB,IAAA,EAAM,WAAA,EAAY;AAAA,UACpD,EAAE,QAAQ,GAAA;AAAI,SAChB;AAAA,MACF;AAEA,MAAA,MAAM,QAAA,GAAW,OAAO,IAAA,CAAK,QAAA;AAG7B,MAAA,IAAI,OAAO,KAAA,EAAO;AAChB,QAAA,OAAA,CAAQ,IAAI,yBAAA,EAA2B;AAAA,UACrC,IAAA;AAAA,UACA,QAAQ,QAAA,CAAS,MAAA;AAAA,UACjB,SAAS,QAAA,CAAS,OAAA;AAAA,UAClB,YAAY,QAAA,CAAS,UAAA;AAAA,UACrB,WAAW,QAAA,CAAS,SAAA;AAAA,UACpB,eAAA,EAAiB,MAAA,CAAO,IAAA,CAAK,SAAA,EAAW,eAAA,IAAmB,cAAA;AAAA,UAC3D,gBAAA,EAAkB,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,SAChC,CAAA;AAAA,MACH;AAKA,MAAA,IAAIC,OAAAA,CAAO,WAAA,EAAY,IAAK,MAAA,CAAO,KAAK,SAAA,EAAW;AACjD,QAAAA,QACG,YAAA,CAAa;AAAA,UACZ,SAAA,EAAW,OAAO,IAAA,CAAK,SAAA;AAAA,UACvB,OAAA,EAAS,EAAE,SAAA,EAAW,SAAA,EAAW,IAAA,EAAM,KAAK,OAAA,CAAQ,GAAA,EAAK,MAAA,EAAQ,OAAA,CAAQ,MAAA;AAAO,SACjF,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAQ;AACd,UAAA,IAAI,OAAO,KAAA,EAAO;AAChB,YAAA,OAAA,CAAQ,KAAA,CAAM,uCAAuC,GAAG,CAAA;AAAA,UAC1D;AAAA,QACF,CAAC,CAAA;AAAA,MACL;AAGA,MAAA,IAAI,QAAA,CAAS,OAAA,IAAW,MAAA,CAAO,eAAA,EAAiB;AAC9C,QAAA,MAAM,MAAA,CAAO,eAAA,CAAgB,OAAA,EAAS,QAAQ,CAAA;AAAA,MAChD;AAGA,MAAA,MAAM,YAAA,GAAe,OAAO,YAAA,IAAgB,UAAA;AAC5C,MAAA,QAAQ,SAAS,MAAA;AAAQ,QACvB,KAAK,OAAA,EAAS;AAEZ,UAAA,IAAI,OAAO,qBAAA,EAAuB;AAChC,YAAA,OAAO,MAAA,CAAO,qBAAA,CAAsB,OAAA,EAAS,QAAQ,CAAA;AAAA,UACvD;AAGA,UAAA,IAAI,MAAA,CAAO,YAAY,UAAA,EAAY;AACjC,YAAA,OAAO,qBAAA,CAAsB,OAAA,EAAS,QAAA,EAAU,MAAM,CAAA;AAAA,UACxD;AAEA,UAAA,OAAO,oBAAA,CAAqB,OAAA,EAAS,QAAA,EAAU,MAAM,CAAA;AAAA,QACvD;AAAA,QAEA,KAAK,UAAA;AAAA,QACL,KAAK,UAAA,EAAY;AAQf,UAAA,IAAI,YAAA,KAAiB,MAAA,IAAU,QAAA,CAAS,MAAA,KAAW,UAAA,EAAY;AAC7D,YAAA,OAAO,qBAAA,CAAsB,OAAA,EAAS,QAAA,EAAU,MAAM,CAAA;AAAA,UACxD;AAEA,UAAA,MAAM,SAAA,GAAY,MAAA,CAAO,WAAA,IAAe,QAAA,CAAS,WAAA;AACjD,UAAA,OAAO,6BAAA,CAA8B,OAAA,EAAS,QAAA,EAAU,SAAS,CAAA;AAAA,QACnE;AAAA,QAEA,KAAK,WAAA,EAAa;AAGhB,UAAA,OAAO,qBAAA,CAAsB,OAAA,EAAS,QAAA,EAAU,MAAM,CAAA;AAAA,QACxD;AAAA,QAEA,KAAK,KAAA;AAAA,QACL,KAAK,OAAA;AAAA,QACL,SAAS;AAEP,UAAA,MAAM,QAAA,GAAWD,oBAAa,IAAA,EAAK;AAGnC,UAAA,IAAI,SAAS,OAAA,EAAS;AACpB,YAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,cAAA,EAAgB,MAAM,CAAA;AAC3C,YAAA,QAAA,CAAS,QAAQ,GAAA,CAAI,gBAAA,EAAkB,QAAA,CAAS,UAAA,CAAW,UAAU,CAAA;AACrE,YAAA,IAAI,SAAS,SAAA,EAAW;AACtB,cAAA,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,WAAA,EAAa,QAAA,CAAS,SAAS,CAAA;AAAA,YACtD;AAAA,UACF;AAEA,UAAA,OAAO,QAAA;AAAA,QACT;AAAA;AACF,IACF,SAAS,KAAA,EAAO;AAEd,MAAA,IAAI,OAAO,KAAA,EAAO;AAChB,QAAA,OAAA,CAAQ,KAAA,CAAM,mCAAmC,KAAK,CAAA;AAAA,MACxD;AAEA,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,OAAOA,oBAAa,IAAA,EAAK;AAAA,MAC3B;AAEA,MAAA,OAAOA,mBAAAA,CAAa,IAAA;AAAA,QAClB,EAAE,KAAA,EAAO,uBAAA,EAAyB,IAAA,EAAM,kBAAA,EAAmB;AAAA,QAC3D,EAAE,QAAQ,GAAA;AAAI,OAChB;AAAA,IACF;AAAA,EACF,CAAA;AACF;AAWO,IAAM,wBAAwB,eAAA","file":"api-middleware.js","sourcesContent":["/**\n * AgentShield API Client\n *\n * Lightweight client for calling the AgentShield enforce API from middleware.\n * Designed for Edge Runtime compatibility (no Node.js-specific APIs).\n */\n\nimport type { EnforcementAction } from '@kya-os/agentshield-shared';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * API client configuration\n */\nexport interface AgentShieldClientConfig {\n /** API key for authentication */\n apiKey: string;\n /** API base URL (defaults to production) */\n baseUrl?: string;\n /**\n * Use edge detection for lower latency (~30-50ms vs ~150ms) and better coverage.\n * Edge detection can identify non-JS clients (curl, Python, Claude Code WebFetch)\n * that the pixel cannot detect since they don't execute JavaScript.\n * @default true\n */\n useEdge?: boolean;\n /** Request timeout in milliseconds (default: 5000) */\n timeout?: number;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Enforcement action — re-exported from `@kya-os/agentshield-shared`\n * so consumers of this package can keep importing it from the same\n * place. The canonical 6-value union is defined in\n * `packages/agentshield-shared/src/policy/constants.ts`. `'instruct'`\n * tells the middleware to emit a 401 with an MCP-I Link header\n * pointing the agent at a connect/consent URL.\n */\nexport type { EnforcementAction };\n\n/**\n * Enforcement decision from the API\n */\nexport interface EnforcementDecision {\n action: EnforcementAction;\n reason: string;\n isAgent: boolean;\n confidence: number;\n agentName?: string;\n agentType?: string;\n redirectUrl?: string;\n message?: string;\n metadata?: {\n policyVersion?: string;\n signatureVerified?: boolean;\n denyListMatch?: {\n clientDid?: string;\n agentDid?: string;\n clientName?: string;\n reason?: string;\n };\n };\n}\n\n/**\n * Detection result (optional in response)\n */\nexport interface DetectionResult {\n isAgent: boolean;\n confidence: number;\n agentName?: string;\n agentType?: string;\n /** Detection class: 'human', 'ai_agent', 'bot', 'incomplete_data' */\n detectionClass?: string;\n verificationMethod?: string;\n reasons?: string[];\n /** Detection engine used: 'wasm' or 'javascript-fallback' */\n detectionMethod?: string;\n}\n\n/**\n * Enforce API response\n */\nexport interface EnforceResponse {\n success: boolean;\n data?: {\n decision: EnforcementDecision;\n processingTimeMs: number;\n requestId: string;\n detection?: DetectionResult;\n };\n error?: {\n code: string;\n message: string;\n };\n}\n\n/**\n * Request input for enforce API\n */\nexport interface EnforceInput {\n /** HTTP headers from the incoming request */\n headers?: Record<string, string>;\n /** User-Agent header */\n userAgent?: string;\n /** Client IP address */\n ipAddress?: string;\n /** Request path */\n path?: string;\n /** Request URL */\n url?: string;\n /** HTTP method */\n method?: string;\n /** Request ID for tracing */\n requestId?: string;\n /** Options */\n options?: {\n /** Include full detection result */\n includeDetectionResult?: boolean;\n /** Cache TTL override */\n cacheTTL?: number;\n };\n}\n\n/**\n * Input for logging a detection result\n */\nexport interface LogDetectionInput {\n /** Detection result from Gateway */\n detection: DetectionResult;\n /** Request context */\n context: {\n userAgent?: string;\n ipAddress?: string;\n path?: string;\n url?: string;\n method?: string;\n };\n /** Source of the detection */\n source?: 'gateway' | 'middleware';\n}\n\n// ============================================================================\n// Client Implementation\n// ============================================================================\n\nconst DEFAULT_BASE_URL = 'https://kya.vouched.id';\nconst EDGE_DETECT_URL = 'https://detect.checkpoint-gateway.ai';\nconst DEFAULT_TIMEOUT = 5000;\n\n/**\n * AgentShield API Client\n *\n * @example\n * ```typescript\n * const client = new AgentShieldClient({\n * apiKey: process.env.AGENTSHIELD_API_KEY!,\n * });\n *\n * const result = await client.enforce({\n * headers: Object.fromEntries(request.headers),\n * path: request.nextUrl.pathname,\n * method: request.method,\n * });\n *\n * if (result.decision.action === 'block') {\n * return new Response('Access denied', { status: 403 });\n * }\n * ```\n */\nexport class AgentShieldClient {\n private apiKey: string;\n private baseUrl: string;\n private useEdge: boolean;\n private timeout: number;\n private debug: boolean;\n\n constructor(config: AgentShieldClientConfig) {\n if (!config.apiKey) {\n throw new Error('AgentShield API key is required');\n }\n\n this.apiKey = config.apiKey;\n // Default to edge detection for better coverage (detects non-JS clients)\n this.useEdge = config.useEdge !== false; // true by default\n this.baseUrl = config.baseUrl || (this.useEdge ? EDGE_DETECT_URL : DEFAULT_BASE_URL);\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.debug = config.debug || false;\n }\n\n /**\n * Call the enforce API to check if a request should be allowed\n */\n async enforce(input: EnforceInput): Promise<EnforceResponse> {\n const startTime = Date.now();\n\n try {\n // Create abort controller for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n // Use edge endpoint or Vercel API based on configuration\n const endpoint = this.useEdge\n ? `${this.baseUrl}/__detect/enforce`\n : `${this.baseUrl}/api/v1/enforce`;\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Request-ID': input.requestId || crypto.randomUUID(),\n },\n body: JSON.stringify(input),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n const data = (await response.json()) as EnforceResponse;\n\n if (this.debug) {\n console.log('[AgentShield] Enforce response:', {\n status: response.status,\n action: data.data?.decision.action,\n processingTimeMs: Date.now() - startTime,\n });\n }\n\n // Handle non-2xx responses\n if (!response.ok) {\n return {\n success: false,\n error: {\n code: `HTTP_${response.status}`,\n message: data.error?.message || `HTTP error: ${response.status}`,\n },\n };\n }\n\n return data;\n } catch (error) {\n clearTimeout(timeoutId);\n throw error;\n }\n } catch (error) {\n // Handle timeout\n if (error instanceof Error && error.name === 'AbortError') {\n if (this.debug) {\n console.warn('[AgentShield] Request timed out');\n }\n return {\n success: false,\n error: {\n code: 'TIMEOUT',\n message: `Request timed out after ${this.timeout}ms`,\n },\n };\n }\n\n // Handle network errors\n if (this.debug) {\n console.error('[AgentShield] Request failed:', error);\n }\n\n return {\n success: false,\n error: {\n code: 'NETWORK_ERROR',\n message: error instanceof Error ? error.message : 'Network request failed',\n },\n };\n }\n }\n\n /**\n * Quick check - returns just the action without full response parsing\n * Useful for very fast middleware that just needs allow/block\n */\n async quickCheck(input: EnforceInput): Promise<{\n action: EnforcementAction;\n error?: string;\n }> {\n const result = await this.enforce(input);\n\n if (!result.success || !result.data) {\n // On error, default to allow (fail-open)\n return {\n action: 'allow',\n error: result.error?.message,\n };\n }\n\n return {\n action: result.data.decision.action,\n };\n }\n\n /**\n * Check if this client is using edge detection (Gateway Worker)\n */\n isUsingEdge(): boolean {\n return this.useEdge;\n }\n\n /**\n * Log a detection result to AgentShield database.\n * Use after Gateway Worker detection to persist results.\n * Fire-and-forget - returns immediately without waiting for DB write.\n *\n * @example\n * ```typescript\n * // After receiving Gateway response\n * if (client.isUsingEdge() && response.data?.detection) {\n * client.logDetection({\n * detection: response.data.detection,\n * context: { userAgent, ipAddress, path, url, method }\n * }).catch(err => console.error('Log failed:', err));\n * }\n * ```\n */\n async logDetection(input: LogDetectionInput): Promise<void> {\n // Don't await - fire and forget\n // Use the base URL (not edge) for logging since this goes to the main API\n const logEndpoint = this.useEdge\n ? `${DEFAULT_BASE_URL}/api/v1/log-detection`\n : `${this.baseUrl}/api/v1/log-detection`;\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(logEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n detection: {\n isAgent: input.detection.isAgent,\n confidence: input.detection.confidence,\n agentName: input.detection.agentName,\n agentType: input.detection.agentType,\n detectionClass: input.detection.detectionClass,\n verificationMethod: input.detection.verificationMethod,\n reasons: input.detection.reasons,\n },\n context: input.context,\n source: input.source || 'gateway',\n }),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok && this.debug) {\n console.warn('[AgentShield] Log detection returned non-2xx:', response.status);\n }\n } catch (error) {\n clearTimeout(timeoutId);\n throw error;\n }\n } catch (error) {\n // Silently fail for fire-and-forget, but log in debug mode\n if (this.debug) {\n console.error('[AgentShield] Log detection failed:', error);\n }\n // Re-throw so caller can catch if needed\n throw error;\n }\n }\n}\n\n/**\n * Create a singleton client instance\n *\n * @example\n * ```typescript\n * // In middleware.ts\n * import { getAgentShieldClient } from '@kya-os/agentshield-nextjs';\n *\n * const client = getAgentShieldClient();\n * ```\n */\nlet clientInstance: AgentShieldClient | null = null;\n\nexport function getAgentShieldClient(config?: Partial<AgentShieldClientConfig>): AgentShieldClient {\n if (!clientInstance) {\n const apiKey = config?.apiKey || process.env.AGENTSHIELD_API_KEY;\n\n if (!apiKey) {\n throw new Error(\n 'AgentShield API key is required. Set AGENTSHIELD_API_KEY environment variable or pass apiKey in config.'\n );\n }\n\n clientInstance = new AgentShieldClient({\n apiKey,\n baseUrl: config?.baseUrl || process.env.AGENTSHIELD_API_URL,\n // Default to edge detection unless explicitly disabled\n useEdge: config?.useEdge ?? process.env.AGENTSHIELD_USE_EDGE !== 'false',\n timeout: config?.timeout,\n debug: config?.debug || process.env.AGENTSHIELD_DEBUG === 'true',\n });\n }\n\n return clientInstance;\n}\n\n/**\n * Reset the singleton client (useful for testing)\n */\nexport function resetAgentShieldClient(): void {\n clientInstance = null;\n}\n","/**\n * Utility functions for agentshield-nextjs\n */\n\nimport type { NextRequest } from 'next/server';\n\n/**\n * Extract client IP address from a NextRequest.\n * In Next.js 15+, the `ip` property was removed from NextRequest.\n * This function uses headers to determine the client IP.\n *\n * @param request - The NextRequest object\n * @returns The client IP address or undefined if not available\n */\nexport function getClientIp(request: NextRequest): string | undefined {\n // Check x-forwarded-for header (standard for proxies/load balancers)\n const forwardedFor = request.headers.get('x-forwarded-for');\n if (forwardedFor) {\n // Take the first IP in the chain (original client)\n const ip = forwardedFor.split(',')[0]?.trim();\n if (ip) return ip;\n }\n\n // Check x-real-ip header (commonly used by nginx)\n const realIp = request.headers.get('x-real-ip');\n if (realIp) return realIp;\n\n // Check cf-connecting-ip header (Cloudflare)\n const cfIp = request.headers.get('cf-connecting-ip');\n if (cfIp) return cfIp;\n\n // Check x-client-ip header (some proxies use this)\n const clientIp = request.headers.get('x-client-ip');\n if (clientIp) return clientIp;\n\n return undefined;\n}\n\n/**\n * Safely extract the hostname from a URL string.\n * Returns a friendly fallback when parsing fails so UX copy doesn't leak\n * \"undefined\" or similar to end users.\n */\nexport function safeHostname(url: string): string {\n try {\n return new URL(url).hostname;\n } catch {\n return 'this site';\n }\n}\n","/**\n * Agent Instruction Response Builder (Next.js)\n *\n * Returns a 401 response with a machine-parseable Link header + JSON body\n * telling an AI agent where to send its user to complete consent / connect.\n *\n * This is the in-app counterpart to the Cloudflare Gateway's builder at\n * `apps/web/workers/gateway/src/responses/agent-instruction.ts`. The response\n * shape is kept in sync so LLM and MCP clients see identical behavior whether\n * a site is protected by the gateway or by the Next.js middleware.\n *\n * Implements:\n * - RFC 7235 (WWW-Authenticate header)\n * - RFC 8288 (Link header for discovery)\n *\n * @see ../../apps/web/workers/gateway/src/responses/agent-instruction.ts\n */\n\nimport { NextResponse, type NextRequest } from 'next/server';\nimport type { EnforcementDecision } from '../api-client';\nimport { safeHostname } from '../utils';\n\nconst MCP_I_DOCS_URL = 'https://docs.knowthat.ai/mcp-i/getting-started';\nconst DEFAULT_CONNECT_PATH = '/connect';\n\n/**\n * Build a 401 \"agent must connect\" response for the Next.js middleware.\n *\n * The caller is responsible for deciding *when* to call this (typically when\n * `decision.action === 'redirect'` or `'instruct'`). This helper only owns the\n * response shape.\n */\nexport function buildAgentInstructionResponse(\n request: NextRequest,\n decision: EnforcementDecision,\n redirectUrl: string | undefined\n): NextResponse {\n // Resolve the target to an absolute URL against the incoming request so the\n // Link header is dereferenceable by strict clients (some LLM fetchers refuse\n // relative URIs in Link).\n const resolved = resolveUrl(redirectUrl ?? DEFAULT_CONNECT_PATH, request.url);\n\n // Match gateway's \"connect page\" branch: attach ?agent= for client-specific\n // install cards on the landing page.\n const agentName = decision.agentName || decision.agentType || 'unknown';\n if (!resolved.searchParams.has('agent')) {\n resolved.searchParams.set('agent', agentName.toLowerCase());\n }\n\n const authUrl = resolved.toString();\n const hostname = safeHostname(request.url);\n\n const body = {\n // Markdown-formatted so clients that render markdown (Claude Desktop,\n // ChatGPT web) surface the URL as a clickable link. Tone mirrors the\n // gateway response so messaging stays consistent across platforms.\n message:\n `I can't access ${hostname} yet — this site checks AI assistants at the front door.\\n\\n` +\n `**To give me access, open this link:**\\n` +\n `[Connect securely to ${hostname}](${authUrl})\\n\\n` +\n `It only takes a moment and you won't need to do it again. ` +\n `Once you're done, ask me to try again and I'll connect through the verified channel automatically.`,\n\n user_action_required: {\n action: `Connect securely to ${hostname}`,\n url: authUrl,\n reason: `${hostname} checks AI assistants before they connect. Open the link to give your assistant a verified key.`,\n },\n\n mcp_i: {\n version: '1.0' as const,\n action: 'authenticate' as const,\n authorization_url: authUrl,\n flow: {\n type: 'oauth2_delegation' as const,\n steps: [\n '1. Direct your user to the authorization_url',\n '2. User reviews requested scopes and grants consent',\n '3. Receive delegation credential (JWT)',\n '4. Include credential in KYA-Delegation header',\n '5. Retry this request with the proof',\n ],\n },\n retry_instructions: {\n header: 'KYA-Delegation' as const,\n format: 'JWT delegation credential from authorization flow',\n },\n documentation: MCP_I_DOCS_URL,\n },\n\n error: 'mcp_authentication_required',\n code: 'AGENT_REQUIRES_DELEGATION',\n\n detection: {\n agent_type: decision.agentType || 'ai_agent',\n agent_name: decision.agentName || 'Unknown Agent',\n confidence: decision.confidence,\n },\n };\n\n const response = NextResponse.json(body, { status: 401 });\n\n // RFC 7235: tells strict clients this is an auth challenge.\n response.headers.set('WWW-Authenticate', `KYA realm=\"api\", authorization_uri=\"${authUrl}\"`);\n\n // RFC 8288: discovery pointer. `rel=\"kya-authorize\"` is the same value\n // the CF gateway emits — keep in sync.\n response.headers.set(\n 'Link',\n `<${authUrl}>; rel=\"kya-authorize\", <${MCP_I_DOCS_URL}>; rel=\"help\"`\n );\n\n // Headers read by MCP-I clients + our own tooling.\n response.headers.set('KYA-Auth-Required', 'true');\n response.headers.set('KYA-Auth-Url', authUrl);\n response.headers.set('KYA-Action', 'instruct');\n response.headers.set('KYA-Detected-Agent', agentName);\n response.headers.set('KYA-Confidence', decision.confidence.toString());\n response.headers.set('Cache-Control', 'no-store');\n\n return response;\n}\n\n/**\n * Resolve a URL that may be absolute or a same-origin path.\n * Falls back to `/connect` on the request origin if parsing fails.\n */\nfunction resolveUrl(target: string, baseUrl: string): URL {\n try {\n return new URL(target, baseUrl);\n } catch {\n return new URL(DEFAULT_CONNECT_PATH, baseUrl);\n }\n}\n","/**\n * API-based AgentShield Middleware for Next.js\n *\n * This middleware uses the AgentShield API for detection and enforcement,\n * instead of running detection locally. This approach:\n *\n * 1. Works reliably in Edge Runtime (no WASM loading issues)\n * 2. Ensures consistent detection across all platforms\n * 3. Applies centralized policies from the dashboard\n * 4. Supports deny lists, thresholds, and path rules\n *\n * @example\n * ```typescript\n * // middleware.ts\n * import { withAgentShield } from '@kya-os/agentshield-nextjs/api-middleware';\n *\n * export default withAgentShield({\n * apiKey: process.env.AGENTSHIELD_API_KEY!,\n * // Optional overrides:\n * onBlock: 'redirect', // 'block' | 'redirect' | 'challenge'\n * redirectUrl: '/blocked',\n * skipPaths: ['/api/health', '/_next/*'],\n * });\n *\n * export const config = {\n * matcher: ['/((?!_next/static|favicon.ico).*)'],\n * };\n * ```\n */\n\nimport { NextRequest, NextResponse } from 'next/server';\nimport { AgentShieldClient, getAgentShieldClient, type EnforcementDecision } from './api-client';\nimport { buildAgentInstructionResponse } from './responses/agent-instruction';\nimport { getClientIp, safeHostname } from './utils';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Middleware configuration\n */\nexport interface AgentShieldMiddlewareConfig {\n /** API key (or use AGENTSHIELD_API_KEY env var) */\n apiKey?: string;\n /** API base URL (defaults to production) */\n apiUrl?: string;\n /**\n * Use edge detection for lower latency (~30-50ms vs ~150ms) and better coverage.\n * Edge detection can identify non-JS clients (curl, Python, Claude Code WebFetch)\n * that the pixel cannot detect since they don't execute JavaScript.\n * Set to false to use the Vercel API instead.\n * @default true\n */\n useEdge?: boolean;\n /** Request timeout in ms (default: 5000) */\n timeout?: number;\n\n /**\n * Action to take when an agent should be blocked\n * - 'block': Return 403 response\n * - 'redirect': Redirect to redirectUrl\n * - 'challenge': Show a challenge page (future)\n * Default: uses policy from dashboard\n */\n onBlock?: 'block' | 'redirect' | 'challenge';\n\n /**\n * URL to redirect to when blocking (if onBlock is 'redirect')\n * Default: uses redirectUrl from dashboard policy\n */\n redirectUrl?: string;\n\n /**\n * How the middleware handles a `redirect` / `instruct` action.\n *\n * - `'instruct'` (default): return HTTP 401 with an MCP-I Link header + JSON\n * body pointing the agent at the redirect URL. LLMs surface the URL as a\n * clickable link for the user. Matches the Cloudflare Gateway contract.\n * - `'http'`: legacy behavior — return HTTP 302 with `Location`. Most LLM\n * fetchers won't follow the redirect, so this is only useful when your\n * traffic is real browsers.\n *\n * @default 'instruct'\n */\n redirectMode?: 'instruct' | 'http';\n\n /**\n * Custom blocked response\n */\n blockedResponse?: {\n status?: number;\n message?: string;\n headers?: Record<string, string>;\n };\n\n /**\n * Paths to skip (in addition to dashboard policy)\n * Supports glob patterns: '/api/*', '/_next/*'\n */\n skipPaths?: string[];\n\n /**\n * Only enforce on these paths (overrides dashboard policy)\n */\n includePaths?: string[];\n\n /**\n * Callback when an agent is detected\n */\n onAgentDetected?: (request: NextRequest, decision: EnforcementDecision) => void | Promise<void>;\n\n /**\n * Callback to customize the blocked response\n */\n customBlockedResponse?: (\n request: NextRequest,\n decision: EnforcementDecision\n ) => NextResponse | Promise<NextResponse>;\n\n /**\n * Whether to fail open (allow) on API errors\n * Default: true (recommended for production)\n */\n failOpen?: boolean;\n\n /**\n * Enable debug logging\n */\n debug?: boolean;\n}\n\n// ============================================================================\n// Path Matching\n// ============================================================================\n\n/**\n * Check if a path matches a pattern\n */\nfunction matchPath(path: string, pattern: string): boolean {\n // Handle exact match\n if (pattern === path) return true;\n\n // Handle glob patterns\n if (pattern.includes('*')) {\n const regexPattern = pattern\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // Escape regex chars\n .replace(/\\*/g, '.*'); // Convert * to .*\n return new RegExp(`^${regexPattern}$`).test(path);\n }\n\n // Handle prefix match\n if (pattern.endsWith('/')) {\n return path.startsWith(pattern) || path === pattern.slice(0, -1);\n }\n\n return path.startsWith(pattern);\n}\n\n/**\n * Check if path should be skipped\n */\nfunction shouldSkipPath(path: string, skipPaths: string[]): boolean {\n return skipPaths.some((pattern) => matchPath(path, pattern));\n}\n\n/**\n * Check if path should be included (if includePaths is set)\n */\nfunction shouldIncludePath(path: string, includePaths?: string[]): boolean {\n if (!includePaths || includePaths.length === 0) return true;\n return includePaths.some((pattern) => matchPath(path, pattern));\n}\n\n// ============================================================================\n// Response Builders\n// ============================================================================\n\n/**\n * Build blocked response.\n *\n * When the policy attaches a `redirectUrl` (e.g. the dashboard's hosted\n * /connect page), we still respect the `block` action but surface the URL to\n * LLM clients so the user can recover: `Link` header + `user_action_required`\n * in the JSON body. Status stays 403 — this is not an auth challenge, it's a\n * blocked request with a recovery hint.\n */\nfunction buildBlockedResponse(\n request: NextRequest,\n decision: EnforcementDecision,\n config: AgentShieldMiddlewareConfig\n): NextResponse {\n const status = config.blockedResponse?.status ?? 403;\n const message = config.blockedResponse?.message ?? decision.message ?? 'Access denied';\n\n const recoveryUrl = resolveRecoveryUrl(request, config.redirectUrl || decision.redirectUrl);\n\n const body: Record<string, unknown> = {\n error: message,\n code: 'AGENT_BLOCKED',\n reason: decision.reason,\n agentType: decision.agentType,\n };\n\n if (recoveryUrl) {\n const hostname = safeHostname(request.url);\n body.user_action_required = {\n action: `Connect securely to ${hostname}`,\n url: recoveryUrl,\n reason: `${hostname} blocks unverified AI assistants. Open the link to give your assistant a verified key and try again.`,\n };\n body.message =\n `I can't access ${hostname} — this site blocks unverified AI assistants.\\n\\n` +\n `**To give me access, open this link:**\\n` +\n `[Connect securely to ${hostname}](${recoveryUrl})\\n\\n` +\n `Once you're done, ask me to try again.`;\n }\n\n const response = NextResponse.json(body, { status });\n\n // Add custom headers\n if (config.blockedResponse?.headers) {\n for (const [key, value] of Object.entries(config.blockedResponse.headers)) {\n response.headers.set(key, value);\n }\n }\n\n if (recoveryUrl) {\n // RFC 8288 discovery pointer — same rel value the 401 instruct path uses\n // so LLM clients can parse it uniformly.\n response.headers.set('Link', `<${recoveryUrl}>; rel=\"kya-authorize\"`);\n response.headers.set('KYA-Auth-Url', recoveryUrl);\n }\n\n // Add AgentShield headers\n response.headers.set('KYA-Action', decision.action);\n response.headers.set('KYA-Reason', decision.reason);\n\n return response;\n}\n\nfunction resolveRecoveryUrl(request: NextRequest, target: string | undefined): string | undefined {\n if (!target) return undefined;\n try {\n return new URL(target, request.url).toString();\n } catch {\n return undefined;\n }\n}\n\n/**\n * Build redirect response\n */\nfunction buildRedirectResponse(\n request: NextRequest,\n decision: EnforcementDecision,\n config: AgentShieldMiddlewareConfig\n): NextResponse {\n const redirectUrl = config.redirectUrl || decision.redirectUrl || '/blocked';\n const url = new URL(redirectUrl, request.url);\n\n // Add query params with detection info\n url.searchParams.set('reason', decision.reason);\n if (decision.agentType) {\n url.searchParams.set('agent', decision.agentType);\n }\n\n return NextResponse.redirect(url);\n}\n\n// ============================================================================\n// Middleware Factory\n// ============================================================================\n\n/**\n * Create AgentShield middleware with API-based detection\n *\n * @example\n * ```typescript\n * // middleware.ts\n * import { withAgentShield } from '@kya-os/agentshield-nextjs/api-middleware';\n *\n * export default withAgentShield({\n * onBlock: 'block',\n * skipPaths: ['/api/health'],\n * });\n * ```\n */\nexport function withAgentShield(config: AgentShieldMiddlewareConfig = {}) {\n // Initialize client (will use AGENTSHIELD_API_KEY env var if not provided)\n let client: AgentShieldClient | null = null;\n\n const getClient = () => {\n if (!client) {\n client = getAgentShieldClient({\n apiKey: config.apiKey,\n baseUrl: config.apiUrl,\n useEdge: config.useEdge,\n timeout: config.timeout,\n debug: config.debug,\n });\n }\n return client;\n };\n\n // Default skip paths (static assets, etc.)\n const defaultSkipPaths = [\n '/_next/static/*',\n '/_next/image/*',\n '/favicon.ico',\n '/robots.txt',\n '/sitemap.xml',\n ];\n\n const skipPaths = [...defaultSkipPaths, ...(config.skipPaths || [])];\n const failOpen = config.failOpen ?? true;\n\n return async function middleware(request: NextRequest): Promise<NextResponse> {\n const path = request.nextUrl.pathname;\n const startTime = Date.now();\n\n // Check skip paths\n if (shouldSkipPath(path, skipPaths)) {\n return NextResponse.next();\n }\n\n // Check include paths\n if (!shouldIncludePath(path, config.includePaths)) {\n return NextResponse.next();\n }\n\n try {\n const client = getClient();\n\n // Extract request context for potential logging\n const userAgent = request.headers.get('user-agent') || undefined;\n const ipAddress = getClientIp(request);\n\n // Call enforce API\n const result = await client.enforce({\n headers: Object.fromEntries(request.headers.entries()),\n userAgent,\n ipAddress,\n path,\n url: request.url,\n method: request.method,\n requestId: request.headers.get('x-request-id') || undefined,\n options: {\n // Always include detection results for logging (needed when using edge)\n includeDetectionResult: true,\n },\n });\n\n // Handle API error\n if (!result.success || !result.data) {\n if (config.debug) {\n console.warn('[AgentShield] API error:', result.error);\n }\n\n if (failOpen) {\n return NextResponse.next();\n }\n\n // Fail closed - block on error\n return NextResponse.json(\n { error: 'Security check failed', code: 'API_ERROR' },\n { status: 503 }\n );\n }\n\n const decision = result.data.decision;\n\n // Log if debug enabled\n if (config.debug) {\n console.log('[AgentShield] Decision:', {\n path,\n action: decision.action,\n isAgent: decision.isAgent,\n confidence: decision.confidence,\n agentName: decision.agentName,\n detectionMethod: result.data.detection?.detectionMethod || 'not-included',\n processingTimeMs: Date.now() - startTime,\n });\n }\n\n // Fire-and-forget logging - ONLY when using Gateway Worker (edge detection)\n // When useEdge: false, the /api/v1/enforce endpoint already logs to the database\n // This prevents double-logging while ensuring Gateway detections are persisted\n if (client.isUsingEdge() && result.data.detection) {\n client\n .logDetection({\n detection: result.data.detection,\n context: { userAgent, ipAddress, path, url: request.url, method: request.method },\n })\n .catch((err) => {\n if (config.debug) {\n console.error('[AgentShield] Log detection failed:', err);\n }\n });\n }\n\n // Handle agent detection callback\n if (decision.isAgent && config.onAgentDetected) {\n await config.onAgentDetected(request, decision);\n }\n\n // Handle enforcement action\n const redirectMode = config.redirectMode ?? 'instruct';\n switch (decision.action) {\n case 'block': {\n // Use custom response if provided\n if (config.customBlockedResponse) {\n return config.customBlockedResponse(request, decision);\n }\n\n // Check if config overrides to redirect\n if (config.onBlock === 'redirect') {\n return buildRedirectResponse(request, decision, config);\n }\n\n return buildBlockedResponse(request, decision, config);\n }\n\n case 'redirect':\n case 'instruct': {\n // Default behavior: 401 + Link header + JSON body so LLM clients can\n // surface the /connect URL as a link for the user to open. This\n // matches `buildAgentInstructionResponse` in the CF gateway, so\n // hostname-routed and self-hosted deployments behave the same.\n //\n // Legacy 302 behavior is available under `redirectMode: 'http'` for\n // customers who want a plain browser redirect.\n if (redirectMode === 'http' && decision.action === 'redirect') {\n return buildRedirectResponse(request, decision, config);\n }\n\n const targetUrl = config.redirectUrl || decision.redirectUrl;\n return buildAgentInstructionResponse(request, decision, targetUrl);\n }\n\n case 'challenge': {\n // Future: implement challenge page\n // For now, treat as redirect\n return buildRedirectResponse(request, decision, config);\n }\n\n case 'log':\n case 'allow':\n default: {\n // Allow the request to proceed\n const response = NextResponse.next();\n\n // Add detection headers for downstream use\n if (decision.isAgent) {\n response.headers.set('KYA-Detected', 'true');\n response.headers.set('KYA-Confidence', decision.confidence.toString());\n if (decision.agentName) {\n response.headers.set('KYA-Agent', decision.agentName);\n }\n }\n\n return response;\n }\n }\n } catch (error) {\n // Unexpected error\n if (config.debug) {\n console.error('[AgentShield] Middleware error:', error);\n }\n\n if (failOpen) {\n return NextResponse.next();\n }\n\n return NextResponse.json(\n { error: 'Security check failed', code: 'MIDDLEWARE_ERROR' },\n { status: 503 }\n );\n }\n };\n}\n\n/**\n * Convenience export for simple setup\n *\n * @example\n * ```typescript\n * // middleware.ts\n * export { agentShieldMiddleware as default } from '@kya-os/agentshield-nextjs/api-middleware';\n * ```\n */\nexport const agentShieldMiddleware = withAgentShield();\n"]}