// Session state for the dashboard. Backed by a pair of Svelte stores // plus a tiny localStorage echo so a page reload doesn't sign you out. // // The bearer token doubles as the cookie value on the server side, so // in browsers that honor the Set-Cookie response the cookie path "just // works"; the token-in-localStorage path covers the rest (HTTP dev, API // clients impersonating the dashboard) by being injected into the // Authorization header in api.ts. import { writable, get } from 'svelte/store'; import { browser } from '$app/environment'; export interface AdminUser { id: string; username: string; } const TOKEN_KEY = 'picloud.admin.token'; function readStoredToken(): string | null { if (!browser) return null; try { return localStorage.getItem(TOKEN_KEY); } catch { return null; } } function writeStoredToken(value: string | null) { if (!browser) return; try { if (value === null) localStorage.removeItem(TOKEN_KEY); else localStorage.setItem(TOKEN_KEY, value); } catch { // Non-fatal: localStorage can be disabled. The session will // just not survive page reloads, but the in-memory store still // works for the current SPA lifetime. } } export const token = writable(readStoredToken()); export const currentUser = writable(null); token.subscribe((value) => writeStoredToken(value)); /** Snapshot of the current token without subscribing — used by the * fetch wrapper. Returns null when no admin is logged in. */ export function getToken(): string | null { return get(token); } export function setSession(user: AdminUser, raw_token: string) { currentUser.set(user); token.set(raw_token); } export function clearSession() { currentUser.set(null); token.set(null); }