import { Cache } from "./cache.interface"; type Entry = { value: V; expiresAt: number }; interface MemoryCacheOptions { defaultTtlMs?: number; cleanupIntervalMs?: number; } export class MemoryCache implements Cache { private store = new Map>(); private defaultTtlMs: number; constructor(opts: MemoryCacheOptions = {}) { this.defaultTtlMs = opts.defaultTtlMs ?? Infinity; const interval = opts.cleanupIntervalMs ?? 60_000; if (isFinite(interval) && interval > 0) { setInterval(() => this.sweep(), interval).unref(); } } async get(key: string): Promise { const e = this.store.get(key); if (!e) return undefined; if (Date.now() > e.expiresAt) { this.store.delete(key); return undefined; } return e.value as T; } async set(key: string, value: any, ttlMs = this.defaultTtlMs) { const expiresAt = isFinite(ttlMs) ? Date.now() + ttlMs : Infinity; this.store.set(key, { value, expiresAt }); } async has(key: string) { return (await this.get(key)) !== undefined; } async delete(key: string) { this.store.delete(key); } async clear() { this.store.clear(); } async getAll(): Promise> { const result = new Map(); const now = Date.now(); for (const [key, entry] of this.store) { if (now <= entry.expiresAt) { result.set(key, entry.value); } else { // Clean up expired entries while we're iterating this.store.delete(key); } } return result; } private sweep() { const now = Date.now(); for (const [k, { expiresAt }] of this.store) if (now > expiresAt) this.store.delete(k); } }