window.forceUpdateHeader = () => { const event = new CustomEvent('force-header-update', { detail: { timestamp: Date.now() }, }); document.dispatchEvent(event); }; document.addEventListener('session-activated', (event) => { if (window.forceUpdateHeader) { window.forceUpdateHeader(); } if (window.webrtcManager && window.webrtcManager.handleSessionActivation) { if (window.DEBUG_MODE) { console.log('🔐 Notifying WebRTC Manager about session activation'); } window.webrtcManager.handleSessionActivation({ sessionId: event.detail.sessionId, sessionManager: window.sessionManager, }); } }); if (window.DEBUG_MODE) { console.log('✅ Global timer management functions loaded'); } // Format a version (build timestamp -> date, or pass through a semver string) function formatUpdateVersion(v) { if (!v) return null; if (/^\d+$/.test(String(v))) { return new Date(parseInt(v, 10)).toLocaleString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); } return String(v); } // Update notification — translated from the Claude Design component // (Update Notification.dc.html). Centered modal with version comparison. window.showUpdateNotification = function showUpdateNotification() { if (window.DEBUG_MODE) console.log('🆕 Showing update notification for PWA'); // Avoid stacking duplicates if the SW fires more than once. const existing = document.getElementById('pwa-update-modal'); if (existing) existing.remove(); if (!document.getElementById('pwa-update-modal-kf')) { const style = document.createElement('style'); style.id = 'pwa-update-modal-kf'; style.textContent = '@keyframes unPop{from{opacity:0;transform:scale(.96) translateY(10px)}to{opacity:1;transform:scale(1) translateY(0)}}' + '@keyframes unFade{from{opacity:0}to{opacity:1}}' + '@keyframes unSpin{to{transform:rotate(360deg)}}'; document.head.appendChild(style); } let currentVersion = null; try { currentVersion = localStorage.getItem('app_version'); } catch (e) {} const currentStr = formatUpdateVersion(currentVersion) || 'Installed build'; const modal = document.createElement('div'); modal.id = 'pwa-update-modal'; modal.style.cssText = "position:fixed; inset:0; z-index:9999; display:flex; align-items:center; justify-content:center; padding:24px; background:rgba(8,8,10,0.55); backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px); animation:unFade .3s ease; font-family:'Manrope',system-ui,-apple-system,sans-serif;"; modal.innerHTML = `

Update available

A newer version of SecureBit has been detected.

Current version ${currentStr}
New version Latest
`; const updNow = modal.querySelector('.upd-now'); updNow.addEventListener('mouseenter', () => { updNow.style.background = '#ff9637'; updNow.style.transform = 'translateY(-2px)'; }); updNow.addEventListener('mouseleave', () => { updNow.style.background = '#f0892a'; updNow.style.transform = 'none'; }); updNow.addEventListener('click', () => window.location.reload()); const updLater = modal.querySelector('.upd-later'); updLater.addEventListener('mouseenter', () => { updLater.style.color = '#e5727a'; updLater.style.borderColor = 'rgba(229,114,122,0.4)'; }); updLater.addEventListener('mouseleave', () => { updLater.style.color = '#9a9aa2'; updLater.style.borderColor = 'rgba(255,255,255,0.1)'; }); updLater.addEventListener('click', () => modal.remove()); document.body.appendChild(modal); // Fill in the new version once meta.json is fetched (best-effort). fetch('/meta.json?t=' + Date.now(), { cache: 'no-store' }) .then((r) => r.json()) .then((meta) => { const label = meta.appVersion ? ('v' + meta.appVersion) : (formatUpdateVersion(meta.version || meta.buildVersion) || 'Latest'); const el = modal.querySelector('.new-ver'); if (el) el.textContent = label; }) .catch(() => {}); }; window.showServiceWorkerError = function showServiceWorkerError(error) { console.warn('⚠️ Service Worker error:', error); };