export interface ICacheEntry { data: T; timestamp: number; } export class MetricsCache { private cache = new Map>(); private readonly defaultTTL: number; constructor(defaultTTL: number = 500) { this.defaultTTL = defaultTTL; } /** * Get cached data or compute and cache it */ public get(key: string, computeFn: () => T | Promise, ttl?: number): T | Promise { const cached = this.cache.get(key); const now = Date.now(); const actualTTL = ttl ?? this.defaultTTL; if (cached && (now - cached.timestamp) < actualTTL) { return cached.data; } const result = computeFn(); // Handle both sync and async compute functions if (result instanceof Promise) { return result.then(data => { this.cache.set(key, { data, timestamp: now }); return data; }); } else { this.cache.set(key, { data: result, timestamp: now }); return result; } } /** * Invalidate a specific cache entry */ public invalidate(key: string): void { this.cache.delete(key); } /** * Clear all cache entries */ public clear(): void { this.cache.clear(); } /** * Get cache statistics */ public getStats(): { size: number; keys: string[] } { return { size: this.cache.size, keys: Array.from(this.cache.keys()) }; } /** * Clean up expired entries */ public cleanup(): void { const now = Date.now(); for (const [key, entry] of this.cache.entries()) { if (now - entry.timestamp > this.defaultTTL) { this.cache.delete(key); } } } }