import { writable } from 'svelte/store'; import type { Writable } from 'svelte/store'; // Types export interface InternalUser { id: string; email: string; first_name: string; last_name: string; role: 'ADMIN' | 'SUPPORT_MANAGER' | 'AGENT' | 'AUDITOR'; is_active: boolean; is_two_factor_enabled: boolean; created_at: string; tenant_id: string; } export interface AuthState { user: InternalUser | null; token: string | null; refreshToken: string | null; isAuthenticated: boolean; isLoading: boolean; } export interface LoginRequest { email: string; password: string; tenant_slug: string; totp_code?: string; } export interface LoginResponse { access_token: string; refresh_token: string; token_type: string; expires_in: number; user: InternalUser; } export interface RefreshTokenRequest { refresh_token: string; } export interface TokenResponse { access_token: string; token_type: string; expires_in: number; } // Initial state const initialState: AuthState = { user: null, token: null, refreshToken: null, isAuthenticated: false, isLoading: false }; // Create auth store function createAuthStore() { const { subscribe, set, update } = writable(initialState); return { subscribe, // Initialize auth from localStorage init: () => { if (typeof window !== 'undefined') { const token = localStorage.getItem('internal_auth_token'); const refreshToken = localStorage.getItem('internal_auth_refresh_token'); const user = localStorage.getItem('internal_auth_user'); if (token && user) { try { const parsedUser = JSON.parse(user); set({ user: parsedUser, token, refreshToken: refreshToken || null, isAuthenticated: true, isLoading: false }); } catch (error) { console.error('Error parsing stored auth data:', error); localStorage.removeItem('internal_auth_token'); localStorage.removeItem('internal_auth_refresh_token'); localStorage.removeItem('internal_auth_user'); } } } }, // Login login: async (credentials: LoginRequest): Promise => { update(state => ({ ...state, isLoading: true })); try { const response = await fetch('/api/v1/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(credentials) }); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Login failed'); } const data: LoginResponse = await response.json(); // Store auth data if (typeof window !== 'undefined') { localStorage.setItem('internal_auth_token', data.access_token); if (data.refresh_token) { localStorage.setItem('internal_auth_refresh_token', data.refresh_token); } localStorage.setItem('internal_auth_user', JSON.stringify(data.user)); } set({ user: data.user, token: data.access_token, refreshToken: data.refresh_token, isAuthenticated: true, isLoading: false }); } catch (error) { update(state => ({ ...state, isLoading: false })); throw error; } }, // Refresh Session refreshSession: async (): Promise => { // Need to get current state to access refresh token, logic simplified let currentRefreshToken: string | null = null; if (typeof window !== 'undefined') { currentRefreshToken = localStorage.getItem('internal_auth_refresh_token'); } if (!currentRefreshToken) { throw new Error("No refresh token available"); } update (state => ({ ...state, isLoading: true })); try { const response = await fetch('/api/v1/auth/refresh', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ refresh_token: currentRefreshToken }) }); if (!response.ok) { // If refresh fails, logout if (response.status === 401 || response.status === 403) { auth.logout(); } const error = await response.json(); throw new Error(error.detail || 'Refresh failed'); } const data: TokenResponse = await response.json(); // Update token in storage and state if (typeof window !== 'undefined') { localStorage.setItem('internal_auth_token', data.access_token); } update(state => ({ ...state, token: data.access_token, isLoading: false })); } catch (error) { update(state => ({ ...state, isLoading: false })); throw error; } }, // Logout logout: () => { if (typeof window !== 'undefined') { localStorage.removeItem('internal_auth_token'); localStorage.removeItem('internal_auth_refresh_token'); localStorage.removeItem('internal_auth_user'); } set(initialState); // Optional: Redirect to login if (typeof window !== 'undefined') { window.location.href = '/login'; } }, // Update user data updateUser: (user: InternalUser) => { update(state => ({ ...state, user })); if (typeof window !== 'undefined') { localStorage.setItem('internal_auth_user', JSON.stringify(user)); } }, // Set loading state setLoading: (isLoading: boolean) => { update(state => ({ ...state, isLoading })); } }; } export const auth = createAuthStore();