@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,398 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AuthAdapterConfig,
|
|
3
|
-
AuthSession,
|
|
4
|
-
GraphQLAuthClient,
|
|
5
|
-
RESTAuthClient,
|
|
6
|
-
} from './types';
|
|
7
|
-
|
|
8
|
-
// ============================================================================
|
|
9
|
-
// GraphQL Client Adapter
|
|
10
|
-
// ============================================================================
|
|
11
|
-
|
|
12
|
-
export type GraphQLClientAdapterOptions<
|
|
13
|
-
TUser = unknown,
|
|
14
|
-
TRole extends string = string,
|
|
15
|
-
TPermission extends string = string,
|
|
16
|
-
TSession extends AuthSession<TUser, TRole, TPermission> = AuthSession<
|
|
17
|
-
TUser,
|
|
18
|
-
TRole,
|
|
19
|
-
TPermission
|
|
20
|
-
>,
|
|
21
|
-
TCredentials = unknown,
|
|
22
|
-
> = {
|
|
23
|
-
client: GraphQLAuthClient<TSession, TCredentials>;
|
|
24
|
-
resolveUser?: (session: TSession | null) => TUser | null;
|
|
25
|
-
resolveRoles?: (session: TSession | null) => TRole[];
|
|
26
|
-
resolvePermissions?: (session: TSession | null) => TPermission[];
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Creates an auth adapter config for GraphQL clients
|
|
31
|
-
* Works with Apollo Client, urql, graphql-request, etc.
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* ```tsx
|
|
35
|
-
* import { ApolloClient } from '@apollo/client';
|
|
36
|
-
* import { createGraphQLAuthAdapter } from '@k3mart/react-kit/auth2';
|
|
37
|
-
*
|
|
38
|
-
* const apolloClient = new ApolloClient({ ... });
|
|
39
|
-
*
|
|
40
|
-
* const authConfig = createGraphQLAuthAdapter({
|
|
41
|
-
* client: {
|
|
42
|
-
* login: async (credentials) => {
|
|
43
|
-
* const result = await apolloClient.mutate({
|
|
44
|
-
* mutation: LOGIN_MUTATION,
|
|
45
|
-
* variables: credentials,
|
|
46
|
-
* });
|
|
47
|
-
* return result.data.login;
|
|
48
|
-
* },
|
|
49
|
-
* logout: async () => {
|
|
50
|
-
* await apolloClient.mutate({ mutation: LOGOUT_MUTATION });
|
|
51
|
-
* },
|
|
52
|
-
* refresh: async (refreshToken) => {
|
|
53
|
-
* const result = await apolloClient.mutate({
|
|
54
|
-
* mutation: REFRESH_MUTATION,
|
|
55
|
-
* variables: { refreshToken },
|
|
56
|
-
* });
|
|
57
|
-
* return result.data.refresh;
|
|
58
|
-
* },
|
|
59
|
-
* getCurrentUser: async () => {
|
|
60
|
-
* const result = await apolloClient.query({
|
|
61
|
-
* query: GET_CURRENT_USER_QUERY,
|
|
62
|
-
* });
|
|
63
|
-
* return result.data.currentUser;
|
|
64
|
-
* },
|
|
65
|
-
* },
|
|
66
|
-
* });
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
|
-
export function createGraphQLAuthAdapter<
|
|
70
|
-
TUser = unknown,
|
|
71
|
-
TRole extends string = string,
|
|
72
|
-
TPermission extends string = string,
|
|
73
|
-
TSession extends AuthSession<TUser, TRole, TPermission> = AuthSession<
|
|
74
|
-
TUser,
|
|
75
|
-
TRole,
|
|
76
|
-
TPermission
|
|
77
|
-
>,
|
|
78
|
-
TCredentials = unknown,
|
|
79
|
-
>(
|
|
80
|
-
options: GraphQLClientAdapterOptions<
|
|
81
|
-
TUser,
|
|
82
|
-
TRole,
|
|
83
|
-
TPermission,
|
|
84
|
-
TSession,
|
|
85
|
-
TCredentials
|
|
86
|
-
>,
|
|
87
|
-
): Partial<
|
|
88
|
-
AuthAdapterConfig<TUser, TRole, TPermission, TSession, TCredentials>
|
|
89
|
-
> {
|
|
90
|
-
return {
|
|
91
|
-
login: options.client.login,
|
|
92
|
-
logout: options.client.logout,
|
|
93
|
-
refresh: options.client.refresh
|
|
94
|
-
? async (session: TSession) => {
|
|
95
|
-
if (!session.refreshToken) {
|
|
96
|
-
throw new Error('No refresh token available');
|
|
97
|
-
}
|
|
98
|
-
if (!options.client.refresh) {
|
|
99
|
-
throw new Error('Refresh function not provided');
|
|
100
|
-
}
|
|
101
|
-
return await options.client.refresh(session.refreshToken);
|
|
102
|
-
}
|
|
103
|
-
: undefined,
|
|
104
|
-
loadSession: options.client.getCurrentUser,
|
|
105
|
-
resolveUser: options.resolveUser,
|
|
106
|
-
resolveRoles: options.resolveRoles,
|
|
107
|
-
resolvePermissions: options.resolvePermissions,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// ============================================================================
|
|
112
|
-
// REST Client Adapter
|
|
113
|
-
// ============================================================================
|
|
114
|
-
|
|
115
|
-
export type RESTClientAdapterOptions<
|
|
116
|
-
TUser = unknown,
|
|
117
|
-
TRole extends string = string,
|
|
118
|
-
TPermission extends string = string,
|
|
119
|
-
TSession extends AuthSession<TUser, TRole, TPermission> = AuthSession<
|
|
120
|
-
TUser,
|
|
121
|
-
TRole,
|
|
122
|
-
TPermission
|
|
123
|
-
>,
|
|
124
|
-
TCredentials = unknown,
|
|
125
|
-
> = {
|
|
126
|
-
client: RESTAuthClient<TSession, TCredentials>;
|
|
127
|
-
resolveUser?: (session: TSession | null) => TUser | null;
|
|
128
|
-
resolveRoles?: (session: TSession | null) => TRole[];
|
|
129
|
-
resolvePermissions?: (session: TSession | null) => TPermission[];
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Creates an auth adapter config for REST API clients
|
|
134
|
-
* Works with fetch, axios, ky, etc.
|
|
135
|
-
*
|
|
136
|
-
* @example
|
|
137
|
-
* ```tsx
|
|
138
|
-
* import axios from 'axios';
|
|
139
|
-
* import { createRESTAuthAdapter } from '@k3mart/react-kit/auth2';
|
|
140
|
-
*
|
|
141
|
-
* const api = axios.create({ baseURL: 'https://api.example.com' });
|
|
142
|
-
*
|
|
143
|
-
* const authConfig = createRESTAuthAdapter({
|
|
144
|
-
* client: {
|
|
145
|
-
* login: async (credentials) => {
|
|
146
|
-
* const response = await api.post('/auth/login', credentials);
|
|
147
|
-
* return response.data;
|
|
148
|
-
* },
|
|
149
|
-
* logout: async () => {
|
|
150
|
-
* await api.post('/auth/logout');
|
|
151
|
-
* },
|
|
152
|
-
* refresh: async (refreshToken) => {
|
|
153
|
-
* const response = await api.post('/auth/refresh', { refreshToken });
|
|
154
|
-
* return response.data;
|
|
155
|
-
* },
|
|
156
|
-
* getCurrentUser: async () => {
|
|
157
|
-
* const response = await api.get('/auth/me');
|
|
158
|
-
* return response.data;
|
|
159
|
-
* },
|
|
160
|
-
* },
|
|
161
|
-
* });
|
|
162
|
-
* ```
|
|
163
|
-
*/
|
|
164
|
-
export function createRESTAuthAdapter<
|
|
165
|
-
TUser = unknown,
|
|
166
|
-
TRole extends string = string,
|
|
167
|
-
TPermission extends string = string,
|
|
168
|
-
TSession extends AuthSession<TUser, TRole, TPermission> = AuthSession<
|
|
169
|
-
TUser,
|
|
170
|
-
TRole,
|
|
171
|
-
TPermission
|
|
172
|
-
>,
|
|
173
|
-
TCredentials = unknown,
|
|
174
|
-
>(
|
|
175
|
-
options: RESTClientAdapterOptions<
|
|
176
|
-
TUser,
|
|
177
|
-
TRole,
|
|
178
|
-
TPermission,
|
|
179
|
-
TSession,
|
|
180
|
-
TCredentials
|
|
181
|
-
>,
|
|
182
|
-
): Partial<
|
|
183
|
-
AuthAdapterConfig<TUser, TRole, TPermission, TSession, TCredentials>
|
|
184
|
-
> {
|
|
185
|
-
return {
|
|
186
|
-
login: options.client.login,
|
|
187
|
-
logout: options.client.logout,
|
|
188
|
-
refresh: options.client.refresh
|
|
189
|
-
? async (session: TSession) => {
|
|
190
|
-
if (!session.refreshToken) {
|
|
191
|
-
throw new Error('No refresh token available');
|
|
192
|
-
}
|
|
193
|
-
if (!options.client.refresh) {
|
|
194
|
-
throw new Error('Refresh function not provided');
|
|
195
|
-
}
|
|
196
|
-
return await options.client.refresh(session.refreshToken);
|
|
197
|
-
}
|
|
198
|
-
: undefined,
|
|
199
|
-
loadSession: options.client.getCurrentUser,
|
|
200
|
-
resolveUser: options.resolveUser,
|
|
201
|
-
resolveRoles: options.resolveRoles,
|
|
202
|
-
resolvePermissions: options.resolvePermissions,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// ============================================================================
|
|
207
|
-
// HTTP Interceptor Utilities
|
|
208
|
-
// ============================================================================
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Helper to create an axios interceptor that automatically adds auth token
|
|
212
|
-
*
|
|
213
|
-
* @example
|
|
214
|
-
* ```tsx
|
|
215
|
-
* import axios from 'axios';
|
|
216
|
-
* import { createAxiosAuthInterceptor } from '@k3mart/react-kit/auth2';
|
|
217
|
-
*
|
|
218
|
-
* const api = axios.create({ baseURL: 'https://api.example.com' });
|
|
219
|
-
*
|
|
220
|
-
* createAxiosAuthInterceptor(api, authAdapter);
|
|
221
|
-
* ```
|
|
222
|
-
*/
|
|
223
|
-
export function createAxiosAuthInterceptor(
|
|
224
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
225
|
-
axiosInstance: any,
|
|
226
|
-
getToken: () => string | null,
|
|
227
|
-
options?: {
|
|
228
|
-
tokenType?: string;
|
|
229
|
-
onTokenExpired?: () => void;
|
|
230
|
-
refreshToken?: () => Promise<void>;
|
|
231
|
-
},
|
|
232
|
-
) {
|
|
233
|
-
const tokenType = options?.tokenType ?? 'Bearer';
|
|
234
|
-
|
|
235
|
-
// Request interceptor
|
|
236
|
-
axiosInstance.interceptors.request.use(
|
|
237
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
238
|
-
async (config: any) => {
|
|
239
|
-
const token = getToken();
|
|
240
|
-
if (token) {
|
|
241
|
-
config.headers.Authorization = `${tokenType} ${token}`;
|
|
242
|
-
}
|
|
243
|
-
return config;
|
|
244
|
-
},
|
|
245
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
246
|
-
(error: any) => Promise.reject(error),
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
// Response interceptor for token refresh
|
|
250
|
-
if (options?.refreshToken) {
|
|
251
|
-
axiosInstance.interceptors.response.use(
|
|
252
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
253
|
-
(response: any) => response,
|
|
254
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
255
|
-
async (error: any) => {
|
|
256
|
-
const originalRequest = error.config;
|
|
257
|
-
|
|
258
|
-
// If token expired and we haven't retried yet
|
|
259
|
-
if (
|
|
260
|
-
error.response?.status === 401 &&
|
|
261
|
-
!originalRequest._retry &&
|
|
262
|
-
options.refreshToken
|
|
263
|
-
) {
|
|
264
|
-
originalRequest._retry = true;
|
|
265
|
-
|
|
266
|
-
try {
|
|
267
|
-
await options.refreshToken();
|
|
268
|
-
const token = getToken();
|
|
269
|
-
if (token) {
|
|
270
|
-
originalRequest.headers.Authorization = `${tokenType} ${token}`;
|
|
271
|
-
}
|
|
272
|
-
return axiosInstance(originalRequest);
|
|
273
|
-
} catch (refreshError) {
|
|
274
|
-
options.onTokenExpired?.();
|
|
275
|
-
return Promise.reject(refreshError);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
return Promise.reject(error);
|
|
280
|
-
},
|
|
281
|
-
);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Helper to create a fetch wrapper with auth token injection
|
|
287
|
-
*
|
|
288
|
-
* @example
|
|
289
|
-
* ```tsx
|
|
290
|
-
* import { createAuthFetch } from '@k3mart/react-kit/auth2';
|
|
291
|
-
*
|
|
292
|
-
* const authenticatedFetch = createAuthFetch(
|
|
293
|
-
* () => authAdapter.getToken(),
|
|
294
|
-
* {
|
|
295
|
-
* onTokenExpired: () => authAdapter.logout(),
|
|
296
|
-
* refreshToken: () => authAdapter.refresh(),
|
|
297
|
-
* }
|
|
298
|
-
* );
|
|
299
|
-
*
|
|
300
|
-
* // Use it like regular fetch
|
|
301
|
-
* const response = await authenticatedFetch('/api/users');
|
|
302
|
-
* ```
|
|
303
|
-
*/
|
|
304
|
-
export function createAuthFetch(
|
|
305
|
-
getToken: () => string | null,
|
|
306
|
-
options?: {
|
|
307
|
-
tokenType?: string;
|
|
308
|
-
onTokenExpired?: () => void;
|
|
309
|
-
refreshToken?: () => Promise<void>;
|
|
310
|
-
},
|
|
311
|
-
): typeof fetch {
|
|
312
|
-
const tokenType = options?.tokenType ?? 'Bearer';
|
|
313
|
-
|
|
314
|
-
return async (
|
|
315
|
-
input: RequestInfo | URL,
|
|
316
|
-
init?: RequestInit,
|
|
317
|
-
): Promise<Response> => {
|
|
318
|
-
const token = getToken();
|
|
319
|
-
const headers = new Headers(init?.headers);
|
|
320
|
-
|
|
321
|
-
if (token) {
|
|
322
|
-
headers.set('Authorization', `${tokenType} ${token}`);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const response = await fetch(input, {
|
|
326
|
-
...init,
|
|
327
|
-
headers,
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
// Handle token expiration
|
|
331
|
-
if (response.status === 401 && options?.refreshToken) {
|
|
332
|
-
try {
|
|
333
|
-
await options.refreshToken();
|
|
334
|
-
const newToken = getToken();
|
|
335
|
-
|
|
336
|
-
if (newToken) {
|
|
337
|
-
headers.set('Authorization', `${tokenType} ${newToken}`);
|
|
338
|
-
return await fetch(input, {
|
|
339
|
-
...init,
|
|
340
|
-
headers,
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
} catch (error) {
|
|
344
|
-
options.onTokenExpired?.();
|
|
345
|
-
throw error;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return response;
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Helper to create Apollo Link with auth token injection
|
|
355
|
-
*
|
|
356
|
-
* @example
|
|
357
|
-
* ```tsx
|
|
358
|
-
* import { ApolloClient, InMemoryCache, from } from '@apollo/client';
|
|
359
|
-
* import { createApolloAuthLink } from '@k3mart/react-kit/auth2';
|
|
360
|
-
*
|
|
361
|
-
* const authLink = createApolloAuthLink(() => authAdapter.getToken());
|
|
362
|
-
*
|
|
363
|
-
* const client = new ApolloClient({
|
|
364
|
-
* link: from([authLink, httpLink]),
|
|
365
|
-
* cache: new InMemoryCache(),
|
|
366
|
-
* });
|
|
367
|
-
* ```
|
|
368
|
-
*/
|
|
369
|
-
export function createApolloAuthLink(
|
|
370
|
-
getToken: () => string | null,
|
|
371
|
-
options?: {
|
|
372
|
-
tokenType?: string;
|
|
373
|
-
},
|
|
374
|
-
) {
|
|
375
|
-
const tokenType = options?.tokenType ?? 'Bearer';
|
|
376
|
-
|
|
377
|
-
// This requires @apollo/client to be installed
|
|
378
|
-
// We'll return a function that creates the link to avoid direct dependency
|
|
379
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
380
|
-
return (ApolloLink: any) => {
|
|
381
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
382
|
-
return new ApolloLink((operation: any, forward: any) => {
|
|
383
|
-
const token = getToken();
|
|
384
|
-
|
|
385
|
-
if (token) {
|
|
386
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
387
|
-
operation.setContext(({ headers = {} }: any) => ({
|
|
388
|
-
headers: {
|
|
389
|
-
...headers,
|
|
390
|
-
authorization: `${tokenType} ${token}`,
|
|
391
|
-
},
|
|
392
|
-
}));
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
return forward(operation);
|
|
396
|
-
});
|
|
397
|
-
};
|
|
398
|
-
}
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import type { ComponentType } from 'react';
|
|
2
|
-
import type {
|
|
3
|
-
CanProps,
|
|
4
|
-
RequireAuthProps,
|
|
5
|
-
WithPermissionOptions,
|
|
6
|
-
} from './types';
|
|
7
|
-
import { useAuthContext } from './AuthProvider';
|
|
8
|
-
import { useCan } from './hooks';
|
|
9
|
-
|
|
10
|
-
// ============================================================================
|
|
11
|
-
// RequireAuth Component
|
|
12
|
-
// ============================================================================
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Component that requires authentication
|
|
16
|
-
* Optionally checks for specific roles and permissions
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```tsx
|
|
20
|
-
* // Basic authentication check
|
|
21
|
-
* <RequireAuth fallback={<Login />}>
|
|
22
|
-
* <Dashboard />
|
|
23
|
-
* </RequireAuth>
|
|
24
|
-
*
|
|
25
|
-
* // With role check
|
|
26
|
-
* <RequireAuth
|
|
27
|
-
* roles="admin"
|
|
28
|
-
* fallback={<Forbidden />}
|
|
29
|
-
* loadingFallback={<Spinner />}
|
|
30
|
-
* >
|
|
31
|
-
* <AdminPanel />
|
|
32
|
-
* </RequireAuth>
|
|
33
|
-
*
|
|
34
|
-
* // With permission check
|
|
35
|
-
* <RequireAuth
|
|
36
|
-
* permissions={['post:edit', 'post:delete']}
|
|
37
|
-
* fallback={<Forbidden />}
|
|
38
|
-
* >
|
|
39
|
-
* <PostEditor />
|
|
40
|
-
* </RequireAuth>
|
|
41
|
-
*
|
|
42
|
-
* // Complex rule
|
|
43
|
-
* <RequireAuth
|
|
44
|
-
* roles={['admin', 'moderator']}
|
|
45
|
-
* permissions={{
|
|
46
|
-
* operator: 'OR',
|
|
47
|
-
* permissions: ['post:edit', 'post:delete']
|
|
48
|
-
* }}
|
|
49
|
-
* requireAll={false}
|
|
50
|
-
* fallback={<Forbidden />}
|
|
51
|
-
* >
|
|
52
|
-
* <ContentManager />
|
|
53
|
-
* </RequireAuth>
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
export function RequireAuth<
|
|
57
|
-
TRole extends string = string,
|
|
58
|
-
TPermission extends string = string,
|
|
59
|
-
>({
|
|
60
|
-
children,
|
|
61
|
-
fallback = null,
|
|
62
|
-
loadingFallback = null,
|
|
63
|
-
roles,
|
|
64
|
-
permissions,
|
|
65
|
-
requireAll = true,
|
|
66
|
-
}: RequireAuthProps<TRole, TPermission>) {
|
|
67
|
-
const { status, can } = useAuthContext();
|
|
68
|
-
|
|
69
|
-
if (status === 'loading' || status === 'idle') {
|
|
70
|
-
return loadingFallback;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (status !== 'authenticated') {
|
|
74
|
-
return fallback;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// If no specific roles/permissions required, just check authentication
|
|
78
|
-
if (!roles && !permissions) {
|
|
79
|
-
return children;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Check role/permission rules
|
|
83
|
-
const allowed = can({ roles, permissions, requireAll });
|
|
84
|
-
|
|
85
|
-
if (!allowed) {
|
|
86
|
-
return fallback;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return children;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ============================================================================
|
|
93
|
-
// Can Component
|
|
94
|
-
// ============================================================================
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Component for conditional rendering based on permissions
|
|
98
|
-
* More flexible than RequireAuth - doesn't check authentication status
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
* ```tsx
|
|
102
|
-
* // Show button only if user can edit
|
|
103
|
-
* <Can permissions="post:edit" fallback={<ReadOnlyView />}>
|
|
104
|
-
* <EditButton />
|
|
105
|
-
* </Can>
|
|
106
|
-
*
|
|
107
|
-
* // Show admin panel if user is admin
|
|
108
|
-
* <Can roles="admin">
|
|
109
|
-
* <AdminPanel />
|
|
110
|
-
* </Can>
|
|
111
|
-
*
|
|
112
|
-
* // Complex permission check
|
|
113
|
-
* <Can
|
|
114
|
-
* roles={['admin', 'moderator']}
|
|
115
|
-
* permissions={{
|
|
116
|
-
* operator: 'OR',
|
|
117
|
-
* permissions: ['post:edit', 'post:delete']
|
|
118
|
-
* }}
|
|
119
|
-
* requireAll={false}
|
|
120
|
-
* >
|
|
121
|
-
* <ManageButton />
|
|
122
|
-
* </Can>
|
|
123
|
-
* ```
|
|
124
|
-
*/
|
|
125
|
-
export function Can<
|
|
126
|
-
TRole extends string = string,
|
|
127
|
-
TPermission extends string = string,
|
|
128
|
-
>({
|
|
129
|
-
children,
|
|
130
|
-
fallback = null,
|
|
131
|
-
roles,
|
|
132
|
-
permissions,
|
|
133
|
-
requireAll = true,
|
|
134
|
-
}: CanProps<TRole, TPermission>) {
|
|
135
|
-
const allowed = useCan({ roles, permissions, requireAll });
|
|
136
|
-
if (!allowed) return fallback;
|
|
137
|
-
return children;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// ============================================================================
|
|
141
|
-
// Higher-Order Component
|
|
142
|
-
// ============================================================================
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Higher-order component that wraps a component with permission checks
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
148
|
-
* ```tsx
|
|
149
|
-
* const AdminButton = withPermission(Button, {
|
|
150
|
-
* roles: 'admin'
|
|
151
|
-
* });
|
|
152
|
-
*
|
|
153
|
-
* const EditButton = withPermission(Button, {
|
|
154
|
-
* permissions: 'post:edit'
|
|
155
|
-
* });
|
|
156
|
-
*
|
|
157
|
-
* // Use like regular component
|
|
158
|
-
* <AdminButton onClick={handleAdmin}>Admin Action</AdminButton>
|
|
159
|
-
* <EditButton onClick={handleEdit}>Edit Post</EditButton>
|
|
160
|
-
* ```
|
|
161
|
-
*/
|
|
162
|
-
export function withPermission<
|
|
163
|
-
TRole extends string = string,
|
|
164
|
-
TPermission extends string = string,
|
|
165
|
-
TProps extends Record<string, unknown> = Record<string, unknown>,
|
|
166
|
-
>(
|
|
167
|
-
Component: ComponentType<TProps>,
|
|
168
|
-
options: WithPermissionOptions<TRole, TPermission>,
|
|
169
|
-
): ComponentType<TProps> {
|
|
170
|
-
const WithPermissionWrapper = (props: TProps) => {
|
|
171
|
-
const allowed = useCan(options);
|
|
172
|
-
if (!allowed) return null;
|
|
173
|
-
return <Component {...props} />;
|
|
174
|
-
};
|
|
175
|
-
WithPermissionWrapper.displayName = `WithPermission(${Component.displayName ?? Component.name ?? 'Component'})`;
|
|
176
|
-
return WithPermissionWrapper as ComponentType<TProps>;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// ============================================================================
|
|
180
|
-
// Show/Hide Components
|
|
181
|
-
// ============================================================================
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Component that shows children only when authenticated
|
|
185
|
-
*/
|
|
186
|
-
export function ShowWhenAuthenticated({
|
|
187
|
-
children,
|
|
188
|
-
}: {
|
|
189
|
-
children: React.ReactNode;
|
|
190
|
-
}) {
|
|
191
|
-
const { status } = useAuthContext();
|
|
192
|
-
return status === 'authenticated' ? children : null;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Component that shows children only when NOT authenticated
|
|
197
|
-
*/
|
|
198
|
-
export function ShowWhenUnauthenticated({
|
|
199
|
-
children,
|
|
200
|
-
}: {
|
|
201
|
-
children: React.ReactNode;
|
|
202
|
-
}) {
|
|
203
|
-
const { status } = useAuthContext();
|
|
204
|
-
return status === 'unauthenticated' ? children : null;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Component that shows children only while loading
|
|
209
|
-
*/
|
|
210
|
-
export function ShowWhenLoading({ children }: { children: React.ReactNode }) {
|
|
211
|
-
const { status } = useAuthContext();
|
|
212
|
-
return status === 'loading' ? children : null;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Component that shows children only when there's an error
|
|
217
|
-
*/
|
|
218
|
-
export function ShowWhenError({ children }: { children: React.ReactNode }) {
|
|
219
|
-
const { status } = useAuthContext();
|
|
220
|
-
return status === 'error' ? children : null;
|
|
221
|
-
}
|