| |
| |
| |
| |
| |
| |
| |
| export class TtlLruCache<V> { |
| private readonly maxEntries: number; |
| private readonly ttlMs: number; |
| private readonly map = new Map<string, { value: V; expiresAt: number }>(); |
|
|
| constructor(opts: { maxEntries: number; ttlMs: number }) { |
| if (opts.maxEntries <= 0) { |
| throw new Error("TtlLruCache: maxEntries must be > 0"); |
| } |
| if (opts.ttlMs <= 0) { |
| throw new Error("TtlLruCache: ttlMs must be > 0"); |
| } |
| this.maxEntries = opts.maxEntries; |
| this.ttlMs = opts.ttlMs; |
| } |
|
|
| get(key: string): V | undefined { |
| const entry = this.map.get(key); |
| if (!entry) return undefined; |
| if (entry.expiresAt < Date.now()) { |
| this.map.delete(key); |
| return undefined; |
| } |
| |
| this.map.delete(key); |
| this.map.set(key, entry); |
| return entry.value; |
| } |
|
|
| set(key: string, value: V): void { |
| if (this.map.has(key)) this.map.delete(key); |
| this.map.set(key, { value, expiresAt: Date.now() + this.ttlMs }); |
| while (this.map.size > this.maxEntries) { |
| const firstKey = this.map.keys().next().value; |
| if (firstKey === undefined) break; |
| this.map.delete(firstKey); |
| } |
| } |
|
|
| size(): number { |
| return this.map.size; |
| } |
|
|
| clear(): void { |
| this.map.clear(); |
| } |
| } |
|
|