@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/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 { getApi } from './api'
24
+ import { createAxiosInstance } from '../utils'
25
25
 
26
- const ax = getApi()
26
+ export class AuthApi {
27
+ private api: AxiosInstance
27
28
 
28
- ax.interceptors.request.use((config: InternalAxiosRequestConfig) => {
29
- const token = localStorage.getItem('access_token')
30
- if (token !== null && config.headers) {
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
- const urlParams = new URLSearchParams(window.location.search)
35
- const resetToken = urlParams.get('token')
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
- if (resetToken !== null && config.headers) {
38
- config.headers.Authorization = `Bearer ${resetToken}`
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
- export function logout() {
53
- localStorage.removeItem('access_token')
54
- window.location.reload()
55
- }
60
+ logout() {
61
+ localStorage.removeItem('access_token')
62
+ window.location.reload()
63
+ }
56
64
 
57
- export async function passwordRecovery(email?: string): Promise<PasswordRecoveryResponse> {
58
- return ax.post('/auth/password-recovery', { email })
59
- }
65
+ async passwordRecovery(email?: string): Promise<PasswordRecoveryResponse> {
66
+ return this.api.post('/auth/password-recovery', { email })
67
+ }
60
68
 
61
- export async function resetPassword(newPassword: NewPassword['new_password']): Promise<ResetPasswordResponse> {
62
- return ax.post('/auth/reset-password', { new_password: newPassword })
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
- // User Management APIs
66
- export async function getCurrentUser(): Promise<GetMeResponse> {
67
- return ax.get<SanitizedUserOut>('/users/me')
68
- }
75
+ async getCurrentUser(): Promise<GetMeResponse> {
76
+ return this.api.get<SanitizedUserOut>('/users/me')
77
+ }
69
78
 
70
- export async function signup(user: NewUser): Promise<SignupResponse> {
71
- return ax.post<SanitizedUserOut>('/users/signup', {
72
- email: user.email.toLowerCase(),
73
- password: user.password,
74
- first_name: user.first_name,
75
- last_name: user.last_name,
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
- export async function updatePassword(form: UpdatePasswordForm): Promise<UpdatePasswordResponse> {
80
- return ax.patch('/users/me/password', {
81
- current_password: form.current_password,
82
- new_password: form.new_password,
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
- export async function updateUserProfile(user: Partial<User>): Promise<UpdateMeResponse> {
87
- return ax.patch<SanitizedUserOut>('/users/me', user)
88
- }
97
+ async updateUserProfile(user: Partial<User>): Promise<UpdateMeResponse> {
98
+ return this.api.patch<SanitizedUserOut>('/users/me', user)
99
+ }
89
100
 
90
- export async function setUserStatus(userId: string, isActive: boolean): Promise<UpdateUserResponse> {
91
- return ax.patch<SanitizedUserOut>(`/users/${userId}`, { is_active: isActive })
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
- export async function deleteUser(userId: string): Promise<DeleteUserResponse> {
95
- return ax.delete(`/users/${userId}`)
96
- }
110
+ async deleteUser(userId: string): Promise<DeleteUserResponse> {
111
+ return this.api.delete(`/users/${userId}`)
112
+ }
97
113
 
98
- export async function getUsers(limit: number = 100, skip?: number): Promise<GetUsersResponse> {
99
- return ax.get<SanitizedUserList>('/users/', { params: { skip, limit } })
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
- export async function createUser(user: UserCreate): Promise<CreateUserResponse> {
103
- return ax.post<SanitizedUserOut>('/users/', user)
104
- }
123
+ async createUser(user: UserCreate): Promise<CreateUserResponse> {
124
+ return this.api.post<SanitizedUserOut>('/users/', user)
125
+ }
105
126
 
106
- export async function getUser(userId: string): Promise<GetUserResponse> {
107
- return ax.get<SanitizedUserOut>(`/users/${userId}`)
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 { User, NewUser, UpdatePasswordForm, ReactiveFactory } from '../types'
3
- import { createDefaultApi } from '../api/api'
4
- import * as authApi from '../api/auth'
5
-
6
- let api: AxiosInstance
7
- let onError: ((error: any) => void)
8
- let createRef: ReactiveFactory
9
-
10
- const defaultReactiveFactory: ReactiveFactory = <T>(initial: T) => {
11
- let value = initial
12
- return {
13
- get value() { return value },
14
- set: (newValue: T) => { value = newValue }
15
- }
16
- }
17
-
18
- // Create Vue reactive factory
19
- function createVueReactiveFactory(app: any): ReactiveFactory {
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
- // Create plugin instance
22
+ // Initialize auth
30
23
  export function initAuth({
31
24
  axios,
32
- errorHandler,
33
- reactive = defaultReactiveFactory,
34
- baseURL
25
+ baseURL,
35
26
  }: {
36
- axios?: AxiosInstance
37
- errorHandler?: (error: any) => void
38
- reactive?: ReactiveFactory
27
+ axios: AxiosInstance
39
28
  baseURL?: string
40
- } = {}) {
41
- // Initialize API
42
- api = axios || createDefaultApi(baseURL)
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: any) {
53
- // If Vue is detected, use Vue's reactivity
54
- if (app.ref) {
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 (!api || !createRef) {
64
- throw new Error('Auth composable not initialized. Call initAuth first.')
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.logout()
99
- } catch (error: any) {
100
- handleError(error)
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.login(email, password)
63
+ await authApi!.login(
64
+ credentials.email.toLowerCase(),
65
+ credentials.password
66
+ )
109
67
  await checkAuth()
110
- } catch (error: any) {
111
- handleError(error)
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.getCurrentUser()
76
+ const { data } = await authApi!.getCurrentUser()
119
77
  currentUser.set(data)
120
78
  }
121
- } catch (error: any) {
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.signup(user)
90
+ const { data } = await authApi!.signup(user)
133
91
  currentUser.set(data)
134
- } catch (error: any) {
135
- handleError(error)
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.passwordRecovery(email)
142
- } catch (error: any) {
143
- handleError(error)
99
+ await authApi!.passwordRecovery(email)
100
+ } catch (error) {
101
+ throw error
144
102
  }
145
103
  }
146
104
 
147
- async function resetPassword(form: UpdatePasswordForm) {
105
+ async function resetPassword(newPassword: string) {
148
106
  try {
149
- if (form.new_password !== form.confirmNewPassword) {
150
- throw new Error('Passwords do not match')
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 (passwordForm.value.new_password !== passwordForm.value.confirmNewPassword) {
115
+ if (form.new_password !== form.confirmNewPassword) {
166
116
  throw new Error('Passwords do not match')
167
117
  }
168
- await authApi.updatePassword(passwordForm.value)
169
- passwordForm.set({
170
- current_password: '',
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.updateUserProfile(user)
126
+ const { data } = await authApi!.updateUserProfile(user)
182
127
  currentUser.set({ ...currentUser.value, ...data })
183
- } catch (error: any) {
184
- handleError(error)
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.setUserStatus(userId, isActive)
191
- } catch (error: any) {
192
- handleError(error)
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.deleteUser(userId)
199
- } catch (error: any) {
200
- handleError(error)
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
- }