@fluxbase/sdk-react 0.0.1-rc.6 → 0.0.1-rc.60

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.
@@ -2,256 +2,385 @@
2
2
  * Storage hooks for Fluxbase SDK
3
3
  */
4
4
 
5
- import { useMutation, useQuery, useQueryClient, type UseQueryOptions } from '@tanstack/react-query'
6
- import { useFluxbaseClient } from './context'
7
- import type { ListOptions, UploadOptions } from '@fluxbase/sdk'
5
+ import { useState } from "react";
6
+ import {
7
+ useMutation,
8
+ useQuery,
9
+ useQueryClient,
10
+ type UseQueryOptions,
11
+ } from "@tanstack/react-query";
12
+ import { useFluxbaseClient } from "./context";
13
+ import type { ListOptions, UploadOptions, UploadProgress } from "@fluxbase/sdk";
8
14
 
9
15
  /**
10
16
  * Hook to list files in a bucket
11
17
  */
12
18
  export function useStorageList(
13
19
  bucket: string,
14
- options?: ListOptions & Omit<UseQueryOptions<any[], Error>, 'queryKey' | 'queryFn'>
20
+ options?: ListOptions &
21
+ Omit<UseQueryOptions<any[], Error>, "queryKey" | "queryFn">,
15
22
  ) {
16
- const client = useFluxbaseClient()
17
- const { prefix, limit, offset, ...queryOptions } = options || {}
23
+ const client = useFluxbaseClient();
24
+ const { prefix, limit, offset, ...queryOptions } = options || {};
18
25
 
19
26
  return useQuery({
20
- queryKey: ['fluxbase', 'storage', bucket, 'list', { prefix, limit, offset }],
27
+ queryKey: [
28
+ "fluxbase",
29
+ "storage",
30
+ bucket,
31
+ "list",
32
+ { prefix, limit, offset },
33
+ ],
21
34
  queryFn: async () => {
22
- const { data, error } = await client.storage.from(bucket).list({ prefix, limit, offset })
35
+ const { data, error } = await client.storage
36
+ .from(bucket)
37
+ .list({ prefix, limit, offset });
23
38
 
24
39
  if (error) {
25
- throw error
40
+ throw error;
26
41
  }
27
42
 
28
- return data || []
43
+ return data || [];
29
44
  },
30
45
  ...queryOptions,
31
- })
46
+ });
32
47
  }
33
48
 
34
49
  /**
35
50
  * Hook to upload a file to a bucket
51
+ *
52
+ * Note: You can track upload progress by passing an `onUploadProgress` callback in the options:
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * const upload = useStorageUpload('avatars')
57
+ *
58
+ * upload.mutate({
59
+ * path: 'user.jpg',
60
+ * file: file,
61
+ * options: {
62
+ * onUploadProgress: (progress) => {
63
+ * console.log(`${progress.percentage}% uploaded`)
64
+ * }
65
+ * }
66
+ * })
67
+ * ```
68
+ *
69
+ * For automatic progress state management, use `useStorageUploadWithProgress` instead.
36
70
  */
37
71
  export function useStorageUpload(bucket: string) {
38
- const client = useFluxbaseClient()
39
- const queryClient = useQueryClient()
72
+ const client = useFluxbaseClient();
73
+ const queryClient = useQueryClient();
40
74
 
41
75
  return useMutation({
42
76
  mutationFn: async (params: {
43
- path: string
44
- file: File | Blob | ArrayBuffer
45
- options?: UploadOptions
77
+ path: string;
78
+ file: File | Blob | ArrayBuffer;
79
+ options?: UploadOptions;
46
80
  }) => {
47
- const { path, file, options } = params
48
- const { data, error } = await client.storage.from(bucket).upload(path, file, options)
81
+ const { path, file, options } = params;
82
+ const { data, error } = await client.storage
83
+ .from(bucket)
84
+ .upload(path, file, options);
49
85
 
50
86
  if (error) {
51
- throw error
87
+ throw error;
52
88
  }
53
89
 
54
- return data
90
+ return data;
55
91
  },
56
92
  onSuccess: () => {
57
93
  // Invalidate list queries for this bucket
58
- queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', bucket, 'list'] })
94
+ queryClient.invalidateQueries({
95
+ queryKey: ["fluxbase", "storage", bucket, "list"],
96
+ });
59
97
  },
60
- })
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Hook to upload a file to a bucket with built-in progress tracking
103
+ *
104
+ * @example
105
+ * ```tsx
106
+ * const { upload, progress, reset } = useStorageUploadWithProgress('avatars')
107
+ *
108
+ * // Upload with automatic progress tracking
109
+ * upload.mutate({
110
+ * path: 'user.jpg',
111
+ * file: file
112
+ * })
113
+ *
114
+ * // Display progress
115
+ * console.log(progress) // { loaded: 1024, total: 2048, percentage: 50 }
116
+ * ```
117
+ */
118
+ export function useStorageUploadWithProgress(bucket: string) {
119
+ const client = useFluxbaseClient();
120
+ const queryClient = useQueryClient();
121
+ const [progress, setProgress] = useState<UploadProgress | null>(null);
122
+
123
+ const mutation = useMutation({
124
+ mutationFn: async (params: {
125
+ path: string;
126
+ file: File | Blob | ArrayBuffer;
127
+ options?: Omit<UploadOptions, "onUploadProgress">;
128
+ }) => {
129
+ const { path, file, options } = params;
130
+
131
+ // Reset progress at the start of upload
132
+ setProgress({ loaded: 0, total: 0, percentage: 0 });
133
+
134
+ const { data, error } = await client.storage
135
+ .from(bucket)
136
+ .upload(path, file, {
137
+ ...options,
138
+ onUploadProgress: (p: import("@fluxbase/sdk").UploadProgress) => {
139
+ setProgress(p);
140
+ },
141
+ });
142
+
143
+ if (error) {
144
+ throw error;
145
+ }
146
+
147
+ return data;
148
+ },
149
+ onSuccess: () => {
150
+ // Invalidate list queries for this bucket
151
+ queryClient.invalidateQueries({
152
+ queryKey: ["fluxbase", "storage", bucket, "list"],
153
+ });
154
+ },
155
+ onError: () => {
156
+ // Reset progress on error
157
+ setProgress(null);
158
+ },
159
+ });
160
+
161
+ return {
162
+ upload: mutation,
163
+ progress,
164
+ reset: () => setProgress(null),
165
+ };
61
166
  }
62
167
 
63
168
  /**
64
169
  * Hook to download a file from a bucket
65
170
  */
66
- export function useStorageDownload(bucket: string, path: string | null, enabled = true) {
67
- const client = useFluxbaseClient()
171
+ export function useStorageDownload(
172
+ bucket: string,
173
+ path: string | null,
174
+ enabled = true,
175
+ ) {
176
+ const client = useFluxbaseClient();
68
177
 
69
178
  return useQuery({
70
- queryKey: ['fluxbase', 'storage', bucket, 'download', path],
179
+ queryKey: ["fluxbase", "storage", bucket, "download", path],
71
180
  queryFn: async () => {
72
181
  if (!path) {
73
- return null
182
+ return null;
74
183
  }
75
184
 
76
- const { data, error } = await client.storage.from(bucket).download(path)
185
+ const { data, error } = await client.storage.from(bucket).download(path);
77
186
 
78
187
  if (error) {
79
- throw error
188
+ throw error;
80
189
  }
81
190
 
82
- return data
191
+ return data;
83
192
  },
84
193
  enabled: enabled && !!path,
85
- })
194
+ });
86
195
  }
87
196
 
88
197
  /**
89
198
  * Hook to delete files from a bucket
90
199
  */
91
200
  export function useStorageDelete(bucket: string) {
92
- const client = useFluxbaseClient()
93
- const queryClient = useQueryClient()
201
+ const client = useFluxbaseClient();
202
+ const queryClient = useQueryClient();
94
203
 
95
204
  return useMutation({
96
205
  mutationFn: async (paths: string[]) => {
97
- const { error } = await client.storage.from(bucket).remove(paths)
206
+ const { error } = await client.storage.from(bucket).remove(paths);
98
207
 
99
208
  if (error) {
100
- throw error
209
+ throw error;
101
210
  }
102
211
  },
103
212
  onSuccess: () => {
104
- queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', bucket, 'list'] })
213
+ queryClient.invalidateQueries({
214
+ queryKey: ["fluxbase", "storage", bucket, "list"],
215
+ });
105
216
  },
106
- })
217
+ });
107
218
  }
108
219
 
109
220
  /**
110
221
  * Hook to get a public URL for a file
111
222
  */
112
223
  export function useStoragePublicUrl(bucket: string, path: string | null) {
113
- const client = useFluxbaseClient()
224
+ const client = useFluxbaseClient();
114
225
 
115
226
  if (!path) {
116
- return null
227
+ return null;
117
228
  }
118
229
 
119
- const { data } = client.storage.from(bucket).getPublicUrl(path)
120
- return data.publicUrl
230
+ const { data } = client.storage.from(bucket).getPublicUrl(path);
231
+ return data.publicUrl;
121
232
  }
122
233
 
123
234
  /**
124
235
  * Hook to create a signed URL
125
236
  */
126
- export function useStorageSignedUrl(bucket: string, path: string | null, expiresIn?: number) {
127
- const client = useFluxbaseClient()
237
+ export function useStorageSignedUrl(
238
+ bucket: string,
239
+ path: string | null,
240
+ expiresIn?: number,
241
+ ) {
242
+ const client = useFluxbaseClient();
128
243
 
129
244
  return useQuery({
130
- queryKey: ['fluxbase', 'storage', bucket, 'signed-url', path, expiresIn],
245
+ queryKey: ["fluxbase", "storage", bucket, "signed-url", path, expiresIn],
131
246
  queryFn: async () => {
132
247
  if (!path) {
133
- return null
248
+ return null;
134
249
  }
135
250
 
136
- const { data, error } = await client.storage.from(bucket).createSignedUrl(path, { expiresIn })
251
+ const { data, error } = await client.storage
252
+ .from(bucket)
253
+ .createSignedUrl(path, { expiresIn });
137
254
 
138
255
  if (error) {
139
- throw error
256
+ throw error;
140
257
  }
141
258
 
142
- return data?.signedUrl || null
259
+ return data?.signedUrl || null;
143
260
  },
144
261
  enabled: !!path,
145
262
  staleTime: expiresIn ? expiresIn * 1000 - 60000 : 1000 * 60 * 50, // Refresh 1 minute before expiry
146
- })
263
+ });
147
264
  }
148
265
 
149
266
  /**
150
267
  * Hook to move a file
151
268
  */
152
269
  export function useStorageMove(bucket: string) {
153
- const client = useFluxbaseClient()
154
- const queryClient = useQueryClient()
270
+ const client = useFluxbaseClient();
271
+ const queryClient = useQueryClient();
155
272
 
156
273
  return useMutation({
157
274
  mutationFn: async (params: { fromPath: string; toPath: string }) => {
158
- const { fromPath, toPath } = params
159
- const { data, error } = await client.storage.from(bucket).move(fromPath, toPath)
275
+ const { fromPath, toPath } = params;
276
+ const { data, error } = await client.storage
277
+ .from(bucket)
278
+ .move(fromPath, toPath);
160
279
 
161
280
  if (error) {
162
- throw error
281
+ throw error;
163
282
  }
164
283
 
165
- return data
284
+ return data;
166
285
  },
167
286
  onSuccess: () => {
168
- queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', bucket, 'list'] })
287
+ queryClient.invalidateQueries({
288
+ queryKey: ["fluxbase", "storage", bucket, "list"],
289
+ });
169
290
  },
170
- })
291
+ });
171
292
  }
172
293
 
173
294
  /**
174
295
  * Hook to copy a file
175
296
  */
176
297
  export function useStorageCopy(bucket: string) {
177
- const client = useFluxbaseClient()
178
- const queryClient = useQueryClient()
298
+ const client = useFluxbaseClient();
299
+ const queryClient = useQueryClient();
179
300
 
180
301
  return useMutation({
181
302
  mutationFn: async (params: { fromPath: string; toPath: string }) => {
182
- const { fromPath, toPath } = params
183
- const { data, error } = await client.storage.from(bucket).copy(fromPath, toPath)
303
+ const { fromPath, toPath } = params;
304
+ const { data, error } = await client.storage
305
+ .from(bucket)
306
+ .copy(fromPath, toPath);
184
307
 
185
308
  if (error) {
186
- throw error
309
+ throw error;
187
310
  }
188
311
 
189
- return data
312
+ return data;
190
313
  },
191
314
  onSuccess: () => {
192
- queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', bucket, 'list'] })
315
+ queryClient.invalidateQueries({
316
+ queryKey: ["fluxbase", "storage", bucket, "list"],
317
+ });
193
318
  },
194
- })
319
+ });
195
320
  }
196
321
 
197
322
  /**
198
323
  * Hook to manage buckets
199
324
  */
200
325
  export function useStorageBuckets() {
201
- const client = useFluxbaseClient()
326
+ const client = useFluxbaseClient();
202
327
 
203
328
  return useQuery({
204
- queryKey: ['fluxbase', 'storage', 'buckets'],
329
+ queryKey: ["fluxbase", "storage", "buckets"],
205
330
  queryFn: async () => {
206
- const { data, error } = await client.storage.listBuckets()
331
+ const { data, error } = await client.storage.listBuckets();
207
332
 
208
333
  if (error) {
209
- throw error
334
+ throw error;
210
335
  }
211
336
 
212
- return data || []
337
+ return data || [];
213
338
  },
214
- })
339
+ });
215
340
  }
216
341
 
217
342
  /**
218
343
  * Hook to create a bucket
219
344
  */
220
345
  export function useCreateBucket() {
221
- const client = useFluxbaseClient()
222
- const queryClient = useQueryClient()
346
+ const client = useFluxbaseClient();
347
+ const queryClient = useQueryClient();
223
348
 
224
349
  return useMutation({
225
350
  mutationFn: async (bucketName: string) => {
226
- const { error } = await client.storage.createBucket(bucketName)
351
+ const { error } = await client.storage.createBucket(bucketName);
227
352
 
228
353
  if (error) {
229
- throw error
354
+ throw error;
230
355
  }
231
356
  },
232
357
  onSuccess: () => {
233
- queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', 'buckets'] })
358
+ queryClient.invalidateQueries({
359
+ queryKey: ["fluxbase", "storage", "buckets"],
360
+ });
234
361
  },
235
- })
362
+ });
236
363
  }
237
364
 
238
365
  /**
239
366
  * Hook to delete a bucket
240
367
  */
241
368
  export function useDeleteBucket() {
242
- const client = useFluxbaseClient()
243
- const queryClient = useQueryClient()
369
+ const client = useFluxbaseClient();
370
+ const queryClient = useQueryClient();
244
371
 
245
372
  return useMutation({
246
373
  mutationFn: async (bucketName: string) => {
247
- const { error } = await client.storage.deleteBucket(bucketName)
374
+ const { error } = await client.storage.deleteBucket(bucketName);
248
375
 
249
376
  if (error) {
250
- throw error
377
+ throw error;
251
378
  }
252
379
  },
253
380
  onSuccess: () => {
254
- queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', 'buckets'] })
381
+ queryClient.invalidateQueries({
382
+ queryKey: ["fluxbase", "storage", "buckets"],
383
+ });
255
384
  },
256
- })
385
+ });
257
386
  }
package/src/use-users.ts CHANGED
@@ -109,9 +109,12 @@ export function useUsers(options: UseUsersOptions = {}): UseUsersReturn {
109
109
  try {
110
110
  setIsLoading(true)
111
111
  setError(null)
112
- const response = await client.admin.listUsers(listOptions)
113
- setUsers(response.users)
114
- setTotal(response.total)
112
+ const { data, error: apiError } = await client.admin.listUsers(listOptions)
113
+ if (apiError) {
114
+ throw apiError
115
+ }
116
+ setUsers(data!.users)
117
+ setTotal(data!.total)
115
118
  } catch (err) {
116
119
  setError(err as Error)
117
120
  } finally {
@@ -157,7 +160,11 @@ export function useUsers(options: UseUsersOptions = {}): UseUsersReturn {
157
160
  */
158
161
  const resetPassword = useCallback(
159
162
  async (userId: string): Promise<{ message: string }> => {
160
- return await client.admin.resetUserPassword(userId)
163
+ const { data, error } = await client.admin.resetUserPassword(userId)
164
+ if (error) {
165
+ throw error
166
+ }
167
+ return data!
161
168
  },
162
169
  [client]
163
170
  )
package/typedoc.json CHANGED
@@ -1,8 +1,6 @@
1
1
  {
2
2
  "$schema": "https://typedoc.org/schema.json",
3
- "entryPoints": [
4
- "src/index.ts"
5
- ],
3
+ "entryPoints": ["src/index.ts"],
6
4
  "out": "../docs/static/api/sdk-react",
7
5
  "name": "@fluxbase/sdk-react",
8
6
  "readme": "README.md",
@@ -29,7 +27,7 @@
29
27
  "*"
30
28
  ],
31
29
  "navigationLinks": {
32
- "GitHub": "https://github.com/yourusername/fluxbase",
30
+ "GitHub": "https://github.com/fluxbase-eu/fluxbase",
33
31
  "Documentation": "https://fluxbase.eu"
34
32
  }
35
33
  }
package/src/use-rpc.ts DELETED
@@ -1,109 +0,0 @@
1
- /**
2
- * React hooks for RPC (Remote Procedure Calls)
3
- * Call PostgreSQL functions with React Query integration
4
- */
5
-
6
- import { useQuery, useMutation, useQueryClient, type UseQueryOptions, type UseMutationOptions } from '@tanstack/react-query'
7
- import { useFluxbaseClient } from './context'
8
- import type { PostgrestResponse } from '@fluxbase/sdk'
9
-
10
- /**
11
- * Hook to call a PostgreSQL function and cache the result
12
- *
13
- * @example
14
- * ```tsx
15
- * const { data, isLoading, error } = useRPC(
16
- * 'calculate_total',
17
- * { order_id: 123 },
18
- * { enabled: !!orderId }
19
- * )
20
- * ```
21
- */
22
- export function useRPC<TData = unknown, TParams extends Record<string, unknown> = Record<string, unknown>>(
23
- functionName: string,
24
- params?: TParams,
25
- options?: Omit<UseQueryOptions<TData, Error>, 'queryKey' | 'queryFn'>
26
- ) {
27
- const client = useFluxbaseClient()
28
-
29
- return useQuery<TData, Error>({
30
- queryKey: ['rpc', functionName, params],
31
- queryFn: async () => {
32
- const { data, error } = await client.rpc<TData>(functionName, params)
33
- if (error) {
34
- throw new Error(error.message)
35
- }
36
- return data as TData
37
- },
38
- ...options,
39
- })
40
- }
41
-
42
- /**
43
- * Hook to create a mutation for calling PostgreSQL functions
44
- * Useful for functions that modify data
45
- *
46
- * @example
47
- * ```tsx
48
- * const createOrder = useRPCMutation('create_order')
49
- *
50
- * const handleSubmit = async () => {
51
- * await createOrder.mutateAsync({
52
- * user_id: 123,
53
- * items: [{ product_id: 1, quantity: 2 }]
54
- * })
55
- * }
56
- * ```
57
- */
58
- export function useRPCMutation<TData = unknown, TParams extends Record<string, unknown> = Record<string, unknown>>(
59
- functionName: string,
60
- options?: Omit<UseMutationOptions<TData, Error, TParams>, 'mutationFn'>
61
- ) {
62
- const client = useFluxbaseClient()
63
-
64
- return useMutation<TData, Error, TParams>({
65
- mutationFn: async (params: TParams) => {
66
- const { data, error } = await client.rpc<TData>(functionName, params)
67
- if (error) {
68
- throw new Error(error.message)
69
- }
70
- return data as TData
71
- },
72
- ...options,
73
- })
74
- }
75
-
76
- /**
77
- * Hook to call multiple RPC functions in parallel
78
- *
79
- * @example
80
- * ```tsx
81
- * const { data, isLoading } = useRPCBatch([
82
- * { name: 'get_user_stats', params: { user_id: 123 } },
83
- * { name: 'get_recent_orders', params: { limit: 10 } },
84
- * ])
85
- * ```
86
- */
87
- export function useRPCBatch<TData = unknown>(
88
- calls: Array<{ name: string; params?: Record<string, unknown> }>,
89
- options?: Omit<UseQueryOptions<TData[], Error, TData[], readonly unknown[]>, 'queryKey' | 'queryFn'>
90
- ) {
91
- const client = useFluxbaseClient()
92
-
93
- return useQuery({
94
- queryKey: ['rpc-batch', calls] as const,
95
- queryFn: async () => {
96
- const results = await Promise.all(
97
- calls.map(async ({ name, params }) => {
98
- const { data, error } = await client.rpc<TData>(name, params)
99
- if (error) {
100
- throw new Error(`${name}: ${error.message}`)
101
- }
102
- return data
103
- })
104
- )
105
- return results as TData[]
106
- },
107
- ...options,
108
- })
109
- }