import { writable, derived } from 'svelte/store'; import type { AuthState } from '$lib/types/client'; import { STORAGE_KEY_AUTH_TOKEN, STORAGE_KEY_USER_PROFILE } from '$lib/utils/constants'; import { getItem, setItem, removeItem } from '$lib/services/storage'; /** * Auth store managing user authentication state * Persists token and user info to localStorage */ // Create initial state from localStorage if available function createInitialState(): AuthState { const token = getItem(STORAGE_KEY_AUTH_TOKEN); const user = getItem(STORAGE_KEY_USER_PROFILE); if (token && user) { // Check if token is expired const tokenExpiry = user.tokenExpiry; if (tokenExpiry && Date.now() < tokenExpiry) { return { user, token, tokenExpiry, isAuthenticated: true }; } } return { user: null, token: null, tokenExpiry: null, isAuthenticated: false }; } // Create the auth store function createAuthStore() { const { subscribe, set, update } = writable(createInitialState()); return { subscribe, /** * Set authenticated user and token */ login: (user: NonNullable, token: string, tokenExpiry?: number) => { const expiry = tokenExpiry || Date.now() + 24 * 60 * 60 * 1000; // Default 24h const newState: AuthState = { user: { ...user, tokenExpiry: expiry }, token, tokenExpiry: expiry, isAuthenticated: true }; // Persist to storage setItem(STORAGE_KEY_AUTH_TOKEN, token); setItem(STORAGE_KEY_USER_PROFILE, newState.user); set(newState); }, /** * Clear authentication state */ logout: () => { // Clear storage removeItem(STORAGE_KEY_AUTH_TOKEN); removeItem(STORAGE_KEY_USER_PROFILE); set({ user: null, token: null, tokenExpiry: null, isAuthenticated: false }); }, /** * Update user profile */ updateUser: (user: NonNullable) => { update((state) => { if (!state.isAuthenticated) return state; const newUser = { ...state.user, ...user }; setItem(STORAGE_KEY_USER_PROFILE, newUser); return { ...state, user: newUser }; }); }, /** * Check if token is expired and logout if needed */ checkExpiration: () => { update((state) => { if (!state.isAuthenticated || !state.tokenExpiry) return state; if (Date.now() >= state.tokenExpiry) { // Token expired - clear state removeItem(STORAGE_KEY_AUTH_TOKEN); removeItem(STORAGE_KEY_USER_PROFILE); return { user: null, token: null, tokenExpiry: null, isAuthenticated: false }; } return state; }); } }; } export const authStore = createAuthStore(); // Derived store for checking if authenticated export const isAuthenticated = derived( authStore, ($auth) => $auth.isAuthenticated ); // Derived store for getting current user export const currentUser = derived( authStore, ($auth) => $auth.user ); // Check token expiration every minute if (typeof window !== 'undefined') { setInterval(() => { authStore.checkExpiration(); }, 60 * 1000); }