function createTodayLockScreen({ storage, getLogin, serviceWorker, NotificationRef, control, status, locationRef, historyRef, randomToken = () => { const bytes = new Uint8Array(16); globalThis.crypto.getRandomValues(bytes); return Array.from(bytes, value => value.toString(16).padStart(2, '0')).join(''); }, fingerprint = async (token, identity) => { const input = new TextEncoder().encode(token + '\0' + identity); const digest = await globalThis.crypto.subtle.digest('SHA-256', input); return Array.from(new Uint8Array(digest), value => value.toString(16).padStart(2, '0')).join(''); }, onAction = () => {}, }) { let activeIdentity = ''; const preferenceKey = () => { const login = String(getLogin?.() || '').trim().toLowerCase(); return login ? 'stackchain.today-lock-screen.v1.' + encodeURIComponent(login) : ''; }; const supported = Boolean(serviceWorker && NotificationRef); const actionKey = () => { const login = String(getLogin?.() || '').trim().toLowerCase(); return login ? 'stackchain.today-lock-screen-action.v1.' + encodeURIComponent(login) : ''; }; const readAction = () => { const key = actionKey(); if (!key) return null; try { const value = JSON.parse(storage?.getItem(key) || 'null'); return typeof value?.token === 'string' && value.token && typeof value.fingerprint === 'string' && value.fingerprint ? value : null; } catch (_error) { return null; } }; const clearAction = () => { const key = actionKey(); try { if (key) storage?.removeItem(key); } catch (_error) { return false; } return true; }; const actionFor = async identity => { const existing = readAction(); if (existing && await fingerprint(existing.token, identity) === existing.fingerprint) return existing; const key = actionKey(); if (!key) return null; try { const token = String(randomToken() || ''); const value = { token, fingerprint:token ? await fingerprint(token, identity) : '' }; if (!value.token) return null; storage?.setItem(key, JSON.stringify(value)); return value; } catch (_error) { return null; } }; const enabled = () => { const key = preferenceKey(); return Boolean(key && storage?.getItem(key) === '1'); }; const setStatus = message => { if (status) status.textContent = message; }; const post = async message => { const target = serviceWorker?.controller || (await serviceWorker?.ready)?.active; target?.postMessage?.(message); }; const hide = () => post({ type:'stackchain-today-lock-screen', active:false, running:false, }); const render = () => { if (control) { control.checked = enabled(); control.disabled = !supported; } if (!supported) setStatus('Lock-screen controls are not supported on this device.'); else if (enabled()) setStatus('Lock-screen Today controls are on.'); }; const consumeAction = async (action, token = '') => { if (!enabled() || !['pause', 'resume', 'complete'].includes(action)) return false; if (action !== 'complete') { onAction(action, null); return true; } const pending = readAction(); if (!pending || !token || !activeIdentity || pending.token !== token || await fingerprint(token, activeIdentity) !== pending.fingerprint) return false; if (!clearAction()) return false; onAction(action, activeIdentity); return true; }; const api = { enabled, async enable() { if (!supported) { render(); return false; } const permission = NotificationRef.permission === 'granted' ? 'granted' : await NotificationRef.requestPermission(); if (permission !== 'granted') { if (control) control.checked = false; setStatus(permission === 'denied' ? 'Lock-screen controls are blocked in browser settings.' : 'Lock-screen controls were not enabled.'); return false; } const key = preferenceKey(); if (!key) return false; storage?.setItem(key, '1'); render(); return true; }, async disable() { const key = preferenceKey(); if (key) storage?.removeItem(key); clearAction(); if (control) control.checked = false; setStatus('Lock-screen Today controls are off.'); await hide(); return true; }, async sync(snapshot, active) { if (!enabled() || NotificationRef?.permission !== 'granted') return false; const visible = Boolean(active && snapshot?.identity); activeIdentity = visible ? snapshot.identity : ''; const pending = visible ? await actionFor(activeIdentity) : null; if (!visible) clearAction(); await post({ type:'stackchain-today-lock-screen', active:visible, running:visible && Boolean(snapshot.running), ...(pending?.token ? { actionToken:pending.token } : {}), }); if (visible && !pending) setStatus('Finish current is unavailable because its one-time action could not be saved.'); return true; }, consumeAction, async consumeLaunchAction() { let url; try { url = new URL(locationRef?.href || ''); } catch (_error) { return false; } const action = url.searchParams.get('today_timer_action'); if (!['pause', 'resume', 'complete'].includes(action)) return false; const token = url.searchParams.get('today_action_token') || ''; url.searchParams.delete('today_timer_action'); url.searchParams.delete('today_action_token'); historyRef?.replaceState?.(null, '', url.pathname + url.search + url.hash); return await consumeAction(action, token); }, render, }; control?.addEventListener?.('change', () => { if (control.checked) api.enable(); else api.disable(); }); serviceWorker?.addEventListener?.('message', event => { if (event.data?.type === 'stackchain-today-timer-action') { consumeAction(String(event.data.action || ''), String(event.data.actionToken || '')); } }); render(); return api; } if (typeof module !== 'undefined' && module.exports) module.exports = createTodayLockScreen;