@nimbleflux/fluxbase-sdk-react 2026.3.6-rc.1
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/.nvmrc +1 -0
- package/README-ADMIN.md +1076 -0
- package/README.md +195 -0
- package/examples/AdminDashboard.tsx +513 -0
- package/examples/README.md +163 -0
- package/package.json +66 -0
- package/src/context.test.tsx +147 -0
- package/src/context.tsx +33 -0
- package/src/index.test.ts +255 -0
- package/src/index.ts +175 -0
- package/src/test-setup.ts +22 -0
- package/src/test-utils.tsx +215 -0
- package/src/use-admin-auth.test.ts +175 -0
- package/src/use-admin-auth.ts +187 -0
- package/src/use-admin-hooks.test.ts +457 -0
- package/src/use-admin-hooks.ts +309 -0
- package/src/use-auth-config.test.ts +145 -0
- package/src/use-auth-config.ts +101 -0
- package/src/use-auth.test.ts +313 -0
- package/src/use-auth.ts +164 -0
- package/src/use-captcha.test.ts +273 -0
- package/src/use-captcha.ts +250 -0
- package/src/use-client-keys.test.ts +286 -0
- package/src/use-client-keys.ts +185 -0
- package/src/use-graphql.test.ts +424 -0
- package/src/use-graphql.ts +392 -0
- package/src/use-query.test.ts +348 -0
- package/src/use-query.ts +211 -0
- package/src/use-realtime.test.ts +359 -0
- package/src/use-realtime.ts +180 -0
- package/src/use-saml.test.ts +269 -0
- package/src/use-saml.ts +221 -0
- package/src/use-storage.test.ts +549 -0
- package/src/use-storage.ts +508 -0
- package/src/use-table-export.ts +481 -0
- package/src/use-users.test.ts +264 -0
- package/src/use-users.ts +198 -0
- package/tsconfig.json +28 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsup.config.ts +11 -0
- package/typedoc.json +33 -0
- package/vitest.config.ts +22 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for authentication hooks
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
6
|
+
import { renderHook, waitFor, act } from '@testing-library/react';
|
|
7
|
+
import {
|
|
8
|
+
useUser,
|
|
9
|
+
useSession,
|
|
10
|
+
useSignIn,
|
|
11
|
+
useSignUp,
|
|
12
|
+
useSignOut,
|
|
13
|
+
useUpdateUser,
|
|
14
|
+
useAuth,
|
|
15
|
+
} from './use-auth';
|
|
16
|
+
import { createMockClient, createWrapper, createTestQueryClient } from './test-utils';
|
|
17
|
+
|
|
18
|
+
describe('useUser', () => {
|
|
19
|
+
it('should return null when no session', async () => {
|
|
20
|
+
const client = createMockClient({
|
|
21
|
+
auth: {
|
|
22
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: null }, error: null }),
|
|
23
|
+
},
|
|
24
|
+
} as any);
|
|
25
|
+
|
|
26
|
+
const { result } = renderHook(() => useUser(), {
|
|
27
|
+
wrapper: createWrapper(client),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
31
|
+
expect(result.current.data).toBeNull();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return user when session exists', async () => {
|
|
35
|
+
const mockUser = { id: '1', email: 'test@example.com' };
|
|
36
|
+
const client = createMockClient({
|
|
37
|
+
auth: {
|
|
38
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: { access_token: 'token' } }, error: null }),
|
|
39
|
+
getCurrentUser: vi.fn().mockResolvedValue({ data: { user: mockUser }, error: null }),
|
|
40
|
+
},
|
|
41
|
+
} as any);
|
|
42
|
+
|
|
43
|
+
const { result } = renderHook(() => useUser(), {
|
|
44
|
+
wrapper: createWrapper(client),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
48
|
+
expect(result.current.data).toEqual(mockUser);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should return null when getCurrentUser fails', async () => {
|
|
52
|
+
const client = createMockClient({
|
|
53
|
+
auth: {
|
|
54
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: { access_token: 'token' } }, error: null }),
|
|
55
|
+
getCurrentUser: vi.fn().mockRejectedValue(new Error('Not authenticated')),
|
|
56
|
+
},
|
|
57
|
+
} as any);
|
|
58
|
+
|
|
59
|
+
const { result } = renderHook(() => useUser(), {
|
|
60
|
+
wrapper: createWrapper(client),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
64
|
+
expect(result.current.data).toBeNull();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('useSession', () => {
|
|
69
|
+
it('should return null when no session', async () => {
|
|
70
|
+
const client = createMockClient({
|
|
71
|
+
auth: {
|
|
72
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: null }, error: null }),
|
|
73
|
+
},
|
|
74
|
+
} as any);
|
|
75
|
+
|
|
76
|
+
const { result } = renderHook(() => useSession(), {
|
|
77
|
+
wrapper: createWrapper(client),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
81
|
+
expect(result.current.data).toBeNull();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should return session when exists', async () => {
|
|
85
|
+
const mockSession = { access_token: 'token', refresh_token: 'refresh' };
|
|
86
|
+
const client = createMockClient({
|
|
87
|
+
auth: {
|
|
88
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: mockSession }, error: null }),
|
|
89
|
+
},
|
|
90
|
+
} as any);
|
|
91
|
+
|
|
92
|
+
const { result } = renderHook(() => useSession(), {
|
|
93
|
+
wrapper: createWrapper(client),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
97
|
+
expect(result.current.data).toEqual(mockSession);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('useSignIn', () => {
|
|
102
|
+
it('should call signIn and update cache on success', async () => {
|
|
103
|
+
const mockSession = { user: { id: '1', email: 'test@example.com' }, access_token: 'token' };
|
|
104
|
+
const signInMock = vi.fn().mockResolvedValue(mockSession);
|
|
105
|
+
const client = createMockClient({
|
|
106
|
+
auth: {
|
|
107
|
+
signIn: signInMock,
|
|
108
|
+
},
|
|
109
|
+
} as any);
|
|
110
|
+
|
|
111
|
+
const queryClient = createTestQueryClient();
|
|
112
|
+
const { result } = renderHook(() => useSignIn(), {
|
|
113
|
+
wrapper: createWrapper(client, queryClient),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
await act(async () => {
|
|
117
|
+
await result.current.mutateAsync({ email: 'test@example.com', password: 'password' });
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
expect(signInMock).toHaveBeenCalledWith({ email: 'test@example.com', password: 'password' });
|
|
121
|
+
expect(queryClient.getQueryData(['fluxbase', 'auth', 'session'])).toEqual(mockSession);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should handle 2FA required response (no user)', async () => {
|
|
125
|
+
const mockResponse = { mfa_required: true };
|
|
126
|
+
const signInMock = vi.fn().mockResolvedValue(mockResponse);
|
|
127
|
+
const client = createMockClient({
|
|
128
|
+
auth: {
|
|
129
|
+
signIn: signInMock,
|
|
130
|
+
},
|
|
131
|
+
} as any);
|
|
132
|
+
|
|
133
|
+
const queryClient = createTestQueryClient();
|
|
134
|
+
const { result } = renderHook(() => useSignIn(), {
|
|
135
|
+
wrapper: createWrapper(client, queryClient),
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
await act(async () => {
|
|
139
|
+
await result.current.mutateAsync({ email: 'test@example.com', password: 'password' });
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// User should not be set when 2FA is required
|
|
143
|
+
expect(queryClient.getQueryData(['fluxbase', 'auth', 'user'])).toBeUndefined();
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('useSignUp', () => {
|
|
148
|
+
it('should call signUp and return response on success', async () => {
|
|
149
|
+
const mockResponse = {
|
|
150
|
+
data: {
|
|
151
|
+
user: { id: '1', email: 'test@example.com' },
|
|
152
|
+
session: { access_token: 'token' },
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
const signUpMock = vi.fn().mockResolvedValue(mockResponse);
|
|
156
|
+
const client = createMockClient({
|
|
157
|
+
auth: {
|
|
158
|
+
signUp: signUpMock,
|
|
159
|
+
},
|
|
160
|
+
} as any);
|
|
161
|
+
|
|
162
|
+
const { result } = renderHook(() => useSignUp(), {
|
|
163
|
+
wrapper: createWrapper(client),
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
let response;
|
|
167
|
+
await act(async () => {
|
|
168
|
+
response = await result.current.mutateAsync({ email: 'test@example.com', password: 'password' });
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
expect(signUpMock).toHaveBeenCalledWith({ email: 'test@example.com', password: 'password' });
|
|
172
|
+
expect(response).toEqual(mockResponse);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should handle signup without immediate session', async () => {
|
|
176
|
+
const mockResponse = { data: null };
|
|
177
|
+
const signUpMock = vi.fn().mockResolvedValue(mockResponse);
|
|
178
|
+
const client = createMockClient({
|
|
179
|
+
auth: {
|
|
180
|
+
signUp: signUpMock,
|
|
181
|
+
},
|
|
182
|
+
} as any);
|
|
183
|
+
|
|
184
|
+
const queryClient = createTestQueryClient();
|
|
185
|
+
const { result } = renderHook(() => useSignUp(), {
|
|
186
|
+
wrapper: createWrapper(client, queryClient),
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
await act(async () => {
|
|
190
|
+
await result.current.mutateAsync({ email: 'test@example.com', password: 'password' });
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Cache should not be updated when data is null
|
|
194
|
+
expect(queryClient.getQueryData(['fluxbase', 'auth', 'session'])).toBeUndefined();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe('useSignOut', () => {
|
|
199
|
+
it('should call signOut successfully', async () => {
|
|
200
|
+
const signOutMock = vi.fn().mockResolvedValue(undefined);
|
|
201
|
+
const client = createMockClient({
|
|
202
|
+
auth: {
|
|
203
|
+
signOut: signOutMock,
|
|
204
|
+
},
|
|
205
|
+
} as any);
|
|
206
|
+
|
|
207
|
+
const { result } = renderHook(() => useSignOut(), {
|
|
208
|
+
wrapper: createWrapper(client),
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
await act(async () => {
|
|
212
|
+
await result.current.mutateAsync();
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
expect(signOutMock).toHaveBeenCalled();
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe('useUpdateUser', () => {
|
|
220
|
+
it('should call updateUser and update cache', async () => {
|
|
221
|
+
const updatedUser = { id: '1', email: 'new@example.com' };
|
|
222
|
+
const updateUserMock = vi.fn().mockResolvedValue(updatedUser);
|
|
223
|
+
const client = createMockClient({
|
|
224
|
+
auth: {
|
|
225
|
+
updateUser: updateUserMock,
|
|
226
|
+
},
|
|
227
|
+
} as any);
|
|
228
|
+
|
|
229
|
+
const queryClient = createTestQueryClient();
|
|
230
|
+
const { result } = renderHook(() => useUpdateUser(), {
|
|
231
|
+
wrapper: createWrapper(client, queryClient),
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
await act(async () => {
|
|
235
|
+
await result.current.mutateAsync({ email: 'new@example.com' });
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
expect(updateUserMock).toHaveBeenCalledWith({ email: 'new@example.com' });
|
|
239
|
+
expect(queryClient.getQueryData(['fluxbase', 'auth', 'user'])).toEqual(updatedUser);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
describe('useAuth', () => {
|
|
244
|
+
it('should return combined auth state', async () => {
|
|
245
|
+
const mockUser = { id: '1', email: 'test@example.com' };
|
|
246
|
+
const mockSession = { access_token: 'token' };
|
|
247
|
+
const client = createMockClient({
|
|
248
|
+
auth: {
|
|
249
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: mockSession }, error: null }),
|
|
250
|
+
getCurrentUser: vi.fn().mockResolvedValue({ data: { user: mockUser }, error: null }),
|
|
251
|
+
},
|
|
252
|
+
} as any);
|
|
253
|
+
|
|
254
|
+
const { result } = renderHook(() => useAuth(), {
|
|
255
|
+
wrapper: createWrapper(client),
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
259
|
+
|
|
260
|
+
expect(result.current.user).toEqual(mockUser);
|
|
261
|
+
expect(result.current.session).toEqual(mockSession);
|
|
262
|
+
expect(result.current.isAuthenticated).toBe(true);
|
|
263
|
+
expect(result.current.signIn).toBeDefined();
|
|
264
|
+
expect(result.current.signUp).toBeDefined();
|
|
265
|
+
expect(result.current.signOut).toBeDefined();
|
|
266
|
+
expect(result.current.updateUser).toBeDefined();
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('should show loading state initially', () => {
|
|
270
|
+
const client = createMockClient({
|
|
271
|
+
auth: {
|
|
272
|
+
getSession: vi.fn().mockImplementation(() => new Promise(() => {})), // Never resolves
|
|
273
|
+
},
|
|
274
|
+
} as any);
|
|
275
|
+
|
|
276
|
+
const { result } = renderHook(() => useAuth(), {
|
|
277
|
+
wrapper: createWrapper(client),
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
expect(result.current.isLoading).toBe(true);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('should show unauthenticated state when no session', async () => {
|
|
284
|
+
const client = createMockClient({
|
|
285
|
+
auth: {
|
|
286
|
+
getSession: vi.fn().mockResolvedValue({ data: { session: null }, error: null }),
|
|
287
|
+
},
|
|
288
|
+
} as any);
|
|
289
|
+
|
|
290
|
+
const { result } = renderHook(() => useAuth(), {
|
|
291
|
+
wrapper: createWrapper(client),
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
295
|
+
|
|
296
|
+
expect(result.current.user).toBeNull();
|
|
297
|
+
expect(result.current.session).toBeNull();
|
|
298
|
+
expect(result.current.isAuthenticated).toBe(false);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('should have pending states for mutations', () => {
|
|
302
|
+
const client = createMockClient();
|
|
303
|
+
|
|
304
|
+
const { result } = renderHook(() => useAuth(), {
|
|
305
|
+
wrapper: createWrapper(client),
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
expect(result.current.isSigningIn).toBe(false);
|
|
309
|
+
expect(result.current.isSigningUp).toBe(false);
|
|
310
|
+
expect(result.current.isSigningOut).toBe(false);
|
|
311
|
+
expect(result.current.isUpdating).toBe(false);
|
|
312
|
+
});
|
|
313
|
+
});
|
package/src/use-auth.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication hooks for Fluxbase SDK
|
|
3
|
+
*/
|
|
4
|
+
|
|
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";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Hook to get the current user
|
|
16
|
+
*/
|
|
17
|
+
export function useUser() {
|
|
18
|
+
const client = useFluxbaseClient();
|
|
19
|
+
|
|
20
|
+
return useQuery({
|
|
21
|
+
queryKey: ["fluxbase", "auth", "user"],
|
|
22
|
+
queryFn: async () => {
|
|
23
|
+
const { data } = await client.auth.getSession();
|
|
24
|
+
if (!data?.session) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const result = await client.auth.getCurrentUser();
|
|
30
|
+
return result.data?.user ?? null;
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Hook to get the current session
|
|
41
|
+
*/
|
|
42
|
+
export function useSession() {
|
|
43
|
+
const client = useFluxbaseClient();
|
|
44
|
+
|
|
45
|
+
return useQuery<AuthSession | null>({
|
|
46
|
+
queryKey: ["fluxbase", "auth", "session"],
|
|
47
|
+
queryFn: async () => {
|
|
48
|
+
const { data } = await client.auth.getSession();
|
|
49
|
+
return data?.session ?? null;
|
|
50
|
+
},
|
|
51
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Hook for signing in
|
|
57
|
+
*/
|
|
58
|
+
export function useSignIn() {
|
|
59
|
+
const client = useFluxbaseClient();
|
|
60
|
+
const queryClient = useQueryClient();
|
|
61
|
+
|
|
62
|
+
return useMutation({
|
|
63
|
+
mutationFn: async (credentials: SignInCredentials) => {
|
|
64
|
+
return await client.auth.signIn(credentials);
|
|
65
|
+
},
|
|
66
|
+
onSuccess: (session) => {
|
|
67
|
+
queryClient.setQueryData(["fluxbase", "auth", "session"], session);
|
|
68
|
+
// Only set user if this is a complete auth session (not 2FA required)
|
|
69
|
+
// Check for truthy user value, not just property existence
|
|
70
|
+
if (session && "user" in session && session.user) {
|
|
71
|
+
queryClient.setQueryData(["fluxbase", "auth", "user"], session.user);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Hook for signing up
|
|
79
|
+
*/
|
|
80
|
+
export function useSignUp() {
|
|
81
|
+
const client = useFluxbaseClient();
|
|
82
|
+
const queryClient = useQueryClient();
|
|
83
|
+
|
|
84
|
+
return useMutation({
|
|
85
|
+
mutationFn: async (credentials: SignUpCredentials) => {
|
|
86
|
+
return await client.auth.signUp(credentials);
|
|
87
|
+
},
|
|
88
|
+
onSuccess: (response) => {
|
|
89
|
+
if (response.data) {
|
|
90
|
+
queryClient.setQueryData(
|
|
91
|
+
["fluxbase", "auth", "session"],
|
|
92
|
+
response.data.session,
|
|
93
|
+
);
|
|
94
|
+
queryClient.setQueryData(
|
|
95
|
+
["fluxbase", "auth", "user"],
|
|
96
|
+
response.data.user,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Hook for signing out
|
|
105
|
+
*/
|
|
106
|
+
export function useSignOut() {
|
|
107
|
+
const client = useFluxbaseClient();
|
|
108
|
+
const queryClient = useQueryClient();
|
|
109
|
+
|
|
110
|
+
return useMutation({
|
|
111
|
+
mutationFn: async () => {
|
|
112
|
+
await client.auth.signOut();
|
|
113
|
+
},
|
|
114
|
+
onSuccess: () => {
|
|
115
|
+
queryClient.setQueryData(["fluxbase", "auth", "session"], null);
|
|
116
|
+
queryClient.setQueryData(["fluxbase", "auth", "user"], null);
|
|
117
|
+
queryClient.invalidateQueries({ queryKey: ["fluxbase"] });
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Hook for updating the current user
|
|
124
|
+
*/
|
|
125
|
+
export function useUpdateUser() {
|
|
126
|
+
const client = useFluxbaseClient();
|
|
127
|
+
const queryClient = useQueryClient();
|
|
128
|
+
|
|
129
|
+
return useMutation({
|
|
130
|
+
mutationFn: async (data: Partial<Pick<User, "email" | "metadata">>) => {
|
|
131
|
+
return await client.auth.updateUser(data);
|
|
132
|
+
},
|
|
133
|
+
onSuccess: (user) => {
|
|
134
|
+
queryClient.setQueryData(["fluxbase", "auth", "user"], user);
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Combined auth hook with all auth state and methods
|
|
141
|
+
*/
|
|
142
|
+
export function useAuth() {
|
|
143
|
+
const { data: user, isLoading: isLoadingUser } = useUser();
|
|
144
|
+
const { data: session, isLoading: isLoadingSession } = useSession();
|
|
145
|
+
const signIn = useSignIn();
|
|
146
|
+
const signUp = useSignUp();
|
|
147
|
+
const signOut = useSignOut();
|
|
148
|
+
const updateUser = useUpdateUser();
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
user,
|
|
152
|
+
session,
|
|
153
|
+
isLoading: isLoadingUser || isLoadingSession,
|
|
154
|
+
isAuthenticated: !!session,
|
|
155
|
+
signIn: signIn.mutateAsync,
|
|
156
|
+
signUp: signUp.mutateAsync,
|
|
157
|
+
signOut: signOut.mutateAsync,
|
|
158
|
+
updateUser: updateUser.mutateAsync,
|
|
159
|
+
isSigningIn: signIn.isPending,
|
|
160
|
+
isSigningUp: signUp.isPending,
|
|
161
|
+
isSigningOut: signOut.isPending,
|
|
162
|
+
isUpdating: updateUser.isPending,
|
|
163
|
+
};
|
|
164
|
+
}
|