halt-rate 0.1.0

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 @@
1
+ {"version":3,"sources":["../../src/core/policy.ts","../../src/core/extractors.ts","../../src/algorithms/token-bucket.ts","../../src/algorithms/fixed-window.ts","../../src/algorithms/sliding-window.ts","../../src/algorithms/leaky-bucket.ts","../../src/core/limiter.ts","../../src/core/decision.ts","../../src/adapters/next.ts"],"names":["ip","NextResponse"],"mappings":"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","file":"next.js","sourcesContent":["/**\n * Policy model for rate limiting configuration.\n */\n\nexport enum KeyStrategy {\n IP = 'ip',\n USER = 'user',\n API_KEY = 'api_key',\n COMPOSITE = 'composite',\n CUSTOM = 'custom',\n}\n\nexport enum Algorithm {\n TOKEN_BUCKET = 'token_bucket',\n FIXED_WINDOW = 'fixed_window',\n SLIDING_WINDOW = 'sliding_window',\n LEAKY_BUCKET = 'leaky_bucket',\n}\n\nexport interface Policy {\n /** Human-readable policy name */\n name: string;\n /** Maximum number of requests allowed */\n limit: number;\n /** Time window in seconds */\n window: number;\n /** Rate limiting algorithm to use */\n algorithm?: Algorithm;\n /** Strategy for extracting the rate limit key */\n keyStrategy?: KeyStrategy;\n /** Maximum burst size (for token bucket) */\n burst?: number;\n /** Cost per request (default: 1) */\n cost?: number;\n /** Duration to block after limit exceeded (seconds) */\n blockDuration?: number;\n /** Custom function to extract key from request */\n keyExtractor?: (request: any) => string | null;\n /** List of paths or IPs to exempt from rate limiting */\n exemptions?: string[];\n}\n\n/**\n * Validate and normalize policy configuration.\n */\nexport function normalizePolicy(policy: Policy): Required<Policy> {\n const normalized: Required<Policy> = {\n name: policy.name,\n limit: policy.limit,\n window: policy.window,\n algorithm: policy.algorithm ?? Algorithm.TOKEN_BUCKET,\n keyStrategy: policy.keyStrategy ?? KeyStrategy.IP,\n burst: policy.burst ?? Math.floor(policy.limit * 1.2),\n cost: policy.cost ?? 1,\n blockDuration: policy.blockDuration ?? undefined,\n keyExtractor: policy.keyExtractor ?? undefined,\n exemptions: policy.exemptions ?? [],\n } as Required<Policy>;\n\n // Validation\n if (normalized.limit <= 0) {\n throw new Error('limit must be positive');\n }\n\n if (normalized.window <= 0) {\n throw new Error('window must be positive');\n }\n\n if (normalized.cost <= 0) {\n throw new Error('cost must be positive');\n }\n\n if (normalized.burst < normalized.limit) {\n throw new Error('burst must be >= limit');\n }\n\n return normalized;\n}\n","/**\n * Utility functions for extracting rate limit keys from requests.\n */\n\n// Default health check paths\nexport const HEALTH_CHECK_PATHS = new Set([\n '/health',\n '/ping',\n '/ready',\n '/healthz',\n '/livez',\n]);\n\n// Private IP ranges (CIDR notation)\nconst PRIVATE_IP_PATTERNS = [\n /^127\\./,\n /^10\\./,\n /^172\\.(1[6-9]|2\\d|3[01])\\./,\n /^192\\.168\\./,\n /^::1$/,\n /^fc00:/,\n];\n\n/**\n * Extract client IP from request, respecting X-Forwarded-For if from trusted proxy.\n */\nexport function extractIp(request: any, trustedProxies: string[] = []): string | null {\n let clientIp: string | null = null;\n\n // Try different request object patterns\n if (request.socket?.remoteAddress) {\n // Node.js/Express\n clientIp = request.socket.remoteAddress;\n } else if (request.ip) {\n // Express with trust proxy\n clientIp = request.ip;\n } else if (request.connection?.remoteAddress) {\n // Older Node.js\n clientIp = request.connection.remoteAddress;\n }\n\n if (!clientIp) {\n return null;\n }\n\n // Clean IPv6-mapped IPv4 addresses\n clientIp = clientIp.replace(/^::ffff:/, '');\n\n // Check if we should trust X-Forwarded-For\n if (trustedProxies.length > 0 && isTrustedProxy(clientIp, trustedProxies)) {\n const forwarded = getForwardedFor(request);\n if (forwarded) {\n return forwarded;\n }\n }\n\n return clientIp;\n}\n\n/**\n * Extract first IP from X-Forwarded-For header.\n */\nfunction getForwardedFor(request: any): string | null {\n const headers = request.headers || {};\n const forwarded = headers['x-forwarded-for'] || headers['X-Forwarded-For'];\n\n if (forwarded) {\n // Take the first IP (client IP)\n return forwarded.split(',')[0].trim();\n }\n\n return null;\n}\n\n/**\n * Check if IP is in trusted proxy list.\n */\nfunction isTrustedProxy(ip: string, trustedProxies: string[]): boolean {\n return trustedProxies.some((proxy) => {\n if (proxy.includes('/')) {\n // CIDR notation - simplified check\n return ip.startsWith(proxy.split('/')[0].split('.').slice(0, -1).join('.'));\n }\n return ip === proxy;\n });\n}\n\n/**\n * Check if IP is in private range.\n */\nexport function isPrivateIp(ip: string): boolean {\n return PRIVATE_IP_PATTERNS.some((pattern) => pattern.test(ip));\n}\n\n/**\n * Check if path is a health check endpoint.\n */\nexport function isHealthCheck(path: string): boolean {\n return HEALTH_CHECK_PATHS.has(path);\n}\n\n/**\n * Extract user ID from request.\n */\nexport function extractUserId(request: any): string | null {\n // Try common patterns\n if (request.user?.id) {\n return String(request.user.id);\n }\n\n if (request.userId) {\n return String(request.userId);\n }\n\n return null;\n}\n\n/**\n * Extract API key from request headers.\n */\nexport function extractApiKey(request: any): string | null {\n const headers = request.headers || {};\n\n // Try common header names\n const apiKey =\n headers['x-api-key'] ||\n headers['X-API-Key'] ||\n headers['authorization'] ||\n headers['Authorization'];\n\n if (apiKey) {\n // Handle Bearer tokens\n if (apiKey.startsWith('Bearer ')) {\n return apiKey.substring(7);\n }\n return apiKey;\n }\n\n return null;\n}\n\n/**\n * Extract path from request.\n */\nexport function extractPath(request: any): string | null {\n // Next.js\n if (request.nextUrl?.pathname) {\n return request.nextUrl.pathname;\n }\n\n // Express\n if (request.path) {\n return request.path;\n }\n\n if (request.url) {\n try {\n const url = new URL(request.url, 'http://localhost');\n return url.pathname;\n } catch {\n return request.url;\n }\n }\n\n return null;\n}\n","/**\n * Token bucket rate limiting algorithm.\n */\n\nimport { Decision } from '../core/decision';\n\nexport interface TokenBucketState {\n tokens: number;\n lastRefill: number;\n}\n\nexport class TokenBucket {\n private capacity: number;\n private rate: number;\n private window: number;\n\n constructor(capacity: number, rate: number, window: number) {\n this.capacity = capacity;\n this.rate = rate / window; // tokens per second\n this.window = window;\n }\n\n /**\n * Check if request is allowed and consume tokens.\n */\n checkAndConsume(\n currentTokens: number,\n lastRefill: number,\n cost: number,\n now: number = Date.now() / 1000\n ): { decision: Decision; newTokens: number; newLastRefill: number } {\n // Refill tokens based on elapsed time\n const elapsed = now - lastRefill;\n const refillAmount = elapsed * this.rate;\n const newTokens = Math.min(this.capacity, currentTokens + refillAmount);\n\n // Calculate reset time (when bucket will be full)\n const tokensNeeded = this.capacity - newTokens;\n const resetAt = Math.floor(now + tokensNeeded / this.rate);\n\n // Check if we have enough tokens\n if (newTokens >= cost) {\n // Consume tokens\n const tokensAfterConsume = newTokens - cost;\n const remaining = Math.floor(tokensAfterConsume);\n\n return {\n decision: {\n allowed: true,\n limit: Math.floor(this.rate * this.window),\n remaining,\n resetAt,\n },\n newTokens: tokensAfterConsume,\n newLastRefill: now,\n };\n } else {\n // Not enough tokens\n const tokensDeficit = cost - newTokens;\n const retryAfter = Math.floor(tokensDeficit / this.rate) + 1;\n\n return {\n decision: {\n allowed: false,\n limit: Math.floor(this.rate * this.window),\n remaining: 0,\n resetAt,\n retryAfter,\n },\n newTokens,\n newLastRefill: lastRefill, // Don't update last_refill on rejection\n };\n }\n }\n\n /**\n * Get initial state for a new key.\n */\n initialState(now: number = Date.now() / 1000): TokenBucketState {\n return {\n tokens: this.capacity,\n lastRefill: now,\n };\n }\n}\n","/**\n * Fixed window rate limiting algorithm.\n */\n\nimport { Decision } from '../core/decision';\n\nexport interface FixedWindowState {\n count: number;\n windowStart: number;\n}\n\nexport class FixedWindow {\n private limit: number;\n private window: number;\n\n constructor(limit: number, window: number) {\n this.limit = limit;\n this.window = window;\n }\n\n /**\n * Check if request is allowed and increment counter.\n */\n checkAndConsume(\n currentCount: number,\n windowStart: number,\n cost: number,\n now: number = Date.now() / 1000\n ): { decision: Decision; newCount: number; newWindowStart: number } {\n // Check if we're in a new window\n const timeSinceStart = now - windowStart;\n if (timeSinceStart >= this.window) {\n // New window - reset counter\n currentCount = 0;\n windowStart = now;\n }\n\n // Calculate reset time (end of current window)\n const resetAt = Math.floor(windowStart + this.window);\n\n // Check if we have capacity\n if (currentCount + cost <= this.limit) {\n // Allow request\n const newCount = currentCount + cost;\n const remaining = this.limit - newCount;\n\n return {\n decision: {\n allowed: true,\n limit: this.limit,\n remaining,\n resetAt,\n },\n newCount,\n newWindowStart: windowStart,\n };\n } else {\n // Block request\n const retryAfter = Math.floor(resetAt - now) + 1;\n\n return {\n decision: {\n allowed: false,\n limit: this.limit,\n remaining: 0,\n resetAt,\n retryAfter,\n },\n newCount: currentCount,\n newWindowStart: windowStart,\n };\n }\n }\n\n /**\n * Get initial state for a new key.\n */\n initialState(now: number = Date.now() / 1000): FixedWindowState {\n return {\n count: 0,\n windowStart: now,\n };\n }\n}\n","/**\n * Sliding window rate limiting algorithm.\n */\n\nimport { Decision } from '../core/decision';\n\nexport type SlidingWindowState = Record<number, number>;\n\nexport class SlidingWindow {\n private limit: number;\n private window: number;\n private precision: number;\n private bucketSize: number;\n\n constructor(limit: number, window: number, precision: number = 10) {\n this.limit = limit;\n this.window = window;\n this.precision = precision;\n this.bucketSize = window / precision;\n }\n\n /**\n * Check if request is allowed and update buckets.\n */\n checkAndConsume(\n buckets: SlidingWindowState,\n cost: number,\n now: number = Date.now() / 1000\n ): { decision: Decision; newBuckets: SlidingWindowState } {\n // Calculate current bucket\n const currentBucket = Math.floor(now / this.bucketSize);\n\n // Remove expired buckets (older than window)\n const cutoffBucket = currentBucket - this.precision;\n const newBuckets: SlidingWindowState = {};\n\n for (const [bucketIdStr, count] of Object.entries(buckets)) {\n const bucketId = parseInt(bucketIdStr, 10);\n if (bucketId > cutoffBucket) {\n newBuckets[bucketId] = count;\n }\n }\n\n // Count requests in sliding window\n const totalCount = Object.values(newBuckets).reduce((sum, count) => sum + count, 0);\n\n // Calculate reset time (when oldest bucket expires)\n const bucketIds = Object.keys(newBuckets).map((id) => parseInt(id, 10));\n const oldestBucket = bucketIds.length > 0 ? Math.min(...bucketIds) : currentBucket;\n const resetAt = Math.floor((oldestBucket + this.precision + 1) * this.bucketSize);\n\n // Check if we have capacity\n if (totalCount + cost <= this.limit) {\n // Allow request\n newBuckets[currentBucket] = (newBuckets[currentBucket] || 0) + cost;\n const remaining = this.limit - (totalCount + cost);\n\n return {\n decision: {\n allowed: true,\n limit: this.limit,\n remaining,\n resetAt,\n },\n newBuckets,\n };\n } else {\n // Block request\n const retryAfter = Math.floor(this.bucketSize) + 1;\n\n return {\n decision: {\n allowed: false,\n limit: this.limit,\n remaining: 0,\n resetAt,\n retryAfter,\n },\n newBuckets,\n };\n }\n }\n\n /**\n * Get initial state for a new key.\n */\n initialState(): SlidingWindowState {\n return {};\n }\n}\n","/**\n * Leaky bucket rate limiting algorithm.\n */\n\nimport { Decision } from '../core/decision';\n\nexport interface LeakyBucketState {\n level: number;\n lastLeak: number;\n}\n\nexport class LeakyBucket {\n private capacity: number;\n private leakRate: number;\n private window: number;\n\n constructor(capacity: number, leakRate: number, window: number) {\n this.capacity = capacity;\n this.leakRate = leakRate; // requests per second\n this.window = window;\n }\n\n /**\n * Check if request is allowed and update bucket level.\n */\n checkAndConsume(\n currentLevel: number,\n lastLeak: number,\n cost: number,\n now: number = Date.now() / 1000\n ): { decision: Decision; newLevel: number; newLastLeak: number } {\n // Calculate how much has leaked since last check\n const elapsed = now - lastLeak;\n const leaked = elapsed * this.leakRate;\n\n // Update bucket level (can't go below 0)\n let newLevel = Math.max(0, currentLevel - leaked);\n\n // Calculate when bucket will be empty\n let resetAt: number;\n if (newLevel > 0) {\n const timeToEmpty = newLevel / this.leakRate;\n resetAt = Math.floor(now + timeToEmpty);\n } else {\n resetAt = Math.floor(now);\n }\n\n // Check if we have capacity\n if (newLevel + cost <= this.capacity) {\n // Allow request - add to bucket\n newLevel += cost;\n const remaining = Math.floor(this.capacity - newLevel);\n\n return {\n decision: {\n allowed: true,\n limit: this.capacity,\n remaining,\n resetAt,\n },\n newLevel,\n newLastLeak: now,\n };\n } else {\n // Block request - bucket is full\n // Calculate when there will be enough capacity\n const spaceNeeded = newLevel + cost - this.capacity;\n const retryAfter = Math.floor(spaceNeeded / this.leakRate) + 1;\n\n return {\n decision: {\n allowed: false,\n limit: this.capacity,\n remaining: 0,\n resetAt,\n retryAfter,\n },\n newLevel,\n newLastLeak: now,\n };\n }\n }\n\n /**\n * Get initial state for a new key.\n */\n initialState(now: number = Date.now() / 1000): LeakyBucketState {\n return {\n level: 0,\n lastLeak: now,\n };\n }\n}\n","/**\n * Main rate limiter implementation.\n */\n\nimport { Decision } from './decision';\nimport { Policy, KeyStrategy, Algorithm, normalizePolicy } from './policy';\nimport {\n extractIp,\n extractUserId,\n extractApiKey,\n extractPath,\n isHealthCheck,\n isPrivateIp,\n} from './extractors';\nimport { TokenBucket } from '../algorithms/token-bucket';\nimport { FixedWindow } from '../algorithms/fixed-window';\nimport { SlidingWindow } from '../algorithms/sliding-window';\nimport { LeakyBucket } from '../algorithms/leaky-bucket';\nimport { Store } from '../stores/memory';\n\ntype AlgorithmInstance = TokenBucket | FixedWindow | SlidingWindow | LeakyBucket;\n\nexport interface RateLimiterOptions {\n store: Store;\n /** Either a static policy or a resolver returning a policy per-request */\n policy: Policy | ((request: any) => Policy | Promise<Policy>);\n trustedProxies?: string[];\n exemptPrivateIps?: boolean;\n /** Optional OpenTelemetry-like tracer (object with startSpan) */\n otelTracer?: any;\n /** Optional metrics recorder: (name, tags?, value?) => void */\n metricsRecorder?: (name: string, tags?: Record<string, string>, value?: number) => void;\n}\n\nexport class RateLimiter {\n private store: Store;\n private policyOrResolver: Policy | ((request: any) => Policy | Promise<Policy>);\n private trustedProxies: string[];\n private exemptPrivateIps: boolean;\n private algorithmCache: Map<string, AlgorithmInstance>;\n private otelTracer?: any;\n private metricsRecorder?: (name: string, tags?: Record<string, string>, value?: number) => void;\n\n constructor(options: RateLimiterOptions) {\n this.store = options.store;\n this.policyOrResolver = options.policy;\n this.trustedProxies = options.trustedProxies ?? [];\n this.exemptPrivateIps = options.exemptPrivateIps ?? true;\n this.algorithmCache = new Map();\n this.otelTracer = options.otelTracer;\n this.metricsRecorder = options.metricsRecorder;\n }\n\n /**\n * Check if request is allowed under rate limit.\n */\n /**\n * Check if request is allowed under rate limit.\n * This method is async because policy resolution may be async (e.g. DB lookup).\n */\n async check(request: any, cost?: number): Promise<Decision> {\n // Resolve policy (static or per-request)\n const resolved =\n typeof this.policyOrResolver === 'function'\n ? await (this.policyOrResolver as (r: any) => Policy | Promise<Policy>)(request)\n : (this.policyOrResolver as Policy);\n\n const policy = normalizePolicy(resolved);\n const requestCost = cost ?? policy.cost;\n\n // Quick exemptions check (policy-aware)\n if (this.isExempt(request, policy)) {\n const resp: Decision = {\n allowed: true,\n limit: policy.limit,\n remaining: policy.limit,\n resetAt: Math.floor(Date.now() / 1000 + policy.window),\n };\n this.metricsRecorder?.('halt.request.exempt', { policy: policy.name }, 1);\n return resp;\n }\n\n // Extract key\n const key = this.extractKey(request, policy);\n if (!key) {\n const resp: Decision = {\n allowed: true,\n limit: policy.limit,\n remaining: policy.limit,\n resetAt: Math.floor(Date.now() / 1000 + policy.window),\n };\n this.metricsRecorder?.('halt.request.no_key', { policy: policy.name }, 1);\n return resp;\n }\n\n const storageKey = `halt:${policy.name}:${key}`;\n\n // Get or create algorithm instance for this policy\n let algorithm = this.algorithmCache.get(policy.name);\n if (!algorithm) {\n if (policy.algorithm === Algorithm.TOKEN_BUCKET) {\n algorithm = new TokenBucket(policy.burst, policy.limit, policy.window);\n } else if (policy.algorithm === Algorithm.FIXED_WINDOW) {\n algorithm = new FixedWindow(policy.limit, policy.window);\n } else if (policy.algorithm === Algorithm.SLIDING_WINDOW) {\n algorithm = new SlidingWindow(policy.limit, policy.window);\n } else if (policy.algorithm === Algorithm.LEAKY_BUCKET) {\n const leakRate = policy.limit / policy.window;\n algorithm = new LeakyBucket(policy.burst, leakRate, policy.window);\n } else {\n throw new Error(`Algorithm ${policy.algorithm} not implemented`);\n }\n this.algorithmCache.set(policy.name, algorithm);\n }\n\n // Instrumentation: start a span if tracer available\n const span = this.otelTracer?.startSpan?.('halt.check', { attributes: { policy: policy.name, key } });\n\n const state = this.store.get(storageKey);\n let decision: Decision;\n\n if (algorithm instanceof TokenBucket) {\n let tokens: number;\n let lastRefill: number;\n\n if (!state) {\n const initialState = algorithm.initialState();\n tokens = initialState.tokens;\n lastRefill = initialState.lastRefill;\n } else {\n tokens = state.tokens;\n lastRefill = state.lastRefill;\n }\n\n const result = algorithm.checkAndConsume(tokens, lastRefill, requestCost);\n decision = result.decision;\n\n const ttl = policy.window * 2;\n this.store.set(storageKey, { tokens: result.newTokens, lastRefill: result.newLastRefill }, ttl);\n } else if (algorithm instanceof FixedWindow) {\n let count: number;\n let windowStart: number;\n\n if (!state) {\n const initialState = algorithm.initialState();\n count = initialState.count;\n windowStart = initialState.windowStart;\n } else {\n count = state.count;\n windowStart = state.windowStart;\n }\n\n const result = algorithm.checkAndConsume(count, windowStart, requestCost);\n decision = result.decision;\n\n const ttl = policy.window * 2;\n this.store.set(storageKey, { count: result.newCount, windowStart: result.newWindowStart }, ttl);\n } else if (algorithm instanceof SlidingWindow) {\n const buckets = state || algorithm.initialState();\n const result = algorithm.checkAndConsume(buckets, requestCost);\n decision = result.decision;\n\n const ttl = policy.window * 2;\n this.store.set(storageKey, result.newBuckets, ttl);\n } else if (algorithm instanceof LeakyBucket) {\n let level: number;\n let lastLeak: number;\n\n if (!state) {\n const initialState = algorithm.initialState();\n level = initialState.level;\n lastLeak = initialState.lastLeak;\n } else {\n level = state.level;\n lastLeak = state.lastLeak;\n }\n\n const result = algorithm.checkAndConsume(level, lastLeak, requestCost);\n decision = result.decision;\n\n const ttl = policy.window * 2;\n this.store.set(storageKey, { level: result.newLevel, lastLeak: result.newLastLeak }, ttl);\n } else {\n throw new Error(`Algorithm ${typeof algorithm} not supported`);\n }\n\n // Metrics and telemetry\n this.metricsRecorder?.('halt.request.checked', { policy: policy.name, allowed: String(decision.allowed) }, 1);\n if (decision.allowed) {\n this.metricsRecorder?.('halt.request.allowed', { policy: policy.name }, 1);\n } else {\n this.metricsRecorder?.('halt.request.blocked', { policy: policy.name }, 1);\n }\n\n span?.end?.();\n\n return decision;\n }\n\n /**\n * Extract rate limit key from request based on policy strategy.\n */\n private extractKey(request: any, policy: Policy): string | null {\n // Use custom extractor if provided\n if (policy.keyExtractor) {\n return policy.keyExtractor(request);\n }\n\n // Use built-in strategies\n if (policy.keyStrategy === KeyStrategy.IP) {\n return extractIp(request, this.trustedProxies);\n }\n\n if (policy.keyStrategy === KeyStrategy.USER) {\n return extractUserId(request);\n }\n\n if (policy.keyStrategy === KeyStrategy.API_KEY) {\n return extractApiKey(request);\n }\n\n if (policy.keyStrategy === KeyStrategy.COMPOSITE) {\n // Composite: user:ip or api_key:ip\n const user = extractUserId(request);\n const apiKey = extractApiKey(request);\n const ip = extractIp(request, this.trustedProxies);\n\n if (user && ip) {\n return `${user}:${ip}`;\n } else if (apiKey && ip) {\n return `${apiKey}:${ip}`;\n } else if (user) {\n return user;\n } else if (apiKey) {\n return apiKey;\n } else {\n return ip;\n }\n }\n\n return null;\n }\n\n /**\n * Check if request is exempt from rate limiting.\n */\n private isExempt(request: any, policy: Policy): boolean {\n // Check health check paths\n const path = extractPath(request);\n if (path && isHealthCheck(path)) {\n return true;\n }\n\n // Check custom exemptions\n if (path && (policy.exemptions ?? []).includes(path)) {\n return true;\n }\n\n // Check private IPs\n if (this.exemptPrivateIps) {\n const ip = extractIp(request, this.trustedProxies);\n if (ip && isPrivateIp(ip)) {\n return true;\n }\n }\n\n // Check IP exemptions\n const ip = extractIp(request, this.trustedProxies);\n if (ip && (policy.exemptions ?? []).includes(ip)) {\n return true;\n }\n\n return false;\n }\n}\n","/**\n * Decision model for rate limiting results.\n */\n\nexport interface Decision {\n /** Whether the request is allowed */\n allowed: boolean;\n /** Maximum number of requests allowed in the window */\n limit: number;\n /** Number of requests remaining in the current window */\n remaining: number;\n /** Unix timestamp when the limit resets */\n resetAt: number;\n /** Seconds to wait before retrying (only set when blocked) */\n retryAfter?: number;\n}\n\n/**\n * Convert decision to standard rate limit headers.\n */\nexport function toHeaders(decision: Decision): Record<string, string> {\n const headers: Record<string, string> = {\n 'RateLimit-Limit': String(decision.limit),\n 'RateLimit-Remaining': String(Math.max(0, decision.remaining)),\n 'RateLimit-Reset': String(decision.resetAt),\n };\n\n if (!decision.allowed && decision.retryAfter !== undefined) {\n headers['Retry-After'] = String(decision.retryAfter);\n }\n\n return headers;\n}\n","/**\n * Next.js adapter for Halt rate limiting.\n */\n\nimport { NextRequest, NextResponse } from 'next/server';\nimport { RateLimiter, RateLimiterOptions } from '../core/limiter';\nimport { toHeaders } from '../core/decision';\nimport { Policy } from '../core/policy';\n\n/**\n * Create Next.js middleware for rate limiting.\n */\nexport function haltMiddleware(options: RateLimiterOptions) {\n const limiter = new RateLimiter(options);\n\n return async (request: NextRequest) => {\n const decision = await limiter.check(request);\n\n if (decision.allowed) {\n // Allow request with rate limit headers\n const response = NextResponse.next();\n const headers = toHeaders(decision);\n for (const [key, value] of Object.entries(headers)) {\n response.headers.set(key, value);\n }\n return response;\n } else {\n // Block request\n const headers = toHeaders(decision);\n return NextResponse.json(\n {\n error: 'rate_limit_exceeded',\n message: 'Too many requests. Please try again later.',\n retryAfter: decision.retryAfter,\n },\n {\n status: 429,\n headers,\n }\n );\n }\n };\n}\n\n/**\n * Wrapper for Next.js route handlers to add rate limiting.\n */\nexport function withHalt<T extends (...args: any[]) => Promise<Response>>(\n handler: T,\n options: RateLimiterOptions\n): T {\n const limiter = new RateLimiter(options);\n\n return (async (...args: any[]) => {\n const request = args[0] as NextRequest;\n const decision = await limiter.check(request);\n\n if (decision.allowed) {\n // Call the original handler\n const response = await handler(...args);\n\n // Add rate limit headers\n const headers = toHeaders(decision);\n for (const [key, value] of Object.entries(headers)) {\n response.headers.set(key, value);\n }\n\n return response;\n } else {\n // Block request\n const headers = toHeaders(decision);\n return NextResponse.json(\n {\n error: 'rate_limit_exceeded',\n message: 'Too many requests. Please try again later.',\n retryAfter: decision.retryAfter,\n },\n {\n status: 429,\n headers,\n }\n );\n }\n }) as T;\n}\n\n/**\n * Simple wrapper that accepts just a policy for convenience.\n */\nexport function withPolicy<T extends (...args: any[]) => Promise<Response>>(\n handler: T,\n policy: Policy,\n store: RateLimiterOptions['store']\n): T {\n return withHalt(handler, { store, policy });\n}\n"]}