@fluxbase/sdk-react 0.0.7-rc.11 → 2026.1.1-rc.1

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.
@@ -1,20 +1,20 @@
1
1
  import { useState, useEffect, useCallback } from 'react'
2
2
  import { useFluxbaseClient } from './context'
3
- import type { APIKey, CreateAPIKeyRequest } from '@fluxbase/sdk'
3
+ import type { ClientKey, CreateClientKeyRequest } from '@fluxbase/sdk'
4
4
 
5
- export interface UseAPIKeysOptions {
5
+ export interface UseClientKeysOptions {
6
6
  /**
7
- * Whether to automatically fetch API keys on mount
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 UseAPIKeysReturn {
13
+ export interface UseClientKeysReturn {
14
14
  /**
15
- * Array of API keys
15
+ * Array of client keys
16
16
  */
17
- keys: APIKey[]
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 API keys
30
+ * Refetch client keys
31
31
  */
32
32
  refetch: () => Promise<void>
33
33
 
34
34
  /**
35
- * Create a new API key
35
+ * Create a new client key
36
36
  */
37
- createKey: (request: CreateAPIKeyRequest) => Promise<{ key: string; keyData: APIKey }>
37
+ createKey: (request: CreateClientKeyRequest) => Promise<{ key: string; keyData: ClientKey }>
38
38
 
39
39
  /**
40
- * Update an API key
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 an API key
45
+ * Revoke a client key
46
46
  */
47
47
  revokeKey: (keyId: string) => Promise<void>
48
48
 
49
49
  /**
50
- * Delete an API key
50
+ * Delete a client key
51
51
  */
52
52
  deleteKey: (keyId: string) => Promise<void>
53
53
  }
54
54
 
55
55
  /**
56
- * Hook for managing API keys
56
+ * Hook for managing client keys
57
57
  *
58
- * Provides API key list and management functions.
58
+ * Provides client key list and management functions.
59
59
  *
60
60
  * @example
61
61
  * ```tsx
62
- * function APIKeyManager() {
63
- * const { keys, isLoading, createKey, revokeKey } = useAPIKeys()
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: 'API key for backend',
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 useAPIKeys(options: UseAPIKeysOptions = {}): UseAPIKeysReturn {
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<APIKey[]>([])
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 API keys from API
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.apiKeys.list()
104
- setKeys(response.api_keys)
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 API key
113
+ * Create a new client key
114
114
  */
115
115
  const createKey = useCallback(
116
- async (request: CreateAPIKeyRequest): Promise<{ key: string; keyData: APIKey }> => {
117
- const response = await client.admin.management.apiKeys.create(request)
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.api_key }
119
+ return { key: response.key, keyData: response.client_key }
120
120
  },
121
121
  [client, fetchKeys]
122
122
  )
123
123
 
124
124
  /**
125
- * Update an API key
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.apiKeys.update(keyId, update)
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 an API key
136
+ * Revoke a client key
137
137
  */
138
138
  const revokeKey = useCallback(
139
139
  async (keyId: string): Promise<void> => {
140
- await client.admin.management.apiKeys.revoke(keyId)
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 an API key
147
+ * Delete a client key
148
148
  */
149
149
  const deleteKey = useCallback(
150
150
  async (keyId: string): Promise<void> => {
151
- await client.admin.management.apiKeys.delete(keyId)
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
+ }