@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.
Files changed (157) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1023 -25
  4. package/dist/kit/builder/auth/components/Can.d.ts +13 -0
  5. package/dist/kit/builder/auth/components/Can.d.ts.map +1 -0
  6. package/dist/kit/builder/auth/components/RequireAuth.d.ts +45 -0
  7. package/dist/kit/builder/auth/components/RequireAuth.d.ts.map +1 -0
  8. package/dist/kit/builder/auth/components/ShowWhenAuthenticated.d.ts +8 -0
  9. package/dist/kit/builder/auth/components/ShowWhenAuthenticated.d.ts.map +1 -0
  10. package/dist/kit/builder/auth/components/ShowWhenError.d.ts +8 -0
  11. package/dist/kit/builder/auth/components/ShowWhenError.d.ts.map +1 -0
  12. package/dist/kit/builder/auth/components/ShowWhenLoading.d.ts +8 -0
  13. package/dist/kit/builder/auth/components/ShowWhenLoading.d.ts.map +1 -0
  14. package/dist/kit/builder/auth/components/ShowWhenUnauthenticated.d.ts +8 -0
  15. package/dist/kit/builder/auth/components/ShowWhenUnauthenticated.d.ts.map +1 -0
  16. package/dist/kit/builder/auth/components/withPermission.d.ts +7 -0
  17. package/dist/kit/builder/auth/components/withPermission.d.ts.map +1 -0
  18. package/dist/kit/builder/auth/hooks/action-hooks.d.ts +18 -0
  19. package/dist/kit/builder/auth/hooks/action-hooks.d.ts.map +1 -0
  20. package/dist/kit/builder/auth/hooks/core-hooks.d.ts +56 -0
  21. package/dist/kit/builder/auth/hooks/core-hooks.d.ts.map +1 -0
  22. package/dist/kit/builder/auth/hooks/index.d.ts +5 -0
  23. package/dist/kit/builder/auth/hooks/index.d.ts.map +1 -0
  24. package/dist/kit/builder/auth/hooks/permission-hooks.d.ts +18 -0
  25. package/dist/kit/builder/auth/hooks/permission-hooks.d.ts.map +1 -0
  26. package/dist/kit/builder/auth/hooks/token-hooks.d.ts +13 -0
  27. package/dist/kit/builder/auth/hooks/token-hooks.d.ts.map +1 -0
  28. package/dist/kit/builder/auth/index.d.ts +14 -8
  29. package/dist/kit/builder/auth/index.d.ts.map +1 -1
  30. package/dist/kit/builder/auth/{AuthProvider.d.ts → providers/AuthProvider.d.ts} +1 -1
  31. package/dist/kit/builder/auth/providers/AuthProvider.d.ts.map +1 -0
  32. package/dist/kit/builder/auth/types/adapter-config.d.ts +31 -0
  33. package/dist/kit/builder/auth/types/adapter-config.d.ts.map +1 -0
  34. package/dist/kit/builder/auth/types/adapter.d.ts +80 -0
  35. package/dist/kit/builder/auth/types/adapter.d.ts.map +1 -0
  36. package/dist/kit/builder/auth/types/core.d.ts +16 -0
  37. package/dist/kit/builder/auth/types/core.d.ts.map +1 -0
  38. package/dist/kit/builder/auth/types/index.d.ts +10 -0
  39. package/dist/kit/builder/auth/types/index.d.ts.map +1 -0
  40. package/dist/kit/builder/auth/types/middleware.d.ts +11 -0
  41. package/dist/kit/builder/auth/types/middleware.d.ts.map +1 -0
  42. package/dist/kit/builder/auth/types/permissions.d.ts +17 -0
  43. package/dist/kit/builder/auth/types/permissions.d.ts.map +1 -0
  44. package/dist/kit/builder/auth/types/state.d.ts +13 -0
  45. package/dist/kit/builder/auth/types/state.d.ts.map +1 -0
  46. package/dist/kit/builder/auth/types/storage.d.ts +20 -0
  47. package/dist/kit/builder/auth/types/storage.d.ts.map +1 -0
  48. package/dist/kit/builder/auth/types/token-manager.d.ts +7 -0
  49. package/dist/kit/builder/auth/types/token-manager.d.ts.map +1 -0
  50. package/dist/kit/builder/auth/types/utils.d.ts +7 -0
  51. package/dist/kit/builder/auth/types/utils.d.ts.map +1 -0
  52. package/dist/kit/builder/auth/{adapter.d.ts → utils/auth-adapter.d.ts} +2 -2
  53. package/dist/kit/builder/auth/utils/auth-adapter.d.ts.map +1 -0
  54. package/dist/kit/builder/auth/utils/client-adapters/apollo-link.d.ts +4 -0
  55. package/dist/kit/builder/auth/utils/client-adapters/apollo-link.d.ts.map +1 -0
  56. package/dist/kit/builder/auth/utils/client-adapters/axios.d.ts +6 -0
  57. package/dist/kit/builder/auth/utils/client-adapters/axios.d.ts.map +1 -0
  58. package/dist/kit/builder/auth/utils/client-adapters/fetch.d.ts +6 -0
  59. package/dist/kit/builder/auth/utils/client-adapters/fetch.d.ts.map +1 -0
  60. package/dist/kit/builder/auth/utils/client-adapters/graphql.d.ts +9 -0
  61. package/dist/kit/builder/auth/utils/client-adapters/graphql.d.ts.map +1 -0
  62. package/dist/kit/builder/auth/utils/client-adapters/index.d.ts +7 -0
  63. package/dist/kit/builder/auth/utils/client-adapters/index.d.ts.map +1 -0
  64. package/dist/kit/builder/auth/utils/client-adapters/rest.d.ts +9 -0
  65. package/dist/kit/builder/auth/utils/client-adapters/rest.d.ts.map +1 -0
  66. package/dist/kit/builder/auth/utils/client-adapters/urql-exchange.d.ts +14 -0
  67. package/dist/kit/builder/auth/utils/client-adapters/urql-exchange.d.ts.map +1 -0
  68. package/dist/kit/builder/auth/{permission-checker.d.ts → utils/permission-checker.d.ts} +1 -1
  69. package/dist/kit/builder/auth/utils/permission-checker.d.ts.map +1 -0
  70. package/dist/kit/builder/auth/utils/storage/browser.d.ts +11 -0
  71. package/dist/kit/builder/auth/utils/storage/browser.d.ts.map +1 -0
  72. package/dist/kit/builder/auth/utils/storage/cookie.d.ts +3 -0
  73. package/dist/kit/builder/auth/utils/storage/cookie.d.ts.map +1 -0
  74. package/dist/kit/builder/auth/utils/storage/encryption.d.ts +7 -0
  75. package/dist/kit/builder/auth/utils/storage/encryption.d.ts.map +1 -0
  76. package/dist/kit/builder/auth/utils/storage/env.d.ts +2 -0
  77. package/dist/kit/builder/auth/utils/storage/env.d.ts.map +1 -0
  78. package/dist/kit/builder/auth/utils/storage/factory.d.ts +6 -0
  79. package/dist/kit/builder/auth/utils/storage/factory.d.ts.map +1 -0
  80. package/dist/kit/builder/auth/utils/storage/index.d.ts +7 -0
  81. package/dist/kit/builder/auth/utils/storage/index.d.ts.map +1 -0
  82. package/dist/kit/builder/auth/utils/storage/memory.d.ts +3 -0
  83. package/dist/kit/builder/auth/utils/storage/memory.d.ts.map +1 -0
  84. package/dist/kit/builder/auth/{token-manager.d.ts → utils/token-manager.d.ts} +1 -1
  85. package/dist/kit/builder/auth/utils/token-manager.d.ts.map +1 -0
  86. package/dist/kit/components/login/Login.d.ts +2 -1
  87. package/dist/kit/components/login/Login.d.ts.map +1 -1
  88. package/dist/kit/layouts/admin/components/AdminLayout.d.ts +2 -1
  89. package/dist/kit/layouts/admin/components/AdminLayout.d.ts.map +1 -1
  90. package/dist/kit/themes/clean-slate.css +28 -4
  91. package/dist/kit/themes/default.css +28 -4
  92. package/dist/kit/themes/minimal-modern.css +28 -4
  93. package/dist/kit/themes/spotify.css +28 -4
  94. package/package.json +1 -1
  95. package/src/index.ts +1 -0
  96. package/src/kit/builder/auth/components/Can.tsx +27 -0
  97. package/src/kit/builder/auth/components/RequireAuth.tsx +78 -0
  98. package/src/kit/builder/auth/components/ShowWhenAuthenticated.tsx +10 -0
  99. package/src/kit/builder/auth/components/ShowWhenError.tsx +10 -0
  100. package/src/kit/builder/auth/components/ShowWhenLoading.tsx +10 -0
  101. package/src/kit/builder/auth/components/ShowWhenUnauthenticated.tsx +10 -0
  102. package/src/kit/builder/auth/components/withPermission.tsx +23 -0
  103. package/src/kit/builder/auth/hooks/action-hooks.ts +34 -0
  104. package/src/kit/builder/auth/hooks/core-hooks.ts +65 -0
  105. package/src/kit/builder/auth/hooks/index.ts +4 -0
  106. package/src/kit/builder/auth/hooks/permission-hooks.ts +43 -0
  107. package/src/kit/builder/auth/hooks/token-hooks.ts +25 -0
  108. package/src/kit/builder/auth/index.ts +16 -18
  109. package/src/kit/builder/auth/{AuthProvider.tsx → providers/AuthProvider.tsx} +1 -1
  110. package/src/kit/builder/auth/types/adapter-config.ts +44 -0
  111. package/src/kit/builder/auth/types/adapter.ts +132 -0
  112. package/src/kit/builder/auth/types/core.ts +27 -0
  113. package/src/kit/builder/auth/types/index.ts +9 -0
  114. package/src/kit/builder/auth/types/middleware.ts +20 -0
  115. package/src/kit/builder/auth/types/permissions.ts +23 -0
  116. package/src/kit/builder/auth/types/state.ts +16 -0
  117. package/src/kit/builder/auth/types/storage.ts +21 -0
  118. package/src/kit/builder/auth/types/token-manager.ts +9 -0
  119. package/src/kit/builder/auth/types/utils.ts +55 -0
  120. package/src/kit/builder/auth/{adapter.ts → utils/auth-adapter.ts} +3 -2
  121. package/src/kit/builder/auth/utils/client-adapters/apollo-link.ts +30 -0
  122. package/src/kit/builder/auth/utils/client-adapters/axios.ts +61 -0
  123. package/src/kit/builder/auth/utils/client-adapters/fetch.ts +48 -0
  124. package/src/kit/builder/auth/utils/client-adapters/graphql.ts +60 -0
  125. package/src/kit/builder/auth/utils/client-adapters/index.ts +6 -0
  126. package/src/kit/builder/auth/utils/client-adapters/rest.ts +60 -0
  127. package/src/kit/builder/auth/utils/client-adapters/urql-exchange.ts +76 -0
  128. package/src/kit/builder/auth/{permission-checker.ts → utils/permission-checker.ts} +1 -1
  129. package/src/kit/builder/auth/utils/storage/browser.ts +99 -0
  130. package/src/kit/builder/auth/utils/storage/cookie.ts +116 -0
  131. package/src/kit/builder/auth/utils/storage/encryption.ts +80 -0
  132. package/src/kit/builder/auth/utils/storage/env.ts +2 -0
  133. package/src/kit/builder/auth/utils/storage/factory.ts +37 -0
  134. package/src/kit/builder/auth/utils/storage/index.ts +6 -0
  135. package/src/kit/builder/auth/utils/storage/memory.ts +15 -0
  136. package/src/kit/builder/auth/{token-manager.ts → utils/token-manager.ts} +1 -1
  137. package/src/kit/components/login/Login.tsx +36 -21
  138. package/src/kit/layouts/admin/components/AdminLayout.tsx +24 -17
  139. package/dist/kit/builder/auth/AuthProvider.d.ts.map +0 -1
  140. package/dist/kit/builder/auth/adapter.d.ts.map +0 -1
  141. package/dist/kit/builder/auth/client-adapters.d.ts +0 -149
  142. package/dist/kit/builder/auth/client-adapters.d.ts.map +0 -1
  143. package/dist/kit/builder/auth/components.d.ts +0 -119
  144. package/dist/kit/builder/auth/components.d.ts.map +0 -1
  145. package/dist/kit/builder/auth/hooks.d.ts +0 -158
  146. package/dist/kit/builder/auth/hooks.d.ts.map +0 -1
  147. package/dist/kit/builder/auth/permission-checker.d.ts.map +0 -1
  148. package/dist/kit/builder/auth/storage.d.ts +0 -17
  149. package/dist/kit/builder/auth/storage.d.ts.map +0 -1
  150. package/dist/kit/builder/auth/token-manager.d.ts.map +0 -1
  151. package/dist/kit/builder/auth/types.d.ts +0 -183
  152. package/dist/kit/builder/auth/types.d.ts.map +0 -1
  153. package/src/kit/builder/auth/client-adapters.ts +0 -398
  154. package/src/kit/builder/auth/components.tsx +0 -221
  155. package/src/kit/builder/auth/hooks.ts +0 -237
  156. package/src/kit/builder/auth/storage.ts +0 -366
  157. package/src/kit/builder/auth/types.ts +0 -393
@@ -0,0 +1,16 @@
1
+ import type { AuthStatus } from './core';
2
+
3
+ export type AuthAdapterState<TSession, TUser, TRole, TPermission> = {
4
+ status: AuthStatus;
5
+ session: TSession | null;
6
+ user: TUser | null;
7
+ roles: TRole[];
8
+ permissions: TPermission[];
9
+ error?: unknown;
10
+ lastRefresh?: number;
11
+ tokenExpiresIn?: number;
12
+ };
13
+
14
+ export type AuthAdapterSubscriber<TSession, TUser, TRole, TPermission> = (
15
+ state: AuthAdapterState<TSession, TUser, TRole, TPermission>,
16
+ ) => void;
@@ -0,0 +1,21 @@
1
+ export type AuthStorage<TSession> = {
2
+ get: () => Promise<TSession | null> | TSession | null;
3
+ set: (value: TSession | null) => Promise<void> | void;
4
+ clear: () => Promise<void> | void;
5
+ };
6
+
7
+ export type StorageType = 'local' | 'session' | 'cookie' | 'memory';
8
+
9
+ export type StorageOptions = {
10
+ key?: string;
11
+ encrypt?: boolean;
12
+ encryptionKey?: string;
13
+ storage?: StorageType;
14
+ cookieOptions?: {
15
+ domain?: string;
16
+ path?: string;
17
+ secure?: boolean;
18
+ sameSite?: 'strict' | 'lax' | 'none';
19
+ maxAge?: number;
20
+ };
21
+ };
@@ -0,0 +1,9 @@
1
+ export type TokenManager = {
2
+ isExpired: (expiresAt?: number | null) => boolean;
3
+ shouldRefresh: (expiresAt?: number | null, threshold?: number) => boolean;
4
+ getTimeUntilExpiry: (expiresAt?: number | null) => number;
5
+ scheduleRefresh?: (
6
+ callback: () => void,
7
+ expiresAt?: number | null,
8
+ ) => () => void;
9
+ };
@@ -0,0 +1,55 @@
1
+ // ============================================================================
2
+ // Utility Types
3
+ // ============================================================================
4
+
5
+ import type { AuthAdapter } from "./adapter";
6
+
7
+ export type InferSession<T> = T extends AuthAdapter<
8
+ infer _User,
9
+ infer _Role extends string,
10
+ infer _Permission extends string,
11
+ infer TSession,
12
+ infer _Credentials
13
+ >
14
+ ? TSession
15
+ : never;
16
+
17
+ export type InferUser<T> = T extends AuthAdapter<
18
+ infer TUser,
19
+ infer _Role extends string,
20
+ infer _Permission extends string,
21
+ infer _Session,
22
+ infer _Credentials
23
+ >
24
+ ? TUser
25
+ : never;
26
+
27
+ export type InferRole<T> = T extends AuthAdapter<
28
+ infer _User,
29
+ infer TRole extends string,
30
+ infer _Permission extends string,
31
+ infer _Session,
32
+ infer _Credentials
33
+ >
34
+ ? TRole
35
+ : never;
36
+
37
+ export type InferPermission<T> = T extends AuthAdapter<
38
+ infer _User,
39
+ infer _Role extends string,
40
+ infer TPermission extends string,
41
+ infer _Session,
42
+ infer _Credentials
43
+ >
44
+ ? TPermission
45
+ : never;
46
+
47
+ export type InferCredentials<T> = T extends AuthAdapter<
48
+ infer _User,
49
+ infer _Role extends string,
50
+ infer _Permission extends string,
51
+ infer _Session,
52
+ infer TCredentials
53
+ >
54
+ ? TCredentials
55
+ : never;
@@ -16,7 +16,7 @@ import type {
16
16
  AuthStatus,
17
17
  PermissionPolicy,
18
18
  PermissionRule,
19
- } from './types';
19
+ } from '../types';
20
20
 
21
21
  const unique = <T>(values: T[]): T[] => {
22
22
  return Array.from(new Set(values));
@@ -334,7 +334,8 @@ export function createAuthAdapter<
334
334
  return nextState;
335
335
  } catch (error) {
336
336
  await executeMiddleware('onError', error);
337
- return await setSession(null, 'error', error);
337
+ await setSession(null, 'error', error);
338
+ throw error;
338
339
  }
339
340
  };
340
341
 
@@ -0,0 +1,30 @@
1
+ export function createApolloAuthLink(
2
+ getToken: () => string | null,
3
+ options?: {
4
+ tokenType?: string
5
+ },
6
+ ) {
7
+ const tokenType = options?.tokenType ?? 'Bearer'
8
+
9
+ // This requires @apollo/client to be installed
10
+ // We'll return a function that creates the link to avoid direct dependency
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ return (ApolloLink: any) => {
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ return new ApolloLink((operation: any, forward: any) => {
15
+ const token = getToken()
16
+
17
+ if (token) {
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ operation.setContext(({ headers = {} }: any) => ({
20
+ headers: {
21
+ ...headers,
22
+ authorization: `${tokenType} ${token}`,
23
+ },
24
+ }))
25
+ }
26
+
27
+ return forward(operation)
28
+ })
29
+ }
30
+ }
@@ -0,0 +1,61 @@
1
+ export function createAxiosAuthInterceptor(
2
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
+ axiosInstance: any,
4
+ getToken: () => string | null,
5
+ options?: {
6
+ tokenType?: string
7
+ onTokenExpired?: () => void
8
+ refreshToken?: () => Promise<void>
9
+ },
10
+ ) {
11
+ const tokenType = options?.tokenType ?? 'Bearer'
12
+
13
+ // Request interceptor
14
+ axiosInstance.interceptors.request.use(
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ async (config: any) => {
17
+ const token = getToken()
18
+ if (token) {
19
+ config.headers.Authorization = `${tokenType} ${token}`
20
+ }
21
+ return config
22
+ },
23
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
+ (error: any) => Promise.reject(error),
25
+ )
26
+
27
+ // Response interceptor for token refresh
28
+ if (options?.refreshToken) {
29
+ axiosInstance.interceptors.response.use(
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ (response: any) => response,
32
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
+ async (error: any) => {
34
+ const originalRequest = error.config
35
+
36
+ // If token expired and we haven't retried yet
37
+ if (
38
+ error.response?.status === 401 &&
39
+ !originalRequest._retry &&
40
+ options.refreshToken
41
+ ) {
42
+ originalRequest._retry = true
43
+
44
+ try {
45
+ await options.refreshToken()
46
+ const token = getToken()
47
+ if (token) {
48
+ originalRequest.headers.Authorization = `${tokenType} ${token}`
49
+ }
50
+ return axiosInstance(originalRequest)
51
+ } catch (refreshError) {
52
+ options.onTokenExpired?.()
53
+ return Promise.reject(refreshError)
54
+ }
55
+ }
56
+
57
+ return Promise.reject(error)
58
+ },
59
+ )
60
+ }
61
+ }
@@ -0,0 +1,48 @@
1
+ export function createAuthFetch(
2
+ getToken: () => string | null,
3
+ options?: {
4
+ tokenType?: string
5
+ onTokenExpired?: () => void
6
+ refreshToken?: () => Promise<void>
7
+ },
8
+ ): typeof fetch {
9
+ const tokenType = options?.tokenType ?? 'Bearer'
10
+
11
+ return async (
12
+ input: RequestInfo | URL,
13
+ init?: RequestInit,
14
+ ): Promise<Response> => {
15
+ const token = getToken()
16
+ const headers = new Headers(init?.headers)
17
+
18
+ if (token) {
19
+ headers.set('Authorization', `${tokenType} ${token}`)
20
+ }
21
+
22
+ const response = await fetch(input, {
23
+ ...init,
24
+ headers,
25
+ })
26
+
27
+ // Handle token expiration
28
+ if (response.status === 401 && options?.refreshToken) {
29
+ try {
30
+ await options.refreshToken()
31
+ const newToken = getToken()
32
+
33
+ if (newToken) {
34
+ headers.set('Authorization', `${tokenType} ${newToken}`)
35
+ return await fetch(input, {
36
+ ...init,
37
+ headers,
38
+ })
39
+ }
40
+ } catch (error) {
41
+ options.onTokenExpired?.()
42
+ throw error
43
+ }
44
+ }
45
+
46
+ return response
47
+ }
48
+ }
@@ -0,0 +1,60 @@
1
+ import type { AuthAdapterConfig, AuthSession, GraphQLAuthClient } from '../../types'
2
+
3
+ export type GraphQLClientAdapterOptions<
4
+ TUser = unknown,
5
+ TRole extends string = string,
6
+ TPermission extends string = string,
7
+ TSession extends AuthSession<TUser, TRole, TPermission> = AuthSession<
8
+ TUser,
9
+ TRole,
10
+ TPermission
11
+ >,
12
+ TCredentials = unknown,
13
+ > = {
14
+ client: GraphQLAuthClient<TSession, TCredentials>
15
+ resolveUser?: (session: TSession | null) => TUser | null
16
+ resolveRoles?: (session: TSession | null) => TRole[]
17
+ resolvePermissions?: (session: TSession | null) => TPermission[]
18
+ }
19
+
20
+ export function createGraphQLAuthAdapter<
21
+ TUser = unknown,
22
+ TRole extends string = string,
23
+ TPermission extends string = string,
24
+ TSession extends AuthSession<TUser, TRole, TPermission> = AuthSession<
25
+ TUser,
26
+ TRole,
27
+ TPermission
28
+ >,
29
+ TCredentials = unknown,
30
+ >(
31
+ options: GraphQLClientAdapterOptions<
32
+ TUser,
33
+ TRole,
34
+ TPermission,
35
+ TSession,
36
+ TCredentials
37
+ >,
38
+ ): Partial<
39
+ AuthAdapterConfig<TUser, TRole, TPermission, TSession, TCredentials>
40
+ > {
41
+ return {
42
+ login: options.client.login,
43
+ logout: options.client.logout,
44
+ refresh: options.client.refresh
45
+ ? async (session: TSession) => {
46
+ if (!session.refreshToken) {
47
+ throw new Error('No refresh token available')
48
+ }
49
+ if (!options.client.refresh) {
50
+ throw new Error('Refresh function not provided')
51
+ }
52
+ return await options.client.refresh(session.refreshToken)
53
+ }
54
+ : undefined,
55
+ loadSession: options.client.getCurrentUser,
56
+ resolveUser: options.resolveUser,
57
+ resolveRoles: options.resolveRoles,
58
+ resolvePermissions: options.resolvePermissions,
59
+ }
60
+ }
@@ -0,0 +1,6 @@
1
+ export * from './graphql'
2
+ export * from './rest'
3
+ export * from './axios'
4
+ export * from './fetch'
5
+ export * from './apollo-link'
6
+ export * from './urql-exchange'
@@ -0,0 +1,60 @@
1
+ import type { AuthAdapterConfig, AuthSession, RESTAuthClient } from '../../types'
2
+
3
+ export type RESTClientAdapterOptions<
4
+ TUser = unknown,
5
+ TRole extends string = string,
6
+ TPermission extends string = string,
7
+ TSession extends AuthSession<TUser, TRole, TPermission> = AuthSession<
8
+ TUser,
9
+ TRole,
10
+ TPermission
11
+ >,
12
+ TCredentials = unknown,
13
+ > = {
14
+ client: RESTAuthClient<TSession, TCredentials>
15
+ resolveUser?: (session: TSession | null) => TUser | null
16
+ resolveRoles?: (session: TSession | null) => TRole[]
17
+ resolvePermissions?: (session: TSession | null) => TPermission[]
18
+ }
19
+
20
+ export function createRESTAuthAdapter<
21
+ TUser = unknown,
22
+ TRole extends string = string,
23
+ TPermission extends string = string,
24
+ TSession extends AuthSession<TUser, TRole, TPermission> = AuthSession<
25
+ TUser,
26
+ TRole,
27
+ TPermission
28
+ >,
29
+ TCredentials = unknown,
30
+ >(
31
+ options: RESTClientAdapterOptions<
32
+ TUser,
33
+ TRole,
34
+ TPermission,
35
+ TSession,
36
+ TCredentials
37
+ >,
38
+ ): Partial<
39
+ AuthAdapterConfig<TUser, TRole, TPermission, TSession, TCredentials>
40
+ > {
41
+ return {
42
+ login: options.client.login,
43
+ logout: options.client.logout,
44
+ refresh: options.client.refresh
45
+ ? async (session: TSession) => {
46
+ if (!session.refreshToken) {
47
+ throw new Error('No refresh token available')
48
+ }
49
+ if (!options.client.refresh) {
50
+ throw new Error('Refresh function not provided')
51
+ }
52
+ return await options.client.refresh(session.refreshToken)
53
+ }
54
+ : undefined,
55
+ loadSession: options.client.getCurrentUser,
56
+ resolveUser: options.resolveUser,
57
+ resolveRoles: options.resolveRoles,
58
+ resolvePermissions: options.resolvePermissions,
59
+ }
60
+ }
@@ -0,0 +1,76 @@
1
+ export function createUrqlAuthExchange(
2
+ getToken: () => string | null,
3
+ options?: {
4
+ tokenType?: string
5
+ refreshToken?: () => Promise<void>
6
+ onTokenExpired?: () => void
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ willAuthError?: (params: { authState: any; operation: any }) => boolean
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ didAuthError?: (params: { error: any; operation: any }) => boolean
11
+ },
12
+ ) {
13
+ const tokenType = options?.tokenType ?? 'Bearer'
14
+
15
+ // Avoid direct dependency on @urql/exchange-auth. Return a factory that accepts it.
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ return (authExchange: any) =>
18
+ authExchange({
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ addAuthToOperation: ({ authState, operation }: any) => {
21
+ const token = authState?.token ?? getToken()
22
+ if (!token) return operation
23
+
24
+ const fetchOptions =
25
+ typeof operation.context.fetchOptions === 'function'
26
+ ? operation.context.fetchOptions()
27
+ : operation.context.fetchOptions || {}
28
+
29
+ return {
30
+ ...operation,
31
+ context: {
32
+ ...operation.context,
33
+ fetchOptions: {
34
+ ...fetchOptions,
35
+ headers: {
36
+ ...fetchOptions.headers,
37
+ Authorization: `${tokenType} ${token}`,
38
+ },
39
+ },
40
+ },
41
+ }
42
+ },
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ getAuth: async ({ authState }: any) => {
45
+ if (!authState) {
46
+ const token = getToken()
47
+ if (token) return { token }
48
+ return null
49
+ }
50
+
51
+ if (options?.refreshToken) {
52
+ try {
53
+ await options.refreshToken()
54
+ const token = getToken()
55
+ if (token) return { token }
56
+ } catch (_e) {
57
+ options.onTokenExpired?.()
58
+ return null
59
+ }
60
+ }
61
+ return null
62
+ },
63
+ willAuthError: options?.willAuthError,
64
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
65
+ didAuthError: (params: { error: any; operation: any }) => {
66
+ if (options?.didAuthError) return options.didAuthError(params)
67
+ const { error } = params
68
+ return (
69
+ error?.graphQLErrors?.some(
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ (e: any) => e.extensions?.code === 'UNAUTHENTICATED',
72
+ ) || error?.response?.status === 401
73
+ )
74
+ },
75
+ })
76
+ }
@@ -3,7 +3,7 @@ import type {
3
3
  PermissionPolicy,
4
4
  PermissionRule,
5
5
  RoleHierarchy,
6
- } from './types';
6
+ } from '../types';
7
7
 
8
8
  /**
9
9
  * Expands permissions based on hierarchy
@@ -0,0 +1,99 @@
1
+ import type { AuthStorage } from '../../types'
2
+ import { isBrowser } from './env'
3
+ import { createMemoryStorage } from './memory'
4
+ import { SimpleEncryption } from './encryption'
5
+
6
+ export type BrowserStorageOptions<T> = {
7
+ key: string
8
+ serialize?: (value: T | null) => Promise<string | null> | string | null
9
+ deserialize?: (value: string | null) => Promise<T | null> | T | null
10
+ storage?: Storage
11
+ encrypt?: boolean
12
+ encryptionKey?: string
13
+ }
14
+
15
+ export const createBrowserStorage = <T>(
16
+ options: BrowserStorageOptions<T>,
17
+ ): AuthStorage<T> => {
18
+ const fallback = createMemoryStorage<T>()
19
+ const targetStorage =
20
+ options.storage ?? (isBrowser ? window.localStorage : undefined)
21
+
22
+ const encryption =
23
+ options.encrypt && options.encryptionKey
24
+ ? new SimpleEncryption(options.encryptionKey)
25
+ : null
26
+
27
+ const defaultSerialize = async (value: T | null): Promise<string | null> => {
28
+ if (value === null) return null
29
+ const json = JSON.stringify(value)
30
+ return encryption ? await encryption.encrypt(json) : json
31
+ }
32
+
33
+ const defaultDeserialize = async (
34
+ value: string | null,
35
+ ): Promise<T | null> => {
36
+ if (!value) return null
37
+ try {
38
+ const decrypted = encryption ? await encryption.decrypt(value) : value
39
+ return JSON.parse(decrypted) as T
40
+ } catch {
41
+ return null
42
+ }
43
+ }
44
+
45
+ const serialize = options.serialize
46
+ ? async (value: T | null) => {
47
+ const result = await options.serialize?.(value)
48
+ return result ?? null
49
+ }
50
+ : defaultSerialize
51
+
52
+ const deserialize = options.deserialize
53
+ ? async (value: string | null) => {
54
+ const result = await options.deserialize?.(value)
55
+ return result ?? null
56
+ }
57
+ : defaultDeserialize
58
+
59
+ if (!targetStorage) {
60
+ return fallback
61
+ }
62
+
63
+ return {
64
+ get: async () => {
65
+ try {
66
+ const raw = targetStorage.getItem(options.key)
67
+ const value = await deserialize(raw)
68
+ fallback.set(value)
69
+ return value
70
+ } catch (error) {
71
+ console.warn('[auth2][storage] Failed to read from storage', error)
72
+ return fallback.get()
73
+ }
74
+ },
75
+ set: async (value) => {
76
+ try {
77
+ const serialized = await serialize(value)
78
+ if (serialized === null) {
79
+ targetStorage.removeItem(options.key)
80
+ } else {
81
+ targetStorage.setItem(options.key, serialized)
82
+ }
83
+ fallback.set(value)
84
+ } catch (error) {
85
+ console.warn('[auth2][storage] Failed to write to storage', error)
86
+ fallback.set(value)
87
+ }
88
+ },
89
+ clear: () => {
90
+ try {
91
+ targetStorage.removeItem(options.key)
92
+ } catch (error) {
93
+ console.warn('[auth2][storage] Failed to clear storage', error)
94
+ } finally {
95
+ fallback.clear()
96
+ }
97
+ },
98
+ }
99
+ }
@@ -0,0 +1,116 @@
1
+ import type { AuthStorage, StorageOptions } from '../../types'
2
+ import { isBrowser } from './env'
3
+ import { createMemoryStorage } from './memory'
4
+ import { SimpleEncryption } from './encryption'
5
+
6
+ export const createCookieStorage = <T>(
7
+ options: StorageOptions,
8
+ ): AuthStorage<T> => {
9
+ const key = options.key ?? 'auth2_session'
10
+ const cookieOpts = options.cookieOptions ?? {}
11
+ const fallback = createMemoryStorage<T>()
12
+ const encryption =
13
+ options.encrypt && options.encryptionKey
14
+ ? new SimpleEncryption(options.encryptionKey)
15
+ : null
16
+ const cookieSetter =
17
+ typeof Document !== 'undefined'
18
+ ? Object.getOwnPropertyDescriptor(Document.prototype, 'cookie')?.set
19
+ : undefined
20
+
21
+ const assignCookie = (value: string) => {
22
+ if (!isBrowser || typeof document === 'undefined') return
23
+ if (cookieSetter) {
24
+ cookieSetter.call(document, value)
25
+ return
26
+ }
27
+ Reflect.set(document, 'cookie', value)
28
+ }
29
+
30
+ const serialize = async (value: T | null): Promise<string | null> => {
31
+ if (value === null) return null
32
+ const json = JSON.stringify(value)
33
+ return encryption ? await encryption.encrypt(json) : json
34
+ }
35
+
36
+ const deserialize = async (value: string | null): Promise<T | null> => {
37
+ if (!value) return null
38
+ try {
39
+ const decrypted = encryption ? await encryption.decrypt(value) : value
40
+ return JSON.parse(decrypted) as T
41
+ } catch {
42
+ return null
43
+ }
44
+ }
45
+
46
+ const getCookie = (name: string): string | null => {
47
+ if (!isBrowser) return null
48
+ const matches = document.cookie.match(
49
+ new RegExp(
50
+ `(?:^|; )${name.replace(/([.$?*|{}()\[\]\\/+^])/g, '\\$1')}=([^;]*)`,
51
+ ),
52
+ )
53
+ return matches ? decodeURIComponent(matches[1]) : null
54
+ }
55
+
56
+ const setCookie = (
57
+ name: string,
58
+ value: string,
59
+ opts: typeof cookieOpts = {},
60
+ ) => {
61
+ if (!isBrowser) return
62
+
63
+ let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`
64
+
65
+ if (opts.maxAge) cookie += `; max-age=${opts.maxAge}`
66
+ if (opts.domain) cookie += `; domain=${opts.domain}`
67
+ if (opts.path !== undefined) cookie += `; path=${opts.path}`
68
+ else cookie += '; path=/'
69
+ if (opts.secure) cookie += '; secure'
70
+ if (opts.sameSite) cookie += `; samesite=${opts.sameSite}`
71
+
72
+ assignCookie(cookie)
73
+ }
74
+
75
+ const deleteCookie = (name: string) => {
76
+ if (!isBrowser) return
77
+ assignCookie(`${name}=; max-age=0; path=/`)
78
+ }
79
+
80
+ return {
81
+ get: async () => {
82
+ try {
83
+ const raw = getCookie(key)
84
+ const value = await deserialize(raw)
85
+ fallback.set(value)
86
+ return value
87
+ } catch (error) {
88
+ console.warn('[auth2][storage] Failed to read from cookie', error)
89
+ return fallback.get()
90
+ }
91
+ },
92
+ set: async (value) => {
93
+ try {
94
+ const serialized = await serialize(value)
95
+ if (serialized === null) {
96
+ deleteCookie(key)
97
+ } else {
98
+ setCookie(key, serialized, cookieOpts)
99
+ }
100
+ fallback.set(value)
101
+ } catch (error) {
102
+ console.warn('[auth2][storage] Failed to write to cookie', error)
103
+ fallback.set(value)
104
+ }
105
+ },
106
+ clear: () => {
107
+ try {
108
+ deleteCookie(key)
109
+ } catch (error) {
110
+ console.warn('[auth2][storage] Failed to clear cookie', error)
111
+ } finally {
112
+ fallback.clear()
113
+ }
114
+ },
115
+ }
116
+ }