UNPKG

@fluxbase/sdk-react

Version:
926 lines (917 loc) 25 kB
// src/context.tsx import { createContext, useContext } from "react"; import { jsx } from "react/jsx-runtime"; var FluxbaseContext = createContext(null); function FluxbaseProvider({ client, children }) { return /* @__PURE__ */ jsx(FluxbaseContext.Provider, { value: client, children }); } function useFluxbaseClient() { const client = useContext(FluxbaseContext); if (!client) { throw new Error("useFluxbaseClient must be used within a FluxbaseProvider"); } return client; } // src/use-auth.ts import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; function useUser() { const client = useFluxbaseClient(); return useQuery({ queryKey: ["fluxbase", "auth", "user"], queryFn: async () => { const session = client.auth.getSession(); if (!session) { return null; } try { return await client.auth.getCurrentUser(); } catch { return null; } }, staleTime: 1e3 * 60 * 5 // 5 minutes }); } function useSession() { const client = useFluxbaseClient(); return useQuery({ queryKey: ["fluxbase", "auth", "session"], queryFn: () => client.auth.getSession(), staleTime: 1e3 * 60 * 5 // 5 minutes }); } function useSignIn() { const client = useFluxbaseClient(); const queryClient = useQueryClient(); return useMutation({ mutationFn: async (credentials) => { return await client.auth.signIn(credentials); }, onSuccess: (session) => { queryClient.setQueryData(["fluxbase", "auth", "session"], session); if ("user" in session) { queryClient.setQueryData(["fluxbase", "auth", "user"], session.user); } } }); } function useSignUp() { const client = useFluxbaseClient(); const queryClient = useQueryClient(); return useMutation({ mutationFn: async (credentials) => { return await client.auth.signUp(credentials); }, onSuccess: (session) => { queryClient.setQueryData(["fluxbase", "auth", "session"], session); queryClient.setQueryData(["fluxbase", "auth", "user"], session.user); } }); } function useSignOut() { const client = useFluxbaseClient(); const queryClient = useQueryClient(); return useMutation({ mutationFn: async () => { await client.auth.signOut(); }, onSuccess: () => { queryClient.setQueryData(["fluxbase", "auth", "session"], null); queryClient.setQueryData(["fluxbase", "auth", "user"], null); queryClient.invalidateQueries({ queryKey: ["fluxbase"] }); } }); } function useUpdateUser() { const client = useFluxbaseClient(); const queryClient = useQueryClient(); return useMutation({ mutationFn: async (data) => { return await client.auth.updateUser(data); }, onSuccess: (user) => { queryClient.setQueryData(["fluxbase", "auth", "user"], user); } }); } function useAuth() { const { data: user, isLoading: isLoadingUser } = useUser(); const { data: session, isLoading: isLoadingSession } = useSession(); const signIn = useSignIn(); const signUp = useSignUp(); const signOut = useSignOut(); const updateUser = useUpdateUser(); return { user, session, isLoading: isLoadingUser || isLoadingSession, isAuthenticated: !!session, signIn: signIn.mutateAsync, signUp: signUp.mutateAsync, signOut: signOut.mutateAsync, updateUser: updateUser.mutateAsync, isSigningIn: signIn.isPending, isSigningUp: signUp.isPending, isSigningOut: signOut.isPending, isUpdating: updateUser.isPending }; } // src/use-query.ts import { useQuery as useQuery2, useMutation as useMutation2, useQueryClient as useQueryClient2 } from "@tanstack/react-query"; function useFluxbaseQuery(buildQuery, options) { const client = useFluxbaseClient(); const queryKey = options?.queryKey || ["fluxbase", "query", buildQuery.toString()]; return useQuery2({ queryKey, queryFn: async () => { const query = buildQuery(client); const { data, error } = await query.execute(); if (error) { throw error; } return Array.isArray(data) ? data : data ? [data] : []; }, ...options }); } function useTable(table, buildQuery, options) { const client = useFluxbaseClient(); return useFluxbaseQuery( (client2) => { const query = client2.from(table); return buildQuery ? buildQuery(query) : query; }, { ...options, queryKey: options?.queryKey || ["fluxbase", "table", table, buildQuery?.toString()] } ); } function useInsert(table) { const client = useFluxbaseClient(); const queryClient = useQueryClient2(); return useMutation2({ mutationFn: async (data) => { const query = client.from(table); const { data: result, error } = await query.insert(data); if (error) { throw error; } return result; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["fluxbase", "table", table] }); } }); } function useUpdate(table) { const client = useFluxbaseClient(); const queryClient = useQueryClient2(); return useMutation2({ mutationFn: async (params) => { const query = client.from(table); const builtQuery = params.buildQuery(query); const { data: result, error } = await builtQuery.update(params.data); if (error) { throw error; } return result; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["fluxbase", "table", table] }); } }); } function useUpsert(table) { const client = useFluxbaseClient(); const queryClient = useQueryClient2(); return useMutation2({ mutationFn: async (data) => { const query = client.from(table); const { data: result, error } = await query.upsert(data); if (error) { throw error; } return result; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["fluxbase", "table", table] }); } }); } function useDelete(table) { const client = useFluxbaseClient(); const queryClient = useQueryClient2(); return useMutation2({ mutationFn: async (buildQuery) => { const query = client.from(table); const builtQuery = buildQuery(query); const { error } = await builtQuery.delete(); if (error) { throw error; } }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["fluxbase", "table", table] }); } }); } // src/use-realtime.ts import { useEffect, useRef } from "react"; import { useQueryClient as useQueryClient3 } from "@tanstack/react-query"; function useRealtime(options) { const client = useFluxbaseClient(); const queryClient = useQueryClient3(); const channelRef = useRef(null); const { channel: channelName, event = "*", callback, autoInvalidate = true, invalidateKey, enabled = true } = options; useEffect(() => { if (!enabled) { return; } const channel = client.realtime.channel(channelName); channelRef.current = channel; const handleChange = (payload) => { if (callback) { callback(payload); } if (autoInvalidate) { const tableName = channelName.replace(/^table:/, ""); const key = invalidateKey || ["fluxbase", "table", tableName]; queryClient.invalidateQueries({ queryKey: key }); } }; channel.on(event, handleChange).subscribe(); return () => { channel.unsubscribe(); channelRef.current = null; }; }, [client, channelName, event, callback, autoInvalidate, invalidateKey, queryClient, enabled]); return { channel: channelRef.current }; } function useTableSubscription(table, options) { return useRealtime({ ...options, channel: `table:${table}` }); } function useTableInserts(table, callback, options) { return useRealtime({ ...options, channel: `table:${table}`, event: "INSERT", callback }); } function useTableUpdates(table, callback, options) { return useRealtime({ ...options, channel: `table:${table}`, event: "UPDATE", callback }); } function useTableDeletes(table, callback, options) { return useRealtime({ ...options, channel: `table:${table}`, event: "DELETE", callback }); } // src/use-storage.ts import { useMutation as useMutation3, useQuery as useQuery3, useQueryClient as useQueryClient4 } from "@tanstack/react-query"; function useStorageList(bucket, options) { const client = useFluxbaseClient(); const { prefix, limit, offset, ...queryOptions } = options || {}; return useQuery3({ queryKey: ["fluxbase", "storage", bucket, "list", { prefix, limit, offset }], queryFn: async () => { const { data, error } = await client.storage.from(bucket).list({ prefix, limit, offset }); if (error) { throw error; } return data || []; }, ...queryOptions }); } function useStorageUpload(bucket) { const client = useFluxbaseClient(); const queryClient = useQueryClient4(); return useMutation3({ mutationFn: async (params) => { const { path, file, options } = params; const { data, error } = await client.storage.from(bucket).upload(path, file, options); if (error) { throw error; } return data; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["fluxbase", "storage", bucket, "list"] }); } }); } function useStorageDownload(bucket, path, enabled = true) { const client = useFluxbaseClient(); return useQuery3({ queryKey: ["fluxbase", "storage", bucket, "download", path], queryFn: async () => { if (!path) { return null; } const { data, error } = await client.storage.from(bucket).download(path); if (error) { throw error; } return data; }, enabled: enabled && !!path }); } function useStorageDelete(bucket) { const client = useFluxbaseClient(); const queryClient = useQueryClient4(); return useMutation3({ mutationFn: async (paths) => { const { error } = await client.storage.from(bucket).remove(paths); if (error) { throw error; } }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["fluxbase", "storage", bucket, "list"] }); } }); } function useStoragePublicUrl(bucket, path) { const client = useFluxbaseClient(); if (!path) { return null; } const { data } = client.storage.from(bucket).getPublicUrl(path); return data.publicUrl; } function useStorageSignedUrl(bucket, path, expiresIn) { const client = useFluxbaseClient(); return useQuery3({ queryKey: ["fluxbase", "storage", bucket, "signed-url", path, expiresIn], queryFn: async () => { if (!path) { return null; } const { data, error } = await client.storage.from(bucket).createSignedUrl(path, { expiresIn }); if (error) { throw error; } return data?.signedUrl || null; }, enabled: !!path, staleTime: expiresIn ? expiresIn * 1e3 - 6e4 : 1e3 * 60 * 50 // Refresh 1 minute before expiry }); } function useStorageMove(bucket) { const client = useFluxbaseClient(); const queryClient = useQueryClient4(); return useMutation3({ mutationFn: async (params) => { const { fromPath, toPath } = params; const { data, error } = await client.storage.from(bucket).move(fromPath, toPath); if (error) { throw error; } return data; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["fluxbase", "storage", bucket, "list"] }); } }); } function useStorageCopy(bucket) { const client = useFluxbaseClient(); const queryClient = useQueryClient4(); return useMutation3({ mutationFn: async (params) => { const { fromPath, toPath } = params; const { data, error } = await client.storage.from(bucket).copy(fromPath, toPath); if (error) { throw error; } return data; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["fluxbase", "storage", bucket, "list"] }); } }); } function useStorageBuckets() { const client = useFluxbaseClient(); return useQuery3({ queryKey: ["fluxbase", "storage", "buckets"], queryFn: async () => { const { data, error } = await client.storage.listBuckets(); if (error) { throw error; } return data || []; } }); } function useCreateBucket() { const client = useFluxbaseClient(); const queryClient = useQueryClient4(); return useMutation3({ mutationFn: async (bucketName) => { const { error } = await client.storage.createBucket(bucketName); if (error) { throw error; } }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["fluxbase", "storage", "buckets"] }); } }); } function useDeleteBucket() { const client = useFluxbaseClient(); const queryClient = useQueryClient4(); return useMutation3({ mutationFn: async (bucketName) => { const { error } = await client.storage.deleteBucket(bucketName); if (error) { throw error; } }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["fluxbase", "storage", "buckets"] }); } }); } // src/use-rpc.ts import { useQuery as useQuery4, useMutation as useMutation4 } from "@tanstack/react-query"; function useRPC(functionName, params, options) { const client = useFluxbaseClient(); return useQuery4({ queryKey: ["rpc", functionName, params], queryFn: async () => { const { data, error } = await client.rpc(functionName, params); if (error) { throw new Error(error.message); } return data; }, ...options }); } function useRPCMutation(functionName, options) { const client = useFluxbaseClient(); return useMutation4({ mutationFn: async (params) => { const { data, error } = await client.rpc(functionName, params); if (error) { throw new Error(error.message); } return data; }, ...options }); } function useRPCBatch(calls, options) { const client = useFluxbaseClient(); return useQuery4({ queryKey: ["rpc-batch", calls], queryFn: async () => { const results = await Promise.all( calls.map(async ({ name, params }) => { const { data, error } = await client.rpc(name, params); if (error) { throw new Error(`${name}: ${error.message}`); } return data; }) ); return results; }, ...options }); } // src/use-admin-auth.ts import { useState, useEffect as useEffect2, useCallback } from "react"; function useAdminAuth(options = {}) { const { autoCheck = true } = options; const client = useFluxbaseClient(); const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(autoCheck); const [error, setError] = useState(null); const checkAuth = useCallback(async () => { try { setIsLoading(true); setError(null); const { user: user2 } = await client.admin.me(); setUser(user2); } catch (err) { setUser(null); setError(err); } finally { setIsLoading(false); } }, [client]); const login = useCallback( async (email, password) => { try { setIsLoading(true); setError(null); const response = await client.admin.login({ email, password }); setUser(response.user); return response; } catch (err) { setError(err); throw err; } finally { setIsLoading(false); } }, [client] ); const logout = useCallback(async () => { try { setIsLoading(true); setError(null); setUser(null); } catch (err) { setError(err); throw err; } finally { setIsLoading(false); } }, []); const refresh = useCallback(async () => { await checkAuth(); }, [checkAuth]); useEffect2(() => { if (autoCheck) { checkAuth(); } }, [autoCheck, checkAuth]); return { user, isAuthenticated: user !== null, isLoading, error, login, logout, refresh }; } // src/use-users.ts import { useState as useState2, useEffect as useEffect3, useCallback as useCallback2 } from "react"; function useUsers(options = {}) { const { autoFetch = true, refetchInterval = 0, ...listOptions } = options; const client = useFluxbaseClient(); const [users, setUsers] = useState2([]); const [total, setTotal] = useState2(0); const [isLoading, setIsLoading] = useState2(autoFetch); const [error, setError] = useState2(null); const fetchUsers = useCallback2(async () => { try { setIsLoading(true); setError(null); const response = await client.admin.listUsers(listOptions); setUsers(response.users); setTotal(response.total); } catch (err) { setError(err); } finally { setIsLoading(false); } }, [client, JSON.stringify(listOptions)]); const inviteUser = useCallback2( async (email, role) => { await client.admin.inviteUser({ email, role }); await fetchUsers(); }, [client, fetchUsers] ); const updateUserRole = useCallback2( async (userId, role) => { await client.admin.updateUserRole(userId, role); await fetchUsers(); }, [client, fetchUsers] ); const deleteUser = useCallback2( async (userId) => { await client.admin.deleteUser(userId); await fetchUsers(); }, [client, fetchUsers] ); const resetPassword = useCallback2( async (userId) => { return await client.admin.resetUserPassword(userId); }, [client] ); useEffect3(() => { if (autoFetch) { fetchUsers(); } }, [autoFetch, fetchUsers]); useEffect3(() => { if (refetchInterval > 0) { const interval = setInterval(fetchUsers, refetchInterval); return () => clearInterval(interval); } }, [refetchInterval, fetchUsers]); return { users, total, isLoading, error, refetch: fetchUsers, inviteUser, updateUserRole, deleteUser, resetPassword }; } // src/use-api-keys.ts import { useState as useState3, useEffect as useEffect4, useCallback as useCallback3 } from "react"; function useAPIKeys(options = {}) { const { autoFetch = true } = options; const client = useFluxbaseClient(); const [keys, setKeys] = useState3([]); const [isLoading, setIsLoading] = useState3(autoFetch); const [error, setError] = useState3(null); const fetchKeys = useCallback3(async () => { try { setIsLoading(true); setError(null); const response = await client.admin.management.apiKeys.list(); setKeys(response.api_keys); } catch (err) { setError(err); } finally { setIsLoading(false); } }, [client]); const createKey = useCallback3( async (request) => { const response = await client.admin.management.apiKeys.create(request); await fetchKeys(); return { key: response.key, keyData: response.api_key }; }, [client, fetchKeys] ); const updateKey = useCallback3( async (keyId, update) => { await client.admin.management.apiKeys.update(keyId, update); await fetchKeys(); }, [client, fetchKeys] ); const revokeKey = useCallback3( async (keyId) => { await client.admin.management.apiKeys.revoke(keyId); await fetchKeys(); }, [client, fetchKeys] ); const deleteKey = useCallback3( async (keyId) => { await client.admin.management.apiKeys.delete(keyId); await fetchKeys(); }, [client, fetchKeys] ); useEffect4(() => { if (autoFetch) { fetchKeys(); } }, [autoFetch, fetchKeys]); return { keys, isLoading, error, refetch: fetchKeys, createKey, updateKey, revokeKey, deleteKey }; } // src/use-admin-hooks.ts import { useState as useState4, useEffect as useEffect5, useCallback as useCallback4 } from "react"; function useAppSettings(options = {}) { const { autoFetch = true } = options; const client = useFluxbaseClient(); const [settings, setSettings] = useState4(null); const [isLoading, setIsLoading] = useState4(autoFetch); const [error, setError] = useState4(null); const fetchSettings = useCallback4(async () => { try { setIsLoading(true); setError(null); const appSettings = await client.admin.settings.app.get(); setSettings(appSettings); } catch (err) { setError(err); } finally { setIsLoading(false); } }, [client]); const updateSettings = useCallback4( async (update) => { await client.admin.settings.app.update(update); await fetchSettings(); }, [client, fetchSettings] ); useEffect5(() => { if (autoFetch) { fetchSettings(); } }, [autoFetch, fetchSettings]); return { settings, isLoading, error, refetch: fetchSettings, updateSettings }; } function useSystemSettings(options = {}) { const { autoFetch = true } = options; const client = useFluxbaseClient(); const [settings, setSettings] = useState4([]); const [isLoading, setIsLoading] = useState4(autoFetch); const [error, setError] = useState4(null); const fetchSettings = useCallback4(async () => { try { setIsLoading(true); setError(null); const response = await client.admin.settings.system.list(); setSettings(response.settings); } catch (err) { setError(err); } finally { setIsLoading(false); } }, [client]); const getSetting = useCallback4( (key) => { return settings.find((s) => s.key === key); }, [settings] ); const updateSetting = useCallback4( async (key, update) => { await client.admin.settings.system.update(key, update); await fetchSettings(); }, [client, fetchSettings] ); const deleteSetting = useCallback4( async (key) => { await client.admin.settings.system.delete(key); await fetchSettings(); }, [client, fetchSettings] ); useEffect5(() => { if (autoFetch) { fetchSettings(); } }, [autoFetch, fetchSettings]); return { settings, isLoading, error, refetch: fetchSettings, getSetting, updateSetting, deleteSetting }; } function useWebhooks(options = {}) { const { autoFetch = true, refetchInterval = 0 } = options; const client = useFluxbaseClient(); const [webhooks, setWebhooks] = useState4([]); const [isLoading, setIsLoading] = useState4(autoFetch); const [error, setError] = useState4(null); const fetchWebhooks = useCallback4(async () => { try { setIsLoading(true); setError(null); const response = await client.admin.management.webhooks.list(); setWebhooks(response.webhooks); } catch (err) { setError(err); } finally { setIsLoading(false); } }, [client]); const createWebhook = useCallback4( async (webhook) => { const created = await client.admin.management.webhooks.create(webhook); await fetchWebhooks(); return created; }, [client, fetchWebhooks] ); const updateWebhook = useCallback4( async (id, update) => { const updated = await client.admin.management.webhooks.update(id, update); await fetchWebhooks(); return updated; }, [client, fetchWebhooks] ); const deleteWebhook = useCallback4( async (id) => { await client.admin.management.webhooks.delete(id); await fetchWebhooks(); }, [client, fetchWebhooks] ); const testWebhook = useCallback4( async (id) => { await client.admin.management.webhooks.test(id); }, [client] ); useEffect5(() => { if (autoFetch) { fetchWebhooks(); } if (refetchInterval > 0) { const interval = setInterval(fetchWebhooks, refetchInterval); return () => clearInterval(interval); } }, [autoFetch, refetchInterval, fetchWebhooks]); return { webhooks, isLoading, error, refetch: fetchWebhooks, createWebhook, updateWebhook, deleteWebhook, testWebhook }; } export { FluxbaseProvider, useAPIKeys, useAdminAuth, useAppSettings, useAuth, useCreateBucket, useDelete, useDeleteBucket, useFluxbaseClient, useFluxbaseQuery, useInsert, useRPC, useRPCBatch, useRPCMutation, useRealtime, useSession, useSignIn, useSignOut, useSignUp, useStorageBuckets, useStorageCopy, useStorageDelete, useStorageDownload, useStorageList, useStorageMove, useStoragePublicUrl, useStorageSignedUrl, useStorageUpload, useSystemSettings, useTable, useTableDeletes, useTableInserts, useTableSubscription, useTableUpdates, useUpdate, useUpdateUser, useUpsert, useUser, useUsers, useWebhooks }; //# sourceMappingURL=index.mjs.map