/** * Bounded LRU (Least Recently Used) Cache * * A memory-safe cache implementation with: * - Maximum entry limits (LRU eviction) * - TTL (time-to-live) support * - Automatic cleanup of expired entries * * Memory Tracking Documentation: * ============================== * Each cache entry consumes approximately: * - Key string: 2 bytes per character (JS strings are UTF-16) * - Entry object overhead: ~32 bytes (object header + hidden class) * - value: varies (stored by reference, not counted) * - expiresAt: 8 bytes (number) * - lastAccessed: 8 bytes (number) * - Total overhead per entry: ~48 bytes + (key.length * 2) bytes * * For a 1000-entry cache with average 20-char keys: * - Memory overhead: ~88KB (excluding cached values) * * LRU Implementation: * - Uses Map's insertion order for O(1) LRU eviction * - On cache hit, entry is deleted and re-inserted to move to end (most recent) * - Eviction simply removes the first entry (oldest/least recent) * - This provides O(1) eviction vs O(n) scanning for oldest timestamp * * @module @dotdo/postgres-shared/cache */ /** * Configuration for the bounded cache */ export interface BoundedCacheConfig { /** * Maximum number of entries to store in the cache. * When exceeded, least recently used entries are evicted. * @default 1000 */ maxSize?: number; /** * Default TTL in milliseconds for cache entries. * Entries older than this are considered expired. * @default 60000 (1 minute) */ defaultTTL?: number; /** * Interval in milliseconds for automatic cleanup of expired entries. * Set to 0 to disable automatic cleanup. * @default 60000 (1 minute) */ cleanupInterval?: number; } /** * A bounded LRU cache with TTL support * * Features: * - O(1) get/set operations (Map-based) * - LRU eviction when maxSize is exceeded * - TTL-based expiration * - Automatic periodic cleanup of expired entries * - Memory-bounded to prevent unbounded growth * * @example * ```typescript * const cache = new BoundedCache({ * maxSize: 100, * defaultTTL: 30000, // 30 seconds * }) * * cache.set('key', 'value') * const value = cache.get('key') // 'value' or null if expired * ``` */ export declare class BoundedCache { private readonly cache; private readonly config; private cleanupTimer; private _evictionCount; private _hitCount; private _missCount; constructor(config?: BoundedCacheConfig); /** * Get a value from the cache * * Moves the entry to the end of the Map (most recently used) via delete-and-reinsert. * Returns null if the entry doesn't exist or is expired. * * Time complexity: O(1) * * @param key - The cache key * @returns The cached value or null */ get(key: string): T | null; /** * Check if a key exists and is not expired * * @param key - The cache key * @returns true if key exists and is not expired */ has(key: string): boolean; /** * Set a value in the cache * * If the cache is at capacity, the least recently used entry is evicted. * * Time complexity: O(1) * * @param key - The cache key * @param value - The value to cache * @param ttl - Optional TTL in milliseconds (overrides defaultTTL) */ set(key: string, value: T, ttl?: number): void; /** * Delete a specific key from the cache * * @param key - The cache key to delete * @returns true if the key was deleted */ delete(key: string): boolean; /** * Clear all entries from the cache */ clear(): void; /** * Get the current number of entries in the cache */ get size(): number; /** * Get cache statistics */ get stats(): CacheStats; /** * Get estimated memory usage in bytes (excluding cached values) * * This is useful for monitoring cache memory overhead. * Approximately 48 bytes per entry + 2 bytes per key character. */ get estimatedMemoryBytes(): number; /** * Reset statistics counters */ resetStats(): void; /** * Cleanup expired entries * * This is called automatically based on cleanupInterval, * but can also be called manually. * * @returns Number of entries removed */ cleanup(): number; /** * Stop the automatic cleanup timer * * Call this when disposing of the cache to prevent memory leaks. */ dispose(): void; /** * Get all non-expired keys in the cache */ keys(): string[]; /** * Evict the least recently used entry * * Time complexity: O(1) - simply removes the first entry in the Map, * which is the oldest due to our delete-and-reinsert LRU strategy. */ private evictLRU; /** * Start the automatic cleanup timer */ private startCleanup; /** * Stop the automatic cleanup timer */ private stopCleanup; } /** * Cache statistics */ export interface CacheStats { /** Current number of entries */ size: number; /** Maximum allowed entries */ maxSize: number; /** Number of cache hits */ hitCount: number; /** Number of cache misses */ missCount: number; /** Number of LRU evictions */ evictionCount: number; /** Hit rate (0-1) */ hitRate: number; } /** * Token validation result (for token caching) */ export interface TokenValidationResult { valid: boolean; user?: { id: string; email: string; name?: string; metadata?: Record; }; error?: string; expiresAt?: Date; } /** * Configuration for the token cache */ export interface TokenCacheConfig extends BoundedCacheConfig { /** * Whether to cache invalid token results * @default false */ cacheInvalidTokens?: boolean; /** * TTL for invalid token cache entries (if cacheInvalidTokens is true) * @default 5000 (5 seconds) */ invalidTokenTTL?: number; } /** * A specialized bounded cache for token validation results * * Extends BoundedCache with token-specific features: * - Respects token expiration from validation results * - Optional caching of invalid tokens to prevent repeated validation * * @example * ```typescript * const tokenCache = new TokenCache({ * maxSize: 500, * defaultTTL: 60000, // 1 minute * }) * * // Cache a valid token * tokenCache.set('token123', { * valid: true, * user: { id: 'user1', email: 'user@example.com' }, * expiresAt: new Date(Date.now() + 3600000), * }) * * // Get cached result * const result = tokenCache.get('token123') * ``` */ export declare class TokenCache { private readonly cache; private readonly config; constructor(config?: TokenCacheConfig); /** * Get a cached token validation result * * @param token - The token string * @returns The cached validation result or null */ get(token: string): TokenValidationResult | null; /** * Cache a token validation result * * The TTL is calculated based on: * 1. The token's expiresAt if available (capped at defaultTTL) * 2. invalidTokenTTL for invalid tokens (if cacheInvalidTokens is true) * 3. defaultTTL as fallback * * @param token - The token string * @param result - The validation result to cache * @param ttl - Optional override TTL in milliseconds */ set(token: string, result: TokenValidationResult, ttl?: number): void; /** * Delete a specific token from the cache */ delete(token: string): boolean; /** * Clear all cached tokens */ clear(): void; /** * Get the current cache size */ get size(): number; /** * Get cache statistics */ get stats(): CacheStats; /** * Cleanup expired entries */ cleanup(): number; /** * Dispose of the cache and stop cleanup timers */ dispose(): void; } /** * Create a bounded cache instance * * @param config - Cache configuration * @returns A new BoundedCache instance */ export declare function createBoundedCache(config?: BoundedCacheConfig): BoundedCache; /** * Create a token cache instance * * @param config - Token cache configuration * @returns A new TokenCache instance */ export declare function createTokenCache(config?: TokenCacheConfig): TokenCache; //# sourceMappingURL=cache.d.ts.map