@fluxbase/sdk-react 0.1.0-rc.1 → 2026.1.1-rc.10

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.
@@ -1,14 +1,14 @@
1
- import { useState, useEffect, useCallback } from 'react'
2
- import { useFluxbaseClient } from './context'
3
- import type { AdminAuthResponse } from '@fluxbase/sdk'
1
+ import { useState, useEffect, useCallback } from "react";
2
+ import { useFluxbaseClient } from "./context";
3
+ import type { AdminAuthResponse, DataResponse } from "@fluxbase/sdk";
4
4
 
5
5
  /**
6
6
  * Simplified admin user type returned by authentication
7
7
  */
8
8
  export interface AdminUser {
9
- id: string
10
- email: string
11
- role: string
9
+ id: string;
10
+ email: string;
11
+ role: string;
12
12
  }
13
13
 
14
14
  export interface UseAdminAuthOptions {
@@ -16,44 +16,44 @@ export interface UseAdminAuthOptions {
16
16
  * Automatically check authentication status on mount
17
17
  * @default true
18
18
  */
19
- autoCheck?: boolean
19
+ autoCheck?: boolean;
20
20
  }
21
21
 
22
22
  export interface UseAdminAuthReturn {
23
23
  /**
24
24
  * Current admin user if authenticated
25
25
  */
26
- user: AdminUser | null
26
+ user: AdminUser | null;
27
27
 
28
28
  /**
29
29
  * Whether the admin is authenticated
30
30
  */
31
- isAuthenticated: boolean
31
+ isAuthenticated: boolean;
32
32
 
33
33
  /**
34
34
  * Whether the authentication check is in progress
35
35
  */
36
- isLoading: boolean
36
+ isLoading: boolean;
37
37
 
38
38
  /**
39
39
  * Any error that occurred during authentication
40
40
  */
41
- error: Error | null
41
+ error: Error | null;
42
42
 
43
43
  /**
44
44
  * Login as admin
45
45
  */
46
- login: (email: string, password: string) => Promise<AdminAuthResponse>
46
+ login: (email: string, password: string) => Promise<AdminAuthResponse>;
47
47
 
48
48
  /**
49
49
  * Logout admin
50
50
  */
51
- logout: () => Promise<void>
51
+ logout: () => Promise<void>;
52
52
 
53
53
  /**
54
54
  * Refresh admin user info
55
55
  */
56
- refresh: () => Promise<void>
56
+ refresh: () => Promise<void>;
57
57
  }
58
58
 
59
59
  /**
@@ -78,30 +78,35 @@ export interface UseAdminAuthReturn {
78
78
  * }
79
79
  * ```
80
80
  */
81
- export function useAdminAuth(options: UseAdminAuthOptions = {}): UseAdminAuthReturn {
82
- const { autoCheck = true } = options
83
- const client = useFluxbaseClient()
81
+ export function useAdminAuth(
82
+ options: UseAdminAuthOptions = {},
83
+ ): UseAdminAuthReturn {
84
+ const { autoCheck = true } = options;
85
+ const client = useFluxbaseClient();
84
86
 
85
- const [user, setUser] = useState<AdminUser | null>(null)
86
- const [isLoading, setIsLoading] = useState(autoCheck)
87
- const [error, setError] = useState<Error | null>(null)
87
+ const [user, setUser] = useState<AdminUser | null>(null);
88
+ const [isLoading, setIsLoading] = useState(autoCheck);
89
+ const [error, setError] = useState<Error | null>(null);
88
90
 
89
91
  /**
90
92
  * Check current authentication status
91
93
  */
92
94
  const checkAuth = useCallback(async () => {
93
95
  try {
94
- setIsLoading(true)
95
- setError(null)
96
- const { user } = await client.admin.me()
97
- setUser(user)
96
+ setIsLoading(true);
97
+ setError(null);
98
+ const { data, error: apiError } = await client.admin.me();
99
+ if (apiError) {
100
+ throw apiError;
101
+ }
102
+ setUser(data!.user);
98
103
  } catch (err) {
99
- setUser(null)
100
- setError(err as Error)
104
+ setUser(null);
105
+ setError(err as Error);
101
106
  } finally {
102
- setIsLoading(false)
107
+ setIsLoading(false);
103
108
  }
104
- }, [client])
109
+ }, [client]);
105
110
 
106
111
  /**
107
112
  * Login as admin
@@ -109,52 +114,58 @@ export function useAdminAuth(options: UseAdminAuthOptions = {}): UseAdminAuthRet
109
114
  const login = useCallback(
110
115
  async (email: string, password: string): Promise<AdminAuthResponse> => {
111
116
  try {
112
- setIsLoading(true)
113
- setError(null)
114
- const response = await client.admin.login({ email, password })
115
- setUser(response.user)
116
- return response
117
+ setIsLoading(true);
118
+ setError(null);
119
+ const { data, error: apiError } = await client.admin.login({
120
+ email,
121
+ password,
122
+ });
123
+ if (apiError) {
124
+ throw apiError;
125
+ }
126
+ setUser(data!.user);
127
+ return data!;
117
128
  } catch (err) {
118
- setError(err as Error)
119
- throw err
129
+ setError(err as Error);
130
+ throw err;
120
131
  } finally {
121
- setIsLoading(false)
132
+ setIsLoading(false);
122
133
  }
123
134
  },
124
- [client]
125
- )
135
+ [client],
136
+ );
126
137
 
127
138
  /**
128
139
  * Logout admin
129
140
  */
130
141
  const logout = useCallback(async (): Promise<void> => {
131
142
  try {
132
- setIsLoading(true)
133
- setError(null)
143
+ setIsLoading(true);
144
+ setError(null);
134
145
  // Clear user state
135
- setUser(null)
146
+ setUser(null);
136
147
  // Note: Add logout endpoint call here when available
137
148
  } catch (err) {
138
- setError(err as Error)
139
- throw err
149
+ setError(err as Error);
150
+ throw err;
140
151
  } finally {
141
- setIsLoading(false)
152
+ setIsLoading(false);
142
153
  }
143
- }, [])
154
+ }, []);
144
155
 
145
156
  /**
146
157
  * Refresh admin user info
147
158
  */
148
159
  const refresh = useCallback(async (): Promise<void> => {
149
- await checkAuth()
150
- }, [checkAuth])
160
+ await checkAuth();
161
+ }, [checkAuth]);
151
162
 
152
163
  // Auto-check authentication on mount
153
164
  useEffect(() => {
154
165
  if (autoCheck) {
155
- checkAuth()
166
+ checkAuth();
156
167
  }
157
- }, [autoCheck, checkAuth])
168
+ }, [autoCheck, checkAuth]);
158
169
 
159
170
  return {
160
171
  user,
@@ -163,6 +174,6 @@ export function useAdminAuth(options: UseAdminAuthOptions = {}): UseAdminAuthRet
163
174
  error,
164
175
  login,
165
176
  logout,
166
- refresh
167
- }
177
+ refresh,
178
+ };
168
179
  }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Auth configuration hooks for Fluxbase SDK
3
+ *
4
+ * Provides hooks to fetch comprehensive authentication configuration
5
+ * from the server including signup status, OAuth/SAML providers,
6
+ * password requirements, and CAPTCHA settings.
7
+ */
8
+
9
+ import { useQuery } from "@tanstack/react-query";
10
+ import { useFluxbaseClient } from "./context";
11
+ import type { AuthConfig } from "@fluxbase/sdk";
12
+
13
+ /**
14
+ * Hook to get the complete authentication configuration from the server
15
+ *
16
+ * Returns all public auth settings in a single request including:
17
+ * - Signup enabled status
18
+ * - Email verification requirements
19
+ * - Magic link availability
20
+ * - MFA availability
21
+ * - Password requirements (length, complexity)
22
+ * - Available OAuth providers (Google, GitHub, etc.)
23
+ * - Available SAML providers (enterprise SSO)
24
+ * - CAPTCHA configuration
25
+ *
26
+ * Use this to conditionally render UI elements based on server configuration,
27
+ * such as hiding signup forms when signup is disabled or displaying available
28
+ * OAuth provider buttons.
29
+ *
30
+ * @returns Query result with authentication configuration
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * function AuthPage() {
35
+ * const { data: config, isLoading } = useAuthConfig();
36
+ *
37
+ * if (isLoading) return <Loading />;
38
+ *
39
+ * return (
40
+ * <div>
41
+ * {config?.signup_enabled && (
42
+ * <SignupForm passwordMinLength={config.password_min_length} />
43
+ * )}
44
+ *
45
+ * {config?.oauth_providers.map(provider => (
46
+ * <OAuthButton
47
+ * key={provider.provider}
48
+ * provider={provider.provider}
49
+ * displayName={provider.display_name}
50
+ * authorizeUrl={provider.authorize_url}
51
+ * />
52
+ * ))}
53
+ *
54
+ * {config?.saml_providers.map(provider => (
55
+ * <SAMLButton
56
+ * key={provider.provider}
57
+ * provider={provider.provider}
58
+ * displayName={provider.display_name}
59
+ * />
60
+ * ))}
61
+ * </div>
62
+ * );
63
+ * }
64
+ * ```
65
+ *
66
+ * @example Showing password requirements
67
+ * ```tsx
68
+ * function PasswordInput() {
69
+ * const { data: config } = useAuthConfig();
70
+ *
71
+ * return (
72
+ * <div>
73
+ * <input type="password" minLength={config?.password_min_length} />
74
+ * <ul>
75
+ * <li>Minimum {config?.password_min_length || 8} characters</li>
76
+ * {config?.password_require_uppercase && <li>One uppercase letter</li>}
77
+ * {config?.password_require_lowercase && <li>One lowercase letter</li>}
78
+ * {config?.password_require_number && <li>One number</li>}
79
+ * {config?.password_require_special && <li>One special character</li>}
80
+ * </ul>
81
+ * </div>
82
+ * );
83
+ * }
84
+ * ```
85
+ */
86
+ export function useAuthConfig() {
87
+ const client = useFluxbaseClient();
88
+
89
+ return useQuery<AuthConfig>({
90
+ queryKey: ["fluxbase", "auth", "config"],
91
+ queryFn: async () => {
92
+ const { data, error } = await client.auth.getAuthConfig();
93
+ if (error) {
94
+ throw error;
95
+ }
96
+ return data!;
97
+ },
98
+ staleTime: 1000 * 60 * 5, // Cache for 5 minutes (config changes infrequently)
99
+ gcTime: 1000 * 60 * 60, // Keep in cache for 1 hour
100
+ });
101
+ }
package/src/use-auth.ts CHANGED
@@ -2,132 +2,149 @@
2
2
  * Authentication hooks for Fluxbase SDK
3
3
  */
4
4
 
5
- import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
6
- import { useFluxbaseClient } from './context'
7
- import type { SignInCredentials, SignUpCredentials, User, AuthSession } from '@fluxbase/sdk'
5
+ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
6
+ import { useFluxbaseClient } from "./context";
7
+ import type {
8
+ SignInCredentials,
9
+ SignUpCredentials,
10
+ User,
11
+ AuthSession,
12
+ } from "@fluxbase/sdk";
8
13
 
9
14
  /**
10
15
  * Hook to get the current user
11
16
  */
12
17
  export function useUser() {
13
- const client = useFluxbaseClient()
18
+ const client = useFluxbaseClient();
14
19
 
15
20
  return useQuery({
16
- queryKey: ['fluxbase', 'auth', 'user'],
21
+ queryKey: ["fluxbase", "auth", "user"],
17
22
  queryFn: async () => {
18
- const session = client.auth.getSession()
19
- if (!session) {
20
- return null
23
+ const { data } = await client.auth.getSession();
24
+ if (!data?.session) {
25
+ return null;
21
26
  }
22
27
 
23
28
  try {
24
- return await client.auth.getCurrentUser()
29
+ const result = await client.auth.getCurrentUser();
30
+ return result.data?.user ?? null;
25
31
  } catch {
26
- return null
32
+ return null;
27
33
  }
28
34
  },
29
35
  staleTime: 1000 * 60 * 5, // 5 minutes
30
- })
36
+ });
31
37
  }
32
38
 
33
39
  /**
34
40
  * Hook to get the current session
35
41
  */
36
42
  export function useSession() {
37
- const client = useFluxbaseClient()
43
+ const client = useFluxbaseClient();
38
44
 
39
45
  return useQuery<AuthSession | null>({
40
- queryKey: ['fluxbase', 'auth', 'session'],
41
- queryFn: () => client.auth.getSession(),
46
+ queryKey: ["fluxbase", "auth", "session"],
47
+ queryFn: async () => {
48
+ const { data } = await client.auth.getSession();
49
+ return data?.session ?? null;
50
+ },
42
51
  staleTime: 1000 * 60 * 5, // 5 minutes
43
- })
52
+ });
44
53
  }
45
54
 
46
55
  /**
47
56
  * Hook for signing in
48
57
  */
49
58
  export function useSignIn() {
50
- const client = useFluxbaseClient()
51
- const queryClient = useQueryClient()
59
+ const client = useFluxbaseClient();
60
+ const queryClient = useQueryClient();
52
61
 
53
62
  return useMutation({
54
63
  mutationFn: async (credentials: SignInCredentials) => {
55
- return await client.auth.signIn(credentials)
64
+ return await client.auth.signIn(credentials);
56
65
  },
57
66
  onSuccess: (session) => {
58
- queryClient.setQueryData(['fluxbase', 'auth', 'session'], session)
67
+ queryClient.setQueryData(["fluxbase", "auth", "session"], session);
59
68
  // Only set user if this is a complete auth session (not 2FA required)
60
- if ('user' in session) {
61
- queryClient.setQueryData(['fluxbase', 'auth', 'user'], session.user)
69
+ if ("user" in session) {
70
+ queryClient.setQueryData(["fluxbase", "auth", "user"], session.user);
62
71
  }
63
72
  },
64
- })
73
+ });
65
74
  }
66
75
 
67
76
  /**
68
77
  * Hook for signing up
69
78
  */
70
79
  export function useSignUp() {
71
- const client = useFluxbaseClient()
72
- const queryClient = useQueryClient()
80
+ const client = useFluxbaseClient();
81
+ const queryClient = useQueryClient();
73
82
 
74
83
  return useMutation({
75
84
  mutationFn: async (credentials: SignUpCredentials) => {
76
- return await client.auth.signUp(credentials)
85
+ return await client.auth.signUp(credentials);
77
86
  },
78
- onSuccess: (session) => {
79
- queryClient.setQueryData(['fluxbase', 'auth', 'session'], session)
80
- queryClient.setQueryData(['fluxbase', 'auth', 'user'], session.user)
87
+ onSuccess: (response) => {
88
+ if (response.data) {
89
+ queryClient.setQueryData(
90
+ ["fluxbase", "auth", "session"],
91
+ response.data.session,
92
+ );
93
+ queryClient.setQueryData(
94
+ ["fluxbase", "auth", "user"],
95
+ response.data.user,
96
+ );
97
+ }
81
98
  },
82
- })
99
+ });
83
100
  }
84
101
 
85
102
  /**
86
103
  * Hook for signing out
87
104
  */
88
105
  export function useSignOut() {
89
- const client = useFluxbaseClient()
90
- const queryClient = useQueryClient()
106
+ const client = useFluxbaseClient();
107
+ const queryClient = useQueryClient();
91
108
 
92
109
  return useMutation({
93
110
  mutationFn: async () => {
94
- await client.auth.signOut()
111
+ await client.auth.signOut();
95
112
  },
96
113
  onSuccess: () => {
97
- queryClient.setQueryData(['fluxbase', 'auth', 'session'], null)
98
- queryClient.setQueryData(['fluxbase', 'auth', 'user'], null)
99
- queryClient.invalidateQueries({ queryKey: ['fluxbase'] })
114
+ queryClient.setQueryData(["fluxbase", "auth", "session"], null);
115
+ queryClient.setQueryData(["fluxbase", "auth", "user"], null);
116
+ queryClient.invalidateQueries({ queryKey: ["fluxbase"] });
100
117
  },
101
- })
118
+ });
102
119
  }
103
120
 
104
121
  /**
105
122
  * Hook for updating the current user
106
123
  */
107
124
  export function useUpdateUser() {
108
- const client = useFluxbaseClient()
109
- const queryClient = useQueryClient()
125
+ const client = useFluxbaseClient();
126
+ const queryClient = useQueryClient();
110
127
 
111
128
  return useMutation({
112
- mutationFn: async (data: Partial<Pick<User, 'email' | 'metadata'>>) => {
113
- return await client.auth.updateUser(data)
129
+ mutationFn: async (data: Partial<Pick<User, "email" | "metadata">>) => {
130
+ return await client.auth.updateUser(data);
114
131
  },
115
132
  onSuccess: (user) => {
116
- queryClient.setQueryData(['fluxbase', 'auth', 'user'], user)
133
+ queryClient.setQueryData(["fluxbase", "auth", "user"], user);
117
134
  },
118
- })
135
+ });
119
136
  }
120
137
 
121
138
  /**
122
139
  * Combined auth hook with all auth state and methods
123
140
  */
124
141
  export function useAuth() {
125
- const { data: user, isLoading: isLoadingUser } = useUser()
126
- const { data: session, isLoading: isLoadingSession } = useSession()
127
- const signIn = useSignIn()
128
- const signUp = useSignUp()
129
- const signOut = useSignOut()
130
- const updateUser = useUpdateUser()
142
+ const { data: user, isLoading: isLoadingUser } = useUser();
143
+ const { data: session, isLoading: isLoadingSession } = useSession();
144
+ const signIn = useSignIn();
145
+ const signUp = useSignUp();
146
+ const signOut = useSignOut();
147
+ const updateUser = useUpdateUser();
131
148
 
132
149
  return {
133
150
  user,
@@ -142,5 +159,5 @@ export function useAuth() {
142
159
  isSigningUp: signUp.isPending,
143
160
  isSigningOut: signOut.isPending,
144
161
  isUpdating: updateUser.isPending,
145
- }
162
+ };
146
163
  }