@fluxbase/sdk-react 0.0.1-rc.2
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/CHANGELOG.md +67 -0
- package/README-ADMIN.md +1076 -0
- package/README.md +178 -0
- package/dist/index.d.mts +606 -0
- package/dist/index.d.ts +606 -0
- package/dist/index.js +992 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +926 -0
- package/dist/index.mjs.map +1 -0
- package/examples/AdminDashboard.tsx +513 -0
- package/examples/README.md +163 -0
- package/package.json +52 -0
- package/src/context.tsx +33 -0
- package/src/index.ts +113 -0
- package/src/use-admin-auth.ts +168 -0
- package/src/use-admin-hooks.ts +309 -0
- package/src/use-api-keys.ts +174 -0
- package/src/use-auth.ts +146 -0
- package/src/use-query.ts +165 -0
- package/src/use-realtime.ts +161 -0
- package/src/use-rpc.ts +109 -0
- package/src/use-storage.ts +257 -0
- package/src/use-users.ts +191 -0
- package/tsconfig.json +24 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsup.config.ts +11 -0
- package/typedoc.json +35 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Settings and Management Hooks
|
|
3
|
+
*
|
|
4
|
+
* Hooks for managing application settings, system settings, and webhooks.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useState, useEffect, useCallback } from 'react'
|
|
8
|
+
import { useFluxbaseClient } from './context'
|
|
9
|
+
import type {
|
|
10
|
+
AppSettings,
|
|
11
|
+
UpdateAppSettingsRequest,
|
|
12
|
+
SystemSetting,
|
|
13
|
+
UpdateSystemSettingRequest,
|
|
14
|
+
Webhook,
|
|
15
|
+
CreateWebhookRequest,
|
|
16
|
+
UpdateWebhookRequest
|
|
17
|
+
} from '@fluxbase/sdk'
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// useAppSettings Hook
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
export interface UseAppSettingsOptions {
|
|
24
|
+
autoFetch?: boolean
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface UseAppSettingsReturn {
|
|
28
|
+
settings: AppSettings | null
|
|
29
|
+
isLoading: boolean
|
|
30
|
+
error: Error | null
|
|
31
|
+
refetch: () => Promise<void>
|
|
32
|
+
updateSettings: (update: UpdateAppSettingsRequest) => Promise<void>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Hook for managing application settings
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* function SettingsPanel() {
|
|
41
|
+
* const { settings, isLoading, updateSettings } = useAppSettings({ autoFetch: true })
|
|
42
|
+
*
|
|
43
|
+
* const handleToggleFeature = async (feature: string, enabled: boolean) => {
|
|
44
|
+
* await updateSettings({
|
|
45
|
+
* features: { ...settings?.features, [feature]: enabled }
|
|
46
|
+
* })
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* return <div>...</div>
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function useAppSettings(options: UseAppSettingsOptions = {}): UseAppSettingsReturn {
|
|
54
|
+
const { autoFetch = true } = options
|
|
55
|
+
const client = useFluxbaseClient()
|
|
56
|
+
|
|
57
|
+
const [settings, setSettings] = useState<AppSettings | null>(null)
|
|
58
|
+
const [isLoading, setIsLoading] = useState(autoFetch)
|
|
59
|
+
const [error, setError] = useState<Error | null>(null)
|
|
60
|
+
|
|
61
|
+
const fetchSettings = useCallback(async () => {
|
|
62
|
+
try {
|
|
63
|
+
setIsLoading(true)
|
|
64
|
+
setError(null)
|
|
65
|
+
const appSettings = await client.admin.settings.app.get()
|
|
66
|
+
setSettings(appSettings)
|
|
67
|
+
} catch (err) {
|
|
68
|
+
setError(err as Error)
|
|
69
|
+
} finally {
|
|
70
|
+
setIsLoading(false)
|
|
71
|
+
}
|
|
72
|
+
}, [client])
|
|
73
|
+
|
|
74
|
+
const updateSettings = useCallback(
|
|
75
|
+
async (update: UpdateAppSettingsRequest): Promise<void> => {
|
|
76
|
+
await client.admin.settings.app.update(update)
|
|
77
|
+
await fetchSettings()
|
|
78
|
+
},
|
|
79
|
+
[client, fetchSettings]
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (autoFetch) {
|
|
84
|
+
fetchSettings()
|
|
85
|
+
}
|
|
86
|
+
}, [autoFetch, fetchSettings])
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
settings,
|
|
90
|
+
isLoading,
|
|
91
|
+
error,
|
|
92
|
+
refetch: fetchSettings,
|
|
93
|
+
updateSettings
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ============================================================================
|
|
98
|
+
// useSystemSettings Hook
|
|
99
|
+
// ============================================================================
|
|
100
|
+
|
|
101
|
+
export interface UseSystemSettingsOptions {
|
|
102
|
+
autoFetch?: boolean
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface UseSystemSettingsReturn {
|
|
106
|
+
settings: SystemSetting[]
|
|
107
|
+
isLoading: boolean
|
|
108
|
+
error: Error | null
|
|
109
|
+
refetch: () => Promise<void>
|
|
110
|
+
getSetting: (key: string) => SystemSetting | undefined
|
|
111
|
+
updateSetting: (key: string, update: UpdateSystemSettingRequest) => Promise<void>
|
|
112
|
+
deleteSetting: (key: string) => Promise<void>
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Hook for managing system settings (key-value storage)
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```tsx
|
|
120
|
+
* function SystemSettings() {
|
|
121
|
+
* const { settings, isLoading, updateSetting } = useSystemSettings({ autoFetch: true })
|
|
122
|
+
*
|
|
123
|
+
* const handleUpdateSetting = async (key: string, value: any) => {
|
|
124
|
+
* await updateSetting(key, { value })
|
|
125
|
+
* }
|
|
126
|
+
*
|
|
127
|
+
* return <div>...</div>
|
|
128
|
+
* }
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export function useSystemSettings(options: UseSystemSettingsOptions = {}): UseSystemSettingsReturn {
|
|
132
|
+
const { autoFetch = true } = options
|
|
133
|
+
const client = useFluxbaseClient()
|
|
134
|
+
|
|
135
|
+
const [settings, setSettings] = useState<SystemSetting[]>([])
|
|
136
|
+
const [isLoading, setIsLoading] = useState(autoFetch)
|
|
137
|
+
const [error, setError] = useState<Error | null>(null)
|
|
138
|
+
|
|
139
|
+
const fetchSettings = useCallback(async () => {
|
|
140
|
+
try {
|
|
141
|
+
setIsLoading(true)
|
|
142
|
+
setError(null)
|
|
143
|
+
const response = await client.admin.settings.system.list()
|
|
144
|
+
setSettings(response.settings)
|
|
145
|
+
} catch (err) {
|
|
146
|
+
setError(err as Error)
|
|
147
|
+
} finally {
|
|
148
|
+
setIsLoading(false)
|
|
149
|
+
}
|
|
150
|
+
}, [client])
|
|
151
|
+
|
|
152
|
+
const getSetting = useCallback(
|
|
153
|
+
(key: string): SystemSetting | undefined => {
|
|
154
|
+
return settings.find((s) => s.key === key)
|
|
155
|
+
},
|
|
156
|
+
[settings]
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
const updateSetting = useCallback(
|
|
160
|
+
async (key: string, update: UpdateSystemSettingRequest): Promise<void> => {
|
|
161
|
+
await client.admin.settings.system.update(key, update)
|
|
162
|
+
await fetchSettings()
|
|
163
|
+
},
|
|
164
|
+
[client, fetchSettings]
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
const deleteSetting = useCallback(
|
|
168
|
+
async (key: string): Promise<void> => {
|
|
169
|
+
await client.admin.settings.system.delete(key)
|
|
170
|
+
await fetchSettings()
|
|
171
|
+
},
|
|
172
|
+
[client, fetchSettings]
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
if (autoFetch) {
|
|
177
|
+
fetchSettings()
|
|
178
|
+
}
|
|
179
|
+
}, [autoFetch, fetchSettings])
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
settings,
|
|
183
|
+
isLoading,
|
|
184
|
+
error,
|
|
185
|
+
refetch: fetchSettings,
|
|
186
|
+
getSetting,
|
|
187
|
+
updateSetting,
|
|
188
|
+
deleteSetting
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ============================================================================
|
|
193
|
+
// useWebhooks Hook
|
|
194
|
+
// ============================================================================
|
|
195
|
+
|
|
196
|
+
export interface UseWebhooksOptions {
|
|
197
|
+
autoFetch?: boolean
|
|
198
|
+
refetchInterval?: number
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export interface UseWebhooksReturn {
|
|
202
|
+
webhooks: Webhook[]
|
|
203
|
+
isLoading: boolean
|
|
204
|
+
error: Error | null
|
|
205
|
+
refetch: () => Promise<void>
|
|
206
|
+
createWebhook: (webhook: CreateWebhookRequest) => Promise<Webhook>
|
|
207
|
+
updateWebhook: (id: string, update: UpdateWebhookRequest) => Promise<Webhook>
|
|
208
|
+
deleteWebhook: (id: string) => Promise<void>
|
|
209
|
+
testWebhook: (id: string) => Promise<void>
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Hook for managing webhooks
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```tsx
|
|
217
|
+
* function WebhooksManager() {
|
|
218
|
+
* const { webhooks, isLoading, createWebhook, deleteWebhook } = useWebhooks({
|
|
219
|
+
* autoFetch: true
|
|
220
|
+
* })
|
|
221
|
+
*
|
|
222
|
+
* const handleCreate = async () => {
|
|
223
|
+
* await createWebhook({
|
|
224
|
+
* url: 'https://example.com/webhook',
|
|
225
|
+
* events: ['user.created', 'user.updated'],
|
|
226
|
+
* enabled: true
|
|
227
|
+
* })
|
|
228
|
+
* }
|
|
229
|
+
*
|
|
230
|
+
* return <div>...</div>
|
|
231
|
+
* }
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
export function useWebhooks(options: UseWebhooksOptions = {}): UseWebhooksReturn {
|
|
235
|
+
const { autoFetch = true, refetchInterval = 0 } = options
|
|
236
|
+
const client = useFluxbaseClient()
|
|
237
|
+
|
|
238
|
+
const [webhooks, setWebhooks] = useState<Webhook[]>([])
|
|
239
|
+
const [isLoading, setIsLoading] = useState(autoFetch)
|
|
240
|
+
const [error, setError] = useState<Error | null>(null)
|
|
241
|
+
|
|
242
|
+
const fetchWebhooks = useCallback(async () => {
|
|
243
|
+
try {
|
|
244
|
+
setIsLoading(true)
|
|
245
|
+
setError(null)
|
|
246
|
+
const response = await client.admin.management.webhooks.list()
|
|
247
|
+
setWebhooks(response.webhooks)
|
|
248
|
+
} catch (err) {
|
|
249
|
+
setError(err as Error)
|
|
250
|
+
} finally {
|
|
251
|
+
setIsLoading(false)
|
|
252
|
+
}
|
|
253
|
+
}, [client])
|
|
254
|
+
|
|
255
|
+
const createWebhook = useCallback(
|
|
256
|
+
async (webhook: CreateWebhookRequest): Promise<Webhook> => {
|
|
257
|
+
const created = await client.admin.management.webhooks.create(webhook)
|
|
258
|
+
await fetchWebhooks()
|
|
259
|
+
return created
|
|
260
|
+
},
|
|
261
|
+
[client, fetchWebhooks]
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
const updateWebhook = useCallback(
|
|
265
|
+
async (id: string, update: UpdateWebhookRequest): Promise<Webhook> => {
|
|
266
|
+
const updated = await client.admin.management.webhooks.update(id, update)
|
|
267
|
+
await fetchWebhooks()
|
|
268
|
+
return updated
|
|
269
|
+
},
|
|
270
|
+
[client, fetchWebhooks]
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
const deleteWebhook = useCallback(
|
|
274
|
+
async (id: string): Promise<void> => {
|
|
275
|
+
await client.admin.management.webhooks.delete(id)
|
|
276
|
+
await fetchWebhooks()
|
|
277
|
+
},
|
|
278
|
+
[client, fetchWebhooks]
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
const testWebhook = useCallback(
|
|
282
|
+
async (id: string): Promise<void> => {
|
|
283
|
+
await client.admin.management.webhooks.test(id)
|
|
284
|
+
},
|
|
285
|
+
[client]
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
useEffect(() => {
|
|
289
|
+
if (autoFetch) {
|
|
290
|
+
fetchWebhooks()
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (refetchInterval > 0) {
|
|
294
|
+
const interval = setInterval(fetchWebhooks, refetchInterval)
|
|
295
|
+
return () => clearInterval(interval)
|
|
296
|
+
}
|
|
297
|
+
}, [autoFetch, refetchInterval, fetchWebhooks])
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
webhooks,
|
|
301
|
+
isLoading,
|
|
302
|
+
error,
|
|
303
|
+
refetch: fetchWebhooks,
|
|
304
|
+
createWebhook,
|
|
305
|
+
updateWebhook,
|
|
306
|
+
deleteWebhook,
|
|
307
|
+
testWebhook
|
|
308
|
+
}
|
|
309
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react'
|
|
2
|
+
import { useFluxbaseClient } from './context'
|
|
3
|
+
import type { APIKey, CreateAPIKeyRequest } from '@fluxbase/sdk'
|
|
4
|
+
|
|
5
|
+
export interface UseAPIKeysOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Whether to automatically fetch API keys on mount
|
|
8
|
+
* @default true
|
|
9
|
+
*/
|
|
10
|
+
autoFetch?: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface UseAPIKeysReturn {
|
|
14
|
+
/**
|
|
15
|
+
* Array of API keys
|
|
16
|
+
*/
|
|
17
|
+
keys: APIKey[]
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Whether keys are being fetched
|
|
21
|
+
*/
|
|
22
|
+
isLoading: boolean
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Any error that occurred
|
|
26
|
+
*/
|
|
27
|
+
error: Error | null
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Refetch API keys
|
|
31
|
+
*/
|
|
32
|
+
refetch: () => Promise<void>
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create a new API key
|
|
36
|
+
*/
|
|
37
|
+
createKey: (request: CreateAPIKeyRequest) => Promise<{ key: string; keyData: APIKey }>
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Update an API key
|
|
41
|
+
*/
|
|
42
|
+
updateKey: (keyId: string, update: { name?: string; description?: string }) => Promise<void>
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Revoke an API key
|
|
46
|
+
*/
|
|
47
|
+
revokeKey: (keyId: string) => Promise<void>
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Delete an API key
|
|
51
|
+
*/
|
|
52
|
+
deleteKey: (keyId: string) => Promise<void>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Hook for managing API keys
|
|
57
|
+
*
|
|
58
|
+
* Provides API key list and management functions.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```tsx
|
|
62
|
+
* function APIKeyManager() {
|
|
63
|
+
* const { keys, isLoading, createKey, revokeKey } = useAPIKeys()
|
|
64
|
+
*
|
|
65
|
+
* const handleCreate = async () => {
|
|
66
|
+
* const { key, keyData } = await createKey({
|
|
67
|
+
* name: 'Backend Service',
|
|
68
|
+
* description: 'API key for backend',
|
|
69
|
+
* expires_at: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString()
|
|
70
|
+
* })
|
|
71
|
+
* alert(`Key created: ${key}`)
|
|
72
|
+
* }
|
|
73
|
+
*
|
|
74
|
+
* return (
|
|
75
|
+
* <div>
|
|
76
|
+
* <button onClick={handleCreate}>Create Key</button>
|
|
77
|
+
* {keys.map(k => (
|
|
78
|
+
* <div key={k.id}>
|
|
79
|
+
* {k.name}
|
|
80
|
+
* <button onClick={() => revokeKey(k.id)}>Revoke</button>
|
|
81
|
+
* </div>
|
|
82
|
+
* ))}
|
|
83
|
+
* </div>
|
|
84
|
+
* )
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export function useAPIKeys(options: UseAPIKeysOptions = {}): UseAPIKeysReturn {
|
|
89
|
+
const { autoFetch = true } = options
|
|
90
|
+
const client = useFluxbaseClient()
|
|
91
|
+
|
|
92
|
+
const [keys, setKeys] = useState<APIKey[]>([])
|
|
93
|
+
const [isLoading, setIsLoading] = useState(autoFetch)
|
|
94
|
+
const [error, setError] = useState<Error | null>(null)
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Fetch API keys from API
|
|
98
|
+
*/
|
|
99
|
+
const fetchKeys = useCallback(async () => {
|
|
100
|
+
try {
|
|
101
|
+
setIsLoading(true)
|
|
102
|
+
setError(null)
|
|
103
|
+
const response = await client.admin.management.apiKeys.list()
|
|
104
|
+
setKeys(response.api_keys)
|
|
105
|
+
} catch (err) {
|
|
106
|
+
setError(err as Error)
|
|
107
|
+
} finally {
|
|
108
|
+
setIsLoading(false)
|
|
109
|
+
}
|
|
110
|
+
}, [client])
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Create a new API key
|
|
114
|
+
*/
|
|
115
|
+
const createKey = useCallback(
|
|
116
|
+
async (request: CreateAPIKeyRequest): Promise<{ key: string; keyData: APIKey }> => {
|
|
117
|
+
const response = await client.admin.management.apiKeys.create(request)
|
|
118
|
+
await fetchKeys() // Refresh list
|
|
119
|
+
return { key: response.key, keyData: response.api_key }
|
|
120
|
+
},
|
|
121
|
+
[client, fetchKeys]
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Update an API key
|
|
126
|
+
*/
|
|
127
|
+
const updateKey = useCallback(
|
|
128
|
+
async (keyId: string, update: { name?: string; description?: string }): Promise<void> => {
|
|
129
|
+
await client.admin.management.apiKeys.update(keyId, update)
|
|
130
|
+
await fetchKeys() // Refresh list
|
|
131
|
+
},
|
|
132
|
+
[client, fetchKeys]
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Revoke an API key
|
|
137
|
+
*/
|
|
138
|
+
const revokeKey = useCallback(
|
|
139
|
+
async (keyId: string): Promise<void> => {
|
|
140
|
+
await client.admin.management.apiKeys.revoke(keyId)
|
|
141
|
+
await fetchKeys() // Refresh list
|
|
142
|
+
},
|
|
143
|
+
[client, fetchKeys]
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Delete an API key
|
|
148
|
+
*/
|
|
149
|
+
const deleteKey = useCallback(
|
|
150
|
+
async (keyId: string): Promise<void> => {
|
|
151
|
+
await client.admin.management.apiKeys.delete(keyId)
|
|
152
|
+
await fetchKeys() // Refresh list
|
|
153
|
+
},
|
|
154
|
+
[client, fetchKeys]
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
// Auto-fetch on mount
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
if (autoFetch) {
|
|
160
|
+
fetchKeys()
|
|
161
|
+
}
|
|
162
|
+
}, [autoFetch, fetchKeys])
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
keys,
|
|
166
|
+
isLoading,
|
|
167
|
+
error,
|
|
168
|
+
refetch: fetchKeys,
|
|
169
|
+
createKey,
|
|
170
|
+
updateKey,
|
|
171
|
+
revokeKey,
|
|
172
|
+
deleteKey
|
|
173
|
+
}
|
|
174
|
+
}
|
package/src/use-auth.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
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 { SignInCredentials, SignUpCredentials, User, AuthSession } from '@fluxbase/sdk'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Hook to get the current user
|
|
11
|
+
*/
|
|
12
|
+
export function useUser() {
|
|
13
|
+
const client = useFluxbaseClient()
|
|
14
|
+
|
|
15
|
+
return useQuery({
|
|
16
|
+
queryKey: ['fluxbase', 'auth', 'user'],
|
|
17
|
+
queryFn: async () => {
|
|
18
|
+
const session = client.auth.getSession()
|
|
19
|
+
if (!session) {
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
return await client.auth.getCurrentUser()
|
|
25
|
+
} catch {
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Hook to get the current session
|
|
35
|
+
*/
|
|
36
|
+
export function useSession() {
|
|
37
|
+
const client = useFluxbaseClient()
|
|
38
|
+
|
|
39
|
+
return useQuery<AuthSession | null>({
|
|
40
|
+
queryKey: ['fluxbase', 'auth', 'session'],
|
|
41
|
+
queryFn: () => client.auth.getSession(),
|
|
42
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Hook for signing in
|
|
48
|
+
*/
|
|
49
|
+
export function useSignIn() {
|
|
50
|
+
const client = useFluxbaseClient()
|
|
51
|
+
const queryClient = useQueryClient()
|
|
52
|
+
|
|
53
|
+
return useMutation({
|
|
54
|
+
mutationFn: async (credentials: SignInCredentials) => {
|
|
55
|
+
return await client.auth.signIn(credentials)
|
|
56
|
+
},
|
|
57
|
+
onSuccess: (session) => {
|
|
58
|
+
queryClient.setQueryData(['fluxbase', 'auth', 'session'], session)
|
|
59
|
+
// 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)
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Hook for signing up
|
|
69
|
+
*/
|
|
70
|
+
export function useSignUp() {
|
|
71
|
+
const client = useFluxbaseClient()
|
|
72
|
+
const queryClient = useQueryClient()
|
|
73
|
+
|
|
74
|
+
return useMutation({
|
|
75
|
+
mutationFn: async (credentials: SignUpCredentials) => {
|
|
76
|
+
return await client.auth.signUp(credentials)
|
|
77
|
+
},
|
|
78
|
+
onSuccess: (session) => {
|
|
79
|
+
queryClient.setQueryData(['fluxbase', 'auth', 'session'], session)
|
|
80
|
+
queryClient.setQueryData(['fluxbase', 'auth', 'user'], session.user)
|
|
81
|
+
},
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Hook for signing out
|
|
87
|
+
*/
|
|
88
|
+
export function useSignOut() {
|
|
89
|
+
const client = useFluxbaseClient()
|
|
90
|
+
const queryClient = useQueryClient()
|
|
91
|
+
|
|
92
|
+
return useMutation({
|
|
93
|
+
mutationFn: async () => {
|
|
94
|
+
await client.auth.signOut()
|
|
95
|
+
},
|
|
96
|
+
onSuccess: () => {
|
|
97
|
+
queryClient.setQueryData(['fluxbase', 'auth', 'session'], null)
|
|
98
|
+
queryClient.setQueryData(['fluxbase', 'auth', 'user'], null)
|
|
99
|
+
queryClient.invalidateQueries({ queryKey: ['fluxbase'] })
|
|
100
|
+
},
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Hook for updating the current user
|
|
106
|
+
*/
|
|
107
|
+
export function useUpdateUser() {
|
|
108
|
+
const client = useFluxbaseClient()
|
|
109
|
+
const queryClient = useQueryClient()
|
|
110
|
+
|
|
111
|
+
return useMutation({
|
|
112
|
+
mutationFn: async (data: Partial<Pick<User, 'email' | 'metadata'>>) => {
|
|
113
|
+
return await client.auth.updateUser(data)
|
|
114
|
+
},
|
|
115
|
+
onSuccess: (user) => {
|
|
116
|
+
queryClient.setQueryData(['fluxbase', 'auth', 'user'], user)
|
|
117
|
+
},
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Combined auth hook with all auth state and methods
|
|
123
|
+
*/
|
|
124
|
+
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()
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
user,
|
|
134
|
+
session,
|
|
135
|
+
isLoading: isLoadingUser || isLoadingSession,
|
|
136
|
+
isAuthenticated: !!session,
|
|
137
|
+
signIn: signIn.mutateAsync,
|
|
138
|
+
signUp: signUp.mutateAsync,
|
|
139
|
+
signOut: signOut.mutateAsync,
|
|
140
|
+
updateUser: updateUser.mutateAsync,
|
|
141
|
+
isSigningIn: signIn.isPending,
|
|
142
|
+
isSigningUp: signUp.isPending,
|
|
143
|
+
isSigningOut: signOut.isPending,
|
|
144
|
+
isUpdating: updateUser.isPending,
|
|
145
|
+
}
|
|
146
|
+
}
|