(() => { const { summary, serviceIds, locale, copy, states } = JSON.parse(document.getElementById('widget-data').textContent); const link = document.querySelector('.widget'), label = document.querySelector('.label'); let expiry, expiryTimer, pollTimer, active = false; link.href = new URL(`/?lang=${locale}`, location.origin).href; const notify = () => { if (parent !== window) parent.postMessage({ type: 'ridebus-status-widget', version: 1, status: link.dataset.status }, '*'); }; function show(status) { link.dataset.status = status; label.textContent = copy[status]; link.setAttribute('aria-label', `${copy.title}: ${copy[status]}`); notify(); } function apply(data, elapsedMs = 0) { if (data?.version !== 1 || !states.includes(data.overall) || !Number.isFinite(data.generatedAt) || !Number.isFinite(data.expiresAt)) throw new Error('Invalid status'); clearTimeout(expiryTimer); expiry = Date.now() + Math.max(0, Math.min(90000, data.expiresAt - data.generatedAt - elapsedMs)); show(expiry > Date.now() ? data.overall : 'unknown'); expiryTimer = setTimeout(() => show('unknown'), Math.max(0, expiry - Date.now())); } async function refresh() { if (active || document.hidden) return; active = true; clearTimeout(pollTimer); const started = performance.now(); try { const url = new URL('/api/widget', location.origin); url.searchParams.set('services', serviceIds.join(',')); const response = await fetch(url, { cache: 'no-store', credentials: 'omit', signal: AbortSignal.timeout(5000) }); if (!response.ok) throw new Error('Status unavailable'); const data = await response.json(); apply(data, performance.now() - started); } catch { clearTimeout(expiryTimer); show('unknown'); } finally { active = false; if (!document.hidden) pollTimer = setTimeout(refresh, 30000); } } window.addEventListener('message', event => { if (event.source === parent && event.data?.type === 'ridebus-status-widget-request') { if (Date.now() >= expiry) show('unknown'); else notify(); } }); document.addEventListener('visibilitychange', () => { clearTimeout(pollTimer); if (!document.hidden) { if (Date.now() >= expiry) show('unknown'); void refresh(); } }); window.addEventListener('online', () => void refresh()); window.addEventListener('offline', () => { clearTimeout(expiryTimer); show('unknown'); }); apply(summary, performance.now()); pollTimer = setTimeout(refresh, 30000); })();