@fluxbase/sdk-react
Version:
React hooks for Fluxbase SDK
1 lines • 62.3 kB
Source Map (JSON)
{"version":3,"sources":["../src/context.tsx","../src/use-auth.ts","../src/use-query.ts","../src/use-realtime.ts","../src/use-storage.ts","../src/use-rpc.ts","../src/use-admin-auth.ts","../src/use-users.ts","../src/use-api-keys.ts","../src/use-admin-hooks.ts"],"sourcesContent":["/**\n * React context for Fluxbase client\n */\n\nimport { createContext, useContext, type ReactNode } from 'react'\nimport type { FluxbaseClient } from '@fluxbase/sdk'\n\nconst FluxbaseContext = createContext<FluxbaseClient | null>(null)\n\nexport interface FluxbaseProviderProps {\n client: FluxbaseClient\n children: ReactNode\n}\n\n/**\n * Provider component to make Fluxbase client available throughout the app\n */\nexport function FluxbaseProvider({ client, children }: FluxbaseProviderProps) {\n return <FluxbaseContext.Provider value={client}>{children}</FluxbaseContext.Provider>\n}\n\n/**\n * Hook to access the Fluxbase client from context\n */\nexport function useFluxbaseClient(): FluxbaseClient {\n const client = useContext(FluxbaseContext)\n\n if (!client) {\n throw new Error('useFluxbaseClient must be used within a FluxbaseProvider')\n }\n\n return client\n}\n","/**\n * Authentication hooks for Fluxbase SDK\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useFluxbaseClient } from './context'\nimport type { SignInCredentials, SignUpCredentials, User, AuthSession } from '@fluxbase/sdk'\n\n/**\n * Hook to get the current user\n */\nexport function useUser() {\n const client = useFluxbaseClient()\n\n return useQuery({\n queryKey: ['fluxbase', 'auth', 'user'],\n queryFn: async () => {\n const session = client.auth.getSession()\n if (!session) {\n return null\n }\n\n try {\n return await client.auth.getCurrentUser()\n } catch {\n return null\n }\n },\n staleTime: 1000 * 60 * 5, // 5 minutes\n })\n}\n\n/**\n * Hook to get the current session\n */\nexport function useSession() {\n const client = useFluxbaseClient()\n\n return useQuery<AuthSession | null>({\n queryKey: ['fluxbase', 'auth', 'session'],\n queryFn: () => client.auth.getSession(),\n staleTime: 1000 * 60 * 5, // 5 minutes\n })\n}\n\n/**\n * Hook for signing in\n */\nexport function useSignIn() {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (credentials: SignInCredentials) => {\n return await client.auth.signIn(credentials)\n },\n onSuccess: (session) => {\n queryClient.setQueryData(['fluxbase', 'auth', 'session'], session)\n // Only set user if this is a complete auth session (not 2FA required)\n if ('user' in session) {\n queryClient.setQueryData(['fluxbase', 'auth', 'user'], session.user)\n }\n },\n })\n}\n\n/**\n * Hook for signing up\n */\nexport function useSignUp() {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (credentials: SignUpCredentials) => {\n return await client.auth.signUp(credentials)\n },\n onSuccess: (session) => {\n queryClient.setQueryData(['fluxbase', 'auth', 'session'], session)\n queryClient.setQueryData(['fluxbase', 'auth', 'user'], session.user)\n },\n })\n}\n\n/**\n * Hook for signing out\n */\nexport function useSignOut() {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async () => {\n await client.auth.signOut()\n },\n onSuccess: () => {\n queryClient.setQueryData(['fluxbase', 'auth', 'session'], null)\n queryClient.setQueryData(['fluxbase', 'auth', 'user'], null)\n queryClient.invalidateQueries({ queryKey: ['fluxbase'] })\n },\n })\n}\n\n/**\n * Hook for updating the current user\n */\nexport function useUpdateUser() {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (data: Partial<Pick<User, 'email' | 'metadata'>>) => {\n return await client.auth.updateUser(data)\n },\n onSuccess: (user) => {\n queryClient.setQueryData(['fluxbase', 'auth', 'user'], user)\n },\n })\n}\n\n/**\n * Combined auth hook with all auth state and methods\n */\nexport function useAuth() {\n const { data: user, isLoading: isLoadingUser } = useUser()\n const { data: session, isLoading: isLoadingSession } = useSession()\n const signIn = useSignIn()\n const signUp = useSignUp()\n const signOut = useSignOut()\n const updateUser = useUpdateUser()\n\n return {\n user,\n session,\n isLoading: isLoadingUser || isLoadingSession,\n isAuthenticated: !!session,\n signIn: signIn.mutateAsync,\n signUp: signUp.mutateAsync,\n signOut: signOut.mutateAsync,\n updateUser: updateUser.mutateAsync,\n isSigningIn: signIn.isPending,\n isSigningUp: signUp.isPending,\n isSigningOut: signOut.isPending,\n isUpdating: updateUser.isPending,\n }\n}\n","/**\n * Database query hooks for Fluxbase SDK\n */\n\nimport { useQuery, useMutation, useQueryClient, type UseQueryOptions } from '@tanstack/react-query'\nimport { useFluxbaseClient } from './context'\nimport type { QueryBuilder } from '@fluxbase/sdk'\n\nexport interface UseFluxbaseQueryOptions<T> extends Omit<UseQueryOptions<T[], Error>, 'queryKey' | 'queryFn'> {\n /**\n * Custom query key. If not provided, will use table name and filters.\n */\n queryKey?: unknown[]\n}\n\n/**\n * Hook to execute a database query\n * @param buildQuery - Function that builds and returns the query\n * @param options - React Query options\n */\nexport function useFluxbaseQuery<T = any>(\n buildQuery: (client: ReturnType<typeof useFluxbaseClient>) => QueryBuilder<T>,\n options?: UseFluxbaseQueryOptions<T>\n) {\n const client = useFluxbaseClient()\n\n // Build a stable query key\n const queryKey = options?.queryKey || ['fluxbase', 'query', buildQuery.toString()]\n\n return useQuery({\n queryKey,\n queryFn: async () => {\n const query = buildQuery(client)\n const { data, error } = await query.execute()\n\n if (error) {\n throw error\n }\n\n return (Array.isArray(data) ? data : data ? [data] : []) as T[]\n },\n ...options,\n })\n}\n\n/**\n * Hook for table queries with a simpler API\n * @param table - Table name\n * @param buildQuery - Function to build the query\n */\nexport function useTable<T = any>(\n table: string,\n buildQuery?: (query: QueryBuilder<T>) => QueryBuilder<T>,\n options?: UseFluxbaseQueryOptions<T>\n) {\n const client = useFluxbaseClient()\n\n return useFluxbaseQuery(\n (client) => {\n const query = client.from<T>(table)\n return buildQuery ? buildQuery(query) : query\n },\n {\n ...options,\n queryKey: options?.queryKey || ['fluxbase', 'table', table, buildQuery?.toString()],\n }\n )\n}\n\n/**\n * Hook to insert data into a table\n */\nexport function useInsert<T = any>(table: string) {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (data: Partial<T> | Partial<T>[]) => {\n const query = client.from<T>(table)\n const { data: result, error } = await query.insert(data as Partial<T>)\n\n if (error) {\n throw error\n }\n\n return result\n },\n onSuccess: () => {\n // Invalidate all queries for this table\n queryClient.invalidateQueries({ queryKey: ['fluxbase', 'table', table] })\n },\n })\n}\n\n/**\n * Hook to update data in a table\n */\nexport function useUpdate<T = any>(table: string) {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (params: { data: Partial<T>; buildQuery: (query: QueryBuilder<T>) => QueryBuilder<T> }) => {\n const query = client.from<T>(table)\n const builtQuery = params.buildQuery(query)\n const { data: result, error } = await builtQuery.update(params.data)\n\n if (error) {\n throw error\n }\n\n return result\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fluxbase', 'table', table] })\n },\n })\n}\n\n/**\n * Hook to upsert data into a table\n */\nexport function useUpsert<T = any>(table: string) {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (data: Partial<T> | Partial<T>[]) => {\n const query = client.from<T>(table)\n const { data: result, error } = await query.upsert(data as Partial<T>)\n\n if (error) {\n throw error\n }\n\n return result\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fluxbase', 'table', table] })\n },\n })\n}\n\n/**\n * Hook to delete data from a table\n */\nexport function useDelete<T = any>(table: string) {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (buildQuery: (query: QueryBuilder<T>) => QueryBuilder<T>) => {\n const query = client.from<T>(table)\n const builtQuery = buildQuery(query)\n const { error } = await builtQuery.delete()\n\n if (error) {\n throw error\n }\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fluxbase', 'table', table] })\n },\n })\n}\n","/**\n * Realtime subscription hooks for Fluxbase SDK\n */\n\nimport { useEffect, useRef } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useFluxbaseClient } from './context'\nimport type { RealtimeCallback, RealtimeChangePayload } from '@fluxbase/sdk'\n\nexport interface UseRealtimeOptions {\n /**\n * The channel name (e.g., 'table:public.products')\n */\n channel: string\n\n /**\n * Event type to listen for ('INSERT', 'UPDATE', 'DELETE', or '*' for all)\n */\n event?: 'INSERT' | 'UPDATE' | 'DELETE' | '*'\n\n /**\n * Callback function when an event is received\n */\n callback?: RealtimeCallback\n\n /**\n * Whether to automatically invalidate queries for the table\n * Default: true\n */\n autoInvalidate?: boolean\n\n /**\n * Custom query key to invalidate (if autoInvalidate is true)\n * Default: ['fluxbase', 'table', tableName]\n */\n invalidateKey?: unknown[]\n\n /**\n * Whether the subscription is enabled\n * Default: true\n */\n enabled?: boolean\n}\n\n/**\n * Hook to subscribe to realtime changes for a channel\n */\nexport function useRealtime(options: UseRealtimeOptions) {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n const channelRef = useRef<ReturnType<typeof client.realtime.channel> | null>(null)\n\n const {\n channel: channelName,\n event = '*',\n callback,\n autoInvalidate = true,\n invalidateKey,\n enabled = true,\n } = options\n\n useEffect(() => {\n if (!enabled) {\n return\n }\n\n // Create channel and subscribe\n const channel = client.realtime.channel(channelName)\n channelRef.current = channel\n\n const handleChange = (payload: RealtimeChangePayload) => {\n // Call user callback\n if (callback) {\n callback(payload)\n }\n\n // Auto-invalidate queries if enabled\n if (autoInvalidate) {\n // Extract table name from channel (e.g., 'table:public.products' -> 'public.products')\n const tableName = channelName.replace(/^table:/, '')\n\n const key = invalidateKey || ['fluxbase', 'table', tableName]\n queryClient.invalidateQueries({ queryKey: key })\n }\n }\n\n channel.on(event, handleChange).subscribe()\n\n return () => {\n channel.unsubscribe()\n channelRef.current = null\n }\n }, [client, channelName, event, callback, autoInvalidate, invalidateKey, queryClient, enabled])\n\n return {\n channel: channelRef.current,\n }\n}\n\n/**\n * Hook to subscribe to a table's changes\n * @param table - Table name (with optional schema, e.g., 'public.products')\n * @param options - Subscription options\n */\nexport function useTableSubscription(\n table: string,\n options?: Omit<UseRealtimeOptions, 'channel'>\n) {\n return useRealtime({\n ...options,\n channel: `table:${table}`,\n })\n}\n\n/**\n * Hook to subscribe to INSERT events on a table\n */\nexport function useTableInserts(\n table: string,\n callback: (payload: RealtimeChangePayload) => void,\n options?: Omit<UseRealtimeOptions, 'channel' | 'event' | 'callback'>\n) {\n return useRealtime({\n ...options,\n channel: `table:${table}`,\n event: 'INSERT',\n callback,\n })\n}\n\n/**\n * Hook to subscribe to UPDATE events on a table\n */\nexport function useTableUpdates(\n table: string,\n callback: (payload: RealtimeChangePayload) => void,\n options?: Omit<UseRealtimeOptions, 'channel' | 'event' | 'callback'>\n) {\n return useRealtime({\n ...options,\n channel: `table:${table}`,\n event: 'UPDATE',\n callback,\n })\n}\n\n/**\n * Hook to subscribe to DELETE events on a table\n */\nexport function useTableDeletes(\n table: string,\n callback: (payload: RealtimeChangePayload) => void,\n options?: Omit<UseRealtimeOptions, 'channel' | 'event' | 'callback'>\n) {\n return useRealtime({\n ...options,\n channel: `table:${table}`,\n event: 'DELETE',\n callback,\n })\n}\n","/**\n * Storage hooks for Fluxbase SDK\n */\n\nimport { useMutation, useQuery, useQueryClient, type UseQueryOptions } from '@tanstack/react-query'\nimport { useFluxbaseClient } from './context'\nimport type { ListOptions, UploadOptions } from '@fluxbase/sdk'\n\n/**\n * Hook to list files in a bucket\n */\nexport function useStorageList(\n bucket: string,\n options?: ListOptions & Omit<UseQueryOptions<any[], Error>, 'queryKey' | 'queryFn'>\n) {\n const client = useFluxbaseClient()\n const { prefix, limit, offset, ...queryOptions } = options || {}\n\n return useQuery({\n queryKey: ['fluxbase', 'storage', bucket, 'list', { prefix, limit, offset }],\n queryFn: async () => {\n const { data, error } = await client.storage.from(bucket).list({ prefix, limit, offset })\n\n if (error) {\n throw error\n }\n\n return data || []\n },\n ...queryOptions,\n })\n}\n\n/**\n * Hook to upload a file to a bucket\n */\nexport function useStorageUpload(bucket: string) {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (params: {\n path: string\n file: File | Blob | ArrayBuffer\n options?: UploadOptions\n }) => {\n const { path, file, options } = params\n const { data, error } = await client.storage.from(bucket).upload(path, file, options)\n\n if (error) {\n throw error\n }\n\n return data\n },\n onSuccess: () => {\n // Invalidate list queries for this bucket\n queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', bucket, 'list'] })\n },\n })\n}\n\n/**\n * Hook to download a file from a bucket\n */\nexport function useStorageDownload(bucket: string, path: string | null, enabled = true) {\n const client = useFluxbaseClient()\n\n return useQuery({\n queryKey: ['fluxbase', 'storage', bucket, 'download', path],\n queryFn: async () => {\n if (!path) {\n return null\n }\n\n const { data, error } = await client.storage.from(bucket).download(path)\n\n if (error) {\n throw error\n }\n\n return data\n },\n enabled: enabled && !!path,\n })\n}\n\n/**\n * Hook to delete files from a bucket\n */\nexport function useStorageDelete(bucket: string) {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (paths: string[]) => {\n const { error } = await client.storage.from(bucket).remove(paths)\n\n if (error) {\n throw error\n }\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', bucket, 'list'] })\n },\n })\n}\n\n/**\n * Hook to get a public URL for a file\n */\nexport function useStoragePublicUrl(bucket: string, path: string | null) {\n const client = useFluxbaseClient()\n\n if (!path) {\n return null\n }\n\n const { data } = client.storage.from(bucket).getPublicUrl(path)\n return data.publicUrl\n}\n\n/**\n * Hook to create a signed URL\n */\nexport function useStorageSignedUrl(bucket: string, path: string | null, expiresIn?: number) {\n const client = useFluxbaseClient()\n\n return useQuery({\n queryKey: ['fluxbase', 'storage', bucket, 'signed-url', path, expiresIn],\n queryFn: async () => {\n if (!path) {\n return null\n }\n\n const { data, error } = await client.storage.from(bucket).createSignedUrl(path, { expiresIn })\n\n if (error) {\n throw error\n }\n\n return data?.signedUrl || null\n },\n enabled: !!path,\n staleTime: expiresIn ? expiresIn * 1000 - 60000 : 1000 * 60 * 50, // Refresh 1 minute before expiry\n })\n}\n\n/**\n * Hook to move a file\n */\nexport function useStorageMove(bucket: string) {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (params: { fromPath: string; toPath: string }) => {\n const { fromPath, toPath } = params\n const { data, error } = await client.storage.from(bucket).move(fromPath, toPath)\n\n if (error) {\n throw error\n }\n\n return data\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', bucket, 'list'] })\n },\n })\n}\n\n/**\n * Hook to copy a file\n */\nexport function useStorageCopy(bucket: string) {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (params: { fromPath: string; toPath: string }) => {\n const { fromPath, toPath } = params\n const { data, error } = await client.storage.from(bucket).copy(fromPath, toPath)\n\n if (error) {\n throw error\n }\n\n return data\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', bucket, 'list'] })\n },\n })\n}\n\n/**\n * Hook to manage buckets\n */\nexport function useStorageBuckets() {\n const client = useFluxbaseClient()\n\n return useQuery({\n queryKey: ['fluxbase', 'storage', 'buckets'],\n queryFn: async () => {\n const { data, error } = await client.storage.listBuckets()\n\n if (error) {\n throw error\n }\n\n return data || []\n },\n })\n}\n\n/**\n * Hook to create a bucket\n */\nexport function useCreateBucket() {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (bucketName: string) => {\n const { error } = await client.storage.createBucket(bucketName)\n\n if (error) {\n throw error\n }\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', 'buckets'] })\n },\n })\n}\n\n/**\n * Hook to delete a bucket\n */\nexport function useDeleteBucket() {\n const client = useFluxbaseClient()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: async (bucketName: string) => {\n const { error } = await client.storage.deleteBucket(bucketName)\n\n if (error) {\n throw error\n }\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['fluxbase', 'storage', 'buckets'] })\n },\n })\n}\n","/**\n * React hooks for RPC (Remote Procedure Calls)\n * Call PostgreSQL functions with React Query integration\n */\n\nimport { useQuery, useMutation, useQueryClient, type UseQueryOptions, type UseMutationOptions } from '@tanstack/react-query'\nimport { useFluxbaseClient } from './context'\nimport type { PostgrestResponse } from '@fluxbase/sdk'\n\n/**\n * Hook to call a PostgreSQL function and cache the result\n *\n * @example\n * ```tsx\n * const { data, isLoading, error } = useRPC(\n * 'calculate_total',\n * { order_id: 123 },\n * { enabled: !!orderId }\n * )\n * ```\n */\nexport function useRPC<TData = unknown, TParams extends Record<string, unknown> = Record<string, unknown>>(\n functionName: string,\n params?: TParams,\n options?: Omit<UseQueryOptions<TData, Error>, 'queryKey' | 'queryFn'>\n) {\n const client = useFluxbaseClient()\n\n return useQuery<TData, Error>({\n queryKey: ['rpc', functionName, params],\n queryFn: async () => {\n const { data, error } = await client.rpc<TData>(functionName, params)\n if (error) {\n throw new Error(error.message)\n }\n return data as TData\n },\n ...options,\n })\n}\n\n/**\n * Hook to create a mutation for calling PostgreSQL functions\n * Useful for functions that modify data\n *\n * @example\n * ```tsx\n * const createOrder = useRPCMutation('create_order')\n *\n * const handleSubmit = async () => {\n * await createOrder.mutateAsync({\n * user_id: 123,\n * items: [{ product_id: 1, quantity: 2 }]\n * })\n * }\n * ```\n */\nexport function useRPCMutation<TData = unknown, TParams extends Record<string, unknown> = Record<string, unknown>>(\n functionName: string,\n options?: Omit<UseMutationOptions<TData, Error, TParams>, 'mutationFn'>\n) {\n const client = useFluxbaseClient()\n\n return useMutation<TData, Error, TParams>({\n mutationFn: async (params: TParams) => {\n const { data, error } = await client.rpc<TData>(functionName, params)\n if (error) {\n throw new Error(error.message)\n }\n return data as TData\n },\n ...options,\n })\n}\n\n/**\n * Hook to call multiple RPC functions in parallel\n *\n * @example\n * ```tsx\n * const { data, isLoading } = useRPCBatch([\n * { name: 'get_user_stats', params: { user_id: 123 } },\n * { name: 'get_recent_orders', params: { limit: 10 } },\n * ])\n * ```\n */\nexport function useRPCBatch<TData = unknown>(\n calls: Array<{ name: string; params?: Record<string, unknown> }>,\n options?: Omit<UseQueryOptions<TData[], Error, TData[], readonly unknown[]>, 'queryKey' | 'queryFn'>\n) {\n const client = useFluxbaseClient()\n\n return useQuery({\n queryKey: ['rpc-batch', calls] as const,\n queryFn: async () => {\n const results = await Promise.all(\n calls.map(async ({ name, params }) => {\n const { data, error } = await client.rpc<TData>(name, params)\n if (error) {\n throw new Error(`${name}: ${error.message}`)\n }\n return data\n })\n )\n return results as TData[]\n },\n ...options,\n })\n}\n","import { useState, useEffect, useCallback } from 'react'\nimport { useFluxbaseClient } from './context'\nimport type { AdminAuthResponse } from '@fluxbase/sdk'\n\n/**\n * Simplified admin user type returned by authentication\n */\nexport interface AdminUser {\n id: string\n email: string\n role: string\n}\n\nexport interface UseAdminAuthOptions {\n /**\n * Automatically check authentication status on mount\n * @default true\n */\n autoCheck?: boolean\n}\n\nexport interface UseAdminAuthReturn {\n /**\n * Current admin user if authenticated\n */\n user: AdminUser | null\n\n /**\n * Whether the admin is authenticated\n */\n isAuthenticated: boolean\n\n /**\n * Whether the authentication check is in progress\n */\n isLoading: boolean\n\n /**\n * Any error that occurred during authentication\n */\n error: Error | null\n\n /**\n * Login as admin\n */\n login: (email: string, password: string) => Promise<AdminAuthResponse>\n\n /**\n * Logout admin\n */\n logout: () => Promise<void>\n\n /**\n * Refresh admin user info\n */\n refresh: () => Promise<void>\n}\n\n/**\n * Hook for admin authentication\n *\n * Manages admin login state, authentication checks, and user info.\n *\n * @example\n * ```tsx\n * function AdminLogin() {\n * const { user, isAuthenticated, isLoading, login, logout } = useAdminAuth()\n *\n * const handleLogin = async (e: React.FormEvent) => {\n * e.preventDefault()\n * await login(email, password)\n * }\n *\n * if (isLoading) return <div>Loading...</div>\n * if (isAuthenticated) return <div>Welcome {user?.email}</div>\n *\n * return <form onSubmit={handleLogin}>...</form>\n * }\n * ```\n */\nexport function useAdminAuth(options: UseAdminAuthOptions = {}): UseAdminAuthReturn {\n const { autoCheck = true } = options\n const client = useFluxbaseClient()\n\n const [user, setUser] = useState<AdminUser | null>(null)\n const [isLoading, setIsLoading] = useState(autoCheck)\n const [error, setError] = useState<Error | null>(null)\n\n /**\n * Check current authentication status\n */\n const checkAuth = useCallback(async () => {\n try {\n setIsLoading(true)\n setError(null)\n const { user } = await client.admin.me()\n setUser(user)\n } catch (err) {\n setUser(null)\n setError(err as Error)\n } finally {\n setIsLoading(false)\n }\n }, [client])\n\n /**\n * Login as admin\n */\n const login = useCallback(\n async (email: string, password: string): Promise<AdminAuthResponse> => {\n try {\n setIsLoading(true)\n setError(null)\n const response = await client.admin.login({ email, password })\n setUser(response.user)\n return response\n } catch (err) {\n setError(err as Error)\n throw err\n } finally {\n setIsLoading(false)\n }\n },\n [client]\n )\n\n /**\n * Logout admin\n */\n const logout = useCallback(async (): Promise<void> => {\n try {\n setIsLoading(true)\n setError(null)\n // Clear user state\n setUser(null)\n // Note: Add logout endpoint call here when available\n } catch (err) {\n setError(err as Error)\n throw err\n } finally {\n setIsLoading(false)\n }\n }, [])\n\n /**\n * Refresh admin user info\n */\n const refresh = useCallback(async (): Promise<void> => {\n await checkAuth()\n }, [checkAuth])\n\n // Auto-check authentication on mount\n useEffect(() => {\n if (autoCheck) {\n checkAuth()\n }\n }, [autoCheck, checkAuth])\n\n return {\n user,\n isAuthenticated: user !== null,\n isLoading,\n error,\n login,\n logout,\n refresh\n }\n}\n","import { useState, useEffect, useCallback } from 'react'\nimport { useFluxbaseClient } from './context'\nimport type { EnrichedUser, ListUsersOptions } from '@fluxbase/sdk'\n\nexport interface UseUsersOptions extends ListUsersOptions {\n /**\n * Whether to automatically fetch users on mount\n * @default true\n */\n autoFetch?: boolean\n\n /**\n * Refetch interval in milliseconds (0 to disable)\n * @default 0\n */\n refetchInterval?: number\n}\n\nexport interface UseUsersReturn {\n /**\n * Array of users\n */\n users: EnrichedUser[]\n\n /**\n * Total number of users (for pagination)\n */\n total: number\n\n /**\n * Whether users are being fetched\n */\n isLoading: boolean\n\n /**\n * Any error that occurred\n */\n error: Error | null\n\n /**\n * Refetch users\n */\n refetch: () => Promise<void>\n\n /**\n * Invite a new user\n */\n inviteUser: (email: string, role: 'user' | 'admin') => Promise<void>\n\n /**\n * Update user role\n */\n updateUserRole: (userId: string, role: 'user' | 'admin') => Promise<void>\n\n /**\n * Delete a user\n */\n deleteUser: (userId: string) => Promise<void>\n\n /**\n * Reset user password\n */\n resetPassword: (userId: string) => Promise<{ message: string }>\n}\n\n/**\n * Hook for managing users\n *\n * Provides user list with pagination, search, and management functions.\n *\n * @example\n * ```tsx\n * function UserList() {\n * const { users, total, isLoading, refetch, inviteUser, deleteUser } = useUsers({\n * limit: 20,\n * search: searchTerm\n * })\n *\n * return (\n * <div>\n * {isLoading ? <Spinner /> : (\n * <ul>\n * {users.map(user => (\n * <li key={user.id}>\n * {user.email} - {user.role}\n * <button onClick={() => deleteUser(user.id)}>Delete</button>\n * </li>\n * ))}\n * </ul>\n * )}\n * </div>\n * )\n * }\n * ```\n */\nexport function useUsers(options: UseUsersOptions = {}): UseUsersReturn {\n const { autoFetch = true, refetchInterval = 0, ...listOptions } = options\n const client = useFluxbaseClient()\n\n const [users, setUsers] = useState<EnrichedUser[]>([])\n const [total, setTotal] = useState(0)\n const [isLoading, setIsLoading] = useState(autoFetch)\n const [error, setError] = useState<Error | null>(null)\n\n /**\n * Fetch users from API\n */\n const fetchUsers = useCallback(async () => {\n try {\n setIsLoading(true)\n setError(null)\n const response = await client.admin.listUsers(listOptions)\n setUsers(response.users)\n setTotal(response.total)\n } catch (err) {\n setError(err as Error)\n } finally {\n setIsLoading(false)\n }\n }, [client, JSON.stringify(listOptions)])\n\n /**\n * Invite a new user\n */\n const inviteUser = useCallback(\n async (email: string, role: 'user' | 'admin'): Promise<void> => {\n await client.admin.inviteUser({ email, role })\n await fetchUsers() // Refresh list\n },\n [client, fetchUsers]\n )\n\n /**\n * Update user role\n */\n const updateUserRole = useCallback(\n async (userId: string, role: 'user' | 'admin'): Promise<void> => {\n await client.admin.updateUserRole(userId, role)\n await fetchUsers() // Refresh list\n },\n [client, fetchUsers]\n )\n\n /**\n * Delete a user\n */\n const deleteUser = useCallback(\n async (userId: string): Promise<void> => {\n await client.admin.deleteUser(userId)\n await fetchUsers() // Refresh list\n },\n [client, fetchUsers]\n )\n\n /**\n * Reset user password\n */\n const resetPassword = useCallback(\n async (userId: string): Promise<{ message: string }> => {\n return await client.admin.resetUserPassword(userId)\n },\n [client]\n )\n\n // Auto-fetch on mount\n useEffect(() => {\n if (autoFetch) {\n fetchUsers()\n }\n }, [autoFetch, fetchUsers])\n\n // Set up refetch interval\n useEffect(() => {\n if (refetchInterval > 0) {\n const interval = setInterval(fetchUsers, refetchInterval)\n return () => clearInterval(interval)\n }\n }, [refetchInterval, fetchUsers])\n\n return {\n users,\n total,\n isLoading,\n error,\n refetch: fetchUsers,\n inviteUser,\n updateUserRole,\n deleteUser,\n resetPassword\n }\n}\n","import { useState, useEffect, useCallback } from 'react'\nimport { useFluxbaseClient } from './context'\nimport type { APIKey, CreateAPIKeyRequest } from '@fluxbase/sdk'\n\nexport interface UseAPIKeysOptions {\n /**\n * Whether to automatically fetch API keys on mount\n * @default true\n */\n autoFetch?: boolean\n}\n\nexport interface UseAPIKeysReturn {\n /**\n * Array of API keys\n */\n keys: APIKey[]\n\n /**\n * Whether keys are being fetched\n */\n isLoading: boolean\n\n /**\n * Any error that occurred\n */\n error: Error | null\n\n /**\n * Refetch API keys\n */\n refetch: () => Promise<void>\n\n /**\n * Create a new API key\n */\n createKey: (request: CreateAPIKeyRequest) => Promise<{ key: string; keyData: APIKey }>\n\n /**\n * Update an API key\n */\n updateKey: (keyId: string, update: { name?: string; description?: string }) => Promise<void>\n\n /**\n * Revoke an API key\n */\n revokeKey: (keyId: string) => Promise<void>\n\n /**\n * Delete an API key\n */\n deleteKey: (keyId: string) => Promise<void>\n}\n\n/**\n * Hook for managing API keys\n *\n * Provides API key list and management functions.\n *\n * @example\n * ```tsx\n * function APIKeyManager() {\n * const { keys, isLoading, createKey, revokeKey } = useAPIKeys()\n *\n * const handleCreate = async () => {\n * const { key, keyData } = await createKey({\n * name: 'Backend Service',\n * description: 'API key for backend',\n * expires_at: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString()\n * })\n * alert(`Key created: ${key}`)\n * }\n *\n * return (\n * <div>\n * <button onClick={handleCreate}>Create Key</button>\n * {keys.map(k => (\n * <div key={k.id}>\n * {k.name}\n * <button onClick={() => revokeKey(k.id)}>Revoke</button>\n * </div>\n * ))}\n * </div>\n * )\n * }\n * ```\n */\nexport function useAPIKeys(options: UseAPIKeysOptions = {}): UseAPIKeysReturn {\n const { autoFetch = true } = options\n const client = useFluxbaseClient()\n\n const [keys, setKeys] = useState<APIKey[]>([])\n const [isLoading, setIsLoading] = useState(autoFetch)\n const [error, setError] = useState<Error | null>(null)\n\n /**\n * Fetch API keys from API\n */\n const fetchKeys = useCallback(async () => {\n try {\n setIsLoading(true)\n setError(null)\n const response = await client.admin.management.apiKeys.list()\n setKeys(response.api_keys)\n } catch (err) {\n setError(err as Error)\n } finally {\n setIsLoading(false)\n }\n }, [client])\n\n /**\n * Create a new API key\n */\n const createKey = useCallback(\n async (request: CreateAPIKeyRequest): Promise<{ key: string; keyData: APIKey }> => {\n const response = await client.admin.management.apiKeys.create(request)\n await fetchKeys() // Refresh list\n return { key: response.key, keyData: response.api_key }\n },\n [client, fetchKeys]\n )\n\n /**\n * Update an API key\n */\n const updateKey = useCallback(\n async (keyId: string, update: { name?: string; description?: string }): Promise<void> => {\n await client.admin.management.apiKeys.update(keyId, update)\n await fetchKeys() // Refresh list\n },\n [client, fetchKeys]\n )\n\n /**\n * Revoke an API key\n */\n const revokeKey = useCallback(\n async (keyId: string): Promise<void> => {\n await client.admin.management.apiKeys.revoke(keyId)\n await fetchKeys() // Refresh list\n },\n [client, fetchKeys]\n )\n\n /**\n * Delete an API key\n */\n const deleteKey = useCallback(\n async (keyId: string): Promise<void> => {\n await client.admin.management.apiKeys.delete(keyId)\n await fetchKeys() // Refresh list\n },\n [client, fetchKeys]\n )\n\n // Auto-fetch on mount\n useEffect(() => {\n if (autoFetch) {\n fetchKeys()\n }\n }, [autoFetch, fetchKeys])\n\n return {\n keys,\n isLoading,\n error,\n refetch: fetchKeys,\n createKey,\n updateKey,\n revokeKey,\n deleteKey\n }\n}\n","/**\n * Admin Settings and Management Hooks\n *\n * Hooks for managing application settings, system settings, and webhooks.\n */\n\nimport { useState, useEffect, useCallback } from 'react'\nimport { useFluxbaseClient } from './context'\nimport type {\n AppSettings,\n UpdateAppSettingsRequest,\n SystemSetting,\n UpdateSystemSettingRequest,\n Webhook,\n CreateWebhookRequest,\n UpdateWebhookRequest\n} from '@fluxbase/sdk'\n\n// ============================================================================\n// useAppSettings Hook\n// ============================================================================\n\nexport interface UseAppSettingsOptions {\n autoFetch?: boolean\n}\n\nexport interface UseAppSettingsReturn {\n settings: AppSettings | null\n isLoading: boolean\n error: Error | null\n refetch: () => Promise<void>\n updateSettings: (update: UpdateAppSettingsRequest) => Promise<void>\n}\n\n/**\n * Hook for managing application settings\n *\n * @example\n * ```tsx\n * function SettingsPanel() {\n * const { settings, isLoading, updateSettings } = useAppSettings({ autoFetch: true })\n *\n * const handleToggleFeature = async (feature: string, enabled: boolean) => {\n * await updateSettings({\n * features: { ...settings?.features, [feature]: enabled }\n * })\n * }\n *\n * return <div>...</div>\n * }\n * ```\n */\nexport function useAppSettings(options: UseAppSettingsOptions = {}): UseAppSettingsReturn {\n const { autoFetch = true } = options\n const client = useFluxbaseClient()\n\n const [settings, setSettings] = useState<AppSettings | null>(null)\n const [isLoading, setIsLoading] = useState(autoFetch)\n const [error, setError] = useState<Error | null>(null)\n\n const fetchSettings = useCallback(async () => {\n try {\n setIsLoading(true)\n setError(null)\n const appSettings = await client.admin.settings.app.get()\n setSettings(appSettings)\n } catch (err) {\n setError(err as Error)\n } finally {\n setIsLoading(false)\n }\n }, [client])\n\n const updateSettings = useCallback(\n async (update: UpdateAppSettingsRequest): Promise<void> => {\n await client.admin.settings.app.update(update)\n await fetchSettings()\n },\n [client, fetchSettings]\n )\n\n useEffect(() => {\n if (autoFetch) {\n fetchSettings()\n }\n }, [autoFetch, fetchSettings])\n\n return {\n settings,\n isLoading,\n error,\n refetch: fetchSettings,\n updateSettings\n }\n}\n\n// ============================================================================\n// useSystemSettings Hook\n// ============================================================================\n\nexport interface UseSystemSettingsOptions {\n autoFetch?: boolean\n}\n\nexport interface UseSystemSettingsReturn {\n settings: SystemSetting[]\n isLoading: boolean\n error: Error | null\n refetch: () => Promise<void>\n getSetting: (key: string) => SystemSetting | undefined\n updateSetting: (key: string, update: UpdateSystemSettingRequest) => Promise<void>\n deleteSetting: (key: string) => Promise<void>\n}\n\n/**\n * Hook for managing system settings (key-value storage)\n *\n * @example\n * ```tsx\n * function SystemSettings() {\n * const { settings, isLoading, updateSetting } = useSystemSettings({ autoFetch: true })\n *\n * const handleUpdateSetting = async (key: string, value: any) => {\n * await updateSetting(key, { value })\n * }\n *\n * return <div>...</div>\n * }\n * ```\n */\nexport function useSystemSettings(options: UseSystemSettingsOptions = {}): UseSystemSettingsReturn {\n const { autoFetch = true } = options\n const client = useFluxbaseClient()\n\n const [settings, setSettings] = useState<SystemSetting[]>([])\n const [isLoading, setIsLoading] = useState(autoFetch)\n const [error, setError] = useState<Error | null>(null)\n\n const fetchSettings = useCallback(async () => {\n try {\n setIsLoading(true)\n setError(null)\n const response = await client.admin.settings.system.list()\n setSettings(response.settings)\n } catch (err) {\n setError(err as Error)\n } finally {\n setIsLoading(false)\n }\n }, [client])\n\n const getSetting = useCallback(\n (key: string): SystemSetting | undefined => {\n return settings.find((s) => s.key === key)\n },\n [settings]\n )\n\n const updateSetting = useCallback(\n async (key: string, update: UpdateSystemSettingRequest): Promise<void> => {\n await client.admin.settings.system.update(key, update)\n await fetchSettings()\n },\n [client, fetchSettings]\n )\n\n const deleteSetting = useCallback(\n async (key: string): Promise<void> => {\n await client.admin.settings.system.delete(key)\n await fetchSettings()\n },\n [client, fetchSettings]\n )\n\n useEffect(() => {\n if (autoFetch) {\n fetchSettings()\n }\n }, [autoFetch, fetchSettings])\n\n return {\n settings,\n isLoading,\n error,\n refetch: fetchSettings,\n getSetting,\n updateSetting,\n deleteSetting\n }\n}\n\n// ============================================================================\n// useWebhooks Hook\n// ============================================================================\n\nexport interface UseWebhooksOptions {\n autoFetch?: boolean\n refetchInterval?: number\n}\n\nexport interface UseWebhooksReturn {\n webhooks: Webhook[]\n isLoading: boolean\n error: Error | null\n refetch: () => Promise<void>\n createWebhook: (webhook: CreateWebhookRequest) => Promise<Webhook>\n updateWebhook: (id: string, update: UpdateWebhookRequest) => Promise<Webhook>\n deleteWebhook: (id: string) => Promise<void>\n testWebhook: (id: string) => Promise<void>\n}\n\n/**\n * Hook for managing webhooks\n *\n * @example\n * ```tsx\n * function WebhooksManager() {\n * const { webhooks, isLoading, createWebhook, deleteWebhook } = useWebhooks({\n * autoFetch: true\n * })\n *\n * const handleCreate = async () => {\n * await createWebhook({\n * url: 'https://example.com/webhook',\n * events: ['user.created', 'user.updated'],\n * enabled: true\n * })\n * }\n *\n * return <div>...</div>\n * }\n * ```\n */\nexport function useWebhooks(options: UseWebhooksOptions = {}): UseWebhooksReturn {\n const { autoFetch = true, refetchInterval = 0 } = options\n const client = useFluxbaseClient()\n\n const [webhooks, setWebhooks] = useState<Webhook[]>([])\n const [isLoading, setIsLoading] = useState(autoFetch)\n const [error, setError] = useState<Error | null>(null)\n\n const fetchWebhooks = useCallback(async () => {\n try {\n setIsLoading(true)\n setError(null)\n const response = await client.admin.management.webhooks.list()\n setWebhooks(response.webhooks)\n } catch (err) {\n setError(err as Error)\n } finally {\n setIsLoading(false)\n }\n }, [client])\n\n const createWebhook = useCallback(\n async (webhook: CreateWebhookRequest): Promise<Webhook> => {\n const created = await client.admin.management.webhooks.create(webhook)\n await fetchWebhooks()\n return created\n },\n [client, fetchWebhooks]\n )\n\n const updateWebhook = useCallback(\n async (id: string, update: UpdateWebhookRequest): Promise<Webhook> => {\n const updated = await client.admin.management.webhooks.update(id, update)\n await fetchWebhooks()\n return updated\n },\n [client, fetchWebhooks]\n )\n\n const deleteWebhook = useCallback(\n async (id: string): Promise<void> => {\n await client.admin.management.webhooks.delete(id)\n await fetchWebhooks()\n },\n [client, fetchWebhooks]\n )\n\n const testWebhook = useCallback(\n async (id: string): Promise<void> => {\n await client.admin.management.webhooks.test(id)\n },\n [client]\n )\n\n useEffect(() => {\n if (autoFetch) {\n fetchWebhooks()\n }\n\n if (refetchInterval > 0) {\n const interval = setInterval(fetchWebhooks, refetchInterval)\n return () => clearInterval(interval)\n }\n }, [autoFetch, refetchInterval, fetchWebhooks])\n\n return {\n webhooks,\n isLoading,\n error,\n refetch: fetchWebhooks,\n createWebhook,\n updateWebhook,\n deleteWebhook,\n testWebhook\n }\n}\n"],"mappings":"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