@fluxbase/sdk-react 0.1.0-rc.1 → 2026.1.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/README-ADMIN.md +8 -8
- package/README.md +27 -14
- package/dist/index.d.mts +638 -83
- package/dist/index.d.ts +638 -83
- package/dist/index.js +552 -175
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +540 -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 +57 -18
- package/src/use-admin-auth.ts +62 -51
- 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
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback } from 'react'
|
|
2
2
|
import { useFluxbaseClient } from './context'
|
|
3
|
-
import type {
|
|
3
|
+
import type { ClientKey, CreateClientKeyRequest } from '@fluxbase/sdk'
|
|
4
4
|
|
|
5
|
-
export interface
|
|
5
|
+
export interface UseClientKeysOptions {
|
|
6
6
|
/**
|
|
7
|
-
* Whether to automatically fetch
|
|
7
|
+
* Whether to automatically fetch client keys on mount
|
|
8
8
|
* @default true
|
|
9
9
|
*/
|
|
10
10
|
autoFetch?: boolean
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export interface
|
|
13
|
+
export interface UseClientKeysReturn {
|
|
14
14
|
/**
|
|
15
|
-
* Array of
|
|
15
|
+
* Array of client keys
|
|
16
16
|
*/
|
|
17
|
-
keys:
|
|
17
|
+
keys: ClientKey[]
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Whether keys are being fetched
|
|
@@ -27,45 +27,45 @@ export interface UseAPIKeysReturn {
|
|
|
27
27
|
error: Error | null
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Refetch
|
|
30
|
+
* Refetch client keys
|
|
31
31
|
*/
|
|
32
32
|
refetch: () => Promise<void>
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
|
-
* Create a new
|
|
35
|
+
* Create a new client key
|
|
36
36
|
*/
|
|
37
|
-
createKey: (request:
|
|
37
|
+
createKey: (request: CreateClientKeyRequest) => Promise<{ key: string; keyData: ClientKey }>
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Update
|
|
40
|
+
* Update a client key
|
|
41
41
|
*/
|
|
42
42
|
updateKey: (keyId: string, update: { name?: string; description?: string }) => Promise<void>
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
* Revoke
|
|
45
|
+
* Revoke a client key
|
|
46
46
|
*/
|
|
47
47
|
revokeKey: (keyId: string) => Promise<void>
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
* Delete
|
|
50
|
+
* Delete a client key
|
|
51
51
|
*/
|
|
52
52
|
deleteKey: (keyId: string) => Promise<void>
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
|
-
* Hook for managing
|
|
56
|
+
* Hook for managing client keys
|
|
57
57
|
*
|
|
58
|
-
* Provides
|
|
58
|
+
* Provides client key list and management functions.
|
|
59
59
|
*
|
|
60
60
|
* @example
|
|
61
61
|
* ```tsx
|
|
62
|
-
* function
|
|
63
|
-
* const { keys, isLoading, createKey, revokeKey } =
|
|
62
|
+
* function ClientKeyManager() {
|
|
63
|
+
* const { keys, isLoading, createKey, revokeKey } = useClientKeys()
|
|
64
64
|
*
|
|
65
65
|
* const handleCreate = async () => {
|
|
66
66
|
* const { key, keyData } = await createKey({
|
|
67
67
|
* name: 'Backend Service',
|
|
68
|
-
* description: '
|
|
68
|
+
* description: 'Client key for backend',
|
|
69
69
|
* expires_at: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString()
|
|
70
70
|
* })
|
|
71
71
|
* alert(`Key created: ${key}`)
|
|
@@ -85,23 +85,23 @@ export interface UseAPIKeysReturn {
|
|
|
85
85
|
* }
|
|
86
86
|
* ```
|
|
87
87
|
*/
|
|
88
|
-
export function
|
|
88
|
+
export function useClientKeys(options: UseClientKeysOptions = {}): UseClientKeysReturn {
|
|
89
89
|
const { autoFetch = true } = options
|
|
90
90
|
const client = useFluxbaseClient()
|
|
91
91
|
|
|
92
|
-
const [keys, setKeys] = useState<
|
|
92
|
+
const [keys, setKeys] = useState<ClientKey[]>([])
|
|
93
93
|
const [isLoading, setIsLoading] = useState(autoFetch)
|
|
94
94
|
const [error, setError] = useState<Error | null>(null)
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
|
-
* Fetch
|
|
97
|
+
* Fetch client keys from API
|
|
98
98
|
*/
|
|
99
99
|
const fetchKeys = useCallback(async () => {
|
|
100
100
|
try {
|
|
101
101
|
setIsLoading(true)
|
|
102
102
|
setError(null)
|
|
103
|
-
const response = await client.admin.management.
|
|
104
|
-
setKeys(response.
|
|
103
|
+
const response = await client.admin.management.clientKeys.list()
|
|
104
|
+
setKeys(response.client_keys)
|
|
105
105
|
} catch (err) {
|
|
106
106
|
setError(err as Error)
|
|
107
107
|
} finally {
|
|
@@ -110,45 +110,45 @@ export function useAPIKeys(options: UseAPIKeysOptions = {}): UseAPIKeysReturn {
|
|
|
110
110
|
}, [client])
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
|
-
* Create a new
|
|
113
|
+
* Create a new client key
|
|
114
114
|
*/
|
|
115
115
|
const createKey = useCallback(
|
|
116
|
-
async (request:
|
|
117
|
-
const response = await client.admin.management.
|
|
116
|
+
async (request: CreateClientKeyRequest): Promise<{ key: string; keyData: ClientKey }> => {
|
|
117
|
+
const response = await client.admin.management.clientKeys.create(request)
|
|
118
118
|
await fetchKeys() // Refresh list
|
|
119
|
-
return { key: response.key, keyData: response.
|
|
119
|
+
return { key: response.key, keyData: response.client_key }
|
|
120
120
|
},
|
|
121
121
|
[client, fetchKeys]
|
|
122
122
|
)
|
|
123
123
|
|
|
124
124
|
/**
|
|
125
|
-
* Update
|
|
125
|
+
* Update a client key
|
|
126
126
|
*/
|
|
127
127
|
const updateKey = useCallback(
|
|
128
128
|
async (keyId: string, update: { name?: string; description?: string }): Promise<void> => {
|
|
129
|
-
await client.admin.management.
|
|
129
|
+
await client.admin.management.clientKeys.update(keyId, update)
|
|
130
130
|
await fetchKeys() // Refresh list
|
|
131
131
|
},
|
|
132
132
|
[client, fetchKeys]
|
|
133
133
|
)
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
|
-
* Revoke
|
|
136
|
+
* Revoke a client key
|
|
137
137
|
*/
|
|
138
138
|
const revokeKey = useCallback(
|
|
139
139
|
async (keyId: string): Promise<void> => {
|
|
140
|
-
await client.admin.management.
|
|
140
|
+
await client.admin.management.clientKeys.revoke(keyId)
|
|
141
141
|
await fetchKeys() // Refresh list
|
|
142
142
|
},
|
|
143
143
|
[client, fetchKeys]
|
|
144
144
|
)
|
|
145
145
|
|
|
146
146
|
/**
|
|
147
|
-
* Delete
|
|
147
|
+
* Delete a client key
|
|
148
148
|
*/
|
|
149
149
|
const deleteKey = useCallback(
|
|
150
150
|
async (keyId: string): Promise<void> => {
|
|
151
|
-
await client.admin.management.
|
|
151
|
+
await client.admin.management.clientKeys.delete(keyId)
|
|
152
152
|
await fetchKeys() // Refresh list
|
|
153
153
|
},
|
|
154
154
|
[client, fetchKeys]
|
|
@@ -172,3 +172,14 @@ export function useAPIKeys(options: UseAPIKeysOptions = {}): UseAPIKeysReturn {
|
|
|
172
172
|
deleteKey
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @deprecated Use useClientKeys instead
|
|
178
|
+
*/
|
|
179
|
+
export const useAPIKeys = useClientKeys
|
|
180
|
+
|
|
181
|
+
/** @deprecated Use UseClientKeysOptions instead */
|
|
182
|
+
export type UseAPIKeysOptions = UseClientKeysOptions
|
|
183
|
+
|
|
184
|
+
/** @deprecated Use UseClientKeysReturn instead */
|
|
185
|
+
export type UseAPIKeysReturn = UseClientKeysReturn
|
|
@@ -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
|
+
}
|