@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.
@@ -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
+ }
@@ -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
+ }