@fluxbase/sdk-react 0.1.0-rc.1 → 2026.1.1-rc.10
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/README-ADMIN.md +8 -8
- package/README.md +27 -14
- package/dist/index.d.mts +713 -83
- package/dist/index.d.ts +713 -83
- package/dist/index.js +574 -175
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +561 -172
- package/dist/index.mjs.map +1 -1
- package/examples/AdminDashboard.tsx +3 -3
- package/examples/README.md +1 -1
- package/package.json +3 -3
- package/src/index.ts +60 -18
- package/src/use-admin-auth.ts +62 -51
- package/src/use-auth-config.ts +101 -0
- package/src/use-auth.ts +66 -49
- package/src/use-captcha.ts +250 -0
- package/src/{use-api-keys.ts → use-client-keys.ts} +43 -32
- package/src/use-graphql.ts +392 -0
- package/src/use-realtime.ts +58 -44
- package/src/use-saml.ts +221 -0
- package/src/use-storage.ts +325 -82
- package/src/use-users.ts +11 -4
- package/tsconfig.tsbuildinfo +1 -1
- package/typedoc.json +2 -4
- package/CHANGELOG.md +0 -67
- package/src/use-rpc.ts +0 -109
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL hooks for Fluxbase React SDK
|
|
3
|
+
*
|
|
4
|
+
* Provides React Query integration for GraphQL queries and mutations.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { useGraphQLQuery, useGraphQLMutation } from '@fluxbase/sdk-react'
|
|
9
|
+
*
|
|
10
|
+
* function UsersList() {
|
|
11
|
+
* const { data, isLoading, error } = useGraphQLQuery<UsersQuery>(
|
|
12
|
+
* 'users-list',
|
|
13
|
+
* `query { users { id email } }`
|
|
14
|
+
* )
|
|
15
|
+
*
|
|
16
|
+
* if (isLoading) return <div>Loading...</div>
|
|
17
|
+
* if (error) return <div>Error: {error.message}</div>
|
|
18
|
+
*
|
|
19
|
+
* return (
|
|
20
|
+
* <ul>
|
|
21
|
+
* {data?.users.map(user => (
|
|
22
|
+
* <li key={user.id}>{user.email}</li>
|
|
23
|
+
* ))}
|
|
24
|
+
* </ul>
|
|
25
|
+
* )
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
31
|
+
import { useFluxbaseClient } from "./context";
|
|
32
|
+
import type {
|
|
33
|
+
GraphQLResponse,
|
|
34
|
+
GraphQLError,
|
|
35
|
+
GraphQLRequestOptions,
|
|
36
|
+
} from "@fluxbase/sdk";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Options for useGraphQLQuery hook
|
|
40
|
+
*/
|
|
41
|
+
export interface UseGraphQLQueryOptions<T> {
|
|
42
|
+
/**
|
|
43
|
+
* Variables to pass to the GraphQL query
|
|
44
|
+
*/
|
|
45
|
+
variables?: Record<string, unknown>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Operation name when the document contains multiple operations
|
|
49
|
+
*/
|
|
50
|
+
operationName?: string;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Additional request options
|
|
54
|
+
*/
|
|
55
|
+
requestOptions?: GraphQLRequestOptions;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Whether the query is enabled
|
|
59
|
+
* @default true
|
|
60
|
+
*/
|
|
61
|
+
enabled?: boolean;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Time in milliseconds after which the query is considered stale
|
|
65
|
+
* @default 0 (considered stale immediately)
|
|
66
|
+
*/
|
|
67
|
+
staleTime?: number;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Time in milliseconds after which inactive query data is garbage collected
|
|
71
|
+
* @default 5 minutes
|
|
72
|
+
*/
|
|
73
|
+
gcTime?: number;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Whether to refetch on window focus
|
|
77
|
+
* @default true
|
|
78
|
+
*/
|
|
79
|
+
refetchOnWindowFocus?: boolean;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Transform function to process the response data
|
|
83
|
+
*/
|
|
84
|
+
select?: (data: T | undefined) => T | undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Options for useGraphQLMutation hook
|
|
89
|
+
*/
|
|
90
|
+
export interface UseGraphQLMutationOptions<T, V> {
|
|
91
|
+
/**
|
|
92
|
+
* Operation name when the document contains multiple operations
|
|
93
|
+
*/
|
|
94
|
+
operationName?: string;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Additional request options
|
|
98
|
+
*/
|
|
99
|
+
requestOptions?: GraphQLRequestOptions;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Callback when mutation succeeds
|
|
103
|
+
*/
|
|
104
|
+
onSuccess?: (data: T, variables: V) => void;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Callback when mutation fails
|
|
108
|
+
*/
|
|
109
|
+
onError?: (error: GraphQLError, variables: V) => void;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Query keys to invalidate on success
|
|
113
|
+
*/
|
|
114
|
+
invalidateQueries?: string[];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Hook to execute GraphQL queries with React Query caching
|
|
119
|
+
*
|
|
120
|
+
* @typeParam T - The expected response data type
|
|
121
|
+
* @param queryKey - Unique key for caching (string or array)
|
|
122
|
+
* @param query - The GraphQL query string
|
|
123
|
+
* @param options - Query options including variables
|
|
124
|
+
* @returns React Query result object
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```tsx
|
|
128
|
+
* interface UsersQuery {
|
|
129
|
+
* users: Array<{ id: string; email: string }>
|
|
130
|
+
* }
|
|
131
|
+
*
|
|
132
|
+
* function UsersList() {
|
|
133
|
+
* const { data, isLoading } = useGraphQLQuery<UsersQuery>(
|
|
134
|
+
* 'users',
|
|
135
|
+
* `query { users { id email } }`
|
|
136
|
+
* )
|
|
137
|
+
*
|
|
138
|
+
* return <div>{data?.users.length} users</div>
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```tsx
|
|
144
|
+
* // With variables
|
|
145
|
+
* const { data } = useGraphQLQuery<UserQuery>(
|
|
146
|
+
* ['user', userId],
|
|
147
|
+
* `query GetUser($id: ID!) { user(id: $id) { id email } }`,
|
|
148
|
+
* { variables: { id: userId } }
|
|
149
|
+
* )
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export function useGraphQLQuery<T = unknown>(
|
|
153
|
+
queryKey: string | readonly unknown[],
|
|
154
|
+
query: string,
|
|
155
|
+
options?: UseGraphQLQueryOptions<T>
|
|
156
|
+
) {
|
|
157
|
+
const client = useFluxbaseClient();
|
|
158
|
+
const normalizedKey = Array.isArray(queryKey)
|
|
159
|
+
? ["fluxbase", "graphql", ...queryKey]
|
|
160
|
+
: ["fluxbase", "graphql", queryKey];
|
|
161
|
+
|
|
162
|
+
return useQuery<T | undefined, GraphQLError>({
|
|
163
|
+
queryKey: normalizedKey,
|
|
164
|
+
queryFn: async () => {
|
|
165
|
+
const response: GraphQLResponse<T> = await client.graphql.execute(
|
|
166
|
+
query,
|
|
167
|
+
options?.variables,
|
|
168
|
+
options?.operationName,
|
|
169
|
+
options?.requestOptions
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
if (response.errors && response.errors.length > 0) {
|
|
173
|
+
throw response.errors[0];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return response.data;
|
|
177
|
+
},
|
|
178
|
+
enabled: options?.enabled ?? true,
|
|
179
|
+
staleTime: options?.staleTime ?? 0,
|
|
180
|
+
gcTime: options?.gcTime,
|
|
181
|
+
refetchOnWindowFocus: options?.refetchOnWindowFocus ?? true,
|
|
182
|
+
select: options?.select,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Hook to execute GraphQL mutations
|
|
188
|
+
*
|
|
189
|
+
* @typeParam T - The expected response data type
|
|
190
|
+
* @typeParam V - The variables type
|
|
191
|
+
* @param mutation - The GraphQL mutation string
|
|
192
|
+
* @param options - Mutation options
|
|
193
|
+
* @returns React Query mutation result object
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```tsx
|
|
197
|
+
* interface CreateUserMutation {
|
|
198
|
+
* insertUser: { id: string; email: string }
|
|
199
|
+
* }
|
|
200
|
+
*
|
|
201
|
+
* interface CreateUserVariables {
|
|
202
|
+
* data: { email: string }
|
|
203
|
+
* }
|
|
204
|
+
*
|
|
205
|
+
* function CreateUserForm() {
|
|
206
|
+
* const mutation = useGraphQLMutation<CreateUserMutation, CreateUserVariables>(
|
|
207
|
+
* `mutation CreateUser($data: UserInput!) {
|
|
208
|
+
* insertUser(data: $data) { id email }
|
|
209
|
+
* }`,
|
|
210
|
+
* {
|
|
211
|
+
* onSuccess: (data) => console.log('Created:', data.insertUser),
|
|
212
|
+
* invalidateQueries: ['users']
|
|
213
|
+
* }
|
|
214
|
+
* )
|
|
215
|
+
*
|
|
216
|
+
* const handleSubmit = (email: string) => {
|
|
217
|
+
* mutation.mutate({ data: { email } })
|
|
218
|
+
* }
|
|
219
|
+
*
|
|
220
|
+
* return (
|
|
221
|
+
* <button
|
|
222
|
+
* onClick={() => handleSubmit('new@example.com')}
|
|
223
|
+
* disabled={mutation.isPending}
|
|
224
|
+
* >
|
|
225
|
+
* Create User
|
|
226
|
+
* </button>
|
|
227
|
+
* )
|
|
228
|
+
* }
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
export function useGraphQLMutation<
|
|
232
|
+
T = unknown,
|
|
233
|
+
V extends Record<string, unknown> = Record<string, unknown>,
|
|
234
|
+
>(mutation: string, options?: UseGraphQLMutationOptions<T, V>) {
|
|
235
|
+
const client = useFluxbaseClient();
|
|
236
|
+
const queryClient = useQueryClient();
|
|
237
|
+
|
|
238
|
+
return useMutation<T | undefined, GraphQLError, V>({
|
|
239
|
+
mutationFn: async (variables: V) => {
|
|
240
|
+
const response: GraphQLResponse<T> = await client.graphql.execute(
|
|
241
|
+
mutation,
|
|
242
|
+
variables,
|
|
243
|
+
options?.operationName,
|
|
244
|
+
options?.requestOptions
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
if (response.errors && response.errors.length > 0) {
|
|
248
|
+
throw response.errors[0];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return response.data;
|
|
252
|
+
},
|
|
253
|
+
onSuccess: (data, variables) => {
|
|
254
|
+
// Invalidate specified queries
|
|
255
|
+
if (options?.invalidateQueries) {
|
|
256
|
+
for (const key of options.invalidateQueries) {
|
|
257
|
+
queryClient.invalidateQueries({
|
|
258
|
+
queryKey: ["fluxbase", "graphql", key],
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Call user's onSuccess callback
|
|
264
|
+
if (options?.onSuccess && data !== undefined) {
|
|
265
|
+
options.onSuccess(data, variables);
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
onError: (error, variables) => {
|
|
269
|
+
if (options?.onError) {
|
|
270
|
+
options.onError(error, variables);
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Hook to fetch the GraphQL schema via introspection
|
|
278
|
+
*
|
|
279
|
+
* @param options - Query options
|
|
280
|
+
* @returns React Query result with schema introspection data
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```tsx
|
|
284
|
+
* function SchemaExplorer() {
|
|
285
|
+
* const { data, isLoading } = useGraphQLIntrospection()
|
|
286
|
+
*
|
|
287
|
+
* if (isLoading) return <div>Loading schema...</div>
|
|
288
|
+
*
|
|
289
|
+
* return (
|
|
290
|
+
* <div>
|
|
291
|
+
* <p>Query type: {data?.__schema.queryType.name}</p>
|
|
292
|
+
* <p>Types: {data?.__schema.types.length}</p>
|
|
293
|
+
* </div>
|
|
294
|
+
* )
|
|
295
|
+
* }
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
export function useGraphQLIntrospection(options?: {
|
|
299
|
+
enabled?: boolean;
|
|
300
|
+
staleTime?: number;
|
|
301
|
+
requestOptions?: GraphQLRequestOptions;
|
|
302
|
+
}) {
|
|
303
|
+
const client = useFluxbaseClient();
|
|
304
|
+
|
|
305
|
+
return useQuery({
|
|
306
|
+
queryKey: ["fluxbase", "graphql", "__introspection"],
|
|
307
|
+
queryFn: async () => {
|
|
308
|
+
const response = await client.graphql.introspect(options?.requestOptions);
|
|
309
|
+
|
|
310
|
+
if (response.errors && response.errors.length > 0) {
|
|
311
|
+
throw response.errors[0];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return response.data;
|
|
315
|
+
},
|
|
316
|
+
enabled: options?.enabled ?? true,
|
|
317
|
+
staleTime: options?.staleTime ?? 1000 * 60 * 5, // 5 minutes - schema doesn't change often
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Hook to execute raw GraphQL operations (query or mutation)
|
|
323
|
+
*
|
|
324
|
+
* This is a lower-level hook that doesn't use React Query caching.
|
|
325
|
+
* Useful for one-off operations or when you need full control.
|
|
326
|
+
*
|
|
327
|
+
* @returns Functions to execute queries and mutations
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* ```tsx
|
|
331
|
+
* function AdminPanel() {
|
|
332
|
+
* const { executeQuery, executeMutation } = useGraphQL()
|
|
333
|
+
*
|
|
334
|
+
* const handleExport = async () => {
|
|
335
|
+
* const result = await executeQuery<ExportData>(
|
|
336
|
+
* `query { exportAllData { url } }`
|
|
337
|
+
* )
|
|
338
|
+
* if (result.data) {
|
|
339
|
+
* window.open(result.data.exportAllData.url)
|
|
340
|
+
* }
|
|
341
|
+
* }
|
|
342
|
+
*
|
|
343
|
+
* return <button onClick={handleExport}>Export Data</button>
|
|
344
|
+
* }
|
|
345
|
+
* ```
|
|
346
|
+
*/
|
|
347
|
+
export function useGraphQL() {
|
|
348
|
+
const client = useFluxbaseClient();
|
|
349
|
+
|
|
350
|
+
return {
|
|
351
|
+
/**
|
|
352
|
+
* Execute a GraphQL query
|
|
353
|
+
*/
|
|
354
|
+
executeQuery: <T = unknown>(
|
|
355
|
+
query: string,
|
|
356
|
+
variables?: Record<string, unknown>,
|
|
357
|
+
options?: GraphQLRequestOptions
|
|
358
|
+
): Promise<GraphQLResponse<T>> => {
|
|
359
|
+
return client.graphql.query<T>(query, variables, options);
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Execute a GraphQL mutation
|
|
364
|
+
*/
|
|
365
|
+
executeMutation: <T = unknown>(
|
|
366
|
+
mutation: string,
|
|
367
|
+
variables?: Record<string, unknown>,
|
|
368
|
+
options?: GraphQLRequestOptions
|
|
369
|
+
): Promise<GraphQLResponse<T>> => {
|
|
370
|
+
return client.graphql.mutation<T>(mutation, variables, options);
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Execute a GraphQL operation with an explicit operation name
|
|
375
|
+
*/
|
|
376
|
+
execute: <T = unknown>(
|
|
377
|
+
document: string,
|
|
378
|
+
variables?: Record<string, unknown>,
|
|
379
|
+
operationName?: string,
|
|
380
|
+
options?: GraphQLRequestOptions
|
|
381
|
+
): Promise<GraphQLResponse<T>> => {
|
|
382
|
+
return client.graphql.execute<T>(document, variables, operationName, options);
|
|
383
|
+
},
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Fetch the GraphQL schema via introspection
|
|
387
|
+
*/
|
|
388
|
+
introspect: (options?: GraphQLRequestOptions) => {
|
|
389
|
+
return client.graphql.introspect(options);
|
|
390
|
+
},
|
|
391
|
+
};
|
|
392
|
+
}
|
package/src/use-realtime.ts
CHANGED
|
@@ -2,99 +2,113 @@
|
|
|
2
2
|
* Realtime subscription hooks for Fluxbase SDK
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { useEffect, useRef } from
|
|
6
|
-
import { useQueryClient } from
|
|
7
|
-
import { useFluxbaseClient } from
|
|
8
|
-
import type {
|
|
5
|
+
import { useEffect, useRef } from "react";
|
|
6
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
7
|
+
import { useFluxbaseClient } from "./context";
|
|
8
|
+
import type {
|
|
9
|
+
RealtimeCallback,
|
|
10
|
+
RealtimePostgresChangesPayload,
|
|
11
|
+
} from "@fluxbase/sdk";
|
|
9
12
|
|
|
10
13
|
export interface UseRealtimeOptions {
|
|
11
14
|
/**
|
|
12
15
|
* The channel name (e.g., 'table:public.products')
|
|
13
16
|
*/
|
|
14
|
-
channel: string
|
|
17
|
+
channel: string;
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* Event type to listen for ('INSERT', 'UPDATE', 'DELETE', or '*' for all)
|
|
18
21
|
*/
|
|
19
|
-
event?:
|
|
22
|
+
event?: "INSERT" | "UPDATE" | "DELETE" | "*";
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* Callback function when an event is received
|
|
23
26
|
*/
|
|
24
|
-
callback?: RealtimeCallback
|
|
27
|
+
callback?: RealtimeCallback;
|
|
25
28
|
|
|
26
29
|
/**
|
|
27
30
|
* Whether to automatically invalidate queries for the table
|
|
28
31
|
* Default: true
|
|
29
32
|
*/
|
|
30
|
-
autoInvalidate?: boolean
|
|
33
|
+
autoInvalidate?: boolean;
|
|
31
34
|
|
|
32
35
|
/**
|
|
33
36
|
* Custom query key to invalidate (if autoInvalidate is true)
|
|
34
37
|
* Default: ['fluxbase', 'table', tableName]
|
|
35
38
|
*/
|
|
36
|
-
invalidateKey?: unknown[]
|
|
39
|
+
invalidateKey?: unknown[];
|
|
37
40
|
|
|
38
41
|
/**
|
|
39
42
|
* Whether the subscription is enabled
|
|
40
43
|
* Default: true
|
|
41
44
|
*/
|
|
42
|
-
enabled?: boolean
|
|
45
|
+
enabled?: boolean;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
/**
|
|
46
49
|
* Hook to subscribe to realtime changes for a channel
|
|
47
50
|
*/
|
|
48
51
|
export function useRealtime(options: UseRealtimeOptions) {
|
|
49
|
-
const client = useFluxbaseClient()
|
|
50
|
-
const queryClient = useQueryClient()
|
|
51
|
-
const channelRef = useRef<ReturnType<typeof client.realtime.channel> | null>(
|
|
52
|
+
const client = useFluxbaseClient();
|
|
53
|
+
const queryClient = useQueryClient();
|
|
54
|
+
const channelRef = useRef<ReturnType<typeof client.realtime.channel> | null>(
|
|
55
|
+
null,
|
|
56
|
+
);
|
|
52
57
|
|
|
53
58
|
const {
|
|
54
59
|
channel: channelName,
|
|
55
|
-
event =
|
|
60
|
+
event = "*",
|
|
56
61
|
callback,
|
|
57
62
|
autoInvalidate = true,
|
|
58
63
|
invalidateKey,
|
|
59
64
|
enabled = true,
|
|
60
|
-
} = options
|
|
65
|
+
} = options;
|
|
61
66
|
|
|
62
67
|
useEffect(() => {
|
|
63
68
|
if (!enabled) {
|
|
64
|
-
return
|
|
69
|
+
return;
|
|
65
70
|
}
|
|
66
71
|
|
|
67
72
|
// Create channel and subscribe
|
|
68
|
-
const channel = client.realtime.channel(channelName)
|
|
69
|
-
channelRef.current = channel
|
|
73
|
+
const channel = client.realtime.channel(channelName);
|
|
74
|
+
channelRef.current = channel;
|
|
70
75
|
|
|
71
|
-
const handleChange = (payload:
|
|
76
|
+
const handleChange = (payload: RealtimePostgresChangesPayload) => {
|
|
72
77
|
// Call user callback
|
|
73
78
|
if (callback) {
|
|
74
|
-
callback(payload)
|
|
79
|
+
callback(payload);
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
// Auto-invalidate queries if enabled
|
|
78
83
|
if (autoInvalidate) {
|
|
79
84
|
// Extract table name from channel (e.g., 'table:public.products' -> 'public.products')
|
|
80
|
-
const tableName = channelName.replace(/^table:/,
|
|
85
|
+
const tableName = channelName.replace(/^table:/, "");
|
|
81
86
|
|
|
82
|
-
const key = invalidateKey || [
|
|
83
|
-
queryClient.invalidateQueries({ queryKey: key })
|
|
87
|
+
const key = invalidateKey || ["fluxbase", "table", tableName];
|
|
88
|
+
queryClient.invalidateQueries({ queryKey: key });
|
|
84
89
|
}
|
|
85
|
-
}
|
|
90
|
+
};
|
|
86
91
|
|
|
87
|
-
channel.on(event, handleChange).subscribe()
|
|
92
|
+
channel.on(event, handleChange).subscribe();
|
|
88
93
|
|
|
89
94
|
return () => {
|
|
90
|
-
channel.unsubscribe()
|
|
91
|
-
channelRef.current = null
|
|
92
|
-
}
|
|
93
|
-
}, [
|
|
95
|
+
channel.unsubscribe();
|
|
96
|
+
channelRef.current = null;
|
|
97
|
+
};
|
|
98
|
+
}, [
|
|
99
|
+
client,
|
|
100
|
+
channelName,
|
|
101
|
+
event,
|
|
102
|
+
callback,
|
|
103
|
+
autoInvalidate,
|
|
104
|
+
invalidateKey,
|
|
105
|
+
queryClient,
|
|
106
|
+
enabled,
|
|
107
|
+
]);
|
|
94
108
|
|
|
95
109
|
return {
|
|
96
110
|
channel: channelRef.current,
|
|
97
|
-
}
|
|
111
|
+
};
|
|
98
112
|
}
|
|
99
113
|
|
|
100
114
|
/**
|
|
@@ -104,12 +118,12 @@ export function useRealtime(options: UseRealtimeOptions) {
|
|
|
104
118
|
*/
|
|
105
119
|
export function useTableSubscription(
|
|
106
120
|
table: string,
|
|
107
|
-
options?: Omit<UseRealtimeOptions,
|
|
121
|
+
options?: Omit<UseRealtimeOptions, "channel">,
|
|
108
122
|
) {
|
|
109
123
|
return useRealtime({
|
|
110
124
|
...options,
|
|
111
125
|
channel: `table:${table}`,
|
|
112
|
-
})
|
|
126
|
+
});
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
/**
|
|
@@ -117,15 +131,15 @@ export function useTableSubscription(
|
|
|
117
131
|
*/
|
|
118
132
|
export function useTableInserts(
|
|
119
133
|
table: string,
|
|
120
|
-
callback: (payload:
|
|
121
|
-
options?: Omit<UseRealtimeOptions,
|
|
134
|
+
callback: (payload: RealtimePostgresChangesPayload) => void,
|
|
135
|
+
options?: Omit<UseRealtimeOptions, "channel" | "event" | "callback">,
|
|
122
136
|
) {
|
|
123
137
|
return useRealtime({
|
|
124
138
|
...options,
|
|
125
139
|
channel: `table:${table}`,
|
|
126
|
-
event:
|
|
140
|
+
event: "INSERT",
|
|
127
141
|
callback,
|
|
128
|
-
})
|
|
142
|
+
});
|
|
129
143
|
}
|
|
130
144
|
|
|
131
145
|
/**
|
|
@@ -133,15 +147,15 @@ export function useTableInserts(
|
|
|
133
147
|
*/
|
|
134
148
|
export function useTableUpdates(
|
|
135
149
|
table: string,
|
|
136
|
-
callback: (payload:
|
|
137
|
-
options?: Omit<UseRealtimeOptions,
|
|
150
|
+
callback: (payload: RealtimePostgresChangesPayload) => void,
|
|
151
|
+
options?: Omit<UseRealtimeOptions, "channel" | "event" | "callback">,
|
|
138
152
|
) {
|
|
139
153
|
return useRealtime({
|
|
140
154
|
...options,
|
|
141
155
|
channel: `table:${table}`,
|
|
142
|
-
event:
|
|
156
|
+
event: "UPDATE",
|
|
143
157
|
callback,
|
|
144
|
-
})
|
|
158
|
+
});
|
|
145
159
|
}
|
|
146
160
|
|
|
147
161
|
/**
|
|
@@ -149,13 +163,13 @@ export function useTableUpdates(
|
|
|
149
163
|
*/
|
|
150
164
|
export function useTableDeletes(
|
|
151
165
|
table: string,
|
|
152
|
-
callback: (payload:
|
|
153
|
-
options?: Omit<UseRealtimeOptions,
|
|
166
|
+
callback: (payload: RealtimePostgresChangesPayload) => void,
|
|
167
|
+
options?: Omit<UseRealtimeOptions, "channel" | "event" | "callback">,
|
|
154
168
|
) {
|
|
155
169
|
return useRealtime({
|
|
156
170
|
...options,
|
|
157
171
|
channel: `table:${table}`,
|
|
158
|
-
event:
|
|
172
|
+
event: "DELETE",
|
|
159
173
|
callback,
|
|
160
|
-
})
|
|
174
|
+
});
|
|
161
175
|
}
|