export interface DebouncedSave { /** (Re)arm the debounce timer; no-op when `canSave()` is false. */ schedule(): void; /** True while a scheduled save hasn't run yet — implements `PendingSave.hasPendingSave`. */ hasPendingSave(): boolean; /** Run a scheduled save now and await it; no-op when nothing is scheduled. */ flushPending(): Promise; /** Drop a scheduled save without running it (e.g. before an authoritative transition, which flushes explicitly, or a reset that discards the draft). */ cancel(): void; } /** * The debounced-autosave timer shared by the editor stores (WP-31). It owns ONLY the timer * bookkeeping; the actual write + save-state transitions live in the caller's `flush` * (store-specific — it touches that store's SaveState/ActionState + adapter). The handle is * nulled the moment it fires, so `hasPendingSave()` means "a write is still owed". Integrates * with the `PendingSave` seam (pending-saves.ts): a store delegates hasPendingSave/flushPending * here so the CanDeactivate guard / beforeunload handler can flush a pending edit. */ export function createDebouncedSave(opts: { delayMs?: number; canSave: () => boolean; flush: () => Promise; }): DebouncedSave { const delay = opts.delayMs ?? 600; let timer: ReturnType | undefined; return { schedule() { if (!opts.canSave()) return; clearTimeout(timer); timer = setTimeout(() => { timer = undefined; void opts.flush(); }, delay); }, hasPendingSave: () => timer !== undefined, async flushPending() { if (timer === undefined) return; clearTimeout(timer); timer = undefined; await opts.flush(); }, cancel() { clearTimeout(timer); timer = undefined; }, }; }