import { User, RateLimitConfig } from './types.js'; export interface RateLimitContext { ip?: string; fingerprint?: string; userAgent?: string; sessionId?: string; } export interface RateLimitResult { allowed: boolean; remaining: number; resetTime: number; limit: number; windowMs: number; limitType: RateLimitWindowType; } export type RateLimitWindowType = 'hourly' | 'daily' | 'custom'; export interface RateLimitUsage { count: number; limit: number; resetTime: number; windowMs: number; limitType: RateLimitWindowType; } export interface RateLimitStats { totalKeys: number; config: RateLimitConfig; type: 'memory'; } /** * Logger interface for RateLimitTool */ export interface RateLimitLogger { info: (message: string, meta?: Record) => void; warn: (message: string, meta?: Record) => void; } export declare const setRateLimitLogger: (logger: RateLimitLogger) => void; export declare class RateLimitTool { private readonly memoryStore; private readonly lockMap; private readonly identifierWindows; protected cleanupInterval: NodeJS.Timeout | null; private cleanupSignalHandlers; private rateLimitCache; private cacheTimestamp; private static readonly CACHE_TTL_MS; private static readonly FALLBACK_CACHE_TTL_MS; private isFallbackCache; private vipAllowlist; private vipAllowlistTimestamp; private adminEmailSet; private adminEmailEnvSignature; private cachedFallbackAdminEmails; private fallbackAdminEmailEnvSignature; private adminUidSet; private adminUidEnvSignature; private secretManagerClient; private static readonly MAX_TRACKED_IDENTIFIERS; private static readonly CLEANUP_INTERVAL_MS; private static readonly CLEANUP_WINDOW_MS; private static isTruthy; private static maskId; private static isLikelyFirebaseUid; constructor(); /** * Dispose of resources such as intervals and signal handlers. * Intended primarily for test environments. */ dispose(): Promise; /** * Get VIP allowlist from Secret Manager */ private getVipAllowlist; /** * Get current rate limit configuration from Secret Manager or environment defaults */ private getRateLimitConfig; /** * Get rate limit for user type */ private getRateLimit; private static isValidEmail; /** * Assembles fallback admin emails using builtin constants and validated env overrides. * * Sources: * - RATE_LIMIT_CONTACT_EMAIL: single contact address. * - RATE_LIMIT_FALLBACK_ADMIN_EMAILS: comma-separated list of fallback admins. * * Results are cached and only recomputed when relevant env vars change. */ private getFallbackAdminEmails; private getAdminEmailSet; /** * FIX: Get admin UIDs as fallback when email is missing from Firebase token * * This resolves the bug where admin users without email claim in their * Firebase token get treated as anonymous, hitting 5/hour rate limit * instead of 1000/hour admin limit. * * Usage: Set FIREBASE_ADMIN_UIDS environment variable with comma-separated UIDs * Example: FIREBASE_ADMIN_UIDS=UlET1VDO7ORksFiAPQ2b9jI9K9t1,anotherUID123 */ private getAdminUidSet; private getMultiWindowLimits; private mergeWindowResults; private selectUsageWindow; private determineLimitType; /** * Check if request is allowed under rate limits * * Note: This implementation uses in-memory storage. For distributed deployments * with multiple instances, consider using Redis-backed rate limiting. */ checkRateLimit(user: User | null, context?: RateLimitContext): Promise; /** * Check if user is authenticated but not admin or VIP * * FIX: Also checks UID-based admin status when email is missing * This ensures admin users with missing email claims still get admin privileges */ private isAuthenticatedNonVIP; /** * Build a stable identifier for rate limiting based on authentication and client metadata */ private buildIdentifier; private buildContextIdentifier; private normalizeIp; private sanitizePart; /** * Memory-based rate limiting */ /** * Truly atomic memory-based rate limiting with proper concurrency control using async-mutex */ private checkRateLimitMemoryAtomic; /** * Perform the actual atomic rate limit check */ private performAtomicRateCheck; /** * Get current usage for a user/IP */ getCurrentUsage(user: User | null, context?: RateLimitContext): Promise; /** * Memory-based current usage */ private getCurrentUsageMemory; /** * Reset rate limit for a specific user/IP (memory-only) */ resetRateLimit(user: User | null, context?: RateLimitContext): Promise; /** * Get statistics about current rate limiting (memory-only) */ getStats(): Promise; /** * Start periodic cleanup to keep the in-memory store bounded over time. */ private startPeriodicCleanup; /** * Stop periodic cleanup */ private stopCleanup; /** * Remove identifiers whose requests have fallen outside the cleanup window. */ cleanupExpiredEntries(): void; /** * Enforce an upper bound on tracked identifiers using efficient LRU-style eviction. * NOTE: This is a temporary solution - production should use Redis for distributed rate limiting. */ private enforceMemoryLimits; private deleteIdentifierState; private pruneRequests; /** * Health check */ healthCheck(): Promise<{ status: string; details: any; }>; } //# sourceMappingURL=RateLimitTool.d.ts.map