@bagelink/auth 1.4.167 → 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/dist/index.cjs +334 -156
- package/dist/index.d.cts +306 -99
- package/dist/index.d.mts +306 -99
- package/dist/index.d.ts +306 -99
- package/dist/index.mjs +334 -156
- package/package.json +1 -1
- package/src/api.ts +230 -72
- package/src/types.ts +191 -70
- package/src/useAuth.ts +195 -105
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 {
|
|
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<
|
|
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 (
|
|
28
|
+
if (authApi === null) {
|
|
30
29
|
authApi = new AuthApi(axios, baseURL)
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
if (
|
|
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
|
|
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
|
|
45
|
+
if (eventEmitter) {
|
|
46
|
+
eventEmitter.off(event, handler)
|
|
47
|
+
}
|
|
45
48
|
},
|
|
46
49
|
|
|
47
50
|
removeAllListeners<K extends AuthState>(event?: K): void {
|
|
48
|
-
eventEmitter
|
|
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 (
|
|
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 = () =>
|
|
66
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
|
137
|
-
|
|
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
|
|
146
|
-
|
|
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
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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
|
-
|
|
264
|
+
logout,
|
|
195
265
|
signup,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
266
|
+
checkAuth,
|
|
267
|
+
refreshSession,
|
|
268
|
+
|
|
269
|
+
// Profile Actions
|
|
199
270
|
updateProfile,
|
|
200
|
-
|
|
201
|
-
|
|
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
|
}
|