@fluxbase/sdk-react
Version:
React hooks for Fluxbase SDK
926 lines (917 loc) • 25 kB
JavaScript
// 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