interface PerfSample { metric: string; operation: string; value: number; } const FLUSH_INTERVAL_MS = 30_000; let batch: PerfSample[] = []; let flushTimer: ReturnType | null = null; export function record(metric: string, operation: string, value: number): void { batch.push({ metric, operation, value }); } function flush(): void { if (batch.length === 0) return; const blob = new Blob([JSON.stringify(batch)], { type: 'application/json' }); batch = []; if (navigator.sendBeacon) { navigator.sendBeacon('/api/perf', blob); } else { fetch('/api/perf', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: blob, keepalive: true, }).catch(() => {}); } } export function startCollector(): void { if (flushTimer) return; flushTimer = setInterval(flush, FLUSH_INTERVAL_MS); document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'hidden') flush(); }); } export function stopCollector(): void { if (flushTimer) { clearInterval(flushTimer); flushTimer = null; } flush(); }