File size: 3,174 Bytes
1fff71f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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<string>(STORAGE_KEY_AUTH_TOKEN);
	const user = getItem<AuthState['user']>(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<AuthState>(createInitialState());

	return {
		subscribe,
		
		/**
		 * Set authenticated user and token
		 */
		login: (user: NonNullable<AuthState['user']>, 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<AuthState['user']>) => {
			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);
}