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