/** Poll visible page content without overlapping requests. Fleet watches use their own monitor. */ export function pollVisible(task: (signal: AbortSignal) => unknown | Promise, interval: number, immediate = true): () => void { let stopped = false; let running = false; let timer: ReturnType | undefined; let controller: AbortController | undefined; let failures = 0; const visible = () => document.visibilityState !== 'hidden'; const run = async () => { if (stopped || running || !visible()) return; clearTimeout(timer); running = true; controller = new AbortController(); const timeout = setTimeout(() => controller?.abort(), 30_000); try { failures = await task(controller.signal) === false ? failures + 1 : 0; } catch (error) { if (!controller.signal.aborted) { failures++; console.error('Page refresh failed', error); } } finally { clearTimeout(timeout); controller = undefined; running = false; if (!stopped && visible()) timer = setTimeout(run, interval * Math.min(8, 2 ** failures)); } }; const visibility = () => { clearTimeout(timer); if (!visible()) controller?.abort(); if (document.visibilityState !== 'hidden') void run(); }; document.addEventListener('visibilitychange', visibility); if (immediate) void run(); else timer = setTimeout(run, interval); return () => { stopped = true; clearTimeout(timer); controller?.abort(); document.removeEventListener('visibilitychange', visibility); }; }