@bagelink/auth 1.4.169 → 1.4.171

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/useAuth.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  import type { AxiosInstance } from 'axios'
2
2
  import type { App } from 'vue'
3
- import type { User, NewUser, UpdatePasswordForm, AuthEventMap } from './types'
3
+ import type {
4
+ AccountInfo,
5
+ NewUser,
6
+ UpdatePasswordForm,
7
+ UpdateAccountRequest,
8
+ AuthEventMap,
9
+ } from './types'
4
10
  import { ref } from 'vue'
5
11
  import { AuthApi } from './api'
6
12
  import { AuthState } from './types'
@@ -9,14 +15,7 @@ import { EventEmitter } from './utils'
9
15
  // Global state
10
16
  let authApi: AuthApi | null = null
11
17
  let eventEmitter: EventEmitter | null = null
12
- const currentUser = ref<User>({
13
- id: '',
14
- email: '',
15
- first_name: '',
16
- last_name: '',
17
- is_superuser: false,
18
- is_active: false,
19
- })
18
+ const currentUser = ref<AccountInfo | null>(null)
20
19
 
21
20
  // Initialize auth
22
21
  export function initAuth({
@@ -26,26 +25,32 @@ export function initAuth({
26
25
  axios: AxiosInstance
27
26
  baseURL?: string
28
27
  }) {
29
- if (!authApi) {
28
+ if (authApi === null) {
30
29
  authApi = new AuthApi(axios, baseURL)
31
30
  }
32
31
 
33
- if (!eventEmitter) {
32
+ if (eventEmitter === null) {
34
33
  eventEmitter = new EventEmitter()
35
34
  }
36
35
 
37
36
  return {
38
37
  // Event listener methods
39
38
  on<K extends AuthState>(event: K, handler: AuthEventMap[K]): void {
40
- eventEmitter!.on(event, handler)
39
+ if (eventEmitter) {
40
+ eventEmitter.on(event, handler)
41
+ }
41
42
  },
42
43
 
43
44
  off<K extends AuthState>(event: K, handler: AuthEventMap[K]): void {
44
- eventEmitter!.off(event, handler)
45
+ if (eventEmitter) {
46
+ eventEmitter.off(event, handler)
47
+ }
45
48
  },
46
49
 
47
50
  removeAllListeners<K extends AuthState>(event?: K): void {
48
- eventEmitter!.removeAllListeners(event)
51
+ if (eventEmitter) {
52
+ eventEmitter.removeAllListeners(event)
53
+ }
49
54
  },
50
55
 
51
56
  install(app: App) {
@@ -57,127 +62,192 @@ export function initAuth({
57
62
 
58
63
  // Composable
59
64
  export function useAuth() {
60
- if (!authApi) {
65
+ if (authApi === null) {
61
66
  throw new Error('Auth not initialized. Call initAuth first.')
62
67
  }
63
68
 
69
+ if (eventEmitter === null) {
70
+ throw new Error('Event emitter not initialized. Call initAuth first.')
71
+ }
72
+
73
+ const api = authApi
74
+ const emitter = eventEmitter
75
+
64
76
  // Getters
65
- const getFullName = () => `${currentUser.value.first_name} ${currentUser.value.last_name}`
66
- const getIsLoggedIn = () => currentUser.value.id.length > 0
77
+ const getFullName = () => {
78
+ const user = currentUser.value
79
+ if (user === null) return ''
80
+ if (user.person !== undefined) return user.person.name
81
+ return user.display_name ?? ''
82
+ }
83
+
84
+ const getIsLoggedIn = () => {
85
+ const user = currentUser.value
86
+ return user !== null && user.id.length > 0
87
+ }
88
+
89
+ const getEmail = () => {
90
+ const user = currentUser.value
91
+ if (user === null) return ''
92
+
93
+ // Try to get email from person info first
94
+ if (user.person?.email !== undefined) {
95
+ return user.person.email
96
+ }
97
+
98
+ // Otherwise look for email in authentication methods
99
+ const emailMethod = user.authentication_methods?.find(
100
+ m => m.type === 'password' || m.type === 'email_token'
101
+ )
102
+ return emailMethod?.identifier ?? ''
103
+ }
67
104
 
68
105
  // Actions
69
106
  async function logout() {
70
- try {
71
- await authApi!.logout()
72
- // Reset current user
73
- currentUser.value = {
74
- id: '',
75
- email: '',
76
- first_name: '',
77
- last_name: '',
78
- is_superuser: false,
79
- is_active: false,
80
- }
81
- eventEmitter!.emit(AuthState.LOGOUT)
82
- } catch (error) {
83
- throw error
84
- }
107
+ // Call logout API
108
+ const logoutPromise = api.logout()
109
+ await logoutPromise.catch(() => {
110
+ // Ignore logout errors
111
+ })
112
+ // Clear local state regardless of API result
113
+ currentUser.value = null
114
+ // Emit logout event
115
+ emitter.emit(AuthState.LOGOUT)
85
116
  }
86
117
 
87
118
  async function login(credentials: { email: string, password: string }) {
88
- try {
89
- await authApi!.login(
90
- credentials.email.toLowerCase(),
91
- credentials.password
92
- )
119
+ const { data } = await api.login(
120
+ credentials.email.toLowerCase(),
121
+ credentials.password
122
+ )
123
+
124
+ // If successful and not requiring verification, fetch user data
125
+ if (data.success === true && data.requires_verification !== true) {
93
126
  await checkAuth()
94
- eventEmitter!.emit(AuthState.LOGIN)
95
- } catch (error) {
96
- throw error
97
127
  }
128
+
129
+ emitter.emit(AuthState.LOGIN)
130
+ return data
98
131
  }
99
132
 
100
133
  async function checkAuth(): Promise<boolean> {
101
134
  try {
102
- if (!getIsLoggedIn()) {
103
- const { data } = await authApi!.getCurrentUser()
104
- currentUser.value = data
105
- if (getIsLoggedIn()) {
106
- eventEmitter!.emit(AuthState.AUTH_CHECK)
107
- }
135
+ const { data } = await api.getCurrentUser()
136
+ currentUser.value = data
137
+ if (getIsLoggedIn()) {
138
+ emitter.emit(AuthState.AUTH_CHECK)
108
139
  }
109
- } catch (error) {
140
+ return true
141
+ } catch {
142
+ currentUser.value = null
110
143
  return false
111
144
  }
112
- return getIsLoggedIn()
113
145
  }
114
146
 
115
147
  async function signup(user: NewUser) {
116
- try {
117
- if (user.password !== user.confirmPassword) {
118
- throw new Error('Passwords do not match')
119
- }
120
- const { data } = await authApi!.signup(user)
121
- currentUser.value = data
122
- eventEmitter!.emit(AuthState.SIGNUP)
123
- } catch (error) {
124
- throw error
148
+ // Check password match if password is provided
149
+ if (user.password && user.password !== user.confirmPassword) {
150
+ throw new Error('Passwords do not match')
125
151
  }
126
- }
127
152
 
128
- async function recoverPassword(email: string) {
129
- try {
130
- await authApi!.passwordRecovery(email)
131
- } catch (error) {
132
- throw error
153
+ const { data } = await api.register({
154
+ email: user.email,
155
+ first_name: user.first_name,
156
+ last_name: user.last_name,
157
+ phone_number: user.phone_number,
158
+ password: user.password,
159
+ })
160
+
161
+ // If successful and not requiring verification, fetch user data
162
+ if (data.success === true && data.requires_verification !== true) {
163
+ await checkAuth()
133
164
  }
165
+
166
+ emitter.emit(AuthState.SIGNUP)
167
+ return data
134
168
  }
135
169
 
136
- async function resetPassword(newPassword: string) {
137
- try {
138
- await authApi!.resetPassword(newPassword)
139
- eventEmitter!.emit(AuthState.PASSWORD_RESET)
140
- } catch (error) {
141
- throw error
142
- }
170
+ async function forgotPassword(email: string) {
171
+ await api.forgotPassword(email)
143
172
  }
144
173
 
145
- async function updatePassword(form: UpdatePasswordForm) {
146
- try {
147
- if (form.new_password !== form.confirmNewPassword) {
148
- throw new Error('Passwords do not match')
149
- }
150
- await authApi!.updatePassword(form)
151
- eventEmitter!.emit(AuthState.PASSWORD_RESET)
152
- } catch (error) {
153
- throw error
154
- }
174
+ async function verifyResetToken(token: string) {
175
+ await api.verifyResetToken(token)
155
176
  }
156
177
 
157
- async function updateProfile(user: Partial<User>) {
158
- try {
159
- const { data } = await authApi!.updateUserProfile(user)
160
- currentUser.value = { ...currentUser.value, ...data }
161
- eventEmitter!.emit(AuthState.PROFILE_UPDATE)
162
- } catch (error) {
163
- throw error
178
+ async function resetPassword(token: string, newPassword: string) {
179
+ await api.resetPassword({ token, new_password: newPassword })
180
+ emitter.emit(AuthState.PASSWORD_RESET)
181
+ }
182
+
183
+ async function changePassword(form: UpdatePasswordForm) {
184
+ if (form.new_password !== form.confirmNewPassword) {
185
+ throw new Error('Passwords do not match')
164
186
  }
187
+ await api.changePassword({
188
+ current_password: form.current_password,
189
+ new_password: form.new_password,
190
+ })
191
+ emitter.emit(AuthState.PASSWORD_CHANGE)
165
192
  }
166
193
 
167
- async function toggleUserStatus(userId: string, isActive: boolean) {
168
- try {
169
- await authApi!.setUserStatus(userId, isActive)
170
- } catch (error) {
171
- throw error
194
+ async function updateProfile(updates: UpdateAccountRequest) {
195
+ const { data } = await api.updateCurrentUser(updates)
196
+ currentUser.value = data
197
+ emitter.emit(AuthState.PROFILE_UPDATE)
198
+ }
199
+
200
+ async function activateAccount(accountId: string) {
201
+ await api.activateAccount(accountId)
202
+ }
203
+
204
+ async function deactivateAccount(accountId: string) {
205
+ await api.deactivateAccount(accountId)
206
+ }
207
+
208
+ async function deleteAccount(accountId: string) {
209
+ await api.deleteAccount(accountId)
210
+ }
211
+
212
+ async function deleteCurrentUser() {
213
+ await api.deleteCurrentUser()
214
+ currentUser.value = null
215
+ }
216
+
217
+ async function sendVerification(email?: string) {
218
+ await api.sendVerification({ email })
219
+ }
220
+
221
+ async function verifyEmail(token: string) {
222
+ await api.verifyEmail(token)
223
+ // Refresh user data to get updated verification status
224
+ await checkAuth()
225
+ emitter.emit(AuthState.EMAIL_VERIFIED)
226
+ }
227
+
228
+ async function refreshSession() {
229
+ await api.refreshSession()
230
+ emitter.emit(AuthState.SESSION_REFRESH)
231
+ }
232
+
233
+ async function getSessions(accountId?: string) {
234
+ const id = accountId ?? currentUser.value?.id
235
+ if (id === undefined || id === '') {
236
+ throw new Error('No account ID available')
172
237
  }
238
+ return api.getSessions(id)
173
239
  }
174
240
 
175
- async function deleteUser(userId: string) {
176
- try {
177
- await authApi!.deleteUser(userId)
178
- } catch (error) {
179
- throw error
241
+ async function revokeSession(sessionToken: string) {
242
+ await api.revokeSession(sessionToken)
243
+ }
244
+
245
+ async function revokeAllSessions(accountId?: string) {
246
+ const id = accountId ?? currentUser.value?.id
247
+ if (id === undefined || id === '') {
248
+ throw new Error('No account ID available')
180
249
  }
250
+ await api.revokeAllSessions(id)
181
251
  }
182
252
 
183
253
  return {
@@ -187,17 +257,37 @@ export function useAuth() {
187
257
  // Getters
188
258
  getFullName,
189
259
  getIsLoggedIn,
260
+ getEmail,
190
261
 
191
- // Actions
192
- logout,
262
+ // Authentication Actions
193
263
  login,
194
- checkAuth,
264
+ logout,
195
265
  signup,
196
- recoverPassword,
197
- resetPassword,
198
- updatePassword,
266
+ checkAuth,
267
+ refreshSession,
268
+
269
+ // Profile Actions
199
270
  updateProfile,
200
- toggleUserStatus,
201
- deleteUser,
271
+ deleteCurrentUser,
272
+
273
+ // Password Actions
274
+ changePassword,
275
+ forgotPassword,
276
+ verifyResetToken,
277
+ resetPassword,
278
+
279
+ // Email Verification Actions
280
+ sendVerification,
281
+ verifyEmail,
282
+
283
+ // Admin Actions
284
+ activateAccount,
285
+ deactivateAccount,
286
+ deleteAccount,
287
+
288
+ // Session Management
289
+ getSessions,
290
+ revokeSession,
291
+ revokeAllSessions,
202
292
  }
203
293
  }