@fluxbase/sdk-react 0.0.1-rc.6 → 0.0.1-rc.61
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 +1 -1
- package/README.md +27 -14
- package/dist/index.d.mts +45 -65
- package/dist/index.d.ts +45 -65
- package/dist/index.js +138 -135
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +111 -101
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +0 -7
- package/src/use-admin-auth.ts +62 -51
- package/src/use-auth.ts +66 -49
- package/src/use-realtime.ts +58 -44
- package/src/use-storage.ts +211 -82
- package/src/use-users.ts +11 -4
- package/typedoc.json +2 -4
- package/src/use-rpc.ts +0 -109
package/src/use-storage.ts
CHANGED
|
@@ -2,256 +2,385 @@
|
|
|
2
2
|
* Storage hooks for Fluxbase SDK
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
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 &
|
|
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: [
|
|
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
|
|
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
|
|
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({
|
|
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(
|
|
67
|
-
|
|
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: [
|
|
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({
|
|
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(
|
|
127
|
-
|
|
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: [
|
|
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
|
|
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
|
|
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({
|
|
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
|
|
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({
|
|
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: [
|
|
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({
|
|
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({
|
|
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
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
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/
|
|
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
|
-
}
|