{"version":3,"file":"rate-limiter.mjs","sources":["../../../../src/lib/api/advanced/rate-limiter.ts"],"sourcesContent":["/**\n * Client-Side Rate Limiter\n *\n * Implements client-side rate limiting to prevent overwhelming APIs\n * and respect rate limit headers from servers.\n *\n * @module api/advanced/rate-limiter\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Rate limit configuration.\n */\nexport interface RateLimitConfig {\n  /** Maximum requests per window */\n  maxRequests: number;\n  /** Time window in milliseconds */\n  windowMs: number;\n  /** Strategy for handling exceeded limits */\n  strategy?: 'queue' | 'reject' | 'delay';\n  /** Maximum queue size (for queue strategy) */\n  maxQueueSize?: number;\n  /** Maximum delay in milliseconds (for delay strategy) */\n  maxDelay?: number;\n  /** Key generator for per-endpoint limits */\n  keyGenerator?: (endpoint: string) => string;\n}\n\n/**\n * Rate limit status.\n */\nexport interface RateLimitStatus {\n  /** Number of requests remaining in current window */\n  remaining: number;\n  /** Total limit for the window */\n  limit: number;\n  /** Time until window resets (ms) */\n  resetIn: number;\n  /** Whether currently rate limited */\n  isLimited: boolean;\n  /** Current queue size */\n  queueSize: number;\n}\n\n/**\n * Server rate limit headers.\n */\nexport interface RateLimitHeaders {\n  /** Remaining requests */\n  'x-ratelimit-remaining'?: string;\n  /** Total limit */\n  'x-ratelimit-limit'?: string;\n  /** Reset timestamp */\n  'x-ratelimit-reset'?: string;\n  /** Retry after (seconds) */\n  'retry-after'?: string;\n}\n\n/**\n * Queued request entry.\n */\ninterface QueuedRequest<T> {\n  /** Execute function */\n  execute: () => Promise<T>;\n  /** Resolve callback */\n  resolve: (value: T) => void;\n  /** Reject callback */\n  reject: (error: Error) => void;\n  /** Request timestamp */\n  timestamp: number;\n  /** Request key */\n  key: string;\n}\n\n// =============================================================================\n// Rate Limiter Class\n// =============================================================================\n\n/**\n * Client-Side Rate Limiter.\n *\n * Implements multiple rate limiting strategies to prevent API abuse\n * and handle server-imposed rate limits gracefully.\n *\n * @example\n * ```typescript\n * const limiter = new RateLimiter({\n *   maxRequests: 100,\n *   windowMs: 60000, // 1 minute\n *   strategy: 'queue',\n * });\n *\n * // Wrap API calls\n * const result = await limiter.execute('/users', () =>\n *   fetch('/api/users')\n * );\n *\n * // Check status\n * const status = limiter.getStatus('/users');\n * console.log(`${status.remaining} requests remaining`);\n * ```\n */\nexport class RateLimiter {\n  private config: Required<RateLimitConfig>;\n  private windows: Map<string, { count: number; resetAt: number }>;\n  private readonly queue: Map<string, QueuedRequest<unknown>[]>;\n  private serverLimits: Map<string, { remaining: number; resetAt: number }>;\n  private processing: Set<string>;\n\n  /**\n   * Create a new rate limiter.\n   *\n   * @param config - Rate limit configuration\n   */\n  constructor(config: RateLimitConfig) {\n    this.config = {\n      strategy: 'queue',\n      maxQueueSize: 100,\n      maxDelay: 30000,\n      keyGenerator: (endpoint) => endpoint.split('?')[0] ?? endpoint,\n      ...config,\n    };\n\n    this.windows = new Map();\n    this.queue = new Map();\n    this.serverLimits = new Map();\n    this.processing = new Set();\n  }\n\n  // ===========================================================================\n  // Main Execution\n  // ===========================================================================\n\n  /**\n   * Execute a request with rate limiting.\n   *\n   * @param endpoint - Request endpoint\n   * @param fn - Function to execute\n   * @returns Promise resolving to function result\n   */\n  async execute<T>(endpoint: string, fn: () => Promise<T>): Promise<T> {\n    const key = this.config.keyGenerator(endpoint);\n\n    // Check server-imposed limits first\n    if (this.isServerLimited(key)) {\n      const serverLimit = this.serverLimits.get(key);\n      if (serverLimit == null) {\n        throw new Error('Server limit not found');\n      }\n      const waitTime = serverLimit.resetAt - Date.now();\n\n      switch (this.config.strategy) {\n        case 'reject':\n          throw new RateLimitError('Server rate limit exceeded', waitTime, key);\n\n        case 'delay':\n          await this.delay(Math.min(waitTime, this.config.maxDelay));\n          break;\n\n        case 'queue':\n        default:\n          return this.enqueue(key, fn);\n      }\n    }\n\n    // Check client-side limits\n    const window = this.getOrCreateWindow(key);\n    const now = Date.now();\n\n    // Reset window if expired\n    if (now >= window.resetAt) {\n      window.count = 0;\n      window.resetAt = now + this.config.windowMs;\n    }\n\n    // Check if limit exceeded\n    if (window.count >= this.config.maxRequests) {\n      const waitTime = window.resetAt - now;\n\n      switch (this.config.strategy) {\n        case 'reject':\n          throw new RateLimitError('Rate limit exceeded', waitTime, key);\n\n        case 'delay':\n          await this.delay(Math.min(waitTime, this.config.maxDelay));\n          // Reset window after delay\n          window.count = 0;\n          window.resetAt = Date.now() + this.config.windowMs;\n          break;\n\n        case 'queue':\n        default:\n          return this.enqueue(key, fn);\n      }\n    }\n\n    // Execute request\n    window.count++;\n\n    try {\n      return await fn();\n    } catch (error) {\n      // Rollback count on error\n      window.count = Math.max(0, window.count - 1);\n      throw error;\n    }\n  }\n\n  /**\n   * Check if request would be rate limited.\n   *\n   * @param endpoint - Request endpoint\n   * @returns Whether request would be limited\n   */\n  wouldBeLimited(endpoint: string): boolean {\n    const key = this.config.keyGenerator(endpoint);\n\n    // Check server limits\n    if (this.isServerLimited(key)) {\n      return true;\n    }\n\n    // Check client limits\n    const window = this.windows.get(key);\n    if (!window) return false;\n\n    const now = Date.now();\n    if (now >= window.resetAt) return false;\n\n    return window.count >= this.config.maxRequests;\n  }\n\n  // ===========================================================================\n  // Queue Management\n  // ===========================================================================\n\n  /**\n   * Update rate limits from server response headers.\n   *\n   * @param endpoint - Request endpoint\n   * @param headers - Response headers\n   */\n  updateFromHeaders(endpoint: string, headers: RateLimitHeaders): void {\n    const key = this.config.keyGenerator(endpoint);\n\n    const remaining = headers['x-ratelimit-remaining'];\n    const reset = headers['x-ratelimit-reset'];\n    const retryAfter = headers['retry-after'];\n\n    if (remaining !== undefined || reset !== undefined) {\n      let resetAt: number;\n\n      if (retryAfter != null && retryAfter !== '') {\n        // Retry-After can be seconds or HTTP date\n        const seconds = parseInt(retryAfter, 10);\n        if (!isNaN(seconds)) {\n          resetAt = Date.now() + seconds * 1000;\n        } else {\n          resetAt = new Date(retryAfter).getTime();\n        }\n      } else if (reset != null && reset !== '') {\n        // Reset can be Unix timestamp (seconds) or milliseconds\n        const resetValue = parseInt(reset, 10);\n        resetAt = resetValue > 1e12 ? resetValue : resetValue * 1000;\n      } else {\n        resetAt = Date.now() + this.config.windowMs;\n      }\n\n      this.serverLimits.set(key, {\n        remaining: (remaining != null && remaining !== '') ? parseInt(remaining, 10) : 0,\n        resetAt,\n      });\n    }\n  }\n\n  /**\n   * Handle 429 Too Many Requests response.\n   *\n   * @param endpoint - Request endpoint\n   * @param retryAfter - Retry-After header value\n   */\n  handle429(endpoint: string, retryAfter?: string): void {\n    const key = this.config.keyGenerator(endpoint);\n\n    let resetAt: number;\n\n    if (retryAfter != null && retryAfter !== '') {\n      const seconds = parseInt(retryAfter, 10);\n      if (!isNaN(seconds)) {\n        resetAt = Date.now() + seconds * 1000;\n      } else {\n        resetAt = new Date(retryAfter).getTime();\n      }\n    } else {\n      // Default to 60 seconds\n      resetAt = Date.now() + 60000;\n    }\n\n    this.serverLimits.set(key, {\n      remaining: 0,\n      resetAt,\n    });\n  }\n\n  /**\n   * Get rate limit status for an endpoint.\n   *\n   * @param endpoint - Request endpoint\n   * @returns Rate limit status\n   */\n  getStatus(endpoint: string): RateLimitStatus {\n    const key = this.config.keyGenerator(endpoint);\n    const window = this.windows.get(key);\n    const serverLimit = this.serverLimits.get(key);\n    const keyQueue = this.queue.get(key);\n\n    const now = Date.now();\n\n    // Check server limits first\n    if (serverLimit && now < serverLimit.resetAt) {\n      return {\n        remaining: serverLimit.remaining,\n        limit: this.config.maxRequests,\n        resetIn: serverLimit.resetAt - now,\n        isLimited: serverLimit.remaining <= 0,\n        queueSize: keyQueue?.length ?? 0,\n      };\n    }\n\n    // Check client limits\n    if (window && now < window.resetAt) {\n      return {\n        remaining: Math.max(0, this.config.maxRequests - window.count),\n        limit: this.config.maxRequests,\n        resetIn: window.resetAt - now,\n        isLimited: window.count >= this.config.maxRequests,\n        queueSize: keyQueue?.length ?? 0,\n      };\n    }\n\n    return {\n      remaining: this.config.maxRequests,\n      limit: this.config.maxRequests,\n      resetIn: 0,\n      isLimited: false,\n      queueSize: keyQueue?.length ?? 0,\n    };\n  }\n\n  // ===========================================================================\n  // Server Rate Limit Handling\n  // ===========================================================================\n\n  /**\n   * Clear rate limit tracking for an endpoint.\n   *\n   * @param endpoint - Request endpoint\n   */\n  clear(endpoint: string): void {\n    const key = this.config.keyGenerator(endpoint);\n    this.windows.delete(key);\n    this.serverLimits.delete(key);\n\n    // Reject queued requests\n    const keyQueue = this.queue.get(key);\n    if (keyQueue) {\n      for (const entry of keyQueue) {\n        entry.reject(new Error('Rate limiter cleared'));\n      }\n      this.queue.delete(key);\n    }\n  }\n\n  /**\n   * Clear all rate limit tracking.\n   */\n  clearAll(): void {\n    // Reject all queued requests\n    for (const [, keyQueue] of this.queue) {\n      for (const entry of keyQueue) {\n        entry.reject(new Error('Rate limiter cleared'));\n      }\n    }\n\n    this.windows.clear();\n    this.serverLimits.clear();\n    this.queue.clear();\n  }\n\n  /**\n   * Get all tracked endpoints.\n   */\n  getTrackedEndpoints(): string[] {\n    return Array.from(\n      new Set([\n        ...this.windows.keys(),\n        ...this.serverLimits.keys(),\n        ...this.queue.keys(),\n      ])\n    );\n  }\n\n  // ===========================================================================\n  // Status & Management\n  // ===========================================================================\n\n  /**\n   * Enqueue a request for later execution.\n   */\n  private async enqueue<T>(key: string, fn: () => Promise<T>): Promise<T> {\n    const keyQueue = this.queue.get(key) ?? [];\n\n    if (keyQueue.length >= this.config.maxQueueSize) {\n      throw new RateLimitError(\n        'Rate limit queue full',\n        this.getWaitTime(key),\n        key\n      );\n    }\n\n    return new Promise<T>((resolve, reject) => {\n      const entry: QueuedRequest<T> = {\n        execute: fn,\n        resolve: resolve as (value: unknown) => void,\n        reject,\n        timestamp: Date.now(),\n        key,\n      };\n\n      keyQueue.push(entry as QueuedRequest<unknown>);\n      this.queue.set(key, keyQueue);\n\n      // Start processing queue\n      void this.processQueue(key);\n    });\n  }\n\n  /**\n   * Process queued requests.\n   */\n  private async processQueue(key: string): Promise<void> {\n    // Prevent concurrent processing\n    if (this.processing.has(key)) {\n      return;\n    }\n\n    this.processing.add(key);\n\n    try {\n      const keyQueue = this.queue.get(key);\n      if (!keyQueue || keyQueue.length === 0) {\n        return;\n      }\n\n      while (keyQueue.length > 0) {\n        // Wait until we can make a request\n        const waitTime = this.getWaitTime(key);\n        if (waitTime > 0) {\n          await this.delay(Math.min(waitTime, 1000)); // Check every second\n          continue;\n        }\n\n        const entry = keyQueue.shift();\n        if (entry == null) break;\n\n        const window = this.getOrCreateWindow(key);\n        window.count++;\n\n        try {\n          const result = await entry.execute();\n          entry.resolve(result);\n        } catch (error) {\n          window.count = Math.max(0, window.count - 1);\n          entry.reject(error as Error);\n        }\n      }\n    } finally {\n      this.processing.delete(key);\n    }\n  }\n\n  /**\n   * Get wait time until next request can be made.\n   */\n  private getWaitTime(key: string): number {\n    // Check server limits\n    const serverLimit = this.serverLimits.get(key);\n    if (serverLimit && serverLimit.remaining <= 0) {\n      return Math.max(0, serverLimit.resetAt - Date.now());\n    }\n\n    // Check client limits\n    const window = this.windows.get(key);\n    if (!window) return 0;\n\n    const now = Date.now();\n    if (now >= window.resetAt) return 0;\n    if (window.count < this.config.maxRequests) return 0;\n\n    return window.resetAt - now;\n  }\n\n  /**\n   * Check if server has imposed rate limit.\n   */\n  private isServerLimited(key: string): boolean {\n    const limit = this.serverLimits.get(key);\n    if (!limit) return false;\n\n    const now = Date.now();\n\n    // Clear expired limits\n    if (now >= limit.resetAt) {\n      this.serverLimits.delete(key);\n      return false;\n    }\n\n    return limit.remaining <= 0;\n  }\n\n  // ===========================================================================\n  // Helper Methods\n  // ===========================================================================\n\n  /**\n   * Get or create window for key.\n   */\n  private getOrCreateWindow(key: string): { count: number; resetAt: number } {\n    let window = this.windows.get(key);\n\n    if (!window) {\n      window = {\n        count: 0,\n        resetAt: Date.now() + this.config.windowMs,\n      };\n      this.windows.set(key, window);\n    }\n\n    return window;\n  }\n\n  /**\n   * Delay execution.\n   */\n  private async delay(ms: number): Promise<void> {\n    return new Promise(resolve => setTimeout(resolve, ms));\n  }\n}\n\n// =============================================================================\n// Rate Limit Error\n// =============================================================================\n\n/**\n * Error thrown when rate limit is exceeded.\n */\nexport class RateLimitError extends Error {\n  /** Time until rate limit resets (ms) */\n  readonly retryAfter: number;\n  /** Endpoint that was rate limited */\n  readonly endpoint: string;\n\n  constructor(message: string, retryAfter: number, endpoint: string) {\n    super(message);\n    this.name = 'RateLimitError';\n    this.retryAfter = retryAfter;\n    this.endpoint = endpoint;\n  }\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Create a new rate limiter.\n *\n * @param config - Rate limit configuration\n * @returns RateLimiter instance\n */\nexport function createRateLimiter(config: RateLimitConfig): RateLimiter {\n  return new RateLimiter(config);\n}\n\n// =============================================================================\n// Preset Configurations\n// =============================================================================\n\n/**\n * Common rate limit presets.\n */\nexport const RATE_LIMIT_PRESETS = {\n  /** Conservative: 60 requests/minute */\n  conservative: {\n    maxRequests: 60,\n    windowMs: 60000,\n    strategy: 'queue' as const,\n  },\n  /** Standard: 100 requests/minute */\n  standard: {\n    maxRequests: 100,\n    windowMs: 60000,\n    strategy: 'queue' as const,\n  },\n  /** Aggressive: 300 requests/minute */\n  aggressive: {\n    maxRequests: 300,\n    windowMs: 60000,\n    strategy: 'delay' as const,\n  },\n  /** Burst: 30 requests/second */\n  burst: {\n    maxRequests: 30,\n    windowMs: 1000,\n    strategy: 'queue' as const,\n    maxQueueSize: 50,\n  },\n};\n"],"names":["RateLimiter","config","endpoint","fn","key","serverLimit","waitTime","RateLimitError","window","now","error","headers","remaining","reset","retryAfter","resetAt","seconds","resetValue","keyQueue","entry","resolve","reject","result","limit","ms","message","createRateLimiter","RATE_LIMIT_PRESETS"],"mappings":"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"}