/** * Svelte 5 Auth Store Factory * * Creates a reactive auth store using Svelte 5 runes. * Generic over user type to support app-specific user models. * * @example * ```ts * // In your app's auth store file * import { createAuthStore } from '@manacore/shared-auth-stores'; * import { authService } from '$lib/auth'; * import type { AppUser } from '$lib/types'; * * export const authStore = createAuthStore(authService); * ``` */ import type { AuthServiceAdapter, AuthResult, BaseUser } from './types'; /** * Create a Svelte 5 runes-based auth store * * @param authService - Auth service adapter implementing the AuthServiceAdapter interface * @returns Reactive auth store with state and actions */ export function createAuthStore(authService: AuthServiceAdapter) { // Reactive state using Svelte 5 runes let user = $state(null); let loading = $state(true); let error = $state(null); return { // Reactive getters get user() { return user; }, get loading() { return loading; }, get error() { return error; }, get isAuthenticated() { return !!user; }, /** * Initialize auth state from stored tokens/session */ async initialize() { loading = true; error = null; try { const isAuth = await authService.isAuthenticated(); if (isAuth) { user = await authService.getUserFromToken(); } else { user = null; } } catch (e) { console.error('Failed to initialize auth:', e); error = e instanceof Error ? e.message : 'Failed to initialize authentication'; user = null; } finally { loading = false; } }, /** * Set user manually (useful for SSR hydration) */ setUser(newUser: TUser | null) { user = newUser; error = null; }, /** * Sign in with email and password */ async signIn(email: string, password: string): Promise> { loading = true; error = null; try { const result = await authService.signIn(email, password); if (result.success) { user = await authService.getUserFromToken(); } else { error = result.error || 'Sign in failed'; } return result; } catch (e) { const errorMessage = e instanceof Error ? e.message : 'Sign in failed'; error = errorMessage; return { success: false, error: errorMessage }; } finally { loading = false; } }, /** * Sign up with email and password */ async signUp(email: string, password: string): Promise> { loading = true; error = null; try { const result = await authService.signUp(email, password); if (result.success && !result.needsVerification) { user = await authService.getUserFromToken(); } else if (!result.success) { error = result.error || 'Sign up failed'; } return result; } catch (e) { const errorMessage = e instanceof Error ? e.message : 'Sign up failed'; error = errorMessage; return { success: false, error: errorMessage }; } finally { loading = false; } }, /** * Send password reset email */ async forgotPassword(email: string): Promise<{ success: boolean; error?: string }> { loading = true; error = null; try { const result = await authService.forgotPassword(email); if (!result.success) { error = result.error || 'Password reset failed'; } return result; } catch (e) { const errorMessage = e instanceof Error ? e.message : 'Password reset failed'; error = errorMessage; return { success: false, error: errorMessage }; } finally { loading = false; } }, /** * Sign out user */ async signOut() { loading = true; error = null; try { await authService.signOut(); user = null; } catch (e) { console.error('Sign out failed:', e); error = e instanceof Error ? e.message : 'Sign out failed'; } finally { loading = false; } }, /** * Check authentication status */ async checkAuth(): Promise { try { const isAuth = await authService.isAuthenticated(); if (!isAuth) { user = null; return false; } return true; } catch (e) { console.error('Auth check failed:', e); user = null; return false; } }, /** * Clear error state */ clearError() { error = null; }, }; }