// Shared, reactive auth + saved-articles state (Svelte 5 runes in a module). import { SvelteSet } from 'svelte/reactivity'; import { getJSON, postJSON, delJSON } from './api.js'; export const auth = $state({ user: null, ready: false }); export const savedIds = new SvelteSet(); // reactive set of saved article ids export async function refresh() { try { auth.user = await getJSON('/api/auth/me'); } catch { auth.user = null; } finally { auth.ready = true; } if (auth.user) await loadSaved(); else savedIds.clear(); } export async function loadSaved() { try { const ids = await getJSON('/api/saved/ids'); savedIds.clear(); for (const id of ids) savedIds.add(id); } catch { /* not signed in / transient — leave as-is */ } } // Optimistic toggle; reverts on failure. export async function toggleSave(id) { if (!auth.user) return false; const willSave = !savedIds.has(id); if (willSave) savedIds.add(id); else savedIds.delete(id); try { if (willSave) await postJSON(`/api/saved/${id}`, {}); else await delJSON(`/api/saved/${id}`); } catch { if (willSave) savedIds.delete(id); else savedIds.add(id); } return savedIds.has(id); } // Request a magic link. Reply is intentionally identical for any address. export function startEmail(email) { return postJSON('/api/auth/email/start', { email }); } export async function verifyToken(token) { const res = await postJSON('/api/auth/email/verify', { token }); auth.user = res.user; await loadSaved(); return res; } export async function logout() { try { await postJSON('/api/auth/logout', {}); } finally { clearLocal(); } } // Clear client auth state without a logout call (cookie already cleared server-side, // e.g. after delete-account or sign-out-everywhere). export function clearLocal() { auth.user = null; savedIds.clear(); }