@kya-os/agentshield-nextjs
Version:
Next.js middleware for AgentShield AI agent detection
127 lines (123 loc) • 3.92 kB
text/typescript
import { NextRequest, NextResponse } from 'next/server';
import { EnforcementDecision } from './api-client.mjs';
/**
* API-based AgentShield Middleware for Next.js
*
* This middleware uses the AgentShield API for detection and enforcement,
* instead of running detection locally. This approach:
*
* 1. Works reliably in Edge Runtime (no WASM loading issues)
* 2. Ensures consistent detection across all platforms
* 3. Applies centralized policies from the dashboard
* 4. Supports deny lists, thresholds, and path rules
*
* @example
* ```typescript
* // middleware.ts
* import { withAgentShield } from '@kya-os/agentshield-nextjs/api-middleware';
*
* export default withAgentShield({
* apiKey: process.env.AGENTSHIELD_API_KEY!,
* // Optional overrides:
* onBlock: 'redirect', // 'block' | 'redirect' | 'challenge'
* redirectUrl: '/blocked',
* skipPaths: ['/api/health', '/_next/*'],
* });
*
* export const config = {
* matcher: ['/((?!_next/static|favicon.ico).*)'],
* };
* ```
*/
/**
* Middleware configuration
*/
interface AgentShieldMiddlewareConfig {
/** API key (or use AGENTSHIELD_API_KEY env var) */
apiKey?: string;
/** API base URL (defaults to production) */
apiUrl?: string;
/**
* Use edge detection for lower latency (~30-50ms vs ~150ms) and better coverage.
* Edge detection can identify non-JS clients (curl, Python, Claude Code WebFetch)
* that the pixel cannot detect since they don't execute JavaScript.
* Set to false to use the Vercel API instead.
* @default true
*/
useEdge?: boolean;
/** Request timeout in ms (default: 5000) */
timeout?: number;
/**
* Action to take when an agent should be blocked
* - 'block': Return 403 response
* - 'redirect': Redirect to redirectUrl
* - 'challenge': Show a challenge page (future)
* Default: uses policy from dashboard
*/
onBlock?: 'block' | 'redirect' | 'challenge';
/**
* URL to redirect to when blocking (if onBlock is 'redirect')
* Default: uses redirectUrl from dashboard policy
*/
redirectUrl?: string;
/**
* Custom blocked response
*/
blockedResponse?: {
status?: number;
message?: string;
headers?: Record<string, string>;
};
/**
* Paths to skip (in addition to dashboard policy)
* Supports glob patterns: '/api/*', '/_next/*'
*/
skipPaths?: string[];
/**
* Only enforce on these paths (overrides dashboard policy)
*/
includePaths?: string[];
/**
* Callback when an agent is detected
*/
onAgentDetected?: (request: NextRequest, decision: EnforcementDecision) => void | Promise<void>;
/**
* Callback to customize the blocked response
*/
customBlockedResponse?: (request: NextRequest, decision: EnforcementDecision) => NextResponse | Promise<NextResponse>;
/**
* Whether to fail open (allow) on API errors
* Default: true (recommended for production)
*/
failOpen?: boolean;
/**
* Enable debug logging
*/
debug?: boolean;
}
/**
* Create AgentShield middleware with API-based detection
*
* @example
* ```typescript
* // middleware.ts
* import { withAgentShield } from '@kya-os/agentshield-nextjs/api-middleware';
*
* export default withAgentShield({
* onBlock: 'block',
* skipPaths: ['/api/health'],
* });
* ```
*/
declare function withAgentShield(config?: AgentShieldMiddlewareConfig): (request: NextRequest) => Promise<NextResponse>;
/**
* Convenience export for simple setup
*
* @example
* ```typescript
* // middleware.ts
* export { agentShieldMiddleware as default } from '@kya-os/agentshield-nextjs/api-middleware';
* ```
*/
declare const agentShieldMiddleware: (request: NextRequest) => Promise<NextResponse>;
export { type AgentShieldMiddlewareConfig, agentShieldMiddleware, withAgentShield };