@bagelink/auth 1.4.54 → 1.4.62
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 +73 -3
- package/dist/index.cjs +72 -0
- package/dist/index.d.cts +22 -2
- package/dist/index.d.mts +22 -2
- package/dist/index.d.ts +22 -2
- package/dist/index.mjs +72 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/types.ts +20 -0
- package/src/useAuth.ts +39 -1
- package/src/utils.ts +34 -0
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ A framework-agnostic authentication composable with Vue support.
|
|
|
10
10
|
- Complete authentication flow (login, signup, password recovery, etc.)
|
|
11
11
|
- Error handling
|
|
12
12
|
- User management
|
|
13
|
+
- Event listeners for authentication state changes
|
|
13
14
|
|
|
14
15
|
## Installation
|
|
15
16
|
|
|
@@ -22,12 +23,23 @@ bun add @bagelink/auth
|
|
|
22
23
|
### Basic Setup
|
|
23
24
|
|
|
24
25
|
```typescript
|
|
25
|
-
import { initAuth } from '@bagelink/auth'
|
|
26
|
+
import { initAuth, AuthState } from '@bagelink/auth'
|
|
26
27
|
|
|
27
28
|
// Initialize with axios instance
|
|
28
29
|
const auth = initAuth({
|
|
29
30
|
axios: axiosInstance,
|
|
30
|
-
|
|
31
|
+
baseURL: 'https://api.example.com'
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
// Add event listeners for authentication state changes
|
|
35
|
+
auth.on(AuthState.LOGIN, () => {
|
|
36
|
+
console.log('User logged in!')
|
|
37
|
+
// Redirect to dashboard, update UI, etc.
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
auth.on(AuthState.LOGOUT, () => {
|
|
41
|
+
console.log('User logged out!')
|
|
42
|
+
// Redirect to login page, clear sensitive data, etc.
|
|
31
43
|
})
|
|
32
44
|
```
|
|
33
45
|
|
|
@@ -73,6 +85,64 @@ export default {
|
|
|
73
85
|
}
|
|
74
86
|
```
|
|
75
87
|
|
|
88
|
+
### Event Listeners
|
|
89
|
+
|
|
90
|
+
You can listen to authentication state changes using the event system:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { initAuth, AuthState } from '@bagelink/auth'
|
|
94
|
+
|
|
95
|
+
const auth = initAuth({
|
|
96
|
+
axios: axiosInstance,
|
|
97
|
+
baseURL: 'https://api.example.com'
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
// Listen to login events
|
|
101
|
+
auth.on(AuthState.LOGIN, () => {
|
|
102
|
+
router.push('/dashboard')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// Listen to logout events
|
|
106
|
+
auth.on(AuthState.LOGOUT, () => {
|
|
107
|
+
router.push('/login')
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// Listen to signup events
|
|
111
|
+
auth.on(AuthState.SIGNUP, () => {
|
|
112
|
+
router.push('/welcome')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
// Listen to password reset events
|
|
116
|
+
auth.on(AuthState.PASSWORD_RESET, () => {
|
|
117
|
+
console.log('Password has been reset')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// Listen to profile update events
|
|
121
|
+
auth.on(AuthState.PROFILE_UPDATE, () => {
|
|
122
|
+
console.log('Profile updated successfully')
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
// Listen to auth check events (when user is authenticated)
|
|
126
|
+
auth.on(AuthState.AUTH_CHECK, () => {
|
|
127
|
+
console.log('User authentication verified')
|
|
128
|
+
})
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
#### Event Methods
|
|
132
|
+
|
|
133
|
+
- `auth.on(event, handler)`: Add an event listener
|
|
134
|
+
- `auth.off(event, handler)`: Remove a specific event listener
|
|
135
|
+
- `auth.removeAllListeners(event?)`: Remove all listeners for an event (or all events if no event specified)
|
|
136
|
+
|
|
137
|
+
#### Available Events
|
|
138
|
+
|
|
139
|
+
- `AuthState.LOGIN`: Fired when user successfully logs in
|
|
140
|
+
- `AuthState.LOGOUT`: Fired when user logs out
|
|
141
|
+
- `AuthState.SIGNUP`: Fired when user successfully signs up
|
|
142
|
+
- `AuthState.PASSWORD_RESET`: Fired when password is reset or updated
|
|
143
|
+
- `AuthState.PROFILE_UPDATE`: Fired when user profile is updated
|
|
144
|
+
- `AuthState.AUTH_CHECK`: Fired when user authentication is verified
|
|
145
|
+
|
|
76
146
|
### Vanilla JavaScript
|
|
77
147
|
|
|
78
148
|
```typescript
|
|
@@ -80,7 +150,7 @@ import { initAuth } from '@bagelink/auth'
|
|
|
80
150
|
|
|
81
151
|
const auth = initAuth({
|
|
82
152
|
axios: axiosInstance,
|
|
83
|
-
|
|
153
|
+
baseURL: 'https://api.example.com'
|
|
84
154
|
})
|
|
85
155
|
|
|
86
156
|
const { login, currentUser, getIsLoggedIn } = auth.useAuth()
|
package/dist/index.cjs
CHANGED
|
@@ -16,6 +16,36 @@ function createAxiosInstance(baseURL = "") {
|
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
+
class EventEmitter {
|
|
20
|
+
listeners = /* @__PURE__ */ new Map();
|
|
21
|
+
on(event, handler) {
|
|
22
|
+
if (!this.listeners.has(event)) {
|
|
23
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
24
|
+
}
|
|
25
|
+
this.listeners.get(event).add(handler);
|
|
26
|
+
}
|
|
27
|
+
off(event, handler) {
|
|
28
|
+
const eventListeners = this.listeners.get(event);
|
|
29
|
+
if (eventListeners) {
|
|
30
|
+
eventListeners.delete(handler);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
emit(event) {
|
|
34
|
+
const eventListeners = this.listeners.get(event);
|
|
35
|
+
if (eventListeners) {
|
|
36
|
+
eventListeners.forEach((handler) => {
|
|
37
|
+
handler();
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
removeAllListeners(event) {
|
|
42
|
+
if (event) {
|
|
43
|
+
this.listeners.delete(event);
|
|
44
|
+
} else {
|
|
45
|
+
this.listeners.clear();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
19
49
|
|
|
20
50
|
class AuthApi {
|
|
21
51
|
api;
|
|
@@ -96,7 +126,18 @@ class AuthApi {
|
|
|
96
126
|
}
|
|
97
127
|
}
|
|
98
128
|
|
|
129
|
+
var AuthState = /* @__PURE__ */ ((AuthState2) => {
|
|
130
|
+
AuthState2["LOGIN"] = "login";
|
|
131
|
+
AuthState2["LOGOUT"] = "logout";
|
|
132
|
+
AuthState2["SIGNUP"] = "signup";
|
|
133
|
+
AuthState2["PASSWORD_RESET"] = "password_reset";
|
|
134
|
+
AuthState2["PROFILE_UPDATE"] = "profile_update";
|
|
135
|
+
AuthState2["AUTH_CHECK"] = "auth_check";
|
|
136
|
+
return AuthState2;
|
|
137
|
+
})(AuthState || {});
|
|
138
|
+
|
|
99
139
|
let authApi = null;
|
|
140
|
+
let eventEmitter = null;
|
|
100
141
|
const currentUser = vue.ref({
|
|
101
142
|
id: "",
|
|
102
143
|
email: "",
|
|
@@ -112,7 +153,20 @@ function initAuth({
|
|
|
112
153
|
if (!authApi) {
|
|
113
154
|
authApi = new AuthApi(axios, baseURL);
|
|
114
155
|
}
|
|
156
|
+
if (!eventEmitter) {
|
|
157
|
+
eventEmitter = new EventEmitter();
|
|
158
|
+
}
|
|
115
159
|
return {
|
|
160
|
+
// Event listener methods
|
|
161
|
+
on(event, handler) {
|
|
162
|
+
eventEmitter.on(event, handler);
|
|
163
|
+
},
|
|
164
|
+
off(event, handler) {
|
|
165
|
+
eventEmitter.off(event, handler);
|
|
166
|
+
},
|
|
167
|
+
removeAllListeners(event) {
|
|
168
|
+
eventEmitter.removeAllListeners(event);
|
|
169
|
+
},
|
|
116
170
|
install(app) {
|
|
117
171
|
app.config.globalProperties.$auth = useAuth();
|
|
118
172
|
}
|
|
@@ -127,6 +181,15 @@ function useAuth() {
|
|
|
127
181
|
async function logout() {
|
|
128
182
|
try {
|
|
129
183
|
await authApi.logout();
|
|
184
|
+
currentUser.value = {
|
|
185
|
+
id: "",
|
|
186
|
+
email: "",
|
|
187
|
+
first_name: "",
|
|
188
|
+
last_name: "",
|
|
189
|
+
is_superuser: false,
|
|
190
|
+
is_active: false
|
|
191
|
+
};
|
|
192
|
+
eventEmitter.emit(AuthState.LOGOUT);
|
|
130
193
|
} catch (error) {
|
|
131
194
|
throw error;
|
|
132
195
|
}
|
|
@@ -138,6 +201,7 @@ function useAuth() {
|
|
|
138
201
|
credentials.password
|
|
139
202
|
);
|
|
140
203
|
await checkAuth();
|
|
204
|
+
eventEmitter.emit(AuthState.LOGIN);
|
|
141
205
|
} catch (error) {
|
|
142
206
|
throw error;
|
|
143
207
|
}
|
|
@@ -147,6 +211,9 @@ function useAuth() {
|
|
|
147
211
|
if (!getIsLoggedIn()) {
|
|
148
212
|
const { data } = await authApi.getCurrentUser();
|
|
149
213
|
currentUser.value = data;
|
|
214
|
+
if (getIsLoggedIn()) {
|
|
215
|
+
eventEmitter.emit(AuthState.AUTH_CHECK);
|
|
216
|
+
}
|
|
150
217
|
}
|
|
151
218
|
} catch (error) {
|
|
152
219
|
return false;
|
|
@@ -160,6 +227,7 @@ function useAuth() {
|
|
|
160
227
|
}
|
|
161
228
|
const { data } = await authApi.signup(user);
|
|
162
229
|
currentUser.value = data;
|
|
230
|
+
eventEmitter.emit(AuthState.SIGNUP);
|
|
163
231
|
} catch (error) {
|
|
164
232
|
throw error;
|
|
165
233
|
}
|
|
@@ -174,6 +242,7 @@ function useAuth() {
|
|
|
174
242
|
async function resetPassword(newPassword) {
|
|
175
243
|
try {
|
|
176
244
|
await authApi.resetPassword(newPassword);
|
|
245
|
+
eventEmitter.emit(AuthState.PASSWORD_RESET);
|
|
177
246
|
} catch (error) {
|
|
178
247
|
throw error;
|
|
179
248
|
}
|
|
@@ -184,6 +253,7 @@ function useAuth() {
|
|
|
184
253
|
throw new Error("Passwords do not match");
|
|
185
254
|
}
|
|
186
255
|
await authApi.updatePassword(form);
|
|
256
|
+
eventEmitter.emit(AuthState.PASSWORD_RESET);
|
|
187
257
|
} catch (error) {
|
|
188
258
|
throw error;
|
|
189
259
|
}
|
|
@@ -192,6 +262,7 @@ function useAuth() {
|
|
|
192
262
|
try {
|
|
193
263
|
const { data } = await authApi.updateUserProfile(user);
|
|
194
264
|
currentUser.value = { ...currentUser.value, ...data };
|
|
265
|
+
eventEmitter.emit(AuthState.PROFILE_UPDATE);
|
|
195
266
|
} catch (error) {
|
|
196
267
|
throw error;
|
|
197
268
|
}
|
|
@@ -231,5 +302,6 @@ function useAuth() {
|
|
|
231
302
|
}
|
|
232
303
|
|
|
233
304
|
exports.AuthApi = AuthApi;
|
|
305
|
+
exports.AuthState = AuthState;
|
|
234
306
|
exports.initAuth = initAuth;
|
|
235
307
|
exports.useAuth = useAuth;
|
package/dist/index.d.cts
CHANGED
|
@@ -24,6 +24,23 @@ interface UpdatePasswordForm {
|
|
|
24
24
|
new_password: string;
|
|
25
25
|
confirmNewPassword: string;
|
|
26
26
|
}
|
|
27
|
+
declare enum AuthState {
|
|
28
|
+
LOGIN = "login",
|
|
29
|
+
LOGOUT = "logout",
|
|
30
|
+
SIGNUP = "signup",
|
|
31
|
+
PASSWORD_RESET = "password_reset",
|
|
32
|
+
PROFILE_UPDATE = "profile_update",
|
|
33
|
+
AUTH_CHECK = "auth_check"
|
|
34
|
+
}
|
|
35
|
+
type AuthEventHandler = () => void;
|
|
36
|
+
interface AuthEventMap {
|
|
37
|
+
[AuthState.LOGIN]: AuthEventHandler;
|
|
38
|
+
[AuthState.LOGOUT]: AuthEventHandler;
|
|
39
|
+
[AuthState.SIGNUP]: AuthEventHandler;
|
|
40
|
+
[AuthState.PASSWORD_RESET]: AuthEventHandler;
|
|
41
|
+
[AuthState.PROFILE_UPDATE]: AuthEventHandler;
|
|
42
|
+
[AuthState.AUTH_CHECK]: AuthEventHandler;
|
|
43
|
+
}
|
|
27
44
|
interface Token {
|
|
28
45
|
access_token: string;
|
|
29
46
|
}
|
|
@@ -105,6 +122,9 @@ declare function initAuth({ axios, baseURL, }: {
|
|
|
105
122
|
axios: AxiosInstance;
|
|
106
123
|
baseURL?: string;
|
|
107
124
|
}): {
|
|
125
|
+
on<K extends AuthState>(event: K, handler: AuthEventMap[K]): void;
|
|
126
|
+
off<K extends AuthState>(event: K, handler: AuthEventMap[K]): void;
|
|
127
|
+
removeAllListeners<K extends AuthState>(event?: K): void;
|
|
108
128
|
install(app: App): void;
|
|
109
129
|
};
|
|
110
130
|
declare function useAuth(): {
|
|
@@ -140,5 +160,5 @@ declare function useAuth(): {
|
|
|
140
160
|
deleteUser: (userId: string) => Promise<void>;
|
|
141
161
|
};
|
|
142
162
|
|
|
143
|
-
export { AuthApi, initAuth, useAuth };
|
|
144
|
-
export type { CreateUserResponse, DeleteUserResponse, GetMeResponse, GetUserResponse, GetUsersResponse, LoginResponse, NewPassword, NewUser, PasswordRecovery, PasswordRecoveryResponse, ResetPasswordResponse, SanitizedUserList, SanitizedUserOut, SignupResponse, Token, UpdateMeResponse, UpdatePassword, UpdatePasswordForm, UpdatePasswordResponse, UpdateUserResponse, User, UserCreate, UserRegister, UserUpdate, UserUpdateMe };
|
|
163
|
+
export { AuthApi, AuthState, initAuth, useAuth };
|
|
164
|
+
export type { AuthEventHandler, AuthEventMap, CreateUserResponse, DeleteUserResponse, GetMeResponse, GetUserResponse, GetUsersResponse, LoginResponse, NewPassword, NewUser, PasswordRecovery, PasswordRecoveryResponse, ResetPasswordResponse, SanitizedUserList, SanitizedUserOut, SignupResponse, Token, UpdateMeResponse, UpdatePassword, UpdatePasswordForm, UpdatePasswordResponse, UpdateUserResponse, User, UserCreate, UserRegister, UserUpdate, UserUpdateMe };
|
package/dist/index.d.mts
CHANGED
|
@@ -24,6 +24,23 @@ interface UpdatePasswordForm {
|
|
|
24
24
|
new_password: string;
|
|
25
25
|
confirmNewPassword: string;
|
|
26
26
|
}
|
|
27
|
+
declare enum AuthState {
|
|
28
|
+
LOGIN = "login",
|
|
29
|
+
LOGOUT = "logout",
|
|
30
|
+
SIGNUP = "signup",
|
|
31
|
+
PASSWORD_RESET = "password_reset",
|
|
32
|
+
PROFILE_UPDATE = "profile_update",
|
|
33
|
+
AUTH_CHECK = "auth_check"
|
|
34
|
+
}
|
|
35
|
+
type AuthEventHandler = () => void;
|
|
36
|
+
interface AuthEventMap {
|
|
37
|
+
[AuthState.LOGIN]: AuthEventHandler;
|
|
38
|
+
[AuthState.LOGOUT]: AuthEventHandler;
|
|
39
|
+
[AuthState.SIGNUP]: AuthEventHandler;
|
|
40
|
+
[AuthState.PASSWORD_RESET]: AuthEventHandler;
|
|
41
|
+
[AuthState.PROFILE_UPDATE]: AuthEventHandler;
|
|
42
|
+
[AuthState.AUTH_CHECK]: AuthEventHandler;
|
|
43
|
+
}
|
|
27
44
|
interface Token {
|
|
28
45
|
access_token: string;
|
|
29
46
|
}
|
|
@@ -105,6 +122,9 @@ declare function initAuth({ axios, baseURL, }: {
|
|
|
105
122
|
axios: AxiosInstance;
|
|
106
123
|
baseURL?: string;
|
|
107
124
|
}): {
|
|
125
|
+
on<K extends AuthState>(event: K, handler: AuthEventMap[K]): void;
|
|
126
|
+
off<K extends AuthState>(event: K, handler: AuthEventMap[K]): void;
|
|
127
|
+
removeAllListeners<K extends AuthState>(event?: K): void;
|
|
108
128
|
install(app: App): void;
|
|
109
129
|
};
|
|
110
130
|
declare function useAuth(): {
|
|
@@ -140,5 +160,5 @@ declare function useAuth(): {
|
|
|
140
160
|
deleteUser: (userId: string) => Promise<void>;
|
|
141
161
|
};
|
|
142
162
|
|
|
143
|
-
export { AuthApi, initAuth, useAuth };
|
|
144
|
-
export type { CreateUserResponse, DeleteUserResponse, GetMeResponse, GetUserResponse, GetUsersResponse, LoginResponse, NewPassword, NewUser, PasswordRecovery, PasswordRecoveryResponse, ResetPasswordResponse, SanitizedUserList, SanitizedUserOut, SignupResponse, Token, UpdateMeResponse, UpdatePassword, UpdatePasswordForm, UpdatePasswordResponse, UpdateUserResponse, User, UserCreate, UserRegister, UserUpdate, UserUpdateMe };
|
|
163
|
+
export { AuthApi, AuthState, initAuth, useAuth };
|
|
164
|
+
export type { AuthEventHandler, AuthEventMap, CreateUserResponse, DeleteUserResponse, GetMeResponse, GetUserResponse, GetUsersResponse, LoginResponse, NewPassword, NewUser, PasswordRecovery, PasswordRecoveryResponse, ResetPasswordResponse, SanitizedUserList, SanitizedUserOut, SignupResponse, Token, UpdateMeResponse, UpdatePassword, UpdatePasswordForm, UpdatePasswordResponse, UpdateUserResponse, User, UserCreate, UserRegister, UserUpdate, UserUpdateMe };
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,23 @@ interface UpdatePasswordForm {
|
|
|
24
24
|
new_password: string;
|
|
25
25
|
confirmNewPassword: string;
|
|
26
26
|
}
|
|
27
|
+
declare enum AuthState {
|
|
28
|
+
LOGIN = "login",
|
|
29
|
+
LOGOUT = "logout",
|
|
30
|
+
SIGNUP = "signup",
|
|
31
|
+
PASSWORD_RESET = "password_reset",
|
|
32
|
+
PROFILE_UPDATE = "profile_update",
|
|
33
|
+
AUTH_CHECK = "auth_check"
|
|
34
|
+
}
|
|
35
|
+
type AuthEventHandler = () => void;
|
|
36
|
+
interface AuthEventMap {
|
|
37
|
+
[AuthState.LOGIN]: AuthEventHandler;
|
|
38
|
+
[AuthState.LOGOUT]: AuthEventHandler;
|
|
39
|
+
[AuthState.SIGNUP]: AuthEventHandler;
|
|
40
|
+
[AuthState.PASSWORD_RESET]: AuthEventHandler;
|
|
41
|
+
[AuthState.PROFILE_UPDATE]: AuthEventHandler;
|
|
42
|
+
[AuthState.AUTH_CHECK]: AuthEventHandler;
|
|
43
|
+
}
|
|
27
44
|
interface Token {
|
|
28
45
|
access_token: string;
|
|
29
46
|
}
|
|
@@ -105,6 +122,9 @@ declare function initAuth({ axios, baseURL, }: {
|
|
|
105
122
|
axios: AxiosInstance;
|
|
106
123
|
baseURL?: string;
|
|
107
124
|
}): {
|
|
125
|
+
on<K extends AuthState>(event: K, handler: AuthEventMap[K]): void;
|
|
126
|
+
off<K extends AuthState>(event: K, handler: AuthEventMap[K]): void;
|
|
127
|
+
removeAllListeners<K extends AuthState>(event?: K): void;
|
|
108
128
|
install(app: App): void;
|
|
109
129
|
};
|
|
110
130
|
declare function useAuth(): {
|
|
@@ -140,5 +160,5 @@ declare function useAuth(): {
|
|
|
140
160
|
deleteUser: (userId: string) => Promise<void>;
|
|
141
161
|
};
|
|
142
162
|
|
|
143
|
-
export { AuthApi, initAuth, useAuth };
|
|
144
|
-
export type { CreateUserResponse, DeleteUserResponse, GetMeResponse, GetUserResponse, GetUsersResponse, LoginResponse, NewPassword, NewUser, PasswordRecovery, PasswordRecoveryResponse, ResetPasswordResponse, SanitizedUserList, SanitizedUserOut, SignupResponse, Token, UpdateMeResponse, UpdatePassword, UpdatePasswordForm, UpdatePasswordResponse, UpdateUserResponse, User, UserCreate, UserRegister, UserUpdate, UserUpdateMe };
|
|
163
|
+
export { AuthApi, AuthState, initAuth, useAuth };
|
|
164
|
+
export type { AuthEventHandler, AuthEventMap, CreateUserResponse, DeleteUserResponse, GetMeResponse, GetUserResponse, GetUsersResponse, LoginResponse, NewPassword, NewUser, PasswordRecovery, PasswordRecoveryResponse, ResetPasswordResponse, SanitizedUserList, SanitizedUserOut, SignupResponse, Token, UpdateMeResponse, UpdatePassword, UpdatePasswordForm, UpdatePasswordResponse, UpdateUserResponse, User, UserCreate, UserRegister, UserUpdate, UserUpdateMe };
|
package/dist/index.mjs
CHANGED
|
@@ -10,6 +10,36 @@ function createAxiosInstance(baseURL = "") {
|
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
|
+
class EventEmitter {
|
|
14
|
+
listeners = /* @__PURE__ */ new Map();
|
|
15
|
+
on(event, handler) {
|
|
16
|
+
if (!this.listeners.has(event)) {
|
|
17
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
18
|
+
}
|
|
19
|
+
this.listeners.get(event).add(handler);
|
|
20
|
+
}
|
|
21
|
+
off(event, handler) {
|
|
22
|
+
const eventListeners = this.listeners.get(event);
|
|
23
|
+
if (eventListeners) {
|
|
24
|
+
eventListeners.delete(handler);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
emit(event) {
|
|
28
|
+
const eventListeners = this.listeners.get(event);
|
|
29
|
+
if (eventListeners) {
|
|
30
|
+
eventListeners.forEach((handler) => {
|
|
31
|
+
handler();
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
removeAllListeners(event) {
|
|
36
|
+
if (event) {
|
|
37
|
+
this.listeners.delete(event);
|
|
38
|
+
} else {
|
|
39
|
+
this.listeners.clear();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
13
43
|
|
|
14
44
|
class AuthApi {
|
|
15
45
|
api;
|
|
@@ -90,7 +120,18 @@ class AuthApi {
|
|
|
90
120
|
}
|
|
91
121
|
}
|
|
92
122
|
|
|
123
|
+
var AuthState = /* @__PURE__ */ ((AuthState2) => {
|
|
124
|
+
AuthState2["LOGIN"] = "login";
|
|
125
|
+
AuthState2["LOGOUT"] = "logout";
|
|
126
|
+
AuthState2["SIGNUP"] = "signup";
|
|
127
|
+
AuthState2["PASSWORD_RESET"] = "password_reset";
|
|
128
|
+
AuthState2["PROFILE_UPDATE"] = "profile_update";
|
|
129
|
+
AuthState2["AUTH_CHECK"] = "auth_check";
|
|
130
|
+
return AuthState2;
|
|
131
|
+
})(AuthState || {});
|
|
132
|
+
|
|
93
133
|
let authApi = null;
|
|
134
|
+
let eventEmitter = null;
|
|
94
135
|
const currentUser = ref({
|
|
95
136
|
id: "",
|
|
96
137
|
email: "",
|
|
@@ -106,7 +147,20 @@ function initAuth({
|
|
|
106
147
|
if (!authApi) {
|
|
107
148
|
authApi = new AuthApi(axios, baseURL);
|
|
108
149
|
}
|
|
150
|
+
if (!eventEmitter) {
|
|
151
|
+
eventEmitter = new EventEmitter();
|
|
152
|
+
}
|
|
109
153
|
return {
|
|
154
|
+
// Event listener methods
|
|
155
|
+
on(event, handler) {
|
|
156
|
+
eventEmitter.on(event, handler);
|
|
157
|
+
},
|
|
158
|
+
off(event, handler) {
|
|
159
|
+
eventEmitter.off(event, handler);
|
|
160
|
+
},
|
|
161
|
+
removeAllListeners(event) {
|
|
162
|
+
eventEmitter.removeAllListeners(event);
|
|
163
|
+
},
|
|
110
164
|
install(app) {
|
|
111
165
|
app.config.globalProperties.$auth = useAuth();
|
|
112
166
|
}
|
|
@@ -121,6 +175,15 @@ function useAuth() {
|
|
|
121
175
|
async function logout() {
|
|
122
176
|
try {
|
|
123
177
|
await authApi.logout();
|
|
178
|
+
currentUser.value = {
|
|
179
|
+
id: "",
|
|
180
|
+
email: "",
|
|
181
|
+
first_name: "",
|
|
182
|
+
last_name: "",
|
|
183
|
+
is_superuser: false,
|
|
184
|
+
is_active: false
|
|
185
|
+
};
|
|
186
|
+
eventEmitter.emit(AuthState.LOGOUT);
|
|
124
187
|
} catch (error) {
|
|
125
188
|
throw error;
|
|
126
189
|
}
|
|
@@ -132,6 +195,7 @@ function useAuth() {
|
|
|
132
195
|
credentials.password
|
|
133
196
|
);
|
|
134
197
|
await checkAuth();
|
|
198
|
+
eventEmitter.emit(AuthState.LOGIN);
|
|
135
199
|
} catch (error) {
|
|
136
200
|
throw error;
|
|
137
201
|
}
|
|
@@ -141,6 +205,9 @@ function useAuth() {
|
|
|
141
205
|
if (!getIsLoggedIn()) {
|
|
142
206
|
const { data } = await authApi.getCurrentUser();
|
|
143
207
|
currentUser.value = data;
|
|
208
|
+
if (getIsLoggedIn()) {
|
|
209
|
+
eventEmitter.emit(AuthState.AUTH_CHECK);
|
|
210
|
+
}
|
|
144
211
|
}
|
|
145
212
|
} catch (error) {
|
|
146
213
|
return false;
|
|
@@ -154,6 +221,7 @@ function useAuth() {
|
|
|
154
221
|
}
|
|
155
222
|
const { data } = await authApi.signup(user);
|
|
156
223
|
currentUser.value = data;
|
|
224
|
+
eventEmitter.emit(AuthState.SIGNUP);
|
|
157
225
|
} catch (error) {
|
|
158
226
|
throw error;
|
|
159
227
|
}
|
|
@@ -168,6 +236,7 @@ function useAuth() {
|
|
|
168
236
|
async function resetPassword(newPassword) {
|
|
169
237
|
try {
|
|
170
238
|
await authApi.resetPassword(newPassword);
|
|
239
|
+
eventEmitter.emit(AuthState.PASSWORD_RESET);
|
|
171
240
|
} catch (error) {
|
|
172
241
|
throw error;
|
|
173
242
|
}
|
|
@@ -178,6 +247,7 @@ function useAuth() {
|
|
|
178
247
|
throw new Error("Passwords do not match");
|
|
179
248
|
}
|
|
180
249
|
await authApi.updatePassword(form);
|
|
250
|
+
eventEmitter.emit(AuthState.PASSWORD_RESET);
|
|
181
251
|
} catch (error) {
|
|
182
252
|
throw error;
|
|
183
253
|
}
|
|
@@ -186,6 +256,7 @@ function useAuth() {
|
|
|
186
256
|
try {
|
|
187
257
|
const { data } = await authApi.updateUserProfile(user);
|
|
188
258
|
currentUser.value = { ...currentUser.value, ...data };
|
|
259
|
+
eventEmitter.emit(AuthState.PROFILE_UPDATE);
|
|
189
260
|
} catch (error) {
|
|
190
261
|
throw error;
|
|
191
262
|
}
|
|
@@ -224,4 +295,4 @@ function useAuth() {
|
|
|
224
295
|
};
|
|
225
296
|
}
|
|
226
297
|
|
|
227
|
-
export { AuthApi, initAuth, useAuth };
|
|
298
|
+
export { AuthApi, AuthState, initAuth, useAuth };
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
1
2
|
import type { AxiosResponse } from 'axios'
|
|
2
3
|
|
|
3
4
|
export interface User {
|
|
@@ -26,6 +27,25 @@ export interface UpdatePasswordForm {
|
|
|
26
27
|
confirmNewPassword: string
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
export enum AuthState {
|
|
31
|
+
LOGIN = 'login',
|
|
32
|
+
LOGOUT = 'logout',
|
|
33
|
+
SIGNUP = 'signup',
|
|
34
|
+
PASSWORD_RESET = 'password_reset',
|
|
35
|
+
PROFILE_UPDATE = 'profile_update',
|
|
36
|
+
AUTH_CHECK = 'auth_check',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type AuthEventHandler = () => void
|
|
40
|
+
export interface AuthEventMap {
|
|
41
|
+
[AuthState.LOGIN]: AuthEventHandler
|
|
42
|
+
[AuthState.LOGOUT]: AuthEventHandler
|
|
43
|
+
[AuthState.SIGNUP]: AuthEventHandler
|
|
44
|
+
[AuthState.PASSWORD_RESET]: AuthEventHandler
|
|
45
|
+
[AuthState.PROFILE_UPDATE]: AuthEventHandler
|
|
46
|
+
[AuthState.AUTH_CHECK]: AuthEventHandler
|
|
47
|
+
}
|
|
48
|
+
|
|
29
49
|
// API Response Types
|
|
30
50
|
export interface Token {
|
|
31
51
|
access_token: string
|
package/src/useAuth.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { AxiosInstance } from 'axios'
|
|
2
2
|
import type { App } from 'vue'
|
|
3
|
-
import type { User, NewUser, UpdatePasswordForm } from './types'
|
|
3
|
+
import type { User, NewUser, UpdatePasswordForm, AuthEventMap } from './types'
|
|
4
4
|
import { ref } from 'vue'
|
|
5
5
|
import { AuthApi } from './api'
|
|
6
|
+
import { AuthState } from './types'
|
|
7
|
+
import { EventEmitter } from './utils'
|
|
6
8
|
|
|
7
9
|
// Global state
|
|
8
10
|
let authApi: AuthApi | null = null
|
|
11
|
+
let eventEmitter: EventEmitter | null = null
|
|
9
12
|
const currentUser = ref<User>({
|
|
10
13
|
id: '',
|
|
11
14
|
email: '',
|
|
@@ -27,7 +30,24 @@ export function initAuth({
|
|
|
27
30
|
authApi = new AuthApi(axios, baseURL)
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
if (!eventEmitter) {
|
|
34
|
+
eventEmitter = new EventEmitter()
|
|
35
|
+
}
|
|
36
|
+
|
|
30
37
|
return {
|
|
38
|
+
// Event listener methods
|
|
39
|
+
on<K extends AuthState>(event: K, handler: AuthEventMap[K]): void {
|
|
40
|
+
eventEmitter!.on(event, handler)
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
off<K extends AuthState>(event: K, handler: AuthEventMap[K]): void {
|
|
44
|
+
eventEmitter!.off(event, handler)
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
removeAllListeners<K extends AuthState>(event?: K): void {
|
|
48
|
+
eventEmitter!.removeAllListeners(event)
|
|
49
|
+
},
|
|
50
|
+
|
|
31
51
|
install(app: App) {
|
|
32
52
|
// Make auth available globally
|
|
33
53
|
app.config.globalProperties.$auth = useAuth()
|
|
@@ -49,6 +69,16 @@ export function useAuth() {
|
|
|
49
69
|
async function logout() {
|
|
50
70
|
try {
|
|
51
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)
|
|
52
82
|
} catch (error) {
|
|
53
83
|
throw error
|
|
54
84
|
}
|
|
@@ -61,6 +91,7 @@ export function useAuth() {
|
|
|
61
91
|
credentials.password
|
|
62
92
|
)
|
|
63
93
|
await checkAuth()
|
|
94
|
+
eventEmitter!.emit(AuthState.LOGIN)
|
|
64
95
|
} catch (error) {
|
|
65
96
|
throw error
|
|
66
97
|
}
|
|
@@ -71,6 +102,9 @@ export function useAuth() {
|
|
|
71
102
|
if (!getIsLoggedIn()) {
|
|
72
103
|
const { data } = await authApi!.getCurrentUser()
|
|
73
104
|
currentUser.value = data
|
|
105
|
+
if (getIsLoggedIn()) {
|
|
106
|
+
eventEmitter!.emit(AuthState.AUTH_CHECK)
|
|
107
|
+
}
|
|
74
108
|
}
|
|
75
109
|
} catch (error) {
|
|
76
110
|
return false
|
|
@@ -85,6 +119,7 @@ export function useAuth() {
|
|
|
85
119
|
}
|
|
86
120
|
const { data } = await authApi!.signup(user)
|
|
87
121
|
currentUser.value = data
|
|
122
|
+
eventEmitter!.emit(AuthState.SIGNUP)
|
|
88
123
|
} catch (error) {
|
|
89
124
|
throw error
|
|
90
125
|
}
|
|
@@ -101,6 +136,7 @@ export function useAuth() {
|
|
|
101
136
|
async function resetPassword(newPassword: string) {
|
|
102
137
|
try {
|
|
103
138
|
await authApi!.resetPassword(newPassword)
|
|
139
|
+
eventEmitter!.emit(AuthState.PASSWORD_RESET)
|
|
104
140
|
} catch (error) {
|
|
105
141
|
throw error
|
|
106
142
|
}
|
|
@@ -112,6 +148,7 @@ export function useAuth() {
|
|
|
112
148
|
throw new Error('Passwords do not match')
|
|
113
149
|
}
|
|
114
150
|
await authApi!.updatePassword(form)
|
|
151
|
+
eventEmitter!.emit(AuthState.PASSWORD_RESET)
|
|
115
152
|
} catch (error) {
|
|
116
153
|
throw error
|
|
117
154
|
}
|
|
@@ -121,6 +158,7 @@ export function useAuth() {
|
|
|
121
158
|
try {
|
|
122
159
|
const { data } = await authApi!.updateUserProfile(user)
|
|
123
160
|
currentUser.value = { ...currentUser.value, ...data }
|
|
161
|
+
eventEmitter!.emit(AuthState.PROFILE_UPDATE)
|
|
124
162
|
} catch (error) {
|
|
125
163
|
throw error
|
|
126
164
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AxiosInstance } from 'axios'
|
|
2
|
+
import type { AuthEventMap, AuthState } from './types'
|
|
2
3
|
import axios from 'axios'
|
|
3
4
|
|
|
4
5
|
export function createAxiosInstance(baseURL: string = ''): AxiosInstance {
|
|
@@ -10,3 +11,36 @@ export function createAxiosInstance(baseURL: string = ''): AxiosInstance {
|
|
|
10
11
|
},
|
|
11
12
|
})
|
|
12
13
|
}
|
|
14
|
+
|
|
15
|
+
export class EventEmitter {
|
|
16
|
+
private listeners: Map<string, Set<() => void>> = new Map()
|
|
17
|
+
|
|
18
|
+
on<K extends AuthState>(event: K, handler: AuthEventMap[K]): void {
|
|
19
|
+
if (!this.listeners.has(event)) {
|
|
20
|
+
this.listeners.set(event, new Set())
|
|
21
|
+
}
|
|
22
|
+
this.listeners.get(event)!.add(handler)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
off<K extends AuthState>(event: K, handler: AuthEventMap[K]): void {
|
|
26
|
+
const eventListeners = this.listeners.get(event)
|
|
27
|
+
if (eventListeners) {
|
|
28
|
+
eventListeners.delete(handler)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
emit<K extends AuthState>(event: K): void {
|
|
33
|
+
const eventListeners = this.listeners.get(event)
|
|
34
|
+
if (eventListeners) {
|
|
35
|
+
eventListeners.forEach((handler) => { handler() })
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
removeAllListeners<K extends AuthState>(event?: K): void {
|
|
40
|
+
if (event) {
|
|
41
|
+
this.listeners.delete(event)
|
|
42
|
+
} else {
|
|
43
|
+
this.listeners.clear()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|