import type { InvalidationEvent } from "./invalidation"; export interface RefreshScheduler { connected(): void; notified(event: InvalidationEvent): void; dispose(): void; } export interface RefreshSchedulerOptions { delayMs?: number; duplicateWindowMs?: number; now?: () => number; } export function createRefreshScheduler( refresh: () => void, options: RefreshSchedulerOptions = {}, ): RefreshScheduler { const delayMs = options.delayMs ?? 75; const duplicateWindowMs = options.duplicateWindowMs ?? 2_000; const now = options.now ?? Date.now; let pending: ReturnType | undefined; let lastEventKey: string | undefined; let lastEventAt = 0; const schedule = (event?: InvalidationEvent) => { if (event) { const key = `${event.type}:${event.id}:${event.version}`; const timestamp = now(); if ( key === lastEventKey && timestamp - lastEventAt < duplicateWindowMs ) { return; } lastEventKey = key; lastEventAt = timestamp; } if (pending) return; pending = setTimeout(() => { pending = undefined; refresh(); }, delayMs); }; return { connected() { schedule(); }, notified(event) { schedule(event); }, dispose() { if (pending) clearTimeout(pending); pending = undefined; }, }; }