const ALL_LIBRARIES = "__all__"; function getToken(): string | null { return localStorage.getItem("token"); } function setToken(token: string): void { localStorage.setItem("token", token); } function removeToken(): void { localStorage.removeItem("token"); } function getRefreshToken(): string | null { return localStorage.getItem("refresh_token"); } function setRefreshToken(token: string): void { localStorage.setItem("refresh_token", token); } function removeRefreshToken(): void { localStorage.removeItem("refresh_token"); } function getTheme(): string { return localStorage.getItem("theme") || "tokyo-night"; } function setTheme(theme: string): void { localStorage.setItem("theme", theme); } function getSelectedLibrary(): string { const stored = localStorage.getItem("selectedLibrary"); if (stored === ALL_LIBRARIES) return ""; if (stored) return stored; return ""; } // Headers for same-origin /api fetches: the localStorage bearer when // present, otherwise nothing — the token COOKIE (always sent on // same-origin requests) carries auth, since the middleware's // TokenLookup checks cookie:token before the header. NEVER gate a // call on the bearer's presence: the global 401 interceptor clears // localStorage, and token-gated calls then strand every click that // should persist ("can no longer change themes", 2026-10-31). function authHeaders(): Record { const token = localStorage.getItem("token"); return token ? { Authorization: `Bearer ${token}` } : {}; } function setSelectedLibrary(libraryId: string): void { const value = libraryId === "" ? ALL_LIBRARIES : libraryId; localStorage.setItem("selectedLibrary", value); document.cookie = `selectedLibrary=${encodeURIComponent(value)};path=/;max-age=${365 * 24 * 60 * 60};samesite=lax`; } function clearAll(): void { localStorage.clear(); } export { ALL_LIBRARIES, authHeaders, clearAll, getRefreshToken, getSelectedLibrary, getTheme, getToken, removeRefreshToken, removeToken, setRefreshToken, setSelectedLibrary, setTheme, setToken, };