@k3-universe/react-kit 0.0.29 → 0.0.31
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.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1023 -25
- package/dist/kit/builder/auth/components/Can.d.ts +13 -0
- package/dist/kit/builder/auth/components/Can.d.ts.map +1 -0
- package/dist/kit/builder/auth/components/RequireAuth.d.ts +45 -0
- package/dist/kit/builder/auth/components/RequireAuth.d.ts.map +1 -0
- package/dist/kit/builder/auth/components/ShowWhenAuthenticated.d.ts +8 -0
- package/dist/kit/builder/auth/components/ShowWhenAuthenticated.d.ts.map +1 -0
- package/dist/kit/builder/auth/components/ShowWhenError.d.ts +8 -0
- package/dist/kit/builder/auth/components/ShowWhenError.d.ts.map +1 -0
- package/dist/kit/builder/auth/components/ShowWhenLoading.d.ts +8 -0
- package/dist/kit/builder/auth/components/ShowWhenLoading.d.ts.map +1 -0
- package/dist/kit/builder/auth/components/ShowWhenUnauthenticated.d.ts +8 -0
- package/dist/kit/builder/auth/components/ShowWhenUnauthenticated.d.ts.map +1 -0
- package/dist/kit/builder/auth/components/withPermission.d.ts +7 -0
- package/dist/kit/builder/auth/components/withPermission.d.ts.map +1 -0
- package/dist/kit/builder/auth/hooks/action-hooks.d.ts +18 -0
- package/dist/kit/builder/auth/hooks/action-hooks.d.ts.map +1 -0
- package/dist/kit/builder/auth/hooks/core-hooks.d.ts +56 -0
- package/dist/kit/builder/auth/hooks/core-hooks.d.ts.map +1 -0
- package/dist/kit/builder/auth/hooks/index.d.ts +5 -0
- package/dist/kit/builder/auth/hooks/index.d.ts.map +1 -0
- package/dist/kit/builder/auth/hooks/permission-hooks.d.ts +18 -0
- package/dist/kit/builder/auth/hooks/permission-hooks.d.ts.map +1 -0
- package/dist/kit/builder/auth/hooks/token-hooks.d.ts +13 -0
- package/dist/kit/builder/auth/hooks/token-hooks.d.ts.map +1 -0
- package/dist/kit/builder/auth/index.d.ts +14 -8
- package/dist/kit/builder/auth/index.d.ts.map +1 -1
- package/dist/kit/builder/auth/{AuthProvider.d.ts → providers/AuthProvider.d.ts} +1 -1
- package/dist/kit/builder/auth/providers/AuthProvider.d.ts.map +1 -0
- package/dist/kit/builder/auth/types/adapter-config.d.ts +31 -0
- package/dist/kit/builder/auth/types/adapter-config.d.ts.map +1 -0
- package/dist/kit/builder/auth/types/adapter.d.ts +80 -0
- package/dist/kit/builder/auth/types/adapter.d.ts.map +1 -0
- package/dist/kit/builder/auth/types/core.d.ts +16 -0
- package/dist/kit/builder/auth/types/core.d.ts.map +1 -0
- package/dist/kit/builder/auth/types/index.d.ts +10 -0
- package/dist/kit/builder/auth/types/index.d.ts.map +1 -0
- package/dist/kit/builder/auth/types/middleware.d.ts +11 -0
- package/dist/kit/builder/auth/types/middleware.d.ts.map +1 -0
- package/dist/kit/builder/auth/types/permissions.d.ts +17 -0
- package/dist/kit/builder/auth/types/permissions.d.ts.map +1 -0
- package/dist/kit/builder/auth/types/state.d.ts +13 -0
- package/dist/kit/builder/auth/types/state.d.ts.map +1 -0
- package/dist/kit/builder/auth/types/storage.d.ts +20 -0
- package/dist/kit/builder/auth/types/storage.d.ts.map +1 -0
- package/dist/kit/builder/auth/types/token-manager.d.ts +7 -0
- package/dist/kit/builder/auth/types/token-manager.d.ts.map +1 -0
- package/dist/kit/builder/auth/types/utils.d.ts +7 -0
- package/dist/kit/builder/auth/types/utils.d.ts.map +1 -0
- package/dist/kit/builder/auth/{adapter.d.ts → utils/auth-adapter.d.ts} +2 -2
- package/dist/kit/builder/auth/utils/auth-adapter.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/client-adapters/apollo-link.d.ts +4 -0
- package/dist/kit/builder/auth/utils/client-adapters/apollo-link.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/client-adapters/axios.d.ts +6 -0
- package/dist/kit/builder/auth/utils/client-adapters/axios.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/client-adapters/fetch.d.ts +6 -0
- package/dist/kit/builder/auth/utils/client-adapters/fetch.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/client-adapters/graphql.d.ts +9 -0
- package/dist/kit/builder/auth/utils/client-adapters/graphql.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/client-adapters/index.d.ts +7 -0
- package/dist/kit/builder/auth/utils/client-adapters/index.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/client-adapters/rest.d.ts +9 -0
- package/dist/kit/builder/auth/utils/client-adapters/rest.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/client-adapters/urql-exchange.d.ts +14 -0
- package/dist/kit/builder/auth/utils/client-adapters/urql-exchange.d.ts.map +1 -0
- package/dist/kit/builder/auth/{permission-checker.d.ts → utils/permission-checker.d.ts} +1 -1
- package/dist/kit/builder/auth/utils/permission-checker.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/storage/browser.d.ts +11 -0
- package/dist/kit/builder/auth/utils/storage/browser.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/storage/cookie.d.ts +3 -0
- package/dist/kit/builder/auth/utils/storage/cookie.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/storage/encryption.d.ts +7 -0
- package/dist/kit/builder/auth/utils/storage/encryption.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/storage/env.d.ts +2 -0
- package/dist/kit/builder/auth/utils/storage/env.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/storage/factory.d.ts +6 -0
- package/dist/kit/builder/auth/utils/storage/factory.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/storage/index.d.ts +7 -0
- package/dist/kit/builder/auth/utils/storage/index.d.ts.map +1 -0
- package/dist/kit/builder/auth/utils/storage/memory.d.ts +3 -0
- package/dist/kit/builder/auth/utils/storage/memory.d.ts.map +1 -0
- package/dist/kit/builder/auth/{token-manager.d.ts → utils/token-manager.d.ts} +1 -1
- package/dist/kit/builder/auth/utils/token-manager.d.ts.map +1 -0
- package/dist/kit/components/login/Login.d.ts +2 -1
- package/dist/kit/components/login/Login.d.ts.map +1 -1
- package/dist/kit/layouts/admin/components/AdminLayout.d.ts +2 -1
- package/dist/kit/layouts/admin/components/AdminLayout.d.ts.map +1 -1
- package/dist/kit/themes/clean-slate.css +28 -4
- package/dist/kit/themes/default.css +28 -4
- package/dist/kit/themes/minimal-modern.css +28 -4
- package/dist/kit/themes/spotify.css +28 -4
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/kit/builder/auth/components/Can.tsx +27 -0
- package/src/kit/builder/auth/components/RequireAuth.tsx +78 -0
- package/src/kit/builder/auth/components/ShowWhenAuthenticated.tsx +10 -0
- package/src/kit/builder/auth/components/ShowWhenError.tsx +10 -0
- package/src/kit/builder/auth/components/ShowWhenLoading.tsx +10 -0
- package/src/kit/builder/auth/components/ShowWhenUnauthenticated.tsx +10 -0
- package/src/kit/builder/auth/components/withPermission.tsx +23 -0
- package/src/kit/builder/auth/hooks/action-hooks.ts +34 -0
- package/src/kit/builder/auth/hooks/core-hooks.ts +65 -0
- package/src/kit/builder/auth/hooks/index.ts +4 -0
- package/src/kit/builder/auth/hooks/permission-hooks.ts +43 -0
- package/src/kit/builder/auth/hooks/token-hooks.ts +25 -0
- package/src/kit/builder/auth/index.ts +16 -18
- package/src/kit/builder/auth/{AuthProvider.tsx → providers/AuthProvider.tsx} +1 -1
- package/src/kit/builder/auth/types/adapter-config.ts +44 -0
- package/src/kit/builder/auth/types/adapter.ts +132 -0
- package/src/kit/builder/auth/types/core.ts +27 -0
- package/src/kit/builder/auth/types/index.ts +9 -0
- package/src/kit/builder/auth/types/middleware.ts +20 -0
- package/src/kit/builder/auth/types/permissions.ts +23 -0
- package/src/kit/builder/auth/types/state.ts +16 -0
- package/src/kit/builder/auth/types/storage.ts +21 -0
- package/src/kit/builder/auth/types/token-manager.ts +9 -0
- package/src/kit/builder/auth/types/utils.ts +55 -0
- package/src/kit/builder/auth/{adapter.ts → utils/auth-adapter.ts} +3 -2
- package/src/kit/builder/auth/utils/client-adapters/apollo-link.ts +30 -0
- package/src/kit/builder/auth/utils/client-adapters/axios.ts +61 -0
- package/src/kit/builder/auth/utils/client-adapters/fetch.ts +48 -0
- package/src/kit/builder/auth/utils/client-adapters/graphql.ts +60 -0
- package/src/kit/builder/auth/utils/client-adapters/index.ts +6 -0
- package/src/kit/builder/auth/utils/client-adapters/rest.ts +60 -0
- package/src/kit/builder/auth/utils/client-adapters/urql-exchange.ts +76 -0
- package/src/kit/builder/auth/{permission-checker.ts → utils/permission-checker.ts} +1 -1
- package/src/kit/builder/auth/utils/storage/browser.ts +99 -0
- package/src/kit/builder/auth/utils/storage/cookie.ts +116 -0
- package/src/kit/builder/auth/utils/storage/encryption.ts +80 -0
- package/src/kit/builder/auth/utils/storage/env.ts +2 -0
- package/src/kit/builder/auth/utils/storage/factory.ts +37 -0
- package/src/kit/builder/auth/utils/storage/index.ts +6 -0
- package/src/kit/builder/auth/utils/storage/memory.ts +15 -0
- package/src/kit/builder/auth/{token-manager.ts → utils/token-manager.ts} +1 -1
- package/src/kit/components/login/Login.tsx +36 -21
- package/src/kit/layouts/admin/components/AdminLayout.tsx +24 -17
- package/dist/kit/builder/auth/AuthProvider.d.ts.map +0 -1
- package/dist/kit/builder/auth/adapter.d.ts.map +0 -1
- package/dist/kit/builder/auth/client-adapters.d.ts +0 -149
- package/dist/kit/builder/auth/client-adapters.d.ts.map +0 -1
- package/dist/kit/builder/auth/components.d.ts +0 -119
- package/dist/kit/builder/auth/components.d.ts.map +0 -1
- package/dist/kit/builder/auth/hooks.d.ts +0 -158
- package/dist/kit/builder/auth/hooks.d.ts.map +0 -1
- package/dist/kit/builder/auth/permission-checker.d.ts.map +0 -1
- package/dist/kit/builder/auth/storage.d.ts +0 -17
- package/dist/kit/builder/auth/storage.d.ts.map +0 -1
- package/dist/kit/builder/auth/token-manager.d.ts.map +0 -1
- package/dist/kit/builder/auth/types.d.ts +0 -183
- package/dist/kit/builder/auth/types.d.ts.map +0 -1
- package/src/kit/builder/auth/client-adapters.ts +0 -398
- package/src/kit/builder/auth/components.tsx +0 -221
- package/src/kit/builder/auth/hooks.ts +0 -237
- package/src/kit/builder/auth/storage.ts +0 -366
- package/src/kit/builder/auth/types.ts +0 -393
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AuthSession,
|
|
3
|
-
PermissionPolicy,
|
|
4
|
-
PermissionRule,
|
|
5
|
-
WithPermissionOptions,
|
|
6
|
-
} from './types';
|
|
7
|
-
import { useAuthContext } from './AuthProvider';
|
|
8
|
-
|
|
9
|
-
// ============================================================================
|
|
10
|
-
// Core Hooks
|
|
11
|
-
// ============================================================================
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Hook to access the entire auth context
|
|
15
|
-
*/
|
|
16
|
-
export function useAuth() {
|
|
17
|
-
return useAuthContext();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Hook to get the current auth status
|
|
22
|
-
*/
|
|
23
|
-
export function useAuthStatus() {
|
|
24
|
-
const { status } = useAuthContext();
|
|
25
|
-
return status;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Hook to check if user is authenticated
|
|
30
|
-
*/
|
|
31
|
-
export function useIsAuthenticated() {
|
|
32
|
-
const { status } = useAuthContext();
|
|
33
|
-
return status === 'authenticated';
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Hook to get the current session
|
|
38
|
-
*/
|
|
39
|
-
export function useAuthSession<TSession extends AuthSession>() {
|
|
40
|
-
const { session } = useAuthContext();
|
|
41
|
-
return session as TSession | null;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Hook to get the current user
|
|
46
|
-
*/
|
|
47
|
-
export function useAuthUser<TUser>() {
|
|
48
|
-
const { user } = useAuthContext();
|
|
49
|
-
return user as TUser | null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Hook to get user roles
|
|
54
|
-
*/
|
|
55
|
-
export function useAuthRoles<TRole extends string = string>() {
|
|
56
|
-
const { roles } = useAuthContext();
|
|
57
|
-
return roles as TRole[];
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Hook to get user permissions
|
|
62
|
-
*/
|
|
63
|
-
export function useAuthPermissions<TPermission extends string = string>() {
|
|
64
|
-
const { permissions } = useAuthContext();
|
|
65
|
-
return permissions as TPermission[];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Hook to get authentication error
|
|
70
|
-
*/
|
|
71
|
-
export function useAuthError() {
|
|
72
|
-
const { error } = useAuthContext();
|
|
73
|
-
return error;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ============================================================================
|
|
77
|
-
// Permission Hooks
|
|
78
|
-
// ============================================================================
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Hook to check if user has specific permission(s)
|
|
82
|
-
* Supports permission policies with AND/OR operators
|
|
83
|
-
*
|
|
84
|
-
* @example
|
|
85
|
-
* ```tsx
|
|
86
|
-
* // Check single permission
|
|
87
|
-
* const canEdit = usePermission('post:edit');
|
|
88
|
-
*
|
|
89
|
-
* // Check multiple permissions (all required by default)
|
|
90
|
-
* const canManage = usePermission(['post:edit', 'post:delete']);
|
|
91
|
-
*
|
|
92
|
-
* // Check multiple permissions (any one required)
|
|
93
|
-
* const canModify = usePermission(['post:edit', 'post:delete'], { requireAll: false });
|
|
94
|
-
*
|
|
95
|
-
* // Check with policy
|
|
96
|
-
* const canAccess = usePermission({
|
|
97
|
-
* operator: 'OR',
|
|
98
|
-
* permissions: ['admin:access', 'moderator:access']
|
|
99
|
-
* });
|
|
100
|
-
* ```
|
|
101
|
-
*/
|
|
102
|
-
export function usePermission<TPermission extends string = string>(
|
|
103
|
-
permission: TPermission | TPermission[] | PermissionPolicy<TPermission>,
|
|
104
|
-
options?: { requireAll?: boolean },
|
|
105
|
-
) {
|
|
106
|
-
const { hasPermission } = useAuthContext();
|
|
107
|
-
return hasPermission(permission, options);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Hook to check if user has specific role(s)
|
|
112
|
-
*
|
|
113
|
-
* @example
|
|
114
|
-
* ```tsx
|
|
115
|
-
* // Check single role
|
|
116
|
-
* const isAdmin = useRole('admin');
|
|
117
|
-
*
|
|
118
|
-
* // Check multiple roles (all required by default)
|
|
119
|
-
* const isSuperAdmin = useRole(['admin', 'super']);
|
|
120
|
-
*
|
|
121
|
-
* // Check multiple roles (any one required)
|
|
122
|
-
* const isStaff = useRole(['admin', 'moderator'], { requireAll: false });
|
|
123
|
-
* ```
|
|
124
|
-
*/
|
|
125
|
-
export function useRole<TRole extends string = string>(
|
|
126
|
-
roles: TRole | TRole[],
|
|
127
|
-
options?: { requireAll?: boolean },
|
|
128
|
-
) {
|
|
129
|
-
const { hasRole } = useAuthContext();
|
|
130
|
-
return hasRole(roles, options);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Hook to check complex permission rules
|
|
135
|
-
* Combines role and permission checks with flexible logic
|
|
136
|
-
*
|
|
137
|
-
* @example
|
|
138
|
-
* ```tsx
|
|
139
|
-
* // Check if user has admin role AND edit permission
|
|
140
|
-
* const canAdminEdit = useCan({
|
|
141
|
-
* roles: 'admin',
|
|
142
|
-
* permissions: 'post:edit',
|
|
143
|
-
* requireAll: true
|
|
144
|
-
* });
|
|
145
|
-
*
|
|
146
|
-
* // Check if user has admin role OR edit permission
|
|
147
|
-
* const canAccess = useCan({
|
|
148
|
-
* roles: 'admin',
|
|
149
|
-
* permissions: 'post:edit',
|
|
150
|
-
* requireAll: false
|
|
151
|
-
* });
|
|
152
|
-
*
|
|
153
|
-
* // Complex policy
|
|
154
|
-
* const canManage = useCan({
|
|
155
|
-
* roles: ['admin', 'moderator'],
|
|
156
|
-
* permissions: {
|
|
157
|
-
* operator: 'OR',
|
|
158
|
-
* permissions: ['post:edit', 'post:delete']
|
|
159
|
-
* }
|
|
160
|
-
* });
|
|
161
|
-
* ```
|
|
162
|
-
*/
|
|
163
|
-
export function useCan<
|
|
164
|
-
TRole extends string = string,
|
|
165
|
-
TPermission extends string = string,
|
|
166
|
-
>(
|
|
167
|
-
rule:
|
|
168
|
-
| WithPermissionOptions<TRole, TPermission>
|
|
169
|
-
| PermissionRule<TRole, TPermission>,
|
|
170
|
-
) {
|
|
171
|
-
const { can } = useAuthContext();
|
|
172
|
-
return can(rule as PermissionRule<TRole, TPermission>);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// ============================================================================
|
|
176
|
-
// Token Hooks
|
|
177
|
-
// ============================================================================
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Hook to get the current auth token
|
|
181
|
-
*/
|
|
182
|
-
export function useAuthToken() {
|
|
183
|
-
const { getToken } = useAuthContext();
|
|
184
|
-
return getToken();
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Hook to check if token is expired
|
|
189
|
-
*/
|
|
190
|
-
export function useIsTokenExpired() {
|
|
191
|
-
const { isTokenExpired } = useAuthContext();
|
|
192
|
-
return isTokenExpired();
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Hook to get time until token expiry in milliseconds
|
|
197
|
-
*/
|
|
198
|
-
export function useTimeUntilExpiry() {
|
|
199
|
-
const { getTimeUntilExpiry } = useAuthContext();
|
|
200
|
-
return getTimeUntilExpiry();
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// ============================================================================
|
|
204
|
-
// Action Hooks
|
|
205
|
-
// ============================================================================
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Hook to get the login function
|
|
209
|
-
*/
|
|
210
|
-
export function useLogin<TCredentials = unknown>() {
|
|
211
|
-
const { login } = useAuthContext();
|
|
212
|
-
return login as ((credentials: TCredentials) => Promise<unknown>) | undefined;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Hook to get the logout function
|
|
217
|
-
*/
|
|
218
|
-
export function useLogout() {
|
|
219
|
-
const { logout } = useAuthContext();
|
|
220
|
-
return logout;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Hook to get the refresh function
|
|
225
|
-
*/
|
|
226
|
-
export function useRefresh() {
|
|
227
|
-
const { refresh } = useAuthContext();
|
|
228
|
-
return refresh;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Hook to get the setSession function
|
|
233
|
-
*/
|
|
234
|
-
export function useSetSession<TSession extends AuthSession>() {
|
|
235
|
-
const { setSession } = useAuthContext();
|
|
236
|
-
return setSession as (session: TSession | null) => Promise<unknown>;
|
|
237
|
-
}
|
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
import type { AuthStorage, StorageOptions } from './types';
|
|
2
|
-
|
|
3
|
-
const isBrowser =
|
|
4
|
-
typeof window !== 'undefined' && typeof window.localStorage !== 'undefined';
|
|
5
|
-
|
|
6
|
-
// ============================================================================
|
|
7
|
-
// Memory Storage
|
|
8
|
-
// ============================================================================
|
|
9
|
-
|
|
10
|
-
export const createMemoryStorage = <T>(): AuthStorage<T> => {
|
|
11
|
-
let value: T | null = null;
|
|
12
|
-
|
|
13
|
-
return {
|
|
14
|
-
get: () => value,
|
|
15
|
-
set: (next) => {
|
|
16
|
-
value = next;
|
|
17
|
-
},
|
|
18
|
-
clear: () => {
|
|
19
|
-
value = null;
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// ============================================================================
|
|
25
|
-
// Encryption Utilities
|
|
26
|
-
// ============================================================================
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Simple encryption/decryption using browser's subtle crypto
|
|
30
|
-
* For production, consider using a more robust encryption library
|
|
31
|
-
*/
|
|
32
|
-
class SimpleEncryption {
|
|
33
|
-
private key: string;
|
|
34
|
-
|
|
35
|
-
constructor(key: string) {
|
|
36
|
-
this.key = key;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async encrypt(text: string): Promise<string> {
|
|
40
|
-
if (!crypto?.subtle) {
|
|
41
|
-
console.warn(
|
|
42
|
-
'[auth2][storage] Crypto API not available, storing unencrypted',
|
|
43
|
-
);
|
|
44
|
-
return text;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
const encoder = new TextEncoder();
|
|
49
|
-
const data = encoder.encode(text);
|
|
50
|
-
const keyData = encoder.encode(this.key.padEnd(32, '0').slice(0, 32));
|
|
51
|
-
|
|
52
|
-
const cryptoKey = await crypto.subtle.importKey(
|
|
53
|
-
'raw',
|
|
54
|
-
keyData,
|
|
55
|
-
{ name: 'AES-GCM', length: 256 },
|
|
56
|
-
false,
|
|
57
|
-
['encrypt'],
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
61
|
-
const encrypted = await crypto.subtle.encrypt(
|
|
62
|
-
{ name: 'AES-GCM', iv },
|
|
63
|
-
cryptoKey,
|
|
64
|
-
data,
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
const result = new Uint8Array(iv.length + encrypted.byteLength);
|
|
68
|
-
result.set(iv, 0);
|
|
69
|
-
result.set(new Uint8Array(encrypted), iv.length);
|
|
70
|
-
|
|
71
|
-
return btoa(String.fromCharCode(...result));
|
|
72
|
-
} catch (error) {
|
|
73
|
-
console.error('[auth2][storage] Encryption failed:', error);
|
|
74
|
-
return text;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async decrypt(encrypted: string): Promise<string> {
|
|
79
|
-
if (!crypto?.subtle) {
|
|
80
|
-
console.warn(
|
|
81
|
-
'[auth2][storage] Crypto API not available, reading unencrypted',
|
|
82
|
-
);
|
|
83
|
-
return encrypted;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
const encoder = new TextEncoder();
|
|
88
|
-
const decoder = new TextDecoder();
|
|
89
|
-
const keyData = encoder.encode(this.key.padEnd(32, '0').slice(0, 32));
|
|
90
|
-
|
|
91
|
-
const cryptoKey = await crypto.subtle.importKey(
|
|
92
|
-
'raw',
|
|
93
|
-
keyData,
|
|
94
|
-
{ name: 'AES-GCM', length: 256 },
|
|
95
|
-
false,
|
|
96
|
-
['decrypt'],
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
const data = Uint8Array.from(atob(encrypted), (c) => c.charCodeAt(0));
|
|
100
|
-
const iv = data.slice(0, 12);
|
|
101
|
-
const encryptedData = data.slice(12);
|
|
102
|
-
|
|
103
|
-
const decrypted = await crypto.subtle.decrypt(
|
|
104
|
-
{ name: 'AES-GCM', iv },
|
|
105
|
-
cryptoKey,
|
|
106
|
-
encryptedData,
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
return decoder.decode(decrypted);
|
|
110
|
-
} catch (error) {
|
|
111
|
-
console.error('[auth2][storage] Decryption failed:', error);
|
|
112
|
-
return encrypted;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// ============================================================================
|
|
118
|
-
// Cookie Storage
|
|
119
|
-
// ============================================================================
|
|
120
|
-
|
|
121
|
-
export const createCookieStorage = <T>(
|
|
122
|
-
options: StorageOptions,
|
|
123
|
-
): AuthStorage<T> => {
|
|
124
|
-
const key = options.key ?? 'auth2_session';
|
|
125
|
-
const cookieOpts = options.cookieOptions ?? {};
|
|
126
|
-
const fallback = createMemoryStorage<T>();
|
|
127
|
-
const encryption =
|
|
128
|
-
options.encrypt && options.encryptionKey
|
|
129
|
-
? new SimpleEncryption(options.encryptionKey)
|
|
130
|
-
: null;
|
|
131
|
-
const cookieSetter =
|
|
132
|
-
typeof Document !== 'undefined'
|
|
133
|
-
? Object.getOwnPropertyDescriptor(Document.prototype, 'cookie')?.set
|
|
134
|
-
: undefined;
|
|
135
|
-
|
|
136
|
-
const assignCookie = (value: string) => {
|
|
137
|
-
if (!isBrowser || typeof document === 'undefined') return;
|
|
138
|
-
if (cookieSetter) {
|
|
139
|
-
cookieSetter.call(document, value);
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
Reflect.set(document, 'cookie', value);
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
const serialize = async (value: T | null): Promise<string | null> => {
|
|
146
|
-
if (value === null) return null;
|
|
147
|
-
const json = JSON.stringify(value);
|
|
148
|
-
return encryption ? await encryption.encrypt(json) : json;
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
const deserialize = async (value: string | null): Promise<T | null> => {
|
|
152
|
-
if (!value) return null;
|
|
153
|
-
try {
|
|
154
|
-
const decrypted = encryption ? await encryption.decrypt(value) : value;
|
|
155
|
-
return JSON.parse(decrypted) as T;
|
|
156
|
-
} catch {
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const getCookie = (name: string): string | null => {
|
|
162
|
-
if (!isBrowser) return null;
|
|
163
|
-
const matches = document.cookie.match(
|
|
164
|
-
new RegExp(
|
|
165
|
-
`(?:^|; )${name.replace(/([.$?*|{}()[\]\\/+^])/g, '\\$1')}=([^;]*)`,
|
|
166
|
-
),
|
|
167
|
-
);
|
|
168
|
-
return matches ? decodeURIComponent(matches[1]) : null;
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const setCookie = (
|
|
172
|
-
name: string,
|
|
173
|
-
value: string,
|
|
174
|
-
opts: typeof cookieOpts = {},
|
|
175
|
-
) => {
|
|
176
|
-
if (!isBrowser) return;
|
|
177
|
-
|
|
178
|
-
let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
|
|
179
|
-
|
|
180
|
-
if (opts.maxAge) cookie += `; max-age=${opts.maxAge}`;
|
|
181
|
-
if (opts.domain) cookie += `; domain=${opts.domain}`;
|
|
182
|
-
if (opts.path !== undefined) cookie += `; path=${opts.path}`;
|
|
183
|
-
else cookie += '; path=/';
|
|
184
|
-
if (opts.secure) cookie += '; secure';
|
|
185
|
-
if (opts.sameSite) cookie += `; samesite=${opts.sameSite}`;
|
|
186
|
-
|
|
187
|
-
assignCookie(cookie);
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
const deleteCookie = (name: string) => {
|
|
191
|
-
if (!isBrowser) return;
|
|
192
|
-
assignCookie(`${name}=; max-age=0; path=/`);
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
return {
|
|
196
|
-
get: async () => {
|
|
197
|
-
try {
|
|
198
|
-
const raw = getCookie(key);
|
|
199
|
-
const value = await deserialize(raw);
|
|
200
|
-
fallback.set(value);
|
|
201
|
-
return value;
|
|
202
|
-
} catch (error) {
|
|
203
|
-
console.warn('[auth2][storage] Failed to read from cookie', error);
|
|
204
|
-
return fallback.get();
|
|
205
|
-
}
|
|
206
|
-
},
|
|
207
|
-
set: async (value) => {
|
|
208
|
-
try {
|
|
209
|
-
const serialized = await serialize(value);
|
|
210
|
-
if (serialized === null) {
|
|
211
|
-
deleteCookie(key);
|
|
212
|
-
} else {
|
|
213
|
-
setCookie(key, serialized, cookieOpts);
|
|
214
|
-
}
|
|
215
|
-
fallback.set(value);
|
|
216
|
-
} catch (error) {
|
|
217
|
-
console.warn('[auth2][storage] Failed to write to cookie', error);
|
|
218
|
-
fallback.set(value);
|
|
219
|
-
}
|
|
220
|
-
},
|
|
221
|
-
clear: () => {
|
|
222
|
-
try {
|
|
223
|
-
deleteCookie(key);
|
|
224
|
-
} catch (error) {
|
|
225
|
-
console.warn('[auth2][storage] Failed to clear cookie', error);
|
|
226
|
-
} finally {
|
|
227
|
-
fallback.clear();
|
|
228
|
-
}
|
|
229
|
-
},
|
|
230
|
-
};
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
// ============================================================================
|
|
234
|
-
// Browser Storage (localStorage/sessionStorage)
|
|
235
|
-
// ============================================================================
|
|
236
|
-
|
|
237
|
-
export type BrowserStorageOptions<T> = {
|
|
238
|
-
key: string;
|
|
239
|
-
serialize?: (value: T | null) => Promise<string | null> | string | null;
|
|
240
|
-
deserialize?: (value: string | null) => Promise<T | null> | T | null;
|
|
241
|
-
storage?: Storage;
|
|
242
|
-
encrypt?: boolean;
|
|
243
|
-
encryptionKey?: string;
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
export const createBrowserStorage = <T>(
|
|
247
|
-
options: BrowserStorageOptions<T>,
|
|
248
|
-
): AuthStorage<T> => {
|
|
249
|
-
const fallback = createMemoryStorage<T>();
|
|
250
|
-
const targetStorage =
|
|
251
|
-
options.storage ?? (isBrowser ? window.localStorage : undefined);
|
|
252
|
-
|
|
253
|
-
const encryption =
|
|
254
|
-
options.encrypt && options.encryptionKey
|
|
255
|
-
? new SimpleEncryption(options.encryptionKey)
|
|
256
|
-
: null;
|
|
257
|
-
|
|
258
|
-
const defaultSerialize = async (value: T | null): Promise<string | null> => {
|
|
259
|
-
if (value === null) return null;
|
|
260
|
-
const json = JSON.stringify(value);
|
|
261
|
-
return encryption ? await encryption.encrypt(json) : json;
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
const defaultDeserialize = async (
|
|
265
|
-
value: string | null,
|
|
266
|
-
): Promise<T | null> => {
|
|
267
|
-
if (!value) return null;
|
|
268
|
-
try {
|
|
269
|
-
const decrypted = encryption ? await encryption.decrypt(value) : value;
|
|
270
|
-
return JSON.parse(decrypted) as T;
|
|
271
|
-
} catch {
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
const serialize = options.serialize
|
|
277
|
-
? async (value: T | null) => {
|
|
278
|
-
const result = await options.serialize?.(value);
|
|
279
|
-
return result ?? null;
|
|
280
|
-
}
|
|
281
|
-
: defaultSerialize;
|
|
282
|
-
|
|
283
|
-
const deserialize = options.deserialize
|
|
284
|
-
? async (value: string | null) => {
|
|
285
|
-
const result = await options.deserialize?.(value);
|
|
286
|
-
return result ?? null;
|
|
287
|
-
}
|
|
288
|
-
: defaultDeserialize;
|
|
289
|
-
|
|
290
|
-
if (!targetStorage) {
|
|
291
|
-
return fallback;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return {
|
|
295
|
-
get: async () => {
|
|
296
|
-
try {
|
|
297
|
-
const raw = targetStorage.getItem(options.key);
|
|
298
|
-
const value = await deserialize(raw);
|
|
299
|
-
fallback.set(value);
|
|
300
|
-
return value;
|
|
301
|
-
} catch (error) {
|
|
302
|
-
console.warn('[auth2][storage] Failed to read from storage', error);
|
|
303
|
-
return fallback.get();
|
|
304
|
-
}
|
|
305
|
-
},
|
|
306
|
-
set: async (value) => {
|
|
307
|
-
try {
|
|
308
|
-
const serialized = await serialize(value);
|
|
309
|
-
if (serialized === null) {
|
|
310
|
-
targetStorage.removeItem(options.key);
|
|
311
|
-
} else {
|
|
312
|
-
targetStorage.setItem(options.key, serialized);
|
|
313
|
-
}
|
|
314
|
-
fallback.set(value);
|
|
315
|
-
} catch (error) {
|
|
316
|
-
console.warn('[auth2][storage] Failed to write to storage', error);
|
|
317
|
-
fallback.set(value);
|
|
318
|
-
}
|
|
319
|
-
},
|
|
320
|
-
clear: () => {
|
|
321
|
-
try {
|
|
322
|
-
targetStorage.removeItem(options.key);
|
|
323
|
-
} catch (error) {
|
|
324
|
-
console.warn('[auth2][storage] Failed to clear storage', error);
|
|
325
|
-
} finally {
|
|
326
|
-
fallback.clear();
|
|
327
|
-
}
|
|
328
|
-
},
|
|
329
|
-
};
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
// ============================================================================
|
|
333
|
-
// Factory Function
|
|
334
|
-
// ============================================================================
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Creates appropriate storage based on options
|
|
338
|
-
*/
|
|
339
|
-
export function createStorage<T>(options: StorageOptions = {}): AuthStorage<T> {
|
|
340
|
-
const storageType = options.storage ?? 'local';
|
|
341
|
-
const key = options.key ?? 'auth2_session';
|
|
342
|
-
|
|
343
|
-
switch (storageType) {
|
|
344
|
-
case 'cookie':
|
|
345
|
-
return createCookieStorage<T>(options);
|
|
346
|
-
|
|
347
|
-
case 'session':
|
|
348
|
-
return createBrowserStorage<T>({
|
|
349
|
-
key,
|
|
350
|
-
storage: isBrowser ? window.sessionStorage : undefined,
|
|
351
|
-
encrypt: options.encrypt,
|
|
352
|
-
encryptionKey: options.encryptionKey,
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
case 'local':
|
|
356
|
-
return createBrowserStorage<T>({
|
|
357
|
-
key,
|
|
358
|
-
storage: isBrowser ? window.localStorage : undefined,
|
|
359
|
-
encrypt: options.encrypt,
|
|
360
|
-
encryptionKey: options.encryptionKey,
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
default:
|
|
364
|
-
return createMemoryStorage<T>();
|
|
365
|
-
}
|
|
366
|
-
}
|