// deno-lint-ignore-file ban-types import { LRUCache } from 'lru-cache'; import { type Gauge } from 'prom-client'; type FetchFn = (key: K, opts: { signal?: AbortSignal }) => Promise; type SimpleLRUOpts = LRUCache.Options & { gauge?: Gauge; errorRefresh?: number; }; export class SimpleLRU< K extends {}, V extends {}, > { protected cache: LRUCache, void>; private tids = new Set(); constructor(private fetchFn: FetchFn, private opts: SimpleLRUOpts>) { this.cache = new LRUCache({ ...opts }); } async fetch(key: K, opts?: { signal?: AbortSignal }): Promise { if (opts?.signal?.aborted) { throw new DOMException('The signal has been aborted', 'AbortError'); } const cached = await this.cache.get(key); if (cached) { return cached; } const promise = this.fetchFn(key, { signal: opts?.signal }); this.cache.set(key, promise); promise.then(() => { this.opts.gauge?.set(this.cache.size); }).catch(() => { const tid = setTimeout(() => { this.cache.delete(key); this.tids.delete(tid); }, this.opts.errorRefresh ?? 10_000); this.tids.add(tid); }); return promise; } [Symbol.dispose](): void { for (const tid of this.tids) { clearTimeout(tid); } } }