halt-rate 0.3.0 → 0.4.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.
@@ -1 +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/store.ts","../src/core/limiter.ts","../src/core/decision.ts","../src/stores/memory.ts","../src/stores/redis-scripts.ts","../src/stores/redis.ts","../src/presets/index.ts","../src/core/quota.ts","../src/core/penalty.ts","../src/core/telemetry.ts","../src/core/stats.ts","../src/observability/otel.ts"],"names":["KeyStrategy","Algorithm","span","decision","ip","QuotaPeriod"],"mappings":"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","file":"index.mjs","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 /** Optional plan/tier label for observability tagging (e.g. \"pro\"). */\n plan?: 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 plan: policy.plan ?? undefined,\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 * Atomic-evaluation protocol.\n *\n * Simple stores (e.g. InMemoryStore) expose get/set and let the limiter run the\n * algorithm in-process. Distributed stores that can compute the decision\n * atomically (e.g. RedisStore via Lua) instead expose `evaluate()`: the limiter\n * hands them the resolved policy params + storage key and gets back a finished\n * Decision. The limiter prefers `evaluate()` when present (see core/limiter.ts).\n */\n\nimport { Decision } from './decision';\nimport { Algorithm } from './policy';\n\n/** Everything an atomic store needs to compute a decision for one request. */\nexport interface EvaluateInput {\n /** Full storage key, already namespaced (e.g. `halt:public_api:1.2.3.4`). */\n key: string;\n /** Algorithm to apply. */\n algorithm: Algorithm;\n /** Requests permitted per window. */\n limit: number;\n /** Window length in seconds. */\n window: number;\n /** Bucket capacity (token/leaky bucket). */\n burst: number;\n /** Cost this request consumes. */\n cost: number;\n /** Seconds to keep the key alive in the backing store. */\n ttl: number;\n}\n\n/** A store that computes the rate-limit decision atomically on its own. */\nexport interface AtomicStore {\n evaluate(input: EvaluateInput): Promise<Decision>;\n}\n\n/** True if the store implements the atomic-evaluation protocol. */\nexport function isAtomicStore(store: unknown): store is AtomicStore {\n return (\n typeof store === 'object' &&\n store !== null &&\n typeof (store as AtomicStore).evaluate === 'function'\n );\n}\n\n/**\n * Minimal structural type for a Redis client (satisfied by ioredis and\n * node-redis v4+). Declared here so Halt has no hard dependency on any concrete\n * Redis package — the user injects their own client.\n */\nexport interface RedisClientLike {\n eval(script: string, numKeys: number, ...args: (string | number)[]): Promise<unknown>;\n evalsha?(sha: string, numKeys: number, ...args: (string | number)[]): Promise<unknown>;\n script?(subcommand: 'LOAD', script: string): Promise<unknown>;\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';\nimport { AtomicStore, isAtomicStore } from './store';\nimport { TelemetryHooks } from './telemetry';\n\ntype AlgorithmInstance = TokenBucket | FixedWindow | SlidingWindow | LeakyBucket;\n\nexport interface RateLimiterOptions {\n /**\n * Storage backend. Either a simple KV store (InMemoryStore — the limiter runs\n * the algorithm in-process) or an atomic store (RedisStore — the store\n * computes the decision atomically via Lua).\n */\n store: Store | AtomicStore;\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 * Optional high-level observability hooks (StatsCollector, OpenTelemetryMetrics,\n * LoggingTelemetry, or a CompositeTelemetry of several). Called on every\n * rate-limited check with rich metadata (policy, algorithm, endpoint, cost, plan).\n */\n telemetry?: TelemetryHooks;\n}\n\nexport class RateLimiter {\n private store: Store | AtomicStore;\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 private telemetry?: TelemetryHooks;\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 this.telemetry = options.telemetry;\n }\n\n /** Fan a finished decision out to the telemetry hooks with rich metadata. */\n private emitTelemetry(\n request: any,\n key: string,\n decision: Decision,\n policy: Required<Policy>,\n cost: number\n ): void {\n if (!this.telemetry) return;\n const metadata: Record<string, any> = {\n policy: policy.name,\n algorithm: policy.algorithm,\n keyStrategy: policy.keyStrategy,\n endpoint: extractPath(request) ?? undefined,\n cost,\n plan: policy.plan,\n };\n this.telemetry.onCheck?.(key, decision, metadata);\n if (decision.allowed) {\n this.telemetry.onAllowed?.(key, decision, metadata);\n } else {\n this.telemetry.onBlocked?.(key, decision, metadata);\n }\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 // Atomic stores (e.g. Redis) compute the whole decision themselves.\n if (isAtomicStore(this.store)) {\n const span = this.otelTracer?.startSpan?.('halt.check', {\n attributes: { policy: policy.name, key },\n });\n const decision = await this.store.evaluate({\n key: storageKey,\n algorithm: policy.algorithm,\n limit: policy.limit,\n window: policy.window,\n burst: policy.burst,\n cost: requestCost,\n ttl: policy.window * 2,\n });\n this.metricsRecorder?.(\n 'halt.request.checked',\n { policy: policy.name, allowed: String(decision.allowed) },\n 1\n );\n this.metricsRecorder?.(\n decision.allowed ? 'halt.request.allowed' : 'halt.request.blocked',\n { policy: policy.name },\n 1\n );\n span?.end?.();\n this.emitTelemetry(request, key, decision, policy, requestCost);\n return decision;\n }\n\n const store = this.store as Store;\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 = 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 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 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 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 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 this.emitTelemetry(request, key, decision, policy, requestCost);\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 * In-memory storage backend for rate limiting.\n */\n\nexport interface Store {\n get(key: string): any;\n set(key: string, value: any, ttl?: number): void;\n increment(key: string, delta?: number, ttl?: number): number;\n delete(key: string): void;\n}\n\ninterface StoreEntry {\n value: any;\n expiry?: number;\n}\n\nexport class InMemoryStore implements Store {\n private data: Map<string, StoreEntry> = new Map();\n\n get(key: string): any {\n this.cleanupExpired(key);\n const entry = this.data.get(key);\n return entry?.value ?? null;\n }\n\n set(key: string, value: any, ttl?: number): void {\n const entry: StoreEntry = { value };\n\n if (ttl !== undefined) {\n entry.expiry = Date.now() + ttl * 1000;\n }\n\n this.data.set(key, entry);\n }\n\n increment(key: string, delta: number = 1, ttl?: number): number {\n this.cleanupExpired(key);\n const entry = this.data.get(key);\n const current = typeof entry?.value === 'number' ? entry.value : 0;\n const newValue = current + delta;\n\n const newEntry: StoreEntry = { value: newValue };\n\n // Set TTL only if key didn't exist\n if (!entry && ttl !== undefined) {\n newEntry.expiry = Date.now() + ttl * 1000;\n } else if (entry?.expiry) {\n newEntry.expiry = entry.expiry;\n }\n\n this.data.set(key, newEntry);\n return newValue;\n }\n\n delete(key: string): void {\n this.data.delete(key);\n }\n\n private cleanupExpired(key: string): void {\n const entry = this.data.get(key);\n if (entry?.expiry && Date.now() >= entry.expiry) {\n this.data.delete(key);\n }\n }\n\n /**\n * Clean up all expired keys.\n */\n cleanupAllExpired(): number {\n const now = Date.now();\n let count = 0;\n\n for (const [key, entry] of this.data.entries()) {\n if (entry.expiry && now >= entry.expiry) {\n this.data.delete(key);\n count++;\n }\n }\n\n return count;\n }\n}\n","/**\n * Lua scripts for atomic rate limiting in Redis.\n *\n * Each script performs the full check-and-consume in a single round trip so the\n * decision is atomic even under concurrent access from many app servers. Every\n * script touches exactly one key (KEYS[1]) and reads the clock from the Redis\n * server (`TIME`), so it is safe on Redis Cluster and immune to app-server clock skew.\n *\n * ARGV (shared by all scripts):\n * ARGV[1] = limit (requests per window)\n * ARGV[2] = window (seconds)\n * ARGV[3] = burst (capacity, for token/leaky bucket)\n * ARGV[4] = cost (tokens this request consumes)\n * ARGV[5] = ttl (seconds to keep the key alive)\n *\n * Return (shared by all scripts), a 5-element array:\n * { allowed(1|0), limit, remaining, resetAt(unix s), retryAfter(s, -1 = none) }\n */\n\n/** Shared Lua prelude: derive a float `now` (seconds) from the Redis server clock. */\nconst NOW = `\nlocal t = redis.call('TIME')\nlocal now = tonumber(t[1]) + (tonumber(t[2]) / 1000000)\n`;\n\nexport const TOKEN_BUCKET_LUA = `\n${NOW}\nlocal limit = tonumber(ARGV[1])\nlocal window = tonumber(ARGV[2])\nlocal capacity = tonumber(ARGV[3])\nlocal cost = tonumber(ARGV[4])\nlocal ttl = tonumber(ARGV[5])\nlocal rate = limit / window\n\nlocal data = redis.call('HMGET', KEYS[1], 'tokens', 'ts')\nlocal tokens, last\nif data[1] then\n tokens = tonumber(data[1])\n last = tonumber(data[2])\nelse\n tokens = capacity\n last = now\nend\n\nlocal elapsed = now - last\nif elapsed < 0 then elapsed = 0 end\ntokens = math.min(capacity, tokens + elapsed * rate)\n\nlocal needed = capacity - tokens\nlocal resetAt = math.floor(now + (needed / rate))\n\nif tokens >= cost then\n tokens = tokens - cost\n redis.call('HMSET', KEYS[1], 'tokens', tokens, 'ts', now)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {1, limit, math.floor(tokens), resetAt, -1}\nelse\n local deficit = cost - tokens\n local retryAfter = math.floor(deficit / rate) + 1\n redis.call('HMSET', KEYS[1], 'tokens', tokens, 'ts', now)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {0, limit, 0, resetAt, retryAfter}\nend\n`;\n\nexport const FIXED_WINDOW_LUA = `\n${NOW}\nlocal limit = tonumber(ARGV[1])\nlocal window = tonumber(ARGV[2])\nlocal cost = tonumber(ARGV[4])\nlocal ttl = tonumber(ARGV[5])\n\nlocal data = redis.call('HMGET', KEYS[1], 'count', 'start')\nlocal count, start\nif data[1] then\n count = tonumber(data[1])\n start = tonumber(data[2])\nelse\n count = 0\n start = now\nend\n\nif (now - start) >= window then\n count = 0\n start = now\nend\n\nlocal resetAt = math.floor(start + window)\n\nif (count + cost) <= limit then\n count = count + cost\n redis.call('HMSET', KEYS[1], 'count', count, 'start', start)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {1, limit, limit - count, resetAt, -1}\nelse\n redis.call('HMSET', KEYS[1], 'count', count, 'start', start)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n local retryAfter = math.floor(resetAt - now) + 1\n return {0, limit, 0, resetAt, retryAfter}\nend\n`;\n\nexport const LEAKY_BUCKET_LUA = `\n${NOW}\nlocal limit = tonumber(ARGV[1])\nlocal window = tonumber(ARGV[2])\nlocal capacity = tonumber(ARGV[3])\nlocal cost = tonumber(ARGV[4])\nlocal ttl = tonumber(ARGV[5])\nlocal leakRate = limit / window\n\nlocal data = redis.call('HMGET', KEYS[1], 'level', 'ts')\nlocal level, last\nif data[1] then\n level = tonumber(data[1])\n last = tonumber(data[2])\nelse\n level = 0\n last = now\nend\n\nlocal elapsed = now - last\nif elapsed < 0 then elapsed = 0 end\nlevel = math.max(0, level - (elapsed * leakRate))\n\nlocal resetAt\nif level > 0 then\n resetAt = math.floor(now + (level / leakRate))\nelse\n resetAt = math.floor(now)\nend\n\nif (level + cost) <= capacity then\n level = level + cost\n redis.call('HMSET', KEYS[1], 'level', level, 'ts', now)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {1, capacity, math.floor(capacity - level), resetAt, -1}\nelse\n local spaceNeeded = level + cost - capacity\n local retryAfter = math.floor(spaceNeeded / leakRate) + 1\n redis.call('HMSET', KEYS[1], 'level', level, 'ts', now)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {0, capacity, 0, resetAt, retryAfter}\nend\n`;\n\nexport const SLIDING_WINDOW_LUA = `\n${NOW}\nlocal limit = tonumber(ARGV[1])\nlocal window = tonumber(ARGV[2])\nlocal cost = tonumber(ARGV[4])\nlocal ttl = tonumber(ARGV[5])\n\n-- Drop entries older than the sliding window.\nlocal windowStart = now - window\nredis.call('ZREMRANGEBYSCORE', KEYS[1], '-inf', windowStart)\n\nlocal count = redis.call('ZCARD', KEYS[1])\n\n-- Oldest remaining entry determines when capacity frees up.\nlocal oldest = redis.call('ZRANGE', KEYS[1], 0, 0, 'WITHSCORES')\nlocal resetAt\nif oldest[2] then\n resetAt = math.floor(tonumber(oldest[2]) + window)\nelse\n resetAt = math.floor(now + window)\nend\n\nif (count + cost) <= limit then\n -- Unique members so concurrent requests in the same instant don't collide.\n math.randomseed(math.floor(now * 1000000))\n for i = 1, cost do\n local member = string.format('%d-%d-%d', math.floor(now * 1000000), i, math.random(1, 1000000000))\n redis.call('ZADD', KEYS[1], now, member)\n end\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {1, limit, limit - (count + cost), resetAt, -1}\nelse\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n local retryAfter\n if oldest[2] then\n retryAfter = math.floor(tonumber(oldest[2]) + window - now) + 1\n else\n retryAfter = math.floor(window) + 1\n end\n return {0, limit, 0, resetAt, retryAfter}\nend\n`;\n\n/** Algorithm value (from core/policy `Algorithm`) → Lua script. */\nexport const SCRIPTS: Record<string, string> = {\n token_bucket: TOKEN_BUCKET_LUA,\n fixed_window: FIXED_WINDOW_LUA,\n sliding_window: SLIDING_WINDOW_LUA,\n leaky_bucket: LEAKY_BUCKET_LUA,\n};\n","/**\n * Redis storage backend for Halt — production-grade, atomic rate limiting.\n *\n * Implements the atomic-evaluation protocol (`AtomicStore`): the full\n * check-and-consume runs inside Redis via a Lua script, so limits stay accurate\n * under concurrent load from any number of app servers. Works on standalone\n * Redis and Redis Cluster (every script touches a single key).\n *\n * The Redis client is injected, so Halt has no hard dependency on any client\n * library. Any ioredis / node-redis v4+ instance works:\n *\n * import Redis from 'ioredis';\n * import { RedisStore } from 'halt-rate';\n * const store = new RedisStore({ client: new Redis(process.env.REDIS_URL) });\n */\n\nimport { Decision } from '../core/decision';\nimport { Algorithm } from '../core/policy';\nimport { AtomicStore, EvaluateInput, RedisClientLike } from '../core/store';\nimport { SCRIPTS } from './redis-scripts';\n\n/** Behavior when Redis is unreachable or errors. */\nexport type FailMode = 'open' | 'closed';\n\nexport interface RedisStoreOptions {\n /** A connected Redis client (ioredis or node-redis v4+). */\n client: RedisClientLike;\n /**\n * What to do when Redis can't be reached.\n * - `'open'` (default): allow the request — don't take down traffic when the\n * limiter's backing store is down.\n * - `'closed'`: block the request (429) — safer for abuse-sensitive routes.\n */\n failMode?: FailMode;\n /** Called with the underlying error whenever a Redis call fails. */\n onError?: (err: unknown) => void;\n /** Metrics hook: (name, tags?, value?) => void. */\n metricsRecorder?: (name: string, tags?: Record<string, string>, value?: number) => void;\n}\n\nexport class RedisStore implements AtomicStore {\n private client: RedisClientLike;\n private failMode: FailMode;\n private onError?: (err: unknown) => void;\n private metricsRecorder?: RedisStoreOptions['metricsRecorder'];\n /** Cache of script source -> SHA loaded into Redis, to use EVALSHA. */\n private shaCache: Map<string, string> = new Map();\n\n constructor(options: RedisStoreOptions) {\n this.client = options.client;\n this.failMode = options.failMode ?? 'open';\n this.onError = options.onError;\n this.metricsRecorder = options.metricsRecorder;\n }\n\n async evaluate(input: EvaluateInput): Promise<Decision> {\n const script = SCRIPTS[input.algorithm];\n if (!script) {\n throw new Error(`Algorithm ${input.algorithm} not supported by RedisStore`);\n }\n\n const args: (string | number)[] = [\n input.limit,\n input.window,\n input.burst,\n input.cost,\n input.ttl,\n ];\n\n try {\n const raw = await this.run(script, input.key, args);\n return this.toDecision(raw, input);\n } catch (err) {\n this.onError?.(err);\n this.metricsRecorder?.('halt.redis.error', { algorithm: input.algorithm }, 1);\n return this.failDecision(input);\n }\n }\n\n /** Run a script via EVALSHA, falling back to EVAL (and caching the SHA). */\n private async run(\n script: string,\n key: string,\n args: (string | number)[]\n ): Promise<unknown> {\n const sha = this.shaCache.get(script);\n if (sha && this.client.evalsha) {\n try {\n return await this.client.evalsha(sha, 1, key, ...args);\n } catch (err) {\n // NOSCRIPT: script was flushed from Redis; fall through to EVAL.\n if (!isNoScriptError(err)) throw err;\n }\n }\n\n const result = await this.client.eval(script, 1, key, ...args);\n // Cache the SHA for subsequent EVALSHA calls (best-effort).\n if (!this.shaCache.has(script) && this.client.script) {\n try {\n const loaded = await this.client.script('LOAD', script);\n if (typeof loaded === 'string') this.shaCache.set(script, loaded);\n } catch {\n /* SHA caching is an optimization; ignore failures. */\n }\n }\n return result;\n }\n\n /** Map the Lua array [allowed, limit, remaining, resetAt, retryAfter] to a Decision. */\n private toDecision(raw: unknown, input: EvaluateInput): Decision {\n if (!Array.isArray(raw) || raw.length < 4) {\n throw new Error(`Unexpected Redis script result: ${JSON.stringify(raw)}`);\n }\n const [allowed, limit, remaining, resetAt, retryAfter] = raw.map((v) => Number(v));\n\n const decision: Decision = {\n allowed: allowed === 1,\n limit,\n remaining,\n resetAt,\n };\n if (!decision.allowed && retryAfter !== undefined && retryAfter >= 0) {\n decision.retryAfter = retryAfter;\n }\n\n this.metricsRecorder?.(\n 'halt.request.checked',\n { algorithm: input.algorithm, allowed: String(decision.allowed) },\n 1\n );\n return decision;\n }\n\n /** Decision returned when Redis is unreachable, per failMode. */\n private failDecision(input: EvaluateInput): Decision {\n const resetAt = Math.floor(Date.now() / 1000 + input.window);\n if (this.failMode === 'open') {\n this.metricsRecorder?.('halt.request.fail_open', { algorithm: input.algorithm }, 1);\n return { allowed: true, limit: input.limit, remaining: input.limit, resetAt };\n }\n this.metricsRecorder?.('halt.request.fail_closed', { algorithm: input.algorithm }, 1);\n return {\n allowed: false,\n limit: input.limit,\n remaining: 0,\n resetAt,\n retryAfter: input.window,\n };\n }\n}\n\nfunction isNoScriptError(err: unknown): boolean {\n return (\n typeof err === 'object' &&\n err !== null &&\n String((err as { message?: string }).message ?? '').includes('NOSCRIPT')\n );\n}\n\n// Re-export the algorithm enum location for convenience in user code.\nexport { Algorithm };\n","/**\n * Preset rate limiting policies for common use cases.\n */\n\nimport { Policy, KeyStrategy, Algorithm } from '../core/policy';\n\n// Public API - moderate limits for general public access\nexport const PUBLIC_API: Policy = {\n name: 'public_api',\n limit: 100,\n window: 60, // 1 minute\n burst: 120,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.IP,\n};\n\n// Authentication endpoints - strict limits to prevent brute force\nexport const AUTH_ENDPOINTS: Policy = {\n name: 'auth_endpoints',\n limit: 5,\n window: 60, // 1 minute\n burst: 10,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.IP,\n blockDuration: 300, // 5 minute cooldown after limit exceeded\n};\n\n// Expensive operations - very strict limits for resource-intensive endpoints\nexport const EXPENSIVE_OPS: Policy = {\n name: 'expensive_ops',\n limit: 10,\n window: 3600, // 1 hour\n burst: 15,\n cost: 10, // Each request costs 10 tokens\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\n// Strict API - for sensitive operations\nexport const STRICT_API: Policy = {\n name: 'strict_api',\n limit: 20,\n window: 60, // 1 minute\n burst: 25,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.API_KEY,\n};\n\n// Generous API - for internal or trusted services\nexport const GENEROUS_API: Policy = {\n name: 'generous_api',\n limit: 1000,\n window: 60, // 1 minute\n burst: 1200,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.IP,\n};\n\n// Plan-based presets for SaaS platforms\nexport const PLAN_FREE: Policy = {\n name: 'free_plan',\n plan: 'free',\n limit: 100,\n window: 3600, // 100 requests per hour\n burst: 120,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_STARTER: Policy = {\n name: 'starter_plan',\n plan: 'starter',\n limit: 500,\n window: 3600, // 500 requests per hour\n burst: 600,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_PRO: Policy = {\n name: 'pro_plan',\n plan: 'pro',\n limit: 2000,\n window: 3600, // 2000 requests per hour\n burst: 2500,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_BUSINESS: Policy = {\n name: 'business_plan',\n plan: 'business',\n limit: 5000,\n window: 3600, // 5000 requests per hour\n burst: 6000,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_ENTERPRISE: Policy = {\n name: 'enterprise_plan',\n plan: 'enterprise',\n limit: 20000,\n window: 3600, // 20000 requests per hour\n burst: 25000,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\n// Plan mapping helper\nexport const PLAN_TIERS: Record<string, Policy> = {\n free: PLAN_FREE,\n starter: PLAN_STARTER,\n pro: PLAN_PRO,\n business: PLAN_BUSINESS,\n enterprise: PLAN_ENTERPRISE,\n};\n\n/**\n * Get policy for a plan tier.\n * @param planName - Plan tier name (free, starter, pro, business, enterprise)\n * @returns Policy for the plan\n * @throws Error if plan name is invalid\n */\nexport function getPlanPolicy(planName: string): Policy {\n const normalized = planName.toLowerCase();\n if (!(normalized in PLAN_TIERS)) {\n throw new Error(\n `Invalid plan: ${planName}. Valid plans: ${Object.keys(PLAN_TIERS).join(', ')}`\n );\n }\n return PLAN_TIERS[normalized];\n}\n","/**\n * Quota management for SaaS platforms.\n */\n\nimport { TelemetryHooks } from './telemetry';\n\nexport enum QuotaPeriod {\n HOURLY = 'hourly',\n DAILY = 'daily',\n MONTHLY = 'monthly',\n YEARLY = 'yearly',\n}\n\nexport interface Quota {\n name: string;\n limit: number;\n period: QuotaPeriod;\n currentUsage?: number;\n resetAt?: number;\n}\n\nexport class QuotaManager {\n constructor(\n private store: any,\n private telemetry?: TelemetryHooks\n ) { }\n\n private getQuotaKey(identifier: string, quotaName: string): string {\n return `halt:quota:${quotaName}:${identifier}`;\n }\n\n private calculateResetTime(period: QuotaPeriod): number {\n const now = new Date();\n\n switch (period) {\n case QuotaPeriod.HOURLY:\n const nextHour = new Date(now);\n nextHour.setHours(now.getHours() + 1, 0, 0, 0);\n return Math.floor(nextHour.getTime() / 1000);\n\n case QuotaPeriod.DAILY:\n const nextDay = new Date(now);\n nextDay.setDate(now.getDate() + 1);\n nextDay.setHours(0, 0, 0, 0);\n return Math.floor(nextDay.getTime() / 1000);\n\n case QuotaPeriod.MONTHLY:\n const nextMonth = new Date(now);\n if (now.getMonth() === 11) {\n nextMonth.setFullYear(now.getFullYear() + 1, 0, 1);\n } else {\n nextMonth.setMonth(now.getMonth() + 1, 1);\n }\n nextMonth.setHours(0, 0, 0, 0);\n return Math.floor(nextMonth.getTime() / 1000);\n\n case QuotaPeriod.YEARLY:\n const nextYear = new Date(now);\n nextYear.setFullYear(now.getFullYear() + 1, 0, 1);\n nextYear.setHours(0, 0, 0, 0);\n return Math.floor(nextYear.getTime() / 1000);\n\n default:\n throw new Error(`Invalid quota period: ${period}`);\n }\n }\n\n async getQuota(identifier: string, quota: Quota): Promise<Quota> {\n const key = this.getQuotaKey(identifier, quota.name);\n const stored = await this.store.get(key);\n\n if (!stored) {\n return {\n name: quota.name,\n limit: quota.limit,\n period: quota.period,\n currentUsage: 0,\n resetAt: this.calculateResetTime(quota.period),\n };\n }\n\n const currentQuota: Quota = {\n name: stored.name || quota.name,\n limit: stored.limit || quota.limit,\n period: stored.period || quota.period,\n currentUsage: stored.currentUsage || 0,\n resetAt: stored.resetAt,\n };\n\n // Check if quota period expired\n const now = Math.floor(Date.now() / 1000);\n if (currentQuota.resetAt && now >= currentQuota.resetAt) {\n currentQuota.currentUsage = 0;\n currentQuota.resetAt = this.calculateResetTime(currentQuota.period);\n }\n\n return currentQuota;\n }\n\n async checkQuota(\n identifier: string,\n quota: Quota,\n cost: number = 1\n ): Promise<{ allowed: boolean; quota: Quota }> {\n const currentQuota = await this.getQuota(identifier, quota);\n const allowed = (currentQuota.currentUsage || 0) + cost <= currentQuota.limit;\n\n this.telemetry?.onQuotaCheck?.(identifier, currentQuota, allowed);\n if (!allowed) {\n this.telemetry?.onQuotaExceeded?.(identifier, currentQuota);\n }\n\n return { allowed, quota: currentQuota };\n }\n\n async consumeQuota(identifier: string, quota: Quota, cost: number = 1): Promise<Quota> {\n const currentQuota = await this.getQuota(identifier, quota);\n\n currentQuota.currentUsage = (currentQuota.currentUsage || 0) + cost;\n\n const key = this.getQuotaKey(identifier, quota.name);\n const ttl = (currentQuota.resetAt || 0) - Math.floor(Date.now() / 1000) + 3600;\n\n await this.store.set(key, currentQuota, ttl);\n\n return currentQuota;\n }\n\n async resetQuota(identifier: string, quota: Quota): Promise<void> {\n const key = this.getQuotaKey(identifier, quota.name);\n await this.store.delete(key);\n }\n\n remaining(quota: Quota): number {\n return Math.max(0, quota.limit - (quota.currentUsage || 0));\n }\n\n isExceeded(quota: Quota): boolean {\n return (quota.currentUsage || 0) >= quota.limit;\n }\n}\n\n// Preset quotas\nexport const QUOTA_FREE_MONTHLY: Quota = {\n name: 'free_monthly_requests',\n limit: 10000,\n period: QuotaPeriod.MONTHLY,\n};\n\nexport const QUOTA_PRO_MONTHLY: Quota = {\n name: 'pro_monthly_requests',\n limit: 100000,\n period: QuotaPeriod.MONTHLY,\n};\n\nexport const QUOTA_ENTERPRISE_MONTHLY: Quota = {\n name: 'enterprise_monthly_requests',\n limit: 1000000,\n period: QuotaPeriod.MONTHLY,\n};\n\nexport const QUOTA_FREE_DAILY: Quota = {\n name: 'free_daily_requests',\n limit: 500,\n period: QuotaPeriod.DAILY,\n};\n\nexport const QUOTA_PRO_DAILY: Quota = {\n name: 'pro_daily_requests',\n limit: 5000,\n period: QuotaPeriod.DAILY,\n};\n","/**\n * Penalty system for abuse detection and progressive rate limiting.\n */\n\nimport { TelemetryHooks } from './telemetry';\n\nexport interface PenaltyConfig {\n threshold: number;\n duration: number;\n multiplier: number;\n decayRate: number;\n}\n\nexport interface Penalty {\n abuseScore: number;\n penaltyUntil: number | null;\n violations: number;\n lastViolation: number | null;\n}\n\nexport class PenaltyManager {\n private config: PenaltyConfig;\n\n constructor(\n private store: any,\n config?: Partial<PenaltyConfig>,\n private telemetry?: TelemetryHooks\n ) {\n this.config = {\n threshold: config?.threshold ?? 10,\n duration: config?.duration ?? 3600,\n multiplier: config?.multiplier ?? 0.5,\n decayRate: config?.decayRate ?? 1.0,\n };\n }\n\n private getPenaltyKey(identifier: string): string {\n return `halt:penalty:${identifier}`;\n }\n\n async getPenalty(identifier: string): Promise<Penalty> {\n const key = this.getPenaltyKey(identifier);\n const stored = await this.store.get(key);\n\n if (!stored) {\n return {\n abuseScore: 0,\n penaltyUntil: null,\n violations: 0,\n lastViolation: null,\n };\n }\n\n const penalty: Penalty = {\n abuseScore: stored.abuseScore || 0,\n penaltyUntil: stored.penaltyUntil || null,\n violations: stored.violations || 0,\n lastViolation: stored.lastViolation || null,\n };\n\n // Apply decay to abuse score\n if (penalty.lastViolation) {\n const hoursElapsed = (Date.now() / 1000 - penalty.lastViolation) / 3600;\n const decay = hoursElapsed * this.config.decayRate;\n penalty.abuseScore = Math.max(0, penalty.abuseScore - decay);\n }\n\n return penalty;\n }\n\n async recordViolation(identifier: string, severity: number = 1.0): Promise<Penalty> {\n const penalty = await this.getPenalty(identifier);\n\n penalty.abuseScore += severity;\n penalty.violations += 1;\n penalty.lastViolation = Math.floor(Date.now() / 1000);\n\n // Check if penalty should be applied\n let penaltyTriggered = false;\n if (penalty.abuseScore >= this.config.threshold && !this.isActive(penalty)) {\n penalty.penaltyUntil = Math.floor(Date.now() / 1000) + this.config.duration;\n penaltyTriggered = true;\n }\n\n await this.savePenalty(identifier, penalty);\n\n this.telemetry?.onViolation?.(identifier, penalty, severity);\n if (penaltyTriggered) {\n this.telemetry?.onPenaltyApplied?.(identifier, penalty);\n }\n\n return penalty;\n }\n\n async applyPenalty(identifier: string, duration?: number): Promise<Penalty> {\n const penalty = await this.getPenalty(identifier);\n\n penalty.penaltyUntil =\n Math.floor(Date.now() / 1000) + (duration ?? this.config.duration);\n\n await this.savePenalty(identifier, penalty);\n\n this.telemetry?.onPenaltyApplied?.(identifier, penalty);\n\n return penalty;\n }\n\n async clearPenalty(identifier: string): Promise<void> {\n const key = this.getPenaltyKey(identifier);\n await this.store.delete(key);\n }\n\n getRateLimitMultiplier(penalty: Penalty): number {\n if (this.isActive(penalty)) {\n return this.config.multiplier;\n }\n return 1.0;\n }\n\n isActive(penalty: Penalty): boolean {\n if (!penalty.penaltyUntil) {\n return false;\n }\n return Math.floor(Date.now() / 1000) < penalty.penaltyUntil;\n }\n\n timeRemaining(penalty: Penalty): number {\n if (!this.isActive(penalty)) {\n return 0;\n }\n return (penalty.penaltyUntil || 0) - Math.floor(Date.now() / 1000);\n }\n\n private async savePenalty(identifier: string, penalty: Penalty): Promise<void> {\n const key = this.getPenaltyKey(identifier);\n const ttl = 7 * 24 * 3600; // 7 days\n\n await this.store.set(key, penalty, ttl);\n }\n}\n\n// Preset penalty configurations\nexport const PENALTY_LENIENT: PenaltyConfig = {\n threshold: 20,\n duration: 1800, // 30 minutes\n multiplier: 0.75,\n decayRate: 2.0,\n};\n\nexport const PENALTY_MODERATE: PenaltyConfig = {\n threshold: 10,\n duration: 3600, // 1 hour\n multiplier: 0.5,\n decayRate: 1.0,\n};\n\nexport const PENALTY_STRICT: PenaltyConfig = {\n threshold: 5,\n duration: 7200, // 2 hours\n multiplier: 0.25,\n decayRate: 0.5,\n};\n","/**\n * Telemetry hooks for observability and monitoring.\n */\n\nimport { Decision } from './decision';\nimport { Quota } from './quota';\nimport { Penalty } from './penalty';\n\nexport interface TelemetryHooks {\n onCheck?(key: string, decision: Decision, metadata?: Record<string, any>): void;\n onAllowed?(key: string, decision: Decision, metadata?: Record<string, any>): void;\n onBlocked?(key: string, decision: Decision, metadata?: Record<string, any>): void;\n onQuotaCheck?(identifier: string, quota: Quota, allowed: boolean): void;\n onQuotaExceeded?(identifier: string, quota: Quota): void;\n onPenaltyApplied?(identifier: string, penalty: Penalty): void;\n onViolation?(identifier: string, penalty: Penalty, severity: number): void;\n}\n\nexport class LoggingTelemetry implements TelemetryHooks {\n constructor(private logger: Console = console) { }\n\n onCheck(key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.logger.debug(\n `Rate limit check: key=${key}, allowed=${decision.allowed}, ` +\n `remaining=${decision.remaining}, metadata=${JSON.stringify(metadata)}`\n );\n }\n\n onAllowed(key: string, decision: Decision, _metadata?: Record<string, any>): void {\n this.logger.info(`Request allowed: key=${key}, remaining=${decision.remaining}`);\n }\n\n onBlocked(key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.logger.warn(\n `Request blocked: key=${key}, retry_after=${decision.retryAfter}s, ` +\n `metadata=${JSON.stringify(metadata)}`\n );\n }\n\n onQuotaCheck(identifier: string, quota: Quota, allowed: boolean): void {\n this.logger.debug(\n `Quota check: identifier=${identifier}, quota=${quota.name}, ` +\n `allowed=${allowed}, remaining=${quota.limit - (quota.currentUsage || 0)}`\n );\n }\n\n onQuotaExceeded(identifier: string, quota: Quota): void {\n this.logger.warn(\n `Quota exceeded: identifier=${identifier}, quota=${quota.name}, ` +\n `limit=${quota.limit}, reset_at=${quota.resetAt}`\n );\n }\n\n onPenaltyApplied(identifier: string, penalty: Penalty): void {\n this.logger.warn(\n `Penalty applied: identifier=${identifier}, ` +\n `abuse_score=${penalty.abuseScore}, penalty_until=${penalty.penaltyUntil}`\n );\n }\n\n onViolation(identifier: string, penalty: Penalty, severity: number): void {\n this.logger.info(\n `Violation recorded: identifier=${identifier}, severity=${severity}, ` +\n `abuse_score=${penalty.abuseScore}, violations=${penalty.violations}`\n );\n }\n}\n\nexport class MetricsTelemetry implements TelemetryHooks {\n constructor(private metricsClient: any) { }\n\n onCheck(_key: string, _decision: Decision, metadata?: Record<string, any>): void {\n this.metricsClient.increment('halt.checks.total', this.getTags(metadata));\n }\n\n onAllowed(_key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.metricsClient.increment('halt.requests.allowed', this.getTags(metadata));\n this.metricsClient.gauge('halt.remaining', decision.remaining, this.getTags(metadata));\n }\n\n onBlocked(_key: string, _decision: Decision, metadata?: Record<string, any>): void {\n this.metricsClient.increment('halt.requests.blocked', this.getTags(metadata));\n }\n\n onQuotaCheck(_identifier: string, quota: Quota, _allowed: boolean): void {\n const tags = { quota: quota.name, period: quota.period };\n this.metricsClient.increment('halt.quota.checks', tags);\n this.metricsClient.gauge(\n 'halt.quota.remaining',\n quota.limit - (quota.currentUsage || 0),\n tags\n );\n }\n\n onQuotaExceeded(_identifier: string, quota: Quota): void {\n const tags = { quota: quota.name, period: quota.period };\n this.metricsClient.increment('halt.quota.exceeded', tags);\n }\n\n onPenaltyApplied(_identifier: string, penalty: Penalty): void {\n this.metricsClient.increment('halt.penalties.applied');\n this.metricsClient.gauge('halt.penalties.abuse_score', penalty.abuseScore);\n }\n\n onViolation(_identifier: string, _penalty: Penalty, severity: number): void {\n this.metricsClient.increment('halt.violations.total');\n this.metricsClient.histogram('halt.violations.severity', severity);\n }\n\n private getTags(metadata?: Record<string, any>): Record<string, any> {\n if (!metadata) {\n return {};\n }\n\n return {\n policy: metadata.policy,\n algorithm: metadata.algorithm,\n };\n }\n}\n\nexport class CompositeTelemetry implements TelemetryHooks {\n constructor(private hooks: TelemetryHooks[]) { }\n\n onCheck(key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.hooks.forEach((hook) => hook.onCheck?.(key, decision, metadata));\n }\n\n onAllowed(key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.hooks.forEach((hook) => hook.onAllowed?.(key, decision, metadata));\n }\n\n onBlocked(key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.hooks.forEach((hook) => hook.onBlocked?.(key, decision, metadata));\n }\n\n onQuotaCheck(identifier: string, quota: Quota, allowed: boolean): void {\n this.hooks.forEach((hook) => hook.onQuotaCheck?.(identifier, quota, allowed));\n }\n\n onQuotaExceeded(identifier: string, quota: Quota): void {\n this.hooks.forEach((hook) => hook.onQuotaExceeded?.(identifier, quota));\n }\n\n onPenaltyApplied(identifier: string, penalty: Penalty): void {\n this.hooks.forEach((hook) => hook.onPenaltyApplied?.(identifier, penalty));\n }\n\n onViolation(identifier: string, penalty: Penalty, severity: number): void {\n this.hooks.forEach((hook) => hook.onViolation?.(identifier, penalty, severity));\n }\n}\n","/**\n * In-process statistics collector for rate-limit observability.\n *\n * Implements `TelemetryHooks`, so you plug it into a RateLimiter (and optionally\n * QuotaManager / PenaltyManager) and it aggregates everything in memory. Call\n * `snapshot()` to expose a `/halt/stats` endpoint or log periodically.\n *\n * It is per-process by design — for a fleet, run it on each instance and roll up\n * across instances with the OpenTelemetry adapter (see observability/otel). Memory\n * is bounded: the tracked-key table is capped and the smallest counters are evicted.\n *\n * const stats = new StatsCollector();\n * const limiter = new RateLimiter({ store, policy, telemetry: stats });\n * app.get('/halt/stats', (_req, res) => res.json(stats.snapshot()));\n */\n\nimport { Decision } from './decision';\nimport { TelemetryHooks } from './telemetry';\nimport { Quota } from './quota';\nimport { Penalty } from './penalty';\n\nexport interface StatsCollectorOptions {\n /** How many top limited keys `snapshot()` returns (default 20). */\n topN?: number;\n /** Max distinct keys tracked for the top-N table before eviction (default 10000). */\n maxTrackedKeys?: number;\n}\n\ninterface Tally {\n allowed: number;\n blocked: number;\n}\n\ninterface EndpointTally extends Tally {\n cost: number;\n}\n\nexport interface StatsSnapshot {\n allowedTotal: number;\n blockedTotal: number;\n /** Per-policy allowed/blocked counts. */\n byPolicy: Record<string, Tally>;\n /** Per-endpoint allowed/blocked counts and consumed cost. */\n byEndpoint: Record<string, EndpointTally>;\n /** Highest-blocked keys (users / API keys / IPs), descending. */\n topLimitedKeys: Array<{ key: string; blocked: number }>;\n /** Consumed cost per plan (allowed requests only). */\n costByPlan: Record<string, number>;\n /** Count of quota-exceeded events (from QuotaManager telemetry). */\n quotaExceeded: number;\n /** Count of penalties applied (from PenaltyManager telemetry). */\n penaltiesApplied: number;\n /** Count of recorded violations (from PenaltyManager telemetry). */\n violations: number;\n /** Number of distinct keys currently tracked for top-N. */\n trackedKeys: number;\n}\n\nexport class StatsCollector implements TelemetryHooks {\n private topN: number;\n private maxTrackedKeys: number;\n\n private allowedTotal = 0;\n private blockedTotal = 0;\n private byPolicy = new Map<string, Tally>();\n private byEndpoint = new Map<string, EndpointTally>();\n private limitedKeys = new Map<string, number>();\n private costByPlan = new Map<string, number>();\n private quotaExceededCount = 0;\n private penaltiesAppliedCount = 0;\n private violationsCount = 0;\n\n constructor(options: StatsCollectorOptions = {}) {\n this.topN = options.topN ?? 20;\n this.maxTrackedKeys = options.maxTrackedKeys ?? 10000;\n }\n\n onAllowed(_key: string, _decision: Decision, metadata?: Record<string, any>): void {\n this.allowedTotal++;\n const cost = Number(metadata?.cost ?? 1);\n this.policyTally(metadata).allowed++;\n\n const endpoint = metadata?.endpoint;\n if (endpoint) {\n const e = this.endpointTally(endpoint);\n e.allowed++;\n e.cost += cost;\n }\n\n const plan = metadata?.plan ?? metadata?.policy ?? 'unknown';\n this.costByPlan.set(plan, (this.costByPlan.get(plan) ?? 0) + cost);\n }\n\n onBlocked(key: string, _decision: Decision, metadata?: Record<string, any>): void {\n this.blockedTotal++;\n this.policyTally(metadata).blocked++;\n\n const endpoint = metadata?.endpoint;\n if (endpoint) {\n this.endpointTally(endpoint).blocked++;\n }\n\n if (key) this.trackLimitedKey(key);\n }\n\n onQuotaExceeded(_identifier: string, _quota: Quota): void {\n this.quotaExceededCount++;\n }\n\n onPenaltyApplied(_identifier: string, _penalty: Penalty): void {\n this.penaltiesAppliedCount++;\n }\n\n onViolation(_identifier: string, _penalty: Penalty, _severity: number): void {\n this.violationsCount++;\n }\n\n /** Point-in-time view of the aggregated stats. */\n snapshot(): StatsSnapshot {\n const topLimitedKeys = [...this.limitedKeys.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, this.topN)\n .map(([key, blocked]) => ({ key, blocked }));\n\n return {\n allowedTotal: this.allowedTotal,\n blockedTotal: this.blockedTotal,\n byPolicy: mapToObject(this.byPolicy),\n byEndpoint: mapToObject(this.byEndpoint),\n topLimitedKeys,\n costByPlan: mapToObject(this.costByPlan),\n quotaExceeded: this.quotaExceededCount,\n penaltiesApplied: this.penaltiesAppliedCount,\n violations: this.violationsCount,\n trackedKeys: this.limitedKeys.size,\n };\n }\n\n /** Clear all counters (e.g. after exporting). */\n reset(): void {\n this.allowedTotal = 0;\n this.blockedTotal = 0;\n this.byPolicy.clear();\n this.byEndpoint.clear();\n this.limitedKeys.clear();\n this.costByPlan.clear();\n this.quotaExceededCount = 0;\n this.penaltiesAppliedCount = 0;\n this.violationsCount = 0;\n }\n\n private policyTally(metadata?: Record<string, any>): Tally {\n const policy = metadata?.policy ?? 'unknown';\n let t = this.byPolicy.get(policy);\n if (!t) {\n t = { allowed: 0, blocked: 0 };\n this.byPolicy.set(policy, t);\n }\n return t;\n }\n\n private endpointTally(endpoint: string): EndpointTally {\n let e = this.byEndpoint.get(endpoint);\n if (!e) {\n e = { allowed: 0, blocked: 0, cost: 0 };\n this.byEndpoint.set(endpoint, e);\n }\n return e;\n }\n\n private trackLimitedKey(key: string): void {\n const current = this.limitedKeys.get(key);\n if (current !== undefined) {\n this.limitedKeys.set(key, current + 1);\n return;\n }\n if (this.limitedKeys.size >= this.maxTrackedKeys) {\n this.evictSmallest();\n }\n this.limitedKeys.set(key, 1);\n }\n\n /** Evict the lowest-count tracked key to keep memory bounded. */\n private evictSmallest(): void {\n let minKey: string | undefined;\n let minVal = Infinity;\n for (const [k, v] of this.limitedKeys) {\n if (v < minVal) {\n minVal = v;\n minKey = k;\n }\n }\n if (minKey !== undefined) this.limitedKeys.delete(minKey);\n }\n}\n\nfunction mapToObject<V>(map: Map<string, V>): Record<string, V> {\n const out: Record<string, V> = {};\n for (const [k, v] of map) out[k] = v;\n return out;\n}\n","/**\n * OpenTelemetry metrics adapter for Halt.\n *\n * Implements `TelemetryHooks` over the OTel metrics API. You inject a Meter, so\n * Halt keeps no hard dependency on `@opentelemetry/api`:\n *\n * import { metrics } from '@opentelemetry/api';\n * import { OpenTelemetryMetrics } from 'halt-rate';\n *\n * const telemetry = new OpenTelemetryMetrics(metrics.getMeter('halt'));\n * const limiter = new RateLimiter({ store, policy, telemetry });\n *\n * Request spans are already covered by the limiter's `otelTracer` option; this\n * adapter adds counters for dashboards/alerts. Roll up across instances with your\n * OTel collector.\n */\n\nimport { Decision } from '../core/decision';\nimport { TelemetryHooks } from '../core/telemetry';\nimport { Quota } from '../core/quota';\nimport { Penalty } from '../core/penalty';\n\n/** Minimal structural types satisfied by `@opentelemetry/api` (no hard dep). */\nexport interface OTelCounterLike {\n add(value: number, attributes?: Record<string, string | number | boolean>): void;\n}\nexport interface OTelMeterLike {\n createCounter(name: string, options?: { description?: string; unit?: string }): OTelCounterLike;\n}\n\nexport class OpenTelemetryMetrics implements TelemetryHooks {\n private requests: OTelCounterLike;\n private blocked: OTelCounterLike;\n private cost: OTelCounterLike;\n private quotaExceededCounter: OTelCounterLike;\n private penaltyAppliedCounter: OTelCounterLike;\n private violationsCounter: OTelCounterLike;\n\n constructor(meter: OTelMeterLike) {\n this.requests = meter.createCounter('halt.requests', {\n description: 'Total rate-limit checks',\n });\n this.blocked = meter.createCounter('halt.blocked', {\n description: 'Rate-limited (blocked) requests',\n });\n this.cost = meter.createCounter('halt.cost', {\n description: 'Consumed request cost (weighted endpoints)',\n });\n this.quotaExceededCounter = meter.createCounter('halt.quota.exceeded', {\n description: 'Quota-exceeded events',\n });\n this.penaltyAppliedCounter = meter.createCounter('halt.penalty.applied', {\n description: 'Penalties applied (abuse controls)',\n });\n this.violationsCounter = meter.createCounter('halt.violations', {\n description: 'Recorded abuse violations',\n });\n }\n\n onAllowed(_key: string, _decision: Decision, metadata?: Record<string, any>): void {\n const policy = String(metadata?.policy ?? 'unknown');\n this.requests.add(1, { policy, allowed: 'true' });\n const endpoint = metadata?.endpoint;\n const plan = String(metadata?.plan ?? metadata?.policy ?? 'unknown');\n const cost = Number(metadata?.cost ?? 1);\n this.cost.add(cost, endpoint ? { endpoint: String(endpoint), plan } : { plan });\n }\n\n onBlocked(_key: string, _decision: Decision, metadata?: Record<string, any>): void {\n const policy = String(metadata?.policy ?? 'unknown');\n this.requests.add(1, { policy, allowed: 'false' });\n const endpoint = metadata?.endpoint;\n this.blocked.add(1, endpoint ? { policy, endpoint: String(endpoint) } : { policy });\n }\n\n onQuotaExceeded(_identifier: string, quota: Quota): void {\n this.quotaExceededCounter.add(1, { quota: quota.name });\n }\n\n onPenaltyApplied(_identifier: string, _penalty: Penalty): void {\n this.penaltyAppliedCounter.add(1);\n }\n\n onViolation(_identifier: string, _penalty: Penalty, severity: number): void {\n this.violationsCounter.add(1, { severity });\n }\n}\n"]}
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/store.ts","../src/core/limiter.ts","../src/core/decision.ts","../src/stores/memory.ts","../src/stores/redis-scripts.ts","../src/stores/redis.ts","../src/presets/index.ts","../src/core/registry.ts","../src/core/quota.ts","../src/core/penalty.ts","../src/core/telemetry.ts","../src/core/stats.ts","../src/observability/otel.ts"],"names":["KeyStrategy","Algorithm","span","decision","ip","QuotaPeriod"],"mappings":"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","file":"index.mjs","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 /** Optional plan/tier label for observability tagging (e.g. \"pro\"). */\n plan?: 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 plan: policy.plan ?? undefined,\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 * Atomic-evaluation protocol.\n *\n * Simple stores (e.g. InMemoryStore) expose get/set and let the limiter run the\n * algorithm in-process. Distributed stores that can compute the decision\n * atomically (e.g. RedisStore via Lua) instead expose `evaluate()`: the limiter\n * hands them the resolved policy params + storage key and gets back a finished\n * Decision. The limiter prefers `evaluate()` when present (see core/limiter.ts).\n */\n\nimport { Decision } from './decision';\nimport { Algorithm } from './policy';\n\n/** Everything an atomic store needs to compute a decision for one request. */\nexport interface EvaluateInput {\n /** Full storage key, already namespaced (e.g. `halt:public_api:1.2.3.4`). */\n key: string;\n /** Algorithm to apply. */\n algorithm: Algorithm;\n /** Requests permitted per window. */\n limit: number;\n /** Window length in seconds. */\n window: number;\n /** Bucket capacity (token/leaky bucket). */\n burst: number;\n /** Cost this request consumes. */\n cost: number;\n /** Seconds to keep the key alive in the backing store. */\n ttl: number;\n}\n\n/** A store that computes the rate-limit decision atomically on its own. */\nexport interface AtomicStore {\n evaluate(input: EvaluateInput): Promise<Decision>;\n}\n\n/** True if the store implements the atomic-evaluation protocol. */\nexport function isAtomicStore(store: unknown): store is AtomicStore {\n return (\n typeof store === 'object' &&\n store !== null &&\n typeof (store as AtomicStore).evaluate === 'function'\n );\n}\n\n/**\n * Minimal structural type for a Redis client (satisfied by ioredis and\n * node-redis v4+). Declared here so Halt has no hard dependency on any concrete\n * Redis package — the user injects their own client.\n */\nexport interface RedisClientLike {\n eval(script: string, numKeys: number, ...args: (string | number)[]): Promise<unknown>;\n evalsha?(sha: string, numKeys: number, ...args: (string | number)[]): Promise<unknown>;\n script?(subcommand: 'LOAD', script: string): Promise<unknown>;\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';\nimport { AtomicStore, isAtomicStore } from './store';\nimport { TelemetryHooks } from './telemetry';\n\ntype AlgorithmInstance = TokenBucket | FixedWindow | SlidingWindow | LeakyBucket;\n\nexport interface RateLimiterOptions {\n /**\n * Storage backend. Either a simple KV store (InMemoryStore — the limiter runs\n * the algorithm in-process) or an atomic store (RedisStore — the store\n * computes the decision atomically via Lua).\n */\n store: Store | AtomicStore;\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 * Optional high-level observability hooks (StatsCollector, OpenTelemetryMetrics,\n * LoggingTelemetry, or a CompositeTelemetry of several). Called on every\n * rate-limited check with rich metadata (policy, algorithm, endpoint, cost, plan).\n */\n telemetry?: TelemetryHooks;\n}\n\nexport class RateLimiter {\n private store: Store | AtomicStore;\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 private telemetry?: TelemetryHooks;\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 this.telemetry = options.telemetry;\n }\n\n /** Fan a finished decision out to the telemetry hooks with rich metadata. */\n private emitTelemetry(\n request: any,\n key: string,\n decision: Decision,\n policy: Required<Policy>,\n cost: number\n ): void {\n if (!this.telemetry) return;\n const metadata: Record<string, any> = {\n policy: policy.name,\n algorithm: policy.algorithm,\n keyStrategy: policy.keyStrategy,\n endpoint: extractPath(request) ?? undefined,\n cost,\n plan: policy.plan,\n };\n this.telemetry.onCheck?.(key, decision, metadata);\n if (decision.allowed) {\n this.telemetry.onAllowed?.(key, decision, metadata);\n } else {\n this.telemetry.onBlocked?.(key, decision, metadata);\n }\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 // Atomic stores (e.g. Redis) compute the whole decision themselves.\n if (isAtomicStore(this.store)) {\n const span = this.otelTracer?.startSpan?.('halt.check', {\n attributes: { policy: policy.name, key },\n });\n const decision = await this.store.evaluate({\n key: storageKey,\n algorithm: policy.algorithm,\n limit: policy.limit,\n window: policy.window,\n burst: policy.burst,\n cost: requestCost,\n ttl: policy.window * 2,\n });\n this.metricsRecorder?.(\n 'halt.request.checked',\n { policy: policy.name, allowed: String(decision.allowed) },\n 1\n );\n this.metricsRecorder?.(\n decision.allowed ? 'halt.request.allowed' : 'halt.request.blocked',\n { policy: policy.name },\n 1\n );\n span?.end?.();\n this.emitTelemetry(request, key, decision, policy, requestCost);\n return decision;\n }\n\n const store = this.store as Store;\n\n // Get or create algorithm instance for this policy. The cache key includes\n // the parameters that affect behavior, so changing a policy's limit/window\n // at runtime (dynamic limits) takes effect immediately on the in-app path.\n const cacheKey = `${policy.name}|${policy.algorithm}|${policy.limit}|${policy.window}|${policy.burst}`;\n let algorithm = this.algorithmCache.get(cacheKey);\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(cacheKey, 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 = 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 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 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 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 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 this.emitTelemetry(request, key, decision, policy, requestCost);\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 * In-memory storage backend for rate limiting.\n */\n\nexport interface Store {\n get(key: string): any;\n set(key: string, value: any, ttl?: number): void;\n increment(key: string, delta?: number, ttl?: number): number;\n delete(key: string): void;\n}\n\ninterface StoreEntry {\n value: any;\n expiry?: number;\n}\n\nexport class InMemoryStore implements Store {\n private data: Map<string, StoreEntry> = new Map();\n\n get(key: string): any {\n this.cleanupExpired(key);\n const entry = this.data.get(key);\n return entry?.value ?? null;\n }\n\n set(key: string, value: any, ttl?: number): void {\n const entry: StoreEntry = { value };\n\n if (ttl !== undefined) {\n entry.expiry = Date.now() + ttl * 1000;\n }\n\n this.data.set(key, entry);\n }\n\n increment(key: string, delta: number = 1, ttl?: number): number {\n this.cleanupExpired(key);\n const entry = this.data.get(key);\n const current = typeof entry?.value === 'number' ? entry.value : 0;\n const newValue = current + delta;\n\n const newEntry: StoreEntry = { value: newValue };\n\n // Set TTL only if key didn't exist\n if (!entry && ttl !== undefined) {\n newEntry.expiry = Date.now() + ttl * 1000;\n } else if (entry?.expiry) {\n newEntry.expiry = entry.expiry;\n }\n\n this.data.set(key, newEntry);\n return newValue;\n }\n\n delete(key: string): void {\n this.data.delete(key);\n }\n\n private cleanupExpired(key: string): void {\n const entry = this.data.get(key);\n if (entry?.expiry && Date.now() >= entry.expiry) {\n this.data.delete(key);\n }\n }\n\n /**\n * Clean up all expired keys.\n */\n cleanupAllExpired(): number {\n const now = Date.now();\n let count = 0;\n\n for (const [key, entry] of this.data.entries()) {\n if (entry.expiry && now >= entry.expiry) {\n this.data.delete(key);\n count++;\n }\n }\n\n return count;\n }\n}\n","/**\n * Lua scripts for atomic rate limiting in Redis.\n *\n * Each script performs the full check-and-consume in a single round trip so the\n * decision is atomic even under concurrent access from many app servers. Every\n * script touches exactly one key (KEYS[1]) and reads the clock from the Redis\n * server (`TIME`), so it is safe on Redis Cluster and immune to app-server clock skew.\n *\n * ARGV (shared by all scripts):\n * ARGV[1] = limit (requests per window)\n * ARGV[2] = window (seconds)\n * ARGV[3] = burst (capacity, for token/leaky bucket)\n * ARGV[4] = cost (tokens this request consumes)\n * ARGV[5] = ttl (seconds to keep the key alive)\n *\n * Return (shared by all scripts), a 5-element array:\n * { allowed(1|0), limit, remaining, resetAt(unix s), retryAfter(s, -1 = none) }\n */\n\n/** Shared Lua prelude: derive a float `now` (seconds) from the Redis server clock. */\nconst NOW = `\nlocal t = redis.call('TIME')\nlocal now = tonumber(t[1]) + (tonumber(t[2]) / 1000000)\n`;\n\nexport const TOKEN_BUCKET_LUA = `\n${NOW}\nlocal limit = tonumber(ARGV[1])\nlocal window = tonumber(ARGV[2])\nlocal capacity = tonumber(ARGV[3])\nlocal cost = tonumber(ARGV[4])\nlocal ttl = tonumber(ARGV[5])\nlocal rate = limit / window\n\nlocal data = redis.call('HMGET', KEYS[1], 'tokens', 'ts')\nlocal tokens, last\nif data[1] then\n tokens = tonumber(data[1])\n last = tonumber(data[2])\nelse\n tokens = capacity\n last = now\nend\n\nlocal elapsed = now - last\nif elapsed < 0 then elapsed = 0 end\ntokens = math.min(capacity, tokens + elapsed * rate)\n\nlocal needed = capacity - tokens\nlocal resetAt = math.floor(now + (needed / rate))\n\nif tokens >= cost then\n tokens = tokens - cost\n redis.call('HMSET', KEYS[1], 'tokens', tokens, 'ts', now)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {1, limit, math.floor(tokens), resetAt, -1}\nelse\n local deficit = cost - tokens\n local retryAfter = math.floor(deficit / rate) + 1\n redis.call('HMSET', KEYS[1], 'tokens', tokens, 'ts', now)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {0, limit, 0, resetAt, retryAfter}\nend\n`;\n\nexport const FIXED_WINDOW_LUA = `\n${NOW}\nlocal limit = tonumber(ARGV[1])\nlocal window = tonumber(ARGV[2])\nlocal cost = tonumber(ARGV[4])\nlocal ttl = tonumber(ARGV[5])\n\nlocal data = redis.call('HMGET', KEYS[1], 'count', 'start')\nlocal count, start\nif data[1] then\n count = tonumber(data[1])\n start = tonumber(data[2])\nelse\n count = 0\n start = now\nend\n\nif (now - start) >= window then\n count = 0\n start = now\nend\n\nlocal resetAt = math.floor(start + window)\n\nif (count + cost) <= limit then\n count = count + cost\n redis.call('HMSET', KEYS[1], 'count', count, 'start', start)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {1, limit, limit - count, resetAt, -1}\nelse\n redis.call('HMSET', KEYS[1], 'count', count, 'start', start)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n local retryAfter = math.floor(resetAt - now) + 1\n return {0, limit, 0, resetAt, retryAfter}\nend\n`;\n\nexport const LEAKY_BUCKET_LUA = `\n${NOW}\nlocal limit = tonumber(ARGV[1])\nlocal window = tonumber(ARGV[2])\nlocal capacity = tonumber(ARGV[3])\nlocal cost = tonumber(ARGV[4])\nlocal ttl = tonumber(ARGV[5])\nlocal leakRate = limit / window\n\nlocal data = redis.call('HMGET', KEYS[1], 'level', 'ts')\nlocal level, last\nif data[1] then\n level = tonumber(data[1])\n last = tonumber(data[2])\nelse\n level = 0\n last = now\nend\n\nlocal elapsed = now - last\nif elapsed < 0 then elapsed = 0 end\nlevel = math.max(0, level - (elapsed * leakRate))\n\nlocal resetAt\nif level > 0 then\n resetAt = math.floor(now + (level / leakRate))\nelse\n resetAt = math.floor(now)\nend\n\nif (level + cost) <= capacity then\n level = level + cost\n redis.call('HMSET', KEYS[1], 'level', level, 'ts', now)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {1, capacity, math.floor(capacity - level), resetAt, -1}\nelse\n local spaceNeeded = level + cost - capacity\n local retryAfter = math.floor(spaceNeeded / leakRate) + 1\n redis.call('HMSET', KEYS[1], 'level', level, 'ts', now)\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {0, capacity, 0, resetAt, retryAfter}\nend\n`;\n\nexport const SLIDING_WINDOW_LUA = `\n${NOW}\nlocal limit = tonumber(ARGV[1])\nlocal window = tonumber(ARGV[2])\nlocal cost = tonumber(ARGV[4])\nlocal ttl = tonumber(ARGV[5])\n\n-- Drop entries older than the sliding window.\nlocal windowStart = now - window\nredis.call('ZREMRANGEBYSCORE', KEYS[1], '-inf', windowStart)\n\nlocal count = redis.call('ZCARD', KEYS[1])\n\n-- Oldest remaining entry determines when capacity frees up.\nlocal oldest = redis.call('ZRANGE', KEYS[1], 0, 0, 'WITHSCORES')\nlocal resetAt\nif oldest[2] then\n resetAt = math.floor(tonumber(oldest[2]) + window)\nelse\n resetAt = math.floor(now + window)\nend\n\nif (count + cost) <= limit then\n -- Unique members so concurrent requests in the same instant don't collide.\n math.randomseed(math.floor(now * 1000000))\n for i = 1, cost do\n local member = string.format('%d-%d-%d', math.floor(now * 1000000), i, math.random(1, 1000000000))\n redis.call('ZADD', KEYS[1], now, member)\n end\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n return {1, limit, limit - (count + cost), resetAt, -1}\nelse\n redis.call('PEXPIRE', KEYS[1], ttl * 1000)\n local retryAfter\n if oldest[2] then\n retryAfter = math.floor(tonumber(oldest[2]) + window - now) + 1\n else\n retryAfter = math.floor(window) + 1\n end\n return {0, limit, 0, resetAt, retryAfter}\nend\n`;\n\n/** Algorithm value (from core/policy `Algorithm`) → Lua script. */\nexport const SCRIPTS: Record<string, string> = {\n token_bucket: TOKEN_BUCKET_LUA,\n fixed_window: FIXED_WINDOW_LUA,\n sliding_window: SLIDING_WINDOW_LUA,\n leaky_bucket: LEAKY_BUCKET_LUA,\n};\n","/**\n * Redis storage backend for Halt — production-grade, atomic rate limiting.\n *\n * Implements the atomic-evaluation protocol (`AtomicStore`): the full\n * check-and-consume runs inside Redis via a Lua script, so limits stay accurate\n * under concurrent load from any number of app servers. Works on standalone\n * Redis and Redis Cluster (every script touches a single key).\n *\n * The Redis client is injected, so Halt has no hard dependency on any client\n * library. Any ioredis / node-redis v4+ instance works:\n *\n * import Redis from 'ioredis';\n * import { RedisStore } from 'halt-rate';\n * const store = new RedisStore({ client: new Redis(process.env.REDIS_URL) });\n */\n\nimport { Decision } from '../core/decision';\nimport { Algorithm } from '../core/policy';\nimport { AtomicStore, EvaluateInput, RedisClientLike } from '../core/store';\nimport { SCRIPTS } from './redis-scripts';\n\n/** Behavior when Redis is unreachable or errors. */\nexport type FailMode = 'open' | 'closed';\n\nexport interface RedisStoreOptions {\n /** A connected Redis client (ioredis or node-redis v4+). */\n client: RedisClientLike;\n /**\n * What to do when Redis can't be reached.\n * - `'open'` (default): allow the request — don't take down traffic when the\n * limiter's backing store is down.\n * - `'closed'`: block the request (429) — safer for abuse-sensitive routes.\n */\n failMode?: FailMode;\n /** Called with the underlying error whenever a Redis call fails. */\n onError?: (err: unknown) => void;\n /** Metrics hook: (name, tags?, value?) => void. */\n metricsRecorder?: (name: string, tags?: Record<string, string>, value?: number) => void;\n}\n\nexport class RedisStore implements AtomicStore {\n private client: RedisClientLike;\n private failMode: FailMode;\n private onError?: (err: unknown) => void;\n private metricsRecorder?: RedisStoreOptions['metricsRecorder'];\n /** Cache of script source -> SHA loaded into Redis, to use EVALSHA. */\n private shaCache: Map<string, string> = new Map();\n\n constructor(options: RedisStoreOptions) {\n this.client = options.client;\n this.failMode = options.failMode ?? 'open';\n this.onError = options.onError;\n this.metricsRecorder = options.metricsRecorder;\n }\n\n async evaluate(input: EvaluateInput): Promise<Decision> {\n const script = SCRIPTS[input.algorithm];\n if (!script) {\n throw new Error(`Algorithm ${input.algorithm} not supported by RedisStore`);\n }\n\n const args: (string | number)[] = [\n input.limit,\n input.window,\n input.burst,\n input.cost,\n input.ttl,\n ];\n\n try {\n const raw = await this.run(script, input.key, args);\n return this.toDecision(raw, input);\n } catch (err) {\n this.onError?.(err);\n this.metricsRecorder?.('halt.redis.error', { algorithm: input.algorithm }, 1);\n return this.failDecision(input);\n }\n }\n\n /** Run a script via EVALSHA, falling back to EVAL (and caching the SHA). */\n private async run(\n script: string,\n key: string,\n args: (string | number)[]\n ): Promise<unknown> {\n const sha = this.shaCache.get(script);\n if (sha && this.client.evalsha) {\n try {\n return await this.client.evalsha(sha, 1, key, ...args);\n } catch (err) {\n // NOSCRIPT: script was flushed from Redis; fall through to EVAL.\n if (!isNoScriptError(err)) throw err;\n }\n }\n\n const result = await this.client.eval(script, 1, key, ...args);\n // Cache the SHA for subsequent EVALSHA calls (best-effort).\n if (!this.shaCache.has(script) && this.client.script) {\n try {\n const loaded = await this.client.script('LOAD', script);\n if (typeof loaded === 'string') this.shaCache.set(script, loaded);\n } catch {\n /* SHA caching is an optimization; ignore failures. */\n }\n }\n return result;\n }\n\n /** Map the Lua array [allowed, limit, remaining, resetAt, retryAfter] to a Decision. */\n private toDecision(raw: unknown, input: EvaluateInput): Decision {\n if (!Array.isArray(raw) || raw.length < 4) {\n throw new Error(`Unexpected Redis script result: ${JSON.stringify(raw)}`);\n }\n const [allowed, limit, remaining, resetAt, retryAfter] = raw.map((v) => Number(v));\n\n const decision: Decision = {\n allowed: allowed === 1,\n limit,\n remaining,\n resetAt,\n };\n if (!decision.allowed && retryAfter !== undefined && retryAfter >= 0) {\n decision.retryAfter = retryAfter;\n }\n\n this.metricsRecorder?.(\n 'halt.request.checked',\n { algorithm: input.algorithm, allowed: String(decision.allowed) },\n 1\n );\n return decision;\n }\n\n /** Decision returned when Redis is unreachable, per failMode. */\n private failDecision(input: EvaluateInput): Decision {\n const resetAt = Math.floor(Date.now() / 1000 + input.window);\n if (this.failMode === 'open') {\n this.metricsRecorder?.('halt.request.fail_open', { algorithm: input.algorithm }, 1);\n return { allowed: true, limit: input.limit, remaining: input.limit, resetAt };\n }\n this.metricsRecorder?.('halt.request.fail_closed', { algorithm: input.algorithm }, 1);\n return {\n allowed: false,\n limit: input.limit,\n remaining: 0,\n resetAt,\n retryAfter: input.window,\n };\n }\n}\n\nfunction isNoScriptError(err: unknown): boolean {\n return (\n typeof err === 'object' &&\n err !== null &&\n String((err as { message?: string }).message ?? '').includes('NOSCRIPT')\n );\n}\n\n// Re-export the algorithm enum location for convenience in user code.\nexport { Algorithm };\n","/**\n * Preset rate limiting policies for common use cases.\n */\n\nimport { Policy, KeyStrategy, Algorithm } from '../core/policy';\n\n// Public API - moderate limits for general public access\nexport const PUBLIC_API: Policy = {\n name: 'public_api',\n limit: 100,\n window: 60, // 1 minute\n burst: 120,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.IP,\n};\n\n// Authentication endpoints - strict limits to prevent brute force\nexport const AUTH_ENDPOINTS: Policy = {\n name: 'auth_endpoints',\n limit: 5,\n window: 60, // 1 minute\n burst: 10,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.IP,\n blockDuration: 300, // 5 minute cooldown after limit exceeded\n};\n\n// Expensive operations - very strict limits for resource-intensive endpoints\nexport const EXPENSIVE_OPS: Policy = {\n name: 'expensive_ops',\n limit: 10,\n window: 3600, // 1 hour\n burst: 15,\n cost: 10, // Each request costs 10 tokens\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\n// Strict API - for sensitive operations\nexport const STRICT_API: Policy = {\n name: 'strict_api',\n limit: 20,\n window: 60, // 1 minute\n burst: 25,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.API_KEY,\n};\n\n// Generous API - for internal or trusted services\nexport const GENEROUS_API: Policy = {\n name: 'generous_api',\n limit: 1000,\n window: 60, // 1 minute\n burst: 1200,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.IP,\n};\n\n// Plan-based presets for SaaS platforms\nexport const PLAN_FREE: Policy = {\n name: 'free_plan',\n plan: 'free',\n limit: 100,\n window: 3600, // 100 requests per hour\n burst: 120,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_STARTER: Policy = {\n name: 'starter_plan',\n plan: 'starter',\n limit: 500,\n window: 3600, // 500 requests per hour\n burst: 600,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_PRO: Policy = {\n name: 'pro_plan',\n plan: 'pro',\n limit: 2000,\n window: 3600, // 2000 requests per hour\n burst: 2500,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_BUSINESS: Policy = {\n name: 'business_plan',\n plan: 'business',\n limit: 5000,\n window: 3600, // 5000 requests per hour\n burst: 6000,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\nexport const PLAN_ENTERPRISE: Policy = {\n name: 'enterprise_plan',\n plan: 'enterprise',\n limit: 20000,\n window: 3600, // 20000 requests per hour\n burst: 25000,\n algorithm: Algorithm.TOKEN_BUCKET,\n keyStrategy: KeyStrategy.USER,\n};\n\n// Plan mapping helper\nexport const PLAN_TIERS: Record<string, Policy> = {\n free: PLAN_FREE,\n starter: PLAN_STARTER,\n pro: PLAN_PRO,\n business: PLAN_BUSINESS,\n enterprise: PLAN_ENTERPRISE,\n};\n\n/**\n * Get policy for a plan tier.\n * @param planName - Plan tier name (free, starter, pro, business, enterprise)\n * @returns Policy for the plan\n * @throws Error if plan name is invalid\n */\nexport function getPlanPolicy(planName: string): Policy {\n const normalized = planName.toLowerCase();\n if (!(normalized in PLAN_TIERS)) {\n throw new Error(\n `Invalid plan: ${planName}. Valid plans: ${Object.keys(PLAN_TIERS).join(', ')}`\n );\n }\n return PLAN_TIERS[normalized];\n}\n","/**\n * Dynamic limits — change policies at runtime without restarting.\n *\n * `PolicyRegistry` holds named policies you can mutate live. Use it as the\n * limiter's `policy` via `registry.resolver(selector)`:\n *\n * const registry = new PolicyRegistry([presets.PUBLIC_API]);\n * const limiter = new RateLimiter({\n * store,\n * policy: registry.resolver((req) => 'public_api'),\n * });\n * // later, no restart:\n * registry.update('public_api', { limit: 500 });\n *\n * For limits stored in Redis/DB/config (and shared across a fleet), use\n * `cachedPolicyResolver` with a loader that reads that shared state.\n */\n\nimport { Policy } from './policy';\n\nexport class PolicyRegistry {\n private policies = new Map<string, Policy>();\n\n constructor(initial: Policy[] = []) {\n for (const p of initial) this.register(p);\n }\n\n /** Add or replace a policy (keyed by `policy.name`). */\n register(policy: Policy): this {\n this.policies.set(policy.name, policy);\n return this;\n }\n\n get(name: string): Policy | undefined {\n return this.policies.get(name);\n }\n\n has(name: string): boolean {\n return this.policies.has(name);\n }\n\n /** Mutate fields of an existing policy at runtime (e.g. `{ limit: 500 }`). */\n update(name: string, patch: Partial<Omit<Policy, 'name'>>): Policy {\n const existing = this.policies.get(name);\n if (!existing) throw new Error(`Unknown policy: ${name}`);\n const updated: Policy = { ...existing, ...patch, name: existing.name };\n // If the limit changed but burst wasn't given, let normalizePolicy recompute\n // the default burst (otherwise a stale smaller burst fails validation).\n if (patch.limit !== undefined && patch.burst === undefined) {\n delete updated.burst;\n }\n this.policies.set(name, updated);\n return updated;\n }\n\n remove(name: string): boolean {\n return this.policies.delete(name);\n }\n\n list(): Policy[] {\n return [...this.policies.values()];\n }\n\n /**\n * Build a resolver for the limiter's `policy` option.\n * @param selector maps a request to a registered policy name.\n */\n resolver(selector: (request: any) => string): (request: any) => Policy {\n return (request: any) => {\n const name = selector(request);\n const policy = this.policies.get(name);\n if (!policy) throw new Error(`Unknown policy: ${name}`);\n return policy;\n };\n }\n}\n\nexport interface CachedPolicyResolverOptions {\n /** Cache entry lifetime in ms (default 5000). */\n ttlMs?: number;\n /** Cache key for a request (default: the loaded policy is shared under one key). */\n key?: (request: any) => string;\n}\n\n/**\n * Wrap a (possibly async) loader with a per-key TTL cache. The loader reads your\n * source of truth (Redis/DB/config), so limits propagate across a fleet and\n * refresh live — without restarting. Use the returned function as `policy`.\n */\nexport function cachedPolicyResolver(\n loader: (request: any) => Policy | Promise<Policy>,\n options: CachedPolicyResolverOptions = {}\n): (request: any) => Promise<Policy> {\n const ttlMs = options.ttlMs ?? 5000;\n const keyFn = options.key ?? (() => '__default__');\n const cache = new Map<string, { policy: Policy; expires: number }>();\n\n return async (request: any): Promise<Policy> => {\n const key = keyFn(request);\n const now = Date.now();\n const hit = cache.get(key);\n if (hit && hit.expires > now) {\n return hit.policy;\n }\n const policy = await loader(request);\n cache.set(key, { policy, expires: now + ttlMs });\n return policy;\n };\n}\n","/**\n * Quota management for SaaS platforms.\n */\n\nimport { TelemetryHooks } from './telemetry';\n\nexport enum QuotaPeriod {\n HOURLY = 'hourly',\n DAILY = 'daily',\n MONTHLY = 'monthly',\n YEARLY = 'yearly',\n}\n\nexport interface Quota {\n name: string;\n limit: number;\n period: QuotaPeriod;\n currentUsage?: number;\n resetAt?: number;\n}\n\nexport class QuotaManager {\n constructor(\n private store: any,\n private telemetry?: TelemetryHooks\n ) { }\n\n private getQuotaKey(identifier: string, quotaName: string): string {\n return `halt:quota:${quotaName}:${identifier}`;\n }\n\n private calculateResetTime(period: QuotaPeriod): number {\n const now = new Date();\n\n switch (period) {\n case QuotaPeriod.HOURLY:\n const nextHour = new Date(now);\n nextHour.setHours(now.getHours() + 1, 0, 0, 0);\n return Math.floor(nextHour.getTime() / 1000);\n\n case QuotaPeriod.DAILY:\n const nextDay = new Date(now);\n nextDay.setDate(now.getDate() + 1);\n nextDay.setHours(0, 0, 0, 0);\n return Math.floor(nextDay.getTime() / 1000);\n\n case QuotaPeriod.MONTHLY:\n const nextMonth = new Date(now);\n if (now.getMonth() === 11) {\n nextMonth.setFullYear(now.getFullYear() + 1, 0, 1);\n } else {\n nextMonth.setMonth(now.getMonth() + 1, 1);\n }\n nextMonth.setHours(0, 0, 0, 0);\n return Math.floor(nextMonth.getTime() / 1000);\n\n case QuotaPeriod.YEARLY:\n const nextYear = new Date(now);\n nextYear.setFullYear(now.getFullYear() + 1, 0, 1);\n nextYear.setHours(0, 0, 0, 0);\n return Math.floor(nextYear.getTime() / 1000);\n\n default:\n throw new Error(`Invalid quota period: ${period}`);\n }\n }\n\n async getQuota(identifier: string, quota: Quota): Promise<Quota> {\n const key = this.getQuotaKey(identifier, quota.name);\n const stored = await this.store.get(key);\n\n if (!stored) {\n return {\n name: quota.name,\n limit: quota.limit,\n period: quota.period,\n currentUsage: 0,\n resetAt: this.calculateResetTime(quota.period),\n };\n }\n\n const currentQuota: Quota = {\n name: stored.name || quota.name,\n limit: stored.limit || quota.limit,\n period: stored.period || quota.period,\n currentUsage: stored.currentUsage || 0,\n resetAt: stored.resetAt,\n };\n\n // Check if quota period expired\n const now = Math.floor(Date.now() / 1000);\n if (currentQuota.resetAt && now >= currentQuota.resetAt) {\n currentQuota.currentUsage = 0;\n currentQuota.resetAt = this.calculateResetTime(currentQuota.period);\n }\n\n return currentQuota;\n }\n\n async checkQuota(\n identifier: string,\n quota: Quota,\n cost: number = 1\n ): Promise<{ allowed: boolean; quota: Quota }> {\n const currentQuota = await this.getQuota(identifier, quota);\n const allowed = (currentQuota.currentUsage || 0) + cost <= currentQuota.limit;\n\n this.telemetry?.onQuotaCheck?.(identifier, currentQuota, allowed);\n if (!allowed) {\n this.telemetry?.onQuotaExceeded?.(identifier, currentQuota);\n }\n\n return { allowed, quota: currentQuota };\n }\n\n async consumeQuota(identifier: string, quota: Quota, cost: number = 1): Promise<Quota> {\n const currentQuota = await this.getQuota(identifier, quota);\n\n currentQuota.currentUsage = (currentQuota.currentUsage || 0) + cost;\n\n const key = this.getQuotaKey(identifier, quota.name);\n const ttl = (currentQuota.resetAt || 0) - Math.floor(Date.now() / 1000) + 3600;\n\n await this.store.set(key, currentQuota, ttl);\n\n return currentQuota;\n }\n\n async resetQuota(identifier: string, quota: Quota): Promise<void> {\n const key = this.getQuotaKey(identifier, quota.name);\n await this.store.delete(key);\n }\n\n remaining(quota: Quota): number {\n return Math.max(0, quota.limit - (quota.currentUsage || 0));\n }\n\n isExceeded(quota: Quota): boolean {\n return (quota.currentUsage || 0) >= quota.limit;\n }\n}\n\n// Preset quotas\nexport const QUOTA_FREE_MONTHLY: Quota = {\n name: 'free_monthly_requests',\n limit: 10000,\n period: QuotaPeriod.MONTHLY,\n};\n\nexport const QUOTA_PRO_MONTHLY: Quota = {\n name: 'pro_monthly_requests',\n limit: 100000,\n period: QuotaPeriod.MONTHLY,\n};\n\nexport const QUOTA_ENTERPRISE_MONTHLY: Quota = {\n name: 'enterprise_monthly_requests',\n limit: 1000000,\n period: QuotaPeriod.MONTHLY,\n};\n\nexport const QUOTA_FREE_DAILY: Quota = {\n name: 'free_daily_requests',\n limit: 500,\n period: QuotaPeriod.DAILY,\n};\n\nexport const QUOTA_PRO_DAILY: Quota = {\n name: 'pro_daily_requests',\n limit: 5000,\n period: QuotaPeriod.DAILY,\n};\n","/**\n * Penalty system for abuse detection and progressive rate limiting.\n */\n\nimport { TelemetryHooks } from './telemetry';\n\nexport interface PenaltyConfig {\n threshold: number;\n duration: number;\n multiplier: number;\n decayRate: number;\n}\n\nexport interface Penalty {\n abuseScore: number;\n penaltyUntil: number | null;\n violations: number;\n lastViolation: number | null;\n}\n\nexport class PenaltyManager {\n private config: PenaltyConfig;\n\n constructor(\n private store: any,\n config?: Partial<PenaltyConfig>,\n private telemetry?: TelemetryHooks\n ) {\n this.config = {\n threshold: config?.threshold ?? 10,\n duration: config?.duration ?? 3600,\n multiplier: config?.multiplier ?? 0.5,\n decayRate: config?.decayRate ?? 1.0,\n };\n }\n\n private getPenaltyKey(identifier: string): string {\n return `halt:penalty:${identifier}`;\n }\n\n async getPenalty(identifier: string): Promise<Penalty> {\n const key = this.getPenaltyKey(identifier);\n const stored = await this.store.get(key);\n\n if (!stored) {\n return {\n abuseScore: 0,\n penaltyUntil: null,\n violations: 0,\n lastViolation: null,\n };\n }\n\n const penalty: Penalty = {\n abuseScore: stored.abuseScore || 0,\n penaltyUntil: stored.penaltyUntil || null,\n violations: stored.violations || 0,\n lastViolation: stored.lastViolation || null,\n };\n\n // Apply decay to abuse score\n if (penalty.lastViolation) {\n const hoursElapsed = (Date.now() / 1000 - penalty.lastViolation) / 3600;\n const decay = hoursElapsed * this.config.decayRate;\n penalty.abuseScore = Math.max(0, penalty.abuseScore - decay);\n }\n\n return penalty;\n }\n\n async recordViolation(identifier: string, severity: number = 1.0): Promise<Penalty> {\n const penalty = await this.getPenalty(identifier);\n\n penalty.abuseScore += severity;\n penalty.violations += 1;\n penalty.lastViolation = Math.floor(Date.now() / 1000);\n\n // Check if penalty should be applied\n let penaltyTriggered = false;\n if (penalty.abuseScore >= this.config.threshold && !this.isActive(penalty)) {\n penalty.penaltyUntil = Math.floor(Date.now() / 1000) + this.config.duration;\n penaltyTriggered = true;\n }\n\n await this.savePenalty(identifier, penalty);\n\n this.telemetry?.onViolation?.(identifier, penalty, severity);\n if (penaltyTriggered) {\n this.telemetry?.onPenaltyApplied?.(identifier, penalty);\n }\n\n return penalty;\n }\n\n async applyPenalty(identifier: string, duration?: number): Promise<Penalty> {\n const penalty = await this.getPenalty(identifier);\n\n penalty.penaltyUntil =\n Math.floor(Date.now() / 1000) + (duration ?? this.config.duration);\n\n await this.savePenalty(identifier, penalty);\n\n this.telemetry?.onPenaltyApplied?.(identifier, penalty);\n\n return penalty;\n }\n\n async clearPenalty(identifier: string): Promise<void> {\n const key = this.getPenaltyKey(identifier);\n await this.store.delete(key);\n }\n\n getRateLimitMultiplier(penalty: Penalty): number {\n if (this.isActive(penalty)) {\n return this.config.multiplier;\n }\n return 1.0;\n }\n\n isActive(penalty: Penalty): boolean {\n if (!penalty.penaltyUntil) {\n return false;\n }\n return Math.floor(Date.now() / 1000) < penalty.penaltyUntil;\n }\n\n timeRemaining(penalty: Penalty): number {\n if (!this.isActive(penalty)) {\n return 0;\n }\n return (penalty.penaltyUntil || 0) - Math.floor(Date.now() / 1000);\n }\n\n private async savePenalty(identifier: string, penalty: Penalty): Promise<void> {\n const key = this.getPenaltyKey(identifier);\n const ttl = 7 * 24 * 3600; // 7 days\n\n await this.store.set(key, penalty, ttl);\n }\n}\n\n// Preset penalty configurations\nexport const PENALTY_LENIENT: PenaltyConfig = {\n threshold: 20,\n duration: 1800, // 30 minutes\n multiplier: 0.75,\n decayRate: 2.0,\n};\n\nexport const PENALTY_MODERATE: PenaltyConfig = {\n threshold: 10,\n duration: 3600, // 1 hour\n multiplier: 0.5,\n decayRate: 1.0,\n};\n\nexport const PENALTY_STRICT: PenaltyConfig = {\n threshold: 5,\n duration: 7200, // 2 hours\n multiplier: 0.25,\n decayRate: 0.5,\n};\n","/**\n * Telemetry hooks for observability and monitoring.\n */\n\nimport { Decision } from './decision';\nimport { Quota } from './quota';\nimport { Penalty } from './penalty';\n\nexport interface TelemetryHooks {\n onCheck?(key: string, decision: Decision, metadata?: Record<string, any>): void;\n onAllowed?(key: string, decision: Decision, metadata?: Record<string, any>): void;\n onBlocked?(key: string, decision: Decision, metadata?: Record<string, any>): void;\n onQuotaCheck?(identifier: string, quota: Quota, allowed: boolean): void;\n onQuotaExceeded?(identifier: string, quota: Quota): void;\n onPenaltyApplied?(identifier: string, penalty: Penalty): void;\n onViolation?(identifier: string, penalty: Penalty, severity: number): void;\n}\n\nexport class LoggingTelemetry implements TelemetryHooks {\n constructor(private logger: Console = console) { }\n\n onCheck(key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.logger.debug(\n `Rate limit check: key=${key}, allowed=${decision.allowed}, ` +\n `remaining=${decision.remaining}, metadata=${JSON.stringify(metadata)}`\n );\n }\n\n onAllowed(key: string, decision: Decision, _metadata?: Record<string, any>): void {\n this.logger.info(`Request allowed: key=${key}, remaining=${decision.remaining}`);\n }\n\n onBlocked(key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.logger.warn(\n `Request blocked: key=${key}, retry_after=${decision.retryAfter}s, ` +\n `metadata=${JSON.stringify(metadata)}`\n );\n }\n\n onQuotaCheck(identifier: string, quota: Quota, allowed: boolean): void {\n this.logger.debug(\n `Quota check: identifier=${identifier}, quota=${quota.name}, ` +\n `allowed=${allowed}, remaining=${quota.limit - (quota.currentUsage || 0)}`\n );\n }\n\n onQuotaExceeded(identifier: string, quota: Quota): void {\n this.logger.warn(\n `Quota exceeded: identifier=${identifier}, quota=${quota.name}, ` +\n `limit=${quota.limit}, reset_at=${quota.resetAt}`\n );\n }\n\n onPenaltyApplied(identifier: string, penalty: Penalty): void {\n this.logger.warn(\n `Penalty applied: identifier=${identifier}, ` +\n `abuse_score=${penalty.abuseScore}, penalty_until=${penalty.penaltyUntil}`\n );\n }\n\n onViolation(identifier: string, penalty: Penalty, severity: number): void {\n this.logger.info(\n `Violation recorded: identifier=${identifier}, severity=${severity}, ` +\n `abuse_score=${penalty.abuseScore}, violations=${penalty.violations}`\n );\n }\n}\n\nexport class MetricsTelemetry implements TelemetryHooks {\n constructor(private metricsClient: any) { }\n\n onCheck(_key: string, _decision: Decision, metadata?: Record<string, any>): void {\n this.metricsClient.increment('halt.checks.total', this.getTags(metadata));\n }\n\n onAllowed(_key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.metricsClient.increment('halt.requests.allowed', this.getTags(metadata));\n this.metricsClient.gauge('halt.remaining', decision.remaining, this.getTags(metadata));\n }\n\n onBlocked(_key: string, _decision: Decision, metadata?: Record<string, any>): void {\n this.metricsClient.increment('halt.requests.blocked', this.getTags(metadata));\n }\n\n onQuotaCheck(_identifier: string, quota: Quota, _allowed: boolean): void {\n const tags = { quota: quota.name, period: quota.period };\n this.metricsClient.increment('halt.quota.checks', tags);\n this.metricsClient.gauge(\n 'halt.quota.remaining',\n quota.limit - (quota.currentUsage || 0),\n tags\n );\n }\n\n onQuotaExceeded(_identifier: string, quota: Quota): void {\n const tags = { quota: quota.name, period: quota.period };\n this.metricsClient.increment('halt.quota.exceeded', tags);\n }\n\n onPenaltyApplied(_identifier: string, penalty: Penalty): void {\n this.metricsClient.increment('halt.penalties.applied');\n this.metricsClient.gauge('halt.penalties.abuse_score', penalty.abuseScore);\n }\n\n onViolation(_identifier: string, _penalty: Penalty, severity: number): void {\n this.metricsClient.increment('halt.violations.total');\n this.metricsClient.histogram('halt.violations.severity', severity);\n }\n\n private getTags(metadata?: Record<string, any>): Record<string, any> {\n if (!metadata) {\n return {};\n }\n\n return {\n policy: metadata.policy,\n algorithm: metadata.algorithm,\n };\n }\n}\n\nexport class CompositeTelemetry implements TelemetryHooks {\n constructor(private hooks: TelemetryHooks[]) { }\n\n onCheck(key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.hooks.forEach((hook) => hook.onCheck?.(key, decision, metadata));\n }\n\n onAllowed(key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.hooks.forEach((hook) => hook.onAllowed?.(key, decision, metadata));\n }\n\n onBlocked(key: string, decision: Decision, metadata?: Record<string, any>): void {\n this.hooks.forEach((hook) => hook.onBlocked?.(key, decision, metadata));\n }\n\n onQuotaCheck(identifier: string, quota: Quota, allowed: boolean): void {\n this.hooks.forEach((hook) => hook.onQuotaCheck?.(identifier, quota, allowed));\n }\n\n onQuotaExceeded(identifier: string, quota: Quota): void {\n this.hooks.forEach((hook) => hook.onQuotaExceeded?.(identifier, quota));\n }\n\n onPenaltyApplied(identifier: string, penalty: Penalty): void {\n this.hooks.forEach((hook) => hook.onPenaltyApplied?.(identifier, penalty));\n }\n\n onViolation(identifier: string, penalty: Penalty, severity: number): void {\n this.hooks.forEach((hook) => hook.onViolation?.(identifier, penalty, severity));\n }\n}\n","/**\n * In-process statistics collector for rate-limit observability.\n *\n * Implements `TelemetryHooks`, so you plug it into a RateLimiter (and optionally\n * QuotaManager / PenaltyManager) and it aggregates everything in memory. Call\n * `snapshot()` to expose a `/halt/stats` endpoint or log periodically.\n *\n * It is per-process by design — for a fleet, run it on each instance and roll up\n * across instances with the OpenTelemetry adapter (see observability/otel). Memory\n * is bounded: the tracked-key table is capped and the smallest counters are evicted.\n *\n * const stats = new StatsCollector();\n * const limiter = new RateLimiter({ store, policy, telemetry: stats });\n * app.get('/halt/stats', (_req, res) => res.json(stats.snapshot()));\n */\n\nimport { Decision } from './decision';\nimport { TelemetryHooks } from './telemetry';\nimport { Quota } from './quota';\nimport { Penalty } from './penalty';\n\nexport interface StatsCollectorOptions {\n /** How many top limited keys `snapshot()` returns (default 20). */\n topN?: number;\n /** Max distinct keys tracked for the top-N table before eviction (default 10000). */\n maxTrackedKeys?: number;\n}\n\ninterface Tally {\n allowed: number;\n blocked: number;\n}\n\ninterface EndpointTally extends Tally {\n cost: number;\n}\n\nexport interface StatsSnapshot {\n allowedTotal: number;\n blockedTotal: number;\n /** Per-policy allowed/blocked counts. */\n byPolicy: Record<string, Tally>;\n /** Per-endpoint allowed/blocked counts and consumed cost. */\n byEndpoint: Record<string, EndpointTally>;\n /** Highest-blocked keys (users / API keys / IPs), descending. */\n topLimitedKeys: Array<{ key: string; blocked: number }>;\n /** Consumed cost per plan (allowed requests only). */\n costByPlan: Record<string, number>;\n /** Count of quota-exceeded events (from QuotaManager telemetry). */\n quotaExceeded: number;\n /** Count of penalties applied (from PenaltyManager telemetry). */\n penaltiesApplied: number;\n /** Count of recorded violations (from PenaltyManager telemetry). */\n violations: number;\n /** Number of distinct keys currently tracked for top-N. */\n trackedKeys: number;\n}\n\nexport class StatsCollector implements TelemetryHooks {\n private topN: number;\n private maxTrackedKeys: number;\n\n private allowedTotal = 0;\n private blockedTotal = 0;\n private byPolicy = new Map<string, Tally>();\n private byEndpoint = new Map<string, EndpointTally>();\n private limitedKeys = new Map<string, number>();\n private costByPlan = new Map<string, number>();\n private quotaExceededCount = 0;\n private penaltiesAppliedCount = 0;\n private violationsCount = 0;\n\n constructor(options: StatsCollectorOptions = {}) {\n this.topN = options.topN ?? 20;\n this.maxTrackedKeys = options.maxTrackedKeys ?? 10000;\n }\n\n onAllowed(_key: string, _decision: Decision, metadata?: Record<string, any>): void {\n this.allowedTotal++;\n const cost = Number(metadata?.cost ?? 1);\n this.policyTally(metadata).allowed++;\n\n const endpoint = metadata?.endpoint;\n if (endpoint) {\n const e = this.endpointTally(endpoint);\n e.allowed++;\n e.cost += cost;\n }\n\n const plan = metadata?.plan ?? metadata?.policy ?? 'unknown';\n this.costByPlan.set(plan, (this.costByPlan.get(plan) ?? 0) + cost);\n }\n\n onBlocked(key: string, _decision: Decision, metadata?: Record<string, any>): void {\n this.blockedTotal++;\n this.policyTally(metadata).blocked++;\n\n const endpoint = metadata?.endpoint;\n if (endpoint) {\n this.endpointTally(endpoint).blocked++;\n }\n\n if (key) this.trackLimitedKey(key);\n }\n\n onQuotaExceeded(_identifier: string, _quota: Quota): void {\n this.quotaExceededCount++;\n }\n\n onPenaltyApplied(_identifier: string, _penalty: Penalty): void {\n this.penaltiesAppliedCount++;\n }\n\n onViolation(_identifier: string, _penalty: Penalty, _severity: number): void {\n this.violationsCount++;\n }\n\n /** Point-in-time view of the aggregated stats. */\n snapshot(): StatsSnapshot {\n const topLimitedKeys = [...this.limitedKeys.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, this.topN)\n .map(([key, blocked]) => ({ key, blocked }));\n\n return {\n allowedTotal: this.allowedTotal,\n blockedTotal: this.blockedTotal,\n byPolicy: mapToObject(this.byPolicy),\n byEndpoint: mapToObject(this.byEndpoint),\n topLimitedKeys,\n costByPlan: mapToObject(this.costByPlan),\n quotaExceeded: this.quotaExceededCount,\n penaltiesApplied: this.penaltiesAppliedCount,\n violations: this.violationsCount,\n trackedKeys: this.limitedKeys.size,\n };\n }\n\n /** Clear all counters (e.g. after exporting). */\n reset(): void {\n this.allowedTotal = 0;\n this.blockedTotal = 0;\n this.byPolicy.clear();\n this.byEndpoint.clear();\n this.limitedKeys.clear();\n this.costByPlan.clear();\n this.quotaExceededCount = 0;\n this.penaltiesAppliedCount = 0;\n this.violationsCount = 0;\n }\n\n private policyTally(metadata?: Record<string, any>): Tally {\n const policy = metadata?.policy ?? 'unknown';\n let t = this.byPolicy.get(policy);\n if (!t) {\n t = { allowed: 0, blocked: 0 };\n this.byPolicy.set(policy, t);\n }\n return t;\n }\n\n private endpointTally(endpoint: string): EndpointTally {\n let e = this.byEndpoint.get(endpoint);\n if (!e) {\n e = { allowed: 0, blocked: 0, cost: 0 };\n this.byEndpoint.set(endpoint, e);\n }\n return e;\n }\n\n private trackLimitedKey(key: string): void {\n const current = this.limitedKeys.get(key);\n if (current !== undefined) {\n this.limitedKeys.set(key, current + 1);\n return;\n }\n if (this.limitedKeys.size >= this.maxTrackedKeys) {\n this.evictSmallest();\n }\n this.limitedKeys.set(key, 1);\n }\n\n /** Evict the lowest-count tracked key to keep memory bounded. */\n private evictSmallest(): void {\n let minKey: string | undefined;\n let minVal = Infinity;\n for (const [k, v] of this.limitedKeys) {\n if (v < minVal) {\n minVal = v;\n minKey = k;\n }\n }\n if (minKey !== undefined) this.limitedKeys.delete(minKey);\n }\n}\n\nfunction mapToObject<V>(map: Map<string, V>): Record<string, V> {\n const out: Record<string, V> = {};\n for (const [k, v] of map) out[k] = v;\n return out;\n}\n","/**\n * OpenTelemetry metrics adapter for Halt.\n *\n * Implements `TelemetryHooks` over the OTel metrics API. You inject a Meter, so\n * Halt keeps no hard dependency on `@opentelemetry/api`:\n *\n * import { metrics } from '@opentelemetry/api';\n * import { OpenTelemetryMetrics } from 'halt-rate';\n *\n * const telemetry = new OpenTelemetryMetrics(metrics.getMeter('halt'));\n * const limiter = new RateLimiter({ store, policy, telemetry });\n *\n * Request spans are already covered by the limiter's `otelTracer` option; this\n * adapter adds counters for dashboards/alerts. Roll up across instances with your\n * OTel collector.\n */\n\nimport { Decision } from '../core/decision';\nimport { TelemetryHooks } from '../core/telemetry';\nimport { Quota } from '../core/quota';\nimport { Penalty } from '../core/penalty';\n\n/** Minimal structural types satisfied by `@opentelemetry/api` (no hard dep). */\nexport interface OTelCounterLike {\n add(value: number, attributes?: Record<string, string | number | boolean>): void;\n}\nexport interface OTelMeterLike {\n createCounter(name: string, options?: { description?: string; unit?: string }): OTelCounterLike;\n}\n\nexport class OpenTelemetryMetrics implements TelemetryHooks {\n private requests: OTelCounterLike;\n private blocked: OTelCounterLike;\n private cost: OTelCounterLike;\n private quotaExceededCounter: OTelCounterLike;\n private penaltyAppliedCounter: OTelCounterLike;\n private violationsCounter: OTelCounterLike;\n\n constructor(meter: OTelMeterLike) {\n this.requests = meter.createCounter('halt.requests', {\n description: 'Total rate-limit checks',\n });\n this.blocked = meter.createCounter('halt.blocked', {\n description: 'Rate-limited (blocked) requests',\n });\n this.cost = meter.createCounter('halt.cost', {\n description: 'Consumed request cost (weighted endpoints)',\n });\n this.quotaExceededCounter = meter.createCounter('halt.quota.exceeded', {\n description: 'Quota-exceeded events',\n });\n this.penaltyAppliedCounter = meter.createCounter('halt.penalty.applied', {\n description: 'Penalties applied (abuse controls)',\n });\n this.violationsCounter = meter.createCounter('halt.violations', {\n description: 'Recorded abuse violations',\n });\n }\n\n onAllowed(_key: string, _decision: Decision, metadata?: Record<string, any>): void {\n const policy = String(metadata?.policy ?? 'unknown');\n this.requests.add(1, { policy, allowed: 'true' });\n const endpoint = metadata?.endpoint;\n const plan = String(metadata?.plan ?? metadata?.policy ?? 'unknown');\n const cost = Number(metadata?.cost ?? 1);\n this.cost.add(cost, endpoint ? { endpoint: String(endpoint), plan } : { plan });\n }\n\n onBlocked(_key: string, _decision: Decision, metadata?: Record<string, any>): void {\n const policy = String(metadata?.policy ?? 'unknown');\n this.requests.add(1, { policy, allowed: 'false' });\n const endpoint = metadata?.endpoint;\n this.blocked.add(1, endpoint ? { policy, endpoint: String(endpoint) } : { policy });\n }\n\n onQuotaExceeded(_identifier: string, quota: Quota): void {\n this.quotaExceededCounter.add(1, { quota: quota.name });\n }\n\n onPenaltyApplied(_identifier: string, _penalty: Penalty): void {\n this.penaltyAppliedCounter.add(1);\n }\n\n onViolation(_identifier: string, _penalty: Penalty, severity: number): void {\n this.violationsCounter.add(1, { severity });\n }\n}\n"]}