@bagelink/auth 1.1.41 → 1.1.45
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 +142 -193
- package/dist/index.d.cts +25 -26
- package/dist/index.d.mts +25 -26
- package/dist/index.d.ts +25 -26
- package/dist/index.mjs +142 -181
- package/package.json +13 -3
- package/src/api/auth.ts +90 -68
- package/src/composable/useAuth.ts +66 -122
- package/src/utils.ts +12 -0
- package/src/api/api.ts +0 -20
package/src/api/auth.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { InternalAxiosRequestConfig } from 'axios'
|
|
1
|
+
import type { AxiosInstance, InternalAxiosRequestConfig } from 'axios'
|
|
2
2
|
import type {
|
|
3
3
|
User,
|
|
4
4
|
NewUser,
|
|
@@ -19,90 +19,112 @@ import type {
|
|
|
19
19
|
GetMeResponse,
|
|
20
20
|
UpdateMeResponse,
|
|
21
21
|
UpdatePasswordResponse,
|
|
22
|
-
SignupResponse
|
|
22
|
+
SignupResponse,
|
|
23
23
|
} from '../types'
|
|
24
|
-
import {
|
|
24
|
+
import { createAxiosInstance } from '../utils'
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
export class AuthApi {
|
|
27
|
+
private api: AxiosInstance
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
config.headers.Authorization = `Bearer ${token}`
|
|
29
|
+
constructor(axiosInstance?: AxiosInstance, baseURL: string = '') {
|
|
30
|
+
this.api = axiosInstance || createAxiosInstance(baseURL)
|
|
31
|
+
this.setupInterceptors()
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
private setupInterceptors() {
|
|
35
|
+
this.api.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
|
36
|
+
const token = localStorage.getItem('access_token')
|
|
37
|
+
if (token !== null && config.headers) {
|
|
38
|
+
config.headers.Authorization = `Bearer ${token}`
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const urlParams = new URLSearchParams(window.location.search)
|
|
42
|
+
const resetToken = urlParams.get('token')
|
|
43
|
+
|
|
44
|
+
if (resetToken !== null && config.headers) {
|
|
45
|
+
config.headers.Authorization = `Bearer ${resetToken}`
|
|
46
|
+
}
|
|
47
|
+
return config
|
|
48
|
+
})
|
|
49
|
+
}
|
|
36
50
|
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
async login(username: string, password: string): Promise<LoginResponse> {
|
|
52
|
+
const { data } = await this.api.post<Token>('/auth/login', {
|
|
53
|
+
username: username.toLowerCase(),
|
|
54
|
+
password,
|
|
55
|
+
})
|
|
56
|
+
localStorage.setItem('access_token', data.access_token)
|
|
57
|
+
return { data } as LoginResponse
|
|
39
58
|
}
|
|
40
|
-
return config
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
export async function login(username: string, password: string): Promise<LoginResponse> {
|
|
44
|
-
const { data } = await ax.post<Token>('/auth/login', {
|
|
45
|
-
username: username.toLowerCase(),
|
|
46
|
-
password,
|
|
47
|
-
})
|
|
48
|
-
localStorage.setItem('access_token', data.access_token)
|
|
49
|
-
return { data } as LoginResponse
|
|
50
|
-
}
|
|
51
59
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
60
|
+
logout() {
|
|
61
|
+
localStorage.removeItem('access_token')
|
|
62
|
+
window.location.reload()
|
|
63
|
+
}
|
|
56
64
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
65
|
+
async passwordRecovery(email?: string): Promise<PasswordRecoveryResponse> {
|
|
66
|
+
return this.api.post('/auth/password-recovery', { email })
|
|
67
|
+
}
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
async resetPassword(
|
|
70
|
+
newPassword: NewPassword['new_password']
|
|
71
|
+
): Promise<ResetPasswordResponse> {
|
|
72
|
+
return this.api.post('/auth/reset-password', { new_password: newPassword })
|
|
73
|
+
}
|
|
64
74
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
75
|
+
async getCurrentUser(): Promise<GetMeResponse> {
|
|
76
|
+
return this.api.get<SanitizedUserOut>('/users/me')
|
|
77
|
+
}
|
|
69
78
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
79
|
+
async signup(user: NewUser): Promise<SignupResponse> {
|
|
80
|
+
return this.api.post<SanitizedUserOut>('/users/signup', {
|
|
81
|
+
email: user.email.toLowerCase(),
|
|
82
|
+
password: user.password,
|
|
83
|
+
first_name: user.first_name,
|
|
84
|
+
last_name: user.last_name,
|
|
85
|
+
})
|
|
86
|
+
}
|
|
78
87
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
async updatePassword(
|
|
89
|
+
form: UpdatePasswordForm
|
|
90
|
+
): Promise<UpdatePasswordResponse> {
|
|
91
|
+
return this.api.patch('/users/me/password', {
|
|
92
|
+
current_password: form.current_password,
|
|
93
|
+
new_password: form.new_password,
|
|
94
|
+
})
|
|
95
|
+
}
|
|
85
96
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
97
|
+
async updateUserProfile(user: Partial<User>): Promise<UpdateMeResponse> {
|
|
98
|
+
return this.api.patch<SanitizedUserOut>('/users/me', user)
|
|
99
|
+
}
|
|
89
100
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
101
|
+
async setUserStatus(
|
|
102
|
+
userId: string,
|
|
103
|
+
isActive: boolean
|
|
104
|
+
): Promise<UpdateUserResponse> {
|
|
105
|
+
return this.api.patch<SanitizedUserOut>(`/users/${userId}`, {
|
|
106
|
+
is_active: isActive,
|
|
107
|
+
})
|
|
108
|
+
}
|
|
93
109
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
110
|
+
async deleteUser(userId: string): Promise<DeleteUserResponse> {
|
|
111
|
+
return this.api.delete(`/users/${userId}`)
|
|
112
|
+
}
|
|
97
113
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
114
|
+
async getUsers(
|
|
115
|
+
limit: number = 100,
|
|
116
|
+
skip?: number
|
|
117
|
+
): Promise<GetUsersResponse> {
|
|
118
|
+
return this.api.get<SanitizedUserList>('/users/', {
|
|
119
|
+
params: { skip, limit },
|
|
120
|
+
})
|
|
121
|
+
}
|
|
101
122
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
123
|
+
async createUser(user: UserCreate): Promise<CreateUserResponse> {
|
|
124
|
+
return this.api.post<SanitizedUserOut>('/users/', user)
|
|
125
|
+
}
|
|
105
126
|
|
|
106
|
-
|
|
107
|
-
|
|
127
|
+
async getUser(userId: string): Promise<GetUserResponse> {
|
|
128
|
+
return this.api.get<SanitizedUserOut>(`/users/${userId}`)
|
|
129
|
+
}
|
|
108
130
|
}
|
|
@@ -1,124 +1,82 @@
|
|
|
1
1
|
import type { AxiosInstance } from 'axios'
|
|
2
|
-
import type {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
let
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return <T>(initial: T) => {
|
|
21
|
-
const refValue = app.ref(initial)
|
|
22
|
-
return {
|
|
23
|
-
get value() { return refValue.value },
|
|
24
|
-
set: (v: T) => { refValue.value = v }
|
|
25
|
-
}
|
|
26
|
-
}
|
|
2
|
+
import type { App } from 'vue'
|
|
3
|
+
import type { User, NewUser, UpdatePasswordForm } from '../types'
|
|
4
|
+
import { AuthApi } from '../api/auth'
|
|
5
|
+
|
|
6
|
+
// Global state
|
|
7
|
+
let authApi: AuthApi | null = null
|
|
8
|
+
const currentUser = {
|
|
9
|
+
value: {
|
|
10
|
+
id: '',
|
|
11
|
+
email: '',
|
|
12
|
+
first_name: '',
|
|
13
|
+
last_name: '',
|
|
14
|
+
is_superuser: false,
|
|
15
|
+
is_active: false,
|
|
16
|
+
} as User,
|
|
17
|
+
set: (newValue: User) => {
|
|
18
|
+
currentUser.value = newValue
|
|
19
|
+
},
|
|
27
20
|
}
|
|
28
21
|
|
|
29
|
-
//
|
|
22
|
+
// Initialize auth
|
|
30
23
|
export function initAuth({
|
|
31
24
|
axios,
|
|
32
|
-
|
|
33
|
-
reactive = defaultReactiveFactory,
|
|
34
|
-
baseURL
|
|
25
|
+
baseURL,
|
|
35
26
|
}: {
|
|
36
|
-
axios
|
|
37
|
-
errorHandler?: (error: any) => void
|
|
38
|
-
reactive?: ReactiveFactory
|
|
27
|
+
axios: AxiosInstance
|
|
39
28
|
baseURL?: string
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Initialize error handler
|
|
45
|
-
if (errorHandler) onError = errorHandler
|
|
46
|
-
|
|
47
|
-
// Initialize reactive factory
|
|
48
|
-
createRef = reactive
|
|
29
|
+
}) {
|
|
30
|
+
if (!authApi) {
|
|
31
|
+
authApi = new AuthApi(axios, baseURL)
|
|
32
|
+
}
|
|
49
33
|
|
|
50
|
-
// Return plugin interface
|
|
51
34
|
return {
|
|
52
|
-
install(app:
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
createRef = createVueReactiveFactory(app)
|
|
56
|
-
}
|
|
35
|
+
install(app: App) {
|
|
36
|
+
// Make auth available globally
|
|
37
|
+
app.config.globalProperties.$auth = useAuth()
|
|
57
38
|
},
|
|
58
|
-
useAuth
|
|
59
39
|
}
|
|
60
40
|
}
|
|
61
41
|
|
|
42
|
+
// Composable
|
|
62
43
|
export function useAuth() {
|
|
63
|
-
if (!
|
|
64
|
-
throw new Error('Auth
|
|
44
|
+
if (!authApi) {
|
|
45
|
+
throw new Error('Auth not initialized. Call initAuth first.')
|
|
65
46
|
}
|
|
66
47
|
|
|
67
|
-
// State
|
|
68
|
-
const currentUser = createRef<User>({
|
|
69
|
-
id: '',
|
|
70
|
-
email: '',
|
|
71
|
-
first_name: '',
|
|
72
|
-
last_name: '',
|
|
73
|
-
is_superuser: false,
|
|
74
|
-
is_active: false,
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
const passwordForm = createRef<UpdatePasswordForm>({
|
|
78
|
-
current_password: '',
|
|
79
|
-
new_password: '',
|
|
80
|
-
confirmNewPassword: '',
|
|
81
|
-
})
|
|
82
|
-
|
|
83
48
|
// Getters
|
|
84
49
|
const getFullName = () => `${currentUser.value.first_name} ${currentUser.value.last_name}`
|
|
85
50
|
const getIsLoggedIn = () => currentUser.value.id.length > 0
|
|
86
51
|
|
|
87
|
-
// Error handling
|
|
88
|
-
function handleError(error: any) {
|
|
89
|
-
if (onError) {
|
|
90
|
-
onError(error)
|
|
91
|
-
}
|
|
92
|
-
throw error
|
|
93
|
-
}
|
|
94
|
-
|
|
95
52
|
// Actions
|
|
96
53
|
async function logout() {
|
|
97
54
|
try {
|
|
98
|
-
await authApi
|
|
99
|
-
} catch (error
|
|
100
|
-
|
|
55
|
+
await authApi!.logout()
|
|
56
|
+
} catch (error) {
|
|
57
|
+
throw error
|
|
101
58
|
}
|
|
102
59
|
}
|
|
103
60
|
|
|
104
61
|
async function login(credentials: { email: string, password: string }) {
|
|
105
|
-
const email = credentials.email.toLowerCase()
|
|
106
|
-
const { password } = credentials
|
|
107
62
|
try {
|
|
108
|
-
await authApi
|
|
63
|
+
await authApi!.login(
|
|
64
|
+
credentials.email.toLowerCase(),
|
|
65
|
+
credentials.password
|
|
66
|
+
)
|
|
109
67
|
await checkAuth()
|
|
110
|
-
} catch (error
|
|
111
|
-
|
|
68
|
+
} catch (error) {
|
|
69
|
+
throw error
|
|
112
70
|
}
|
|
113
71
|
}
|
|
114
72
|
|
|
115
73
|
async function checkAuth(): Promise<boolean> {
|
|
116
74
|
try {
|
|
117
75
|
if (!getIsLoggedIn()) {
|
|
118
|
-
const { data } = await authApi
|
|
76
|
+
const { data } = await authApi!.getCurrentUser()
|
|
119
77
|
currentUser.set(data)
|
|
120
78
|
}
|
|
121
|
-
} catch (error
|
|
79
|
+
} catch (error) {
|
|
122
80
|
return false
|
|
123
81
|
}
|
|
124
82
|
return getIsLoggedIn()
|
|
@@ -129,82 +87,68 @@ export function useAuth() {
|
|
|
129
87
|
if (user.password !== user.confirmPassword) {
|
|
130
88
|
throw new Error('Passwords do not match')
|
|
131
89
|
}
|
|
132
|
-
const { data } = await authApi
|
|
90
|
+
const { data } = await authApi!.signup(user)
|
|
133
91
|
currentUser.set(data)
|
|
134
|
-
} catch (error
|
|
135
|
-
|
|
92
|
+
} catch (error) {
|
|
93
|
+
throw error
|
|
136
94
|
}
|
|
137
95
|
}
|
|
138
96
|
|
|
139
97
|
async function recoverPassword(email: string) {
|
|
140
98
|
try {
|
|
141
|
-
await authApi
|
|
142
|
-
} catch (error
|
|
143
|
-
|
|
99
|
+
await authApi!.passwordRecovery(email)
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw error
|
|
144
102
|
}
|
|
145
103
|
}
|
|
146
104
|
|
|
147
|
-
async function resetPassword(
|
|
105
|
+
async function resetPassword(newPassword: string) {
|
|
148
106
|
try {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
await authApi.resetPassword(form.new_password)
|
|
153
|
-
form = {
|
|
154
|
-
current_password: '',
|
|
155
|
-
new_password: '',
|
|
156
|
-
confirmNewPassword: '',
|
|
157
|
-
}
|
|
158
|
-
} catch (error: any) {
|
|
159
|
-
handleError(error)
|
|
107
|
+
await authApi!.resetPassword(newPassword)
|
|
108
|
+
} catch (error) {
|
|
109
|
+
throw error
|
|
160
110
|
}
|
|
161
111
|
}
|
|
162
112
|
|
|
163
|
-
async function updatePassword() {
|
|
113
|
+
async function updatePassword(form: UpdatePasswordForm) {
|
|
164
114
|
try {
|
|
165
|
-
if (
|
|
115
|
+
if (form.new_password !== form.confirmNewPassword) {
|
|
166
116
|
throw new Error('Passwords do not match')
|
|
167
117
|
}
|
|
168
|
-
await authApi
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
new_password: '',
|
|
172
|
-
confirmNewPassword: '',
|
|
173
|
-
})
|
|
174
|
-
} catch (error: any) {
|
|
175
|
-
handleError(error)
|
|
118
|
+
await authApi!.updatePassword(form)
|
|
119
|
+
} catch (error) {
|
|
120
|
+
throw error
|
|
176
121
|
}
|
|
177
122
|
}
|
|
178
123
|
|
|
179
124
|
async function updateProfile(user: Partial<User>) {
|
|
180
125
|
try {
|
|
181
|
-
const { data } = await authApi
|
|
126
|
+
const { data } = await authApi!.updateUserProfile(user)
|
|
182
127
|
currentUser.set({ ...currentUser.value, ...data })
|
|
183
|
-
} catch (error
|
|
184
|
-
|
|
128
|
+
} catch (error) {
|
|
129
|
+
throw error
|
|
185
130
|
}
|
|
186
131
|
}
|
|
187
132
|
|
|
188
133
|
async function toggleUserStatus(userId: string, isActive: boolean) {
|
|
189
134
|
try {
|
|
190
|
-
await authApi
|
|
191
|
-
} catch (error
|
|
192
|
-
|
|
135
|
+
await authApi!.setUserStatus(userId, isActive)
|
|
136
|
+
} catch (error) {
|
|
137
|
+
throw error
|
|
193
138
|
}
|
|
194
139
|
}
|
|
195
140
|
|
|
196
141
|
async function deleteUser(userId: string) {
|
|
197
142
|
try {
|
|
198
|
-
await authApi
|
|
199
|
-
} catch (error
|
|
200
|
-
|
|
143
|
+
await authApi!.deleteUser(userId)
|
|
144
|
+
} catch (error) {
|
|
145
|
+
throw error
|
|
201
146
|
}
|
|
202
147
|
}
|
|
203
148
|
|
|
204
149
|
return {
|
|
205
150
|
// State
|
|
206
151
|
currentUser,
|
|
207
|
-
passwordForm,
|
|
208
152
|
|
|
209
153
|
// Getters
|
|
210
154
|
getFullName,
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AxiosInstance } from 'axios'
|
|
2
|
+
import axios from 'axios'
|
|
3
|
+
|
|
4
|
+
export function createAxiosInstance(baseURL: string = ''): AxiosInstance {
|
|
5
|
+
return axios.create({
|
|
6
|
+
baseURL: baseURL || '',
|
|
7
|
+
headers: {
|
|
8
|
+
'Content-Type': 'application/json',
|
|
9
|
+
'withCredentials': true,
|
|
10
|
+
},
|
|
11
|
+
})
|
|
12
|
+
}
|
package/src/api/api.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { AxiosInstance } from 'axios'
|
|
2
|
-
import axios from 'axios'
|
|
3
|
-
|
|
4
|
-
const api: AxiosInstance | undefined = undefined
|
|
5
|
-
|
|
6
|
-
export function getApi(): AxiosInstance {
|
|
7
|
-
if (!api) {
|
|
8
|
-
throw new Error('API not initialized. Call initAuth first.')
|
|
9
|
-
}
|
|
10
|
-
return api
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function createDefaultApi(baseURL?: string) {
|
|
14
|
-
return axios.create({
|
|
15
|
-
baseURL,
|
|
16
|
-
headers: {
|
|
17
|
-
'Content-Type': 'application/json',
|
|
18
|
-
},
|
|
19
|
-
})
|
|
20
|
-
}
|