import { invalidateAll } from '$app/navigation'; import { navigating, page } from '$app/stores'; import { get } from 'svelte/store'; import { shouldAutoRefresh } from '$lib/shared/refresh-policy'; /** Away for at least this long before refocus re-runs the page load. */ const MIN_AWAY_MS = 10_000; /** Poll cadence: near-live for a shared list, cheap for one open tab. */ const POLL_INTERVAL_MS = 15_000; /** * Keeps the current page near-live: polls the server while the tab is visible, * and refetches on refocus after an absence. Call from `onMount`; the returned * function tears the listeners and timer down. */ export function startAutoRefresh(): () => void { // When the tab stopped being the active one; null while it is active. let deactivatedAt: number | null = null; const conditions = () => ({ routeId: get(page).route.id, visible: document.visibilityState === 'visible', online: navigator.onLine, navigating: get(navigating) !== null, }); const deactivate = () => { deactivatedAt ??= Date.now(); }; const activate = () => { if (deactivatedAt === null) return; const awayMs = Date.now() - deactivatedAt; deactivatedAt = null; if (awayMs >= MIN_AWAY_MS && shouldAutoRefresh(conditions())) void invalidateAll(); }; const onVisibilityChange = () => { if (document.visibilityState === 'hidden') deactivate(); else activate(); }; const timer = setInterval(() => { if (shouldAutoRefresh(conditions())) void invalidateAll(); }, POLL_INTERVAL_MS); document.addEventListener('visibilitychange', onVisibilityChange); window.addEventListener('blur', deactivate); window.addEventListener('focus', activate); return () => { clearInterval(timer); document.removeEventListener('visibilitychange', onVisibilityChange); window.removeEventListener('blur', deactivate); window.removeEventListener('focus', activate); }; }