@mimdb/react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ MimDBProvider: () => MimDBProvider,
24
+ useAuth: () => useAuth,
25
+ useClient: () => useClient,
26
+ useDelete: () => useDelete,
27
+ useInsert: () => useInsert,
28
+ useQuery: () => useQuery,
29
+ useRealtime: () => useRealtime,
30
+ useUpdate: () => useUpdate,
31
+ useUpload: () => useUpload
32
+ });
33
+ module.exports = __toCommonJS(index_exports);
34
+
35
+ // src/context.ts
36
+ var import_react = require("react");
37
+ var MimDBContext = (0, import_react.createContext)(null);
38
+ function useClient() {
39
+ const client = (0, import_react.useContext)(MimDBContext);
40
+ if (!client) {
41
+ throw new Error("useClient must be used within <MimDBProvider>");
42
+ }
43
+ return client;
44
+ }
45
+
46
+ // src/provider.tsx
47
+ var import_jsx_runtime = require("react/jsx-runtime");
48
+ function MimDBProvider({ client, children }) {
49
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MimDBContext.Provider, { value: client, children });
50
+ }
51
+
52
+ // src/use-query.ts
53
+ var import_react_query = require("@tanstack/react-query");
54
+ function useQuery(table, options) {
55
+ const client = useClient();
56
+ return (0, import_react_query.useQuery)({
57
+ queryKey: ["mimdb", table, options],
58
+ queryFn: async () => {
59
+ let query = client.from(table).select(options?.select ?? "*");
60
+ if (options?.eq) {
61
+ for (const [col, val] of Object.entries(options.eq)) {
62
+ query = query.eq(col, val);
63
+ }
64
+ }
65
+ if (options?.neq) {
66
+ for (const [col, val] of Object.entries(options.neq)) {
67
+ query = query.neq(col, val);
68
+ }
69
+ }
70
+ if (options?.order) {
71
+ query = query.order(options.order.column, {
72
+ ascending: options.order.ascending
73
+ });
74
+ }
75
+ if (options?.limit) query = query.limit(options.limit);
76
+ if (options?.offset) query = query.offset(options.offset);
77
+ const { data, error } = await query;
78
+ if (error) throw error;
79
+ return data ?? [];
80
+ },
81
+ enabled: options?.enabled,
82
+ staleTime: options?.staleTime,
83
+ refetchInterval: options?.refetchInterval
84
+ });
85
+ }
86
+
87
+ // src/use-mutation.ts
88
+ var import_react_query2 = require("@tanstack/react-query");
89
+ function useInsert(table) {
90
+ const client = useClient();
91
+ const queryClient = (0, import_react_query2.useQueryClient)();
92
+ return (0, import_react_query2.useMutation)({
93
+ mutationFn: async (data) => {
94
+ const { data: result, error } = await client.from(table).insert(data).select().single();
95
+ if (error) throw error;
96
+ return result;
97
+ },
98
+ onSuccess: () => {
99
+ queryClient.invalidateQueries({ queryKey: ["mimdb", table] });
100
+ }
101
+ });
102
+ }
103
+ function useUpdate(table) {
104
+ const client = useClient();
105
+ const queryClient = (0, import_react_query2.useQueryClient)();
106
+ return (0, import_react_query2.useMutation)({
107
+ mutationFn: async ({ data, eq }) => {
108
+ let query = client.from(table).update(data);
109
+ for (const [col, val] of Object.entries(eq)) {
110
+ query = query.eq(col, val);
111
+ }
112
+ const { data: result, error } = await query.select().single();
113
+ if (error) throw error;
114
+ return result;
115
+ },
116
+ onSuccess: () => {
117
+ queryClient.invalidateQueries({ queryKey: ["mimdb", table] });
118
+ }
119
+ });
120
+ }
121
+ function useDelete(table) {
122
+ const client = useClient();
123
+ const queryClient = (0, import_react_query2.useQueryClient)();
124
+ return (0, import_react_query2.useMutation)({
125
+ mutationFn: async (eq) => {
126
+ let query = client.from(table).delete();
127
+ for (const [col, val] of Object.entries(eq)) {
128
+ query = query.eq(col, val);
129
+ }
130
+ const { error } = await query;
131
+ if (error) throw error;
132
+ },
133
+ onSuccess: () => {
134
+ queryClient.invalidateQueries({ queryKey: ["mimdb", table] });
135
+ }
136
+ });
137
+ }
138
+
139
+ // src/use-realtime.ts
140
+ var import_react2 = require("react");
141
+ var import_react_query3 = require("@tanstack/react-query");
142
+ var import_realtime = require("@mimdb/realtime");
143
+ function useRealtime(table, options) {
144
+ const client = useClient();
145
+ const queryClient = (0, import_react_query3.useQueryClient)();
146
+ const [status, setStatus] = (0, import_react2.useState)("pending");
147
+ const realtimeRef = (0, import_react2.useRef)(null);
148
+ (0, import_react2.useEffect)(() => {
149
+ const config = client.getConfig();
150
+ if (!realtimeRef.current) {
151
+ realtimeRef.current = new import_realtime.MimDBRealtimeClient({
152
+ url: config.url,
153
+ projectRef: config.ref,
154
+ apiKey: config.apiKey
155
+ });
156
+ }
157
+ const sub = realtimeRef.current.subscribe(table, {
158
+ event: options?.event ?? "*",
159
+ filter: options?.filter,
160
+ onEvent(event) {
161
+ options?.onEvent?.(event);
162
+ if (options?.invalidateQueries !== false) {
163
+ queryClient.invalidateQueries({ queryKey: ["mimdb", table] });
164
+ }
165
+ },
166
+ onSubscribed() {
167
+ setStatus("active");
168
+ },
169
+ onError() {
170
+ setStatus("error");
171
+ }
172
+ });
173
+ setStatus("pending");
174
+ return () => {
175
+ sub.unsubscribe();
176
+ setStatus("closed");
177
+ };
178
+ }, [table, options?.event, options?.filter]);
179
+ return { status };
180
+ }
181
+
182
+ // src/use-auth.ts
183
+ var import_react3 = require("react");
184
+ function useAuth() {
185
+ const client = useClient();
186
+ const [user, setUser] = (0, import_react3.useState)(null);
187
+ const [isLoading, setIsLoading] = (0, import_react3.useState)(true);
188
+ (0, import_react3.useEffect)(() => {
189
+ const session = client.auth.getSession();
190
+ if (session) {
191
+ client.auth.getUser().then(setUser).catch(() => setUser(null)).finally(() => setIsLoading(false));
192
+ } else {
193
+ setIsLoading(false);
194
+ }
195
+ const unsub = client.auth.onAuthStateChange((event, _session) => {
196
+ if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED") {
197
+ client.auth.getUser().then(setUser).catch(() => setUser(null));
198
+ } else if (event === "SIGNED_OUT") {
199
+ setUser(null);
200
+ }
201
+ });
202
+ return unsub;
203
+ }, [client]);
204
+ const signIn = (0, import_react3.useCallback)(
205
+ async (email, password) => {
206
+ await client.auth.signIn(email, password);
207
+ },
208
+ [client]
209
+ );
210
+ const signUp = (0, import_react3.useCallback)(
211
+ async (email, password) => {
212
+ await client.auth.signUp(email, password);
213
+ },
214
+ [client]
215
+ );
216
+ const signOut = (0, import_react3.useCallback)(async () => {
217
+ await client.auth.signOut();
218
+ }, [client]);
219
+ const signInWithOAuth = (0, import_react3.useCallback)(
220
+ (provider, opts) => {
221
+ const url = client.auth.signInWithOAuth(provider, opts);
222
+ window.location.href = url;
223
+ },
224
+ [client]
225
+ );
226
+ return { user, isLoading, signIn, signUp, signOut, signInWithOAuth };
227
+ }
228
+
229
+ // src/use-upload.ts
230
+ var import_react4 = require("react");
231
+ function useUpload(bucket) {
232
+ const client = useClient();
233
+ const [isUploading, setIsUploading] = (0, import_react4.useState)(false);
234
+ const [error, setError] = (0, import_react4.useState)(null);
235
+ const upload = (0, import_react4.useCallback)(
236
+ async (path, file, opts) => {
237
+ setIsUploading(true);
238
+ setError(null);
239
+ try {
240
+ await client.storage.from(bucket).upload(path, file, opts);
241
+ } catch (err) {
242
+ const uploadError = err instanceof Error ? err : new Error(String(err));
243
+ setError(uploadError);
244
+ throw uploadError;
245
+ } finally {
246
+ setIsUploading(false);
247
+ }
248
+ },
249
+ [client, bucket]
250
+ );
251
+ return { upload, isUploading, error };
252
+ }
253
+ // Annotate the CommonJS export names for ESM import in node:
254
+ 0 && (module.exports = {
255
+ MimDBProvider,
256
+ useAuth,
257
+ useClient,
258
+ useDelete,
259
+ useInsert,
260
+ useQuery,
261
+ useRealtime,
262
+ useUpdate,
263
+ useUpload
264
+ });
265
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/context.ts","../src/provider.tsx","../src/use-query.ts","../src/use-mutation.ts","../src/use-realtime.ts","../src/use-auth.ts","../src/use-upload.ts"],"sourcesContent":["export { MimDBProvider, type MimDBProviderProps } from './provider'\nexport { useClient } from './context'\nexport { useQuery, type UseQueryOptions } from './use-query'\nexport { useInsert, useUpdate, useDelete, type UpdateInput } from './use-mutation'\nexport { useRealtime, type UseRealtimeOptions } from './use-realtime'\nexport { useAuth, type UseAuthResult } from './use-auth'\nexport { useUpload, type UseUploadResult } from './use-upload'\n","import { createContext, useContext } from 'react'\nimport type { MimDBClient } from '@mimdb/client'\n\n/**\n * React context that holds the MimDB client instance.\n *\n * Consumers should use the {@link useClient} hook rather than accessing\n * this context directly.\n *\n * @internal\n */\nconst MimDBContext = createContext<MimDBClient | null>(null)\n\n/**\n * Retrieve the MimDB client from the nearest `<MimDBProvider>`.\n *\n * @returns The `MimDBClient` instance provided by the enclosing provider.\n * @throws If called outside of a `<MimDBProvider>` tree.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useClient()\n * // Use client.from(), client.auth, etc.\n * }\n * ```\n */\nexport function useClient(): MimDBClient {\n const client = useContext(MimDBContext)\n if (!client) {\n throw new Error('useClient must be used within <MimDBProvider>')\n }\n return client\n}\n\nexport { MimDBContext }\n","import { type ReactNode } from 'react'\nimport { MimDBContext } from './context'\nimport type { MimDBClient } from '@mimdb/client'\n\n/**\n * Props for the {@link MimDBProvider} component.\n */\nexport interface MimDBProviderProps {\n /** A configured `MimDBClient` instance to make available to child components. */\n client: MimDBClient\n /** The React subtree that will have access to the MimDB client. */\n children: ReactNode\n}\n\n/**\n * Context provider that makes a `MimDBClient` available to all descendant\n * components via the {@link useClient} hook.\n *\n * Wrap your application (or a subtree) with this provider and pass a\n * pre-configured client instance.\n *\n * @param props - Provider props containing the client and children.\n *\n * @example\n * ```tsx\n * import { createClient } from '@mimdb/client'\n * import { MimDBProvider } from '@mimdb/react'\n *\n * const client = createClient('https://api.mimdb.dev', 'ref', 'key')\n *\n * function App() {\n * return (\n * <MimDBProvider client={client}>\n * <MyApp />\n * </MimDBProvider>\n * )\n * }\n * ```\n */\nexport function MimDBProvider({ client, children }: MimDBProviderProps) {\n return <MimDBContext.Provider value={client}>{children}</MimDBContext.Provider>\n}\n","import {\n useQuery as useTanstackQuery,\n type UseQueryResult,\n} from '@tanstack/react-query'\nimport { useClient } from './context'\n\n/**\n * Options for the {@link useQuery} hook.\n */\nexport interface UseQueryOptions {\n /** Column selection string (PostgREST format). Defaults to `'*'`. */\n select?: string\n /** Equality filters applied as `query.eq(column, value)`. */\n eq?: Record<string, string>\n /** Not-equal filters applied as `query.neq(column, value)`. */\n neq?: Record<string, string>\n /** Column ordering configuration. */\n order?: { column: string; ascending?: boolean }\n /** Maximum number of rows to return. */\n limit?: number\n /** Number of rows to skip before returning results. */\n offset?: number\n /** Whether the query should execute. Maps to TanStack Query's `enabled`. */\n enabled?: boolean\n /** Duration in ms before cached data is considered stale. */\n staleTime?: number\n /** Polling interval in ms, or `false` to disable. */\n refetchInterval?: number | false\n}\n\n/**\n * Fetch rows from a MimDB table using the REST API, backed by TanStack Query\n * for caching, deduplication, and background refetching.\n *\n * Automatically derives a stable query key from the table name and options\n * so cache invalidation works out of the box with the mutation hooks.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table to query.\n * @param options - Query filters, modifiers, and TanStack Query settings.\n * @returns A TanStack `UseQueryResult` containing the row array and status flags.\n *\n * @example\n * ```tsx\n * const { data, isLoading } = useQuery<Todo>('todos', {\n * eq: { done: 'false' },\n * order: { column: 'created_at', ascending: false },\n * limit: 20,\n * })\n * ```\n */\nexport function useQuery<T = Record<string, unknown>>(\n table: string,\n options?: UseQueryOptions,\n): UseQueryResult<T[], Error> {\n const client = useClient()\n\n return useTanstackQuery({\n queryKey: ['mimdb', table, options],\n queryFn: async () => {\n let query = client.from<T>(table).select(options?.select ?? '*')\n\n if (options?.eq) {\n for (const [col, val] of Object.entries(options.eq)) {\n query = query.eq(col, val)\n }\n }\n if (options?.neq) {\n for (const [col, val] of Object.entries(options.neq)) {\n query = query.neq(col, val)\n }\n }\n if (options?.order) {\n query = query.order(options.order.column, {\n ascending: options.order.ascending,\n })\n }\n if (options?.limit) query = query.limit(options.limit)\n if (options?.offset) query = query.offset(options.offset)\n\n const { data, error } = await query\n if (error) throw error\n return (data ?? []) as T[]\n },\n enabled: options?.enabled,\n staleTime: options?.staleTime,\n refetchInterval: options?.refetchInterval,\n })\n}\n","import {\n useMutation as useTanstackMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query'\nimport { useClient } from './context'\nimport type { MimDBError } from '@mimdb/client'\n\n/**\n * React hook for inserting a row into a MimDB table.\n *\n * On success, all `useQuery` caches for the same table are automatically\n * invalidated so lists stay in sync.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @returns A TanStack `UseMutationResult` whose `mutate` / `mutateAsync`\n * accepts a partial row to insert.\n *\n * @example\n * ```tsx\n * const insert = useInsert<Todo>('todos')\n * insert.mutate({ task: 'Buy milk', done: false })\n * ```\n */\nexport function useInsert<T = Record<string, unknown>>(\n table: string,\n): UseMutationResult<T, MimDBError, Partial<T>> {\n const client = useClient()\n const queryClient = useQueryClient()\n\n return useTanstackMutation({\n mutationFn: async (data: Partial<T>) => {\n const { data: result, error } = await client\n .from<T>(table)\n .insert(data)\n .select()\n .single()\n if (error) throw error\n return result as T\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n },\n })\n}\n\n/**\n * Input shape for the {@link useUpdate} mutation.\n *\n * @typeParam T - Expected row type.\n */\nexport interface UpdateInput<T> {\n /** Fields to update. */\n data: Partial<T>\n /** Equality filters identifying which rows to update. */\n eq: Record<string, string>\n}\n\n/**\n * React hook for updating rows in a MimDB table.\n *\n * The mutation function accepts an object with `data` (fields to set) and\n * `eq` (equality filters to target specific rows). On success, all\n * `useQuery` caches for the same table are invalidated.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @returns A TanStack `UseMutationResult`.\n *\n * @example\n * ```tsx\n * const update = useUpdate<Todo>('todos')\n * update.mutate({ data: { done: true }, eq: { id: '42' } })\n * ```\n */\nexport function useUpdate<T = Record<string, unknown>>(\n table: string,\n): UseMutationResult<T, MimDBError, UpdateInput<T>> {\n const client = useClient()\n const queryClient = useQueryClient()\n\n return useTanstackMutation({\n mutationFn: async ({ data, eq }: UpdateInput<T>) => {\n let query = client.from<T>(table).update(data)\n for (const [col, val] of Object.entries(eq)) {\n query = query.eq(col, val)\n }\n const { data: result, error } = await query.select().single()\n if (error) throw error\n return result as T\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n },\n })\n}\n\n/**\n * React hook for deleting rows from a MimDB table.\n *\n * The mutation function accepts equality filters identifying which rows\n * to delete. On success, all `useQuery` caches for the same table are\n * invalidated.\n *\n * @param table - Name of the database table.\n * @returns A TanStack `UseMutationResult` whose `mutate` accepts equality filters.\n *\n * @example\n * ```tsx\n * const del = useDelete('todos')\n * del.mutate({ id: '42' })\n * ```\n */\nexport function useDelete(\n table: string,\n): UseMutationResult<void, MimDBError, Record<string, string>> {\n const client = useClient()\n const queryClient = useQueryClient()\n\n return useTanstackMutation({\n mutationFn: async (eq: Record<string, string>) => {\n let query = client.from(table).delete()\n for (const [col, val] of Object.entries(eq)) {\n query = query.eq(col, val)\n }\n const { error } = await query\n if (error) throw error\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n },\n })\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport {\n MimDBRealtimeClient,\n type RealtimeEvent,\n type SubscriptionStatus,\n} from '@mimdb/realtime'\nimport { useClient } from './context'\n\n/**\n * Options for the {@link useRealtime} hook.\n *\n * @typeParam T - Expected row type for realtime events.\n */\nexport interface UseRealtimeOptions<T = Record<string, unknown>> {\n /** Event type filter. Defaults to `'*'` (all events). */\n event?: '*' | 'INSERT' | 'UPDATE' | 'DELETE'\n /** Row filter expression (e.g. `'user_id=eq.42'`). */\n filter?: string\n /** Called for each matching realtime event. */\n onEvent?: (event: RealtimeEvent<T>) => void\n /**\n * Whether to automatically invalidate the table's TanStack Query cache\n * when an event is received. Defaults to `true`.\n */\n invalidateQueries?: boolean\n}\n\n/**\n * Subscribe to realtime database changes for a table via WebSocket.\n *\n * Creates a `MimDBRealtimeClient` using the connection config from\n * `MimDBClient.getConfig()` and subscribes to the specified table.\n * On each event, the table's TanStack Query cache is invalidated\n * (unless opted out) so queries refetch automatically.\n *\n * The subscription is cleaned up when the component unmounts or when\n * the `table`, `event`, or `filter` options change.\n *\n * @typeParam T - Expected row type for realtime events.\n * @param table - Database table to subscribe to.\n * @param options - Event filters and callbacks.\n * @returns An object containing the current subscription status.\n *\n * @example\n * ```tsx\n * const { status } = useRealtime<Message>('messages', {\n * event: 'INSERT',\n * onEvent: (e) => console.log('New message:', e.new),\n * })\n * ```\n */\nexport function useRealtime<T = Record<string, unknown>>(\n table: string,\n options?: UseRealtimeOptions<T>,\n): { status: SubscriptionStatus } {\n const client = useClient()\n const queryClient = useQueryClient()\n const [status, setStatus] = useState<SubscriptionStatus>('pending')\n const realtimeRef = useRef<MimDBRealtimeClient | null>(null)\n\n useEffect(() => {\n const config = client.getConfig()\n\n if (!realtimeRef.current) {\n realtimeRef.current = new MimDBRealtimeClient({\n url: config.url,\n projectRef: config.ref,\n apiKey: config.apiKey,\n })\n }\n\n const sub = realtimeRef.current.subscribe<T>(table, {\n event: options?.event ?? '*',\n filter: options?.filter,\n onEvent(event) {\n options?.onEvent?.(event)\n if (options?.invalidateQueries !== false) {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n }\n },\n onSubscribed() {\n setStatus('active')\n },\n onError() {\n setStatus('error')\n },\n })\n\n setStatus('pending')\n\n return () => {\n sub.unsubscribe()\n setStatus('closed')\n }\n }, [table, options?.event, options?.filter]) // eslint-disable-line react-hooks/exhaustive-deps\n\n return { status }\n}\n","import { useState, useEffect, useCallback } from 'react'\nimport { useClient } from './context'\nimport type { User } from '@mimdb/client'\n\n/**\n * Return type of the {@link useAuth} hook.\n */\nexport interface UseAuthResult {\n /** The currently authenticated user, or null if signed out. */\n user: User | null\n /** True while the initial session check is in progress. */\n isLoading: boolean\n /** Sign in with email and password. */\n signIn: (email: string, password: string) => Promise<void>\n /** Create a new account with email and password. */\n signUp: (email: string, password: string) => Promise<void>\n /** Sign out the current user. */\n signOut: () => Promise<void>\n /** Redirect to an OAuth provider's authorization page. */\n signInWithOAuth: (provider: string, opts: { redirectTo: string }) => void\n}\n\n/**\n * React hook for authentication state management.\n *\n * On mount, checks for an existing session and fetches the current user.\n * Subscribes to auth state changes so the returned `user` stays in sync\n * with sign-in, sign-out, and token refresh events.\n *\n * @returns An object with the current user, loading state, and auth methods.\n *\n * @example\n * ```tsx\n * function LoginPage() {\n * const { user, isLoading, signIn, signOut } = useAuth()\n *\n * if (isLoading) return <p>Loading...</p>\n * if (user) return <button onClick={signOut}>Sign Out</button>\n *\n * return (\n * <button onClick={() => signIn('user@example.com', 'password')}>\n * Sign In\n * </button>\n * )\n * }\n * ```\n */\nexport function useAuth(): UseAuthResult {\n const client = useClient()\n const [user, setUser] = useState<User | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n\n useEffect(() => {\n const session = client.auth.getSession()\n if (session) {\n client.auth\n .getUser()\n .then(setUser)\n .catch(() => setUser(null))\n .finally(() => setIsLoading(false))\n } else {\n setIsLoading(false)\n }\n\n const unsub = client.auth.onAuthStateChange((event, _session) => {\n if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') {\n client.auth\n .getUser()\n .then(setUser)\n .catch(() => setUser(null))\n } else if (event === 'SIGNED_OUT') {\n setUser(null)\n }\n })\n\n return unsub\n }, [client])\n\n const signIn = useCallback(\n async (email: string, password: string) => {\n await client.auth.signIn(email, password)\n },\n [client],\n )\n\n const signUp = useCallback(\n async (email: string, password: string) => {\n await client.auth.signUp(email, password)\n },\n [client],\n )\n\n const signOut = useCallback(async () => {\n await client.auth.signOut()\n }, [client])\n\n const signInWithOAuth = useCallback(\n (provider: string, opts: { redirectTo: string }) => {\n const url = client.auth.signInWithOAuth(provider, opts)\n window.location.href = url\n },\n [client],\n )\n\n return { user, isLoading, signIn, signUp, signOut, signInWithOAuth }\n}\n","import { useState, useCallback } from 'react'\nimport { useClient } from './context'\nimport type { UploadOptions } from '@mimdb/client'\n\n/**\n * Return type of the {@link useUpload} hook.\n */\nexport interface UseUploadResult {\n /** Upload a file to the bucket. Re-throws on failure after setting `error`. */\n upload: (path: string, file: Blob | File, opts?: UploadOptions) => Promise<void>\n /** True while an upload is in progress. */\n isUploading: boolean\n /** The error from the most recent failed upload, or null. */\n error: Error | null\n}\n\n/**\n * React hook for uploading files to a MimDB storage bucket.\n *\n * Tracks the upload's loading and error state so components can show\n * progress indicators or error messages without manual state management.\n *\n * @param bucket - Name of the storage bucket to upload to.\n * @returns An object with the `upload` function and status flags.\n *\n * @example\n * ```tsx\n * function AvatarUpload() {\n * const { upload, isUploading, error } = useUpload('avatars')\n *\n * const handleFile = (file: File) => {\n * upload(`users/${userId}/avatar.png`, file, { contentType: 'image/png' })\n * }\n *\n * return (\n * <>\n * <input type=\"file\" onChange={(e) => handleFile(e.target.files![0])} />\n * {isUploading && <p>Uploading...</p>}\n * {error && <p>Error: {error.message}</p>}\n * </>\n * )\n * }\n * ```\n */\nexport function useUpload(bucket: string): UseUploadResult {\n const client = useClient()\n const [isUploading, setIsUploading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const upload = useCallback(\n async (path: string, file: Blob | File, opts?: UploadOptions) => {\n setIsUploading(true)\n setError(null)\n try {\n await client.storage.from(bucket).upload(path, file, opts)\n } catch (err) {\n const uploadError =\n err instanceof Error ? err : new Error(String(err))\n setError(uploadError)\n throw uploadError\n } finally {\n setIsUploading(false)\n }\n },\n [client, bucket],\n )\n\n return { upload, isUploading, error }\n}\n"],"mappings":"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","names":["useTanstackQuery","import_react_query","useTanstackMutation","import_react","import_react_query","import_react","import_react"]}
@@ -0,0 +1,306 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { MimDBClient, MimDBError, User, UploadOptions } from '@mimdb/client';
4
+ import { UseQueryResult, UseMutationResult } from '@tanstack/react-query';
5
+ import { RealtimeEvent, SubscriptionStatus } from '@mimdb/realtime';
6
+
7
+ /**
8
+ * Props for the {@link MimDBProvider} component.
9
+ */
10
+ interface MimDBProviderProps {
11
+ /** A configured `MimDBClient` instance to make available to child components. */
12
+ client: MimDBClient;
13
+ /** The React subtree that will have access to the MimDB client. */
14
+ children: ReactNode;
15
+ }
16
+ /**
17
+ * Context provider that makes a `MimDBClient` available to all descendant
18
+ * components via the {@link useClient} hook.
19
+ *
20
+ * Wrap your application (or a subtree) with this provider and pass a
21
+ * pre-configured client instance.
22
+ *
23
+ * @param props - Provider props containing the client and children.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * import { createClient } from '@mimdb/client'
28
+ * import { MimDBProvider } from '@mimdb/react'
29
+ *
30
+ * const client = createClient('https://api.mimdb.dev', 'ref', 'key')
31
+ *
32
+ * function App() {
33
+ * return (
34
+ * <MimDBProvider client={client}>
35
+ * <MyApp />
36
+ * </MimDBProvider>
37
+ * )
38
+ * }
39
+ * ```
40
+ */
41
+ declare function MimDBProvider({ client, children }: MimDBProviderProps): react_jsx_runtime.JSX.Element;
42
+
43
+ /**
44
+ * Retrieve the MimDB client from the nearest `<MimDBProvider>`.
45
+ *
46
+ * @returns The `MimDBClient` instance provided by the enclosing provider.
47
+ * @throws If called outside of a `<MimDBProvider>` tree.
48
+ *
49
+ * @example
50
+ * ```tsx
51
+ * function MyComponent() {
52
+ * const client = useClient()
53
+ * // Use client.from(), client.auth, etc.
54
+ * }
55
+ * ```
56
+ */
57
+ declare function useClient(): MimDBClient;
58
+
59
+ /**
60
+ * Options for the {@link useQuery} hook.
61
+ */
62
+ interface UseQueryOptions {
63
+ /** Column selection string (PostgREST format). Defaults to `'*'`. */
64
+ select?: string;
65
+ /** Equality filters applied as `query.eq(column, value)`. */
66
+ eq?: Record<string, string>;
67
+ /** Not-equal filters applied as `query.neq(column, value)`. */
68
+ neq?: Record<string, string>;
69
+ /** Column ordering configuration. */
70
+ order?: {
71
+ column: string;
72
+ ascending?: boolean;
73
+ };
74
+ /** Maximum number of rows to return. */
75
+ limit?: number;
76
+ /** Number of rows to skip before returning results. */
77
+ offset?: number;
78
+ /** Whether the query should execute. Maps to TanStack Query's `enabled`. */
79
+ enabled?: boolean;
80
+ /** Duration in ms before cached data is considered stale. */
81
+ staleTime?: number;
82
+ /** Polling interval in ms, or `false` to disable. */
83
+ refetchInterval?: number | false;
84
+ }
85
+ /**
86
+ * Fetch rows from a MimDB table using the REST API, backed by TanStack Query
87
+ * for caching, deduplication, and background refetching.
88
+ *
89
+ * Automatically derives a stable query key from the table name and options
90
+ * so cache invalidation works out of the box with the mutation hooks.
91
+ *
92
+ * @typeParam T - Expected row type. Defaults to a generic record.
93
+ * @param table - Name of the database table to query.
94
+ * @param options - Query filters, modifiers, and TanStack Query settings.
95
+ * @returns A TanStack `UseQueryResult` containing the row array and status flags.
96
+ *
97
+ * @example
98
+ * ```tsx
99
+ * const { data, isLoading } = useQuery<Todo>('todos', {
100
+ * eq: { done: 'false' },
101
+ * order: { column: 'created_at', ascending: false },
102
+ * limit: 20,
103
+ * })
104
+ * ```
105
+ */
106
+ declare function useQuery<T = Record<string, unknown>>(table: string, options?: UseQueryOptions): UseQueryResult<T[], Error>;
107
+
108
+ /**
109
+ * React hook for inserting a row into a MimDB table.
110
+ *
111
+ * On success, all `useQuery` caches for the same table are automatically
112
+ * invalidated so lists stay in sync.
113
+ *
114
+ * @typeParam T - Expected row type. Defaults to a generic record.
115
+ * @param table - Name of the database table.
116
+ * @returns A TanStack `UseMutationResult` whose `mutate` / `mutateAsync`
117
+ * accepts a partial row to insert.
118
+ *
119
+ * @example
120
+ * ```tsx
121
+ * const insert = useInsert<Todo>('todos')
122
+ * insert.mutate({ task: 'Buy milk', done: false })
123
+ * ```
124
+ */
125
+ declare function useInsert<T = Record<string, unknown>>(table: string): UseMutationResult<T, MimDBError, Partial<T>>;
126
+ /**
127
+ * Input shape for the {@link useUpdate} mutation.
128
+ *
129
+ * @typeParam T - Expected row type.
130
+ */
131
+ interface UpdateInput<T> {
132
+ /** Fields to update. */
133
+ data: Partial<T>;
134
+ /** Equality filters identifying which rows to update. */
135
+ eq: Record<string, string>;
136
+ }
137
+ /**
138
+ * React hook for updating rows in a MimDB table.
139
+ *
140
+ * The mutation function accepts an object with `data` (fields to set) and
141
+ * `eq` (equality filters to target specific rows). On success, all
142
+ * `useQuery` caches for the same table are invalidated.
143
+ *
144
+ * @typeParam T - Expected row type. Defaults to a generic record.
145
+ * @param table - Name of the database table.
146
+ * @returns A TanStack `UseMutationResult`.
147
+ *
148
+ * @example
149
+ * ```tsx
150
+ * const update = useUpdate<Todo>('todos')
151
+ * update.mutate({ data: { done: true }, eq: { id: '42' } })
152
+ * ```
153
+ */
154
+ declare function useUpdate<T = Record<string, unknown>>(table: string): UseMutationResult<T, MimDBError, UpdateInput<T>>;
155
+ /**
156
+ * React hook for deleting rows from a MimDB table.
157
+ *
158
+ * The mutation function accepts equality filters identifying which rows
159
+ * to delete. On success, all `useQuery` caches for the same table are
160
+ * invalidated.
161
+ *
162
+ * @param table - Name of the database table.
163
+ * @returns A TanStack `UseMutationResult` whose `mutate` accepts equality filters.
164
+ *
165
+ * @example
166
+ * ```tsx
167
+ * const del = useDelete('todos')
168
+ * del.mutate({ id: '42' })
169
+ * ```
170
+ */
171
+ declare function useDelete(table: string): UseMutationResult<void, MimDBError, Record<string, string>>;
172
+
173
+ /**
174
+ * Options for the {@link useRealtime} hook.
175
+ *
176
+ * @typeParam T - Expected row type for realtime events.
177
+ */
178
+ interface UseRealtimeOptions<T = Record<string, unknown>> {
179
+ /** Event type filter. Defaults to `'*'` (all events). */
180
+ event?: '*' | 'INSERT' | 'UPDATE' | 'DELETE';
181
+ /** Row filter expression (e.g. `'user_id=eq.42'`). */
182
+ filter?: string;
183
+ /** Called for each matching realtime event. */
184
+ onEvent?: (event: RealtimeEvent<T>) => void;
185
+ /**
186
+ * Whether to automatically invalidate the table's TanStack Query cache
187
+ * when an event is received. Defaults to `true`.
188
+ */
189
+ invalidateQueries?: boolean;
190
+ }
191
+ /**
192
+ * Subscribe to realtime database changes for a table via WebSocket.
193
+ *
194
+ * Creates a `MimDBRealtimeClient` using the connection config from
195
+ * `MimDBClient.getConfig()` and subscribes to the specified table.
196
+ * On each event, the table's TanStack Query cache is invalidated
197
+ * (unless opted out) so queries refetch automatically.
198
+ *
199
+ * The subscription is cleaned up when the component unmounts or when
200
+ * the `table`, `event`, or `filter` options change.
201
+ *
202
+ * @typeParam T - Expected row type for realtime events.
203
+ * @param table - Database table to subscribe to.
204
+ * @param options - Event filters and callbacks.
205
+ * @returns An object containing the current subscription status.
206
+ *
207
+ * @example
208
+ * ```tsx
209
+ * const { status } = useRealtime<Message>('messages', {
210
+ * event: 'INSERT',
211
+ * onEvent: (e) => console.log('New message:', e.new),
212
+ * })
213
+ * ```
214
+ */
215
+ declare function useRealtime<T = Record<string, unknown>>(table: string, options?: UseRealtimeOptions<T>): {
216
+ status: SubscriptionStatus;
217
+ };
218
+
219
+ /**
220
+ * Return type of the {@link useAuth} hook.
221
+ */
222
+ interface UseAuthResult {
223
+ /** The currently authenticated user, or null if signed out. */
224
+ user: User | null;
225
+ /** True while the initial session check is in progress. */
226
+ isLoading: boolean;
227
+ /** Sign in with email and password. */
228
+ signIn: (email: string, password: string) => Promise<void>;
229
+ /** Create a new account with email and password. */
230
+ signUp: (email: string, password: string) => Promise<void>;
231
+ /** Sign out the current user. */
232
+ signOut: () => Promise<void>;
233
+ /** Redirect to an OAuth provider's authorization page. */
234
+ signInWithOAuth: (provider: string, opts: {
235
+ redirectTo: string;
236
+ }) => void;
237
+ }
238
+ /**
239
+ * React hook for authentication state management.
240
+ *
241
+ * On mount, checks for an existing session and fetches the current user.
242
+ * Subscribes to auth state changes so the returned `user` stays in sync
243
+ * with sign-in, sign-out, and token refresh events.
244
+ *
245
+ * @returns An object with the current user, loading state, and auth methods.
246
+ *
247
+ * @example
248
+ * ```tsx
249
+ * function LoginPage() {
250
+ * const { user, isLoading, signIn, signOut } = useAuth()
251
+ *
252
+ * if (isLoading) return <p>Loading...</p>
253
+ * if (user) return <button onClick={signOut}>Sign Out</button>
254
+ *
255
+ * return (
256
+ * <button onClick={() => signIn('user@example.com', 'password')}>
257
+ * Sign In
258
+ * </button>
259
+ * )
260
+ * }
261
+ * ```
262
+ */
263
+ declare function useAuth(): UseAuthResult;
264
+
265
+ /**
266
+ * Return type of the {@link useUpload} hook.
267
+ */
268
+ interface UseUploadResult {
269
+ /** Upload a file to the bucket. Re-throws on failure after setting `error`. */
270
+ upload: (path: string, file: Blob | File, opts?: UploadOptions) => Promise<void>;
271
+ /** True while an upload is in progress. */
272
+ isUploading: boolean;
273
+ /** The error from the most recent failed upload, or null. */
274
+ error: Error | null;
275
+ }
276
+ /**
277
+ * React hook for uploading files to a MimDB storage bucket.
278
+ *
279
+ * Tracks the upload's loading and error state so components can show
280
+ * progress indicators or error messages without manual state management.
281
+ *
282
+ * @param bucket - Name of the storage bucket to upload to.
283
+ * @returns An object with the `upload` function and status flags.
284
+ *
285
+ * @example
286
+ * ```tsx
287
+ * function AvatarUpload() {
288
+ * const { upload, isUploading, error } = useUpload('avatars')
289
+ *
290
+ * const handleFile = (file: File) => {
291
+ * upload(`users/${userId}/avatar.png`, file, { contentType: 'image/png' })
292
+ * }
293
+ *
294
+ * return (
295
+ * <>
296
+ * <input type="file" onChange={(e) => handleFile(e.target.files![0])} />
297
+ * {isUploading && <p>Uploading...</p>}
298
+ * {error && <p>Error: {error.message}</p>}
299
+ * </>
300
+ * )
301
+ * }
302
+ * ```
303
+ */
304
+ declare function useUpload(bucket: string): UseUploadResult;
305
+
306
+ export { MimDBProvider, type MimDBProviderProps, type UpdateInput, type UseAuthResult, type UseQueryOptions, type UseRealtimeOptions, type UseUploadResult, useAuth, useClient, useDelete, useInsert, useQuery, useRealtime, useUpdate, useUpload };
@@ -0,0 +1,306 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { MimDBClient, MimDBError, User, UploadOptions } from '@mimdb/client';
4
+ import { UseQueryResult, UseMutationResult } from '@tanstack/react-query';
5
+ import { RealtimeEvent, SubscriptionStatus } from '@mimdb/realtime';
6
+
7
+ /**
8
+ * Props for the {@link MimDBProvider} component.
9
+ */
10
+ interface MimDBProviderProps {
11
+ /** A configured `MimDBClient` instance to make available to child components. */
12
+ client: MimDBClient;
13
+ /** The React subtree that will have access to the MimDB client. */
14
+ children: ReactNode;
15
+ }
16
+ /**
17
+ * Context provider that makes a `MimDBClient` available to all descendant
18
+ * components via the {@link useClient} hook.
19
+ *
20
+ * Wrap your application (or a subtree) with this provider and pass a
21
+ * pre-configured client instance.
22
+ *
23
+ * @param props - Provider props containing the client and children.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * import { createClient } from '@mimdb/client'
28
+ * import { MimDBProvider } from '@mimdb/react'
29
+ *
30
+ * const client = createClient('https://api.mimdb.dev', 'ref', 'key')
31
+ *
32
+ * function App() {
33
+ * return (
34
+ * <MimDBProvider client={client}>
35
+ * <MyApp />
36
+ * </MimDBProvider>
37
+ * )
38
+ * }
39
+ * ```
40
+ */
41
+ declare function MimDBProvider({ client, children }: MimDBProviderProps): react_jsx_runtime.JSX.Element;
42
+
43
+ /**
44
+ * Retrieve the MimDB client from the nearest `<MimDBProvider>`.
45
+ *
46
+ * @returns The `MimDBClient` instance provided by the enclosing provider.
47
+ * @throws If called outside of a `<MimDBProvider>` tree.
48
+ *
49
+ * @example
50
+ * ```tsx
51
+ * function MyComponent() {
52
+ * const client = useClient()
53
+ * // Use client.from(), client.auth, etc.
54
+ * }
55
+ * ```
56
+ */
57
+ declare function useClient(): MimDBClient;
58
+
59
+ /**
60
+ * Options for the {@link useQuery} hook.
61
+ */
62
+ interface UseQueryOptions {
63
+ /** Column selection string (PostgREST format). Defaults to `'*'`. */
64
+ select?: string;
65
+ /** Equality filters applied as `query.eq(column, value)`. */
66
+ eq?: Record<string, string>;
67
+ /** Not-equal filters applied as `query.neq(column, value)`. */
68
+ neq?: Record<string, string>;
69
+ /** Column ordering configuration. */
70
+ order?: {
71
+ column: string;
72
+ ascending?: boolean;
73
+ };
74
+ /** Maximum number of rows to return. */
75
+ limit?: number;
76
+ /** Number of rows to skip before returning results. */
77
+ offset?: number;
78
+ /** Whether the query should execute. Maps to TanStack Query's `enabled`. */
79
+ enabled?: boolean;
80
+ /** Duration in ms before cached data is considered stale. */
81
+ staleTime?: number;
82
+ /** Polling interval in ms, or `false` to disable. */
83
+ refetchInterval?: number | false;
84
+ }
85
+ /**
86
+ * Fetch rows from a MimDB table using the REST API, backed by TanStack Query
87
+ * for caching, deduplication, and background refetching.
88
+ *
89
+ * Automatically derives a stable query key from the table name and options
90
+ * so cache invalidation works out of the box with the mutation hooks.
91
+ *
92
+ * @typeParam T - Expected row type. Defaults to a generic record.
93
+ * @param table - Name of the database table to query.
94
+ * @param options - Query filters, modifiers, and TanStack Query settings.
95
+ * @returns A TanStack `UseQueryResult` containing the row array and status flags.
96
+ *
97
+ * @example
98
+ * ```tsx
99
+ * const { data, isLoading } = useQuery<Todo>('todos', {
100
+ * eq: { done: 'false' },
101
+ * order: { column: 'created_at', ascending: false },
102
+ * limit: 20,
103
+ * })
104
+ * ```
105
+ */
106
+ declare function useQuery<T = Record<string, unknown>>(table: string, options?: UseQueryOptions): UseQueryResult<T[], Error>;
107
+
108
+ /**
109
+ * React hook for inserting a row into a MimDB table.
110
+ *
111
+ * On success, all `useQuery` caches for the same table are automatically
112
+ * invalidated so lists stay in sync.
113
+ *
114
+ * @typeParam T - Expected row type. Defaults to a generic record.
115
+ * @param table - Name of the database table.
116
+ * @returns A TanStack `UseMutationResult` whose `mutate` / `mutateAsync`
117
+ * accepts a partial row to insert.
118
+ *
119
+ * @example
120
+ * ```tsx
121
+ * const insert = useInsert<Todo>('todos')
122
+ * insert.mutate({ task: 'Buy milk', done: false })
123
+ * ```
124
+ */
125
+ declare function useInsert<T = Record<string, unknown>>(table: string): UseMutationResult<T, MimDBError, Partial<T>>;
126
+ /**
127
+ * Input shape for the {@link useUpdate} mutation.
128
+ *
129
+ * @typeParam T - Expected row type.
130
+ */
131
+ interface UpdateInput<T> {
132
+ /** Fields to update. */
133
+ data: Partial<T>;
134
+ /** Equality filters identifying which rows to update. */
135
+ eq: Record<string, string>;
136
+ }
137
+ /**
138
+ * React hook for updating rows in a MimDB table.
139
+ *
140
+ * The mutation function accepts an object with `data` (fields to set) and
141
+ * `eq` (equality filters to target specific rows). On success, all
142
+ * `useQuery` caches for the same table are invalidated.
143
+ *
144
+ * @typeParam T - Expected row type. Defaults to a generic record.
145
+ * @param table - Name of the database table.
146
+ * @returns A TanStack `UseMutationResult`.
147
+ *
148
+ * @example
149
+ * ```tsx
150
+ * const update = useUpdate<Todo>('todos')
151
+ * update.mutate({ data: { done: true }, eq: { id: '42' } })
152
+ * ```
153
+ */
154
+ declare function useUpdate<T = Record<string, unknown>>(table: string): UseMutationResult<T, MimDBError, UpdateInput<T>>;
155
+ /**
156
+ * React hook for deleting rows from a MimDB table.
157
+ *
158
+ * The mutation function accepts equality filters identifying which rows
159
+ * to delete. On success, all `useQuery` caches for the same table are
160
+ * invalidated.
161
+ *
162
+ * @param table - Name of the database table.
163
+ * @returns A TanStack `UseMutationResult` whose `mutate` accepts equality filters.
164
+ *
165
+ * @example
166
+ * ```tsx
167
+ * const del = useDelete('todos')
168
+ * del.mutate({ id: '42' })
169
+ * ```
170
+ */
171
+ declare function useDelete(table: string): UseMutationResult<void, MimDBError, Record<string, string>>;
172
+
173
+ /**
174
+ * Options for the {@link useRealtime} hook.
175
+ *
176
+ * @typeParam T - Expected row type for realtime events.
177
+ */
178
+ interface UseRealtimeOptions<T = Record<string, unknown>> {
179
+ /** Event type filter. Defaults to `'*'` (all events). */
180
+ event?: '*' | 'INSERT' | 'UPDATE' | 'DELETE';
181
+ /** Row filter expression (e.g. `'user_id=eq.42'`). */
182
+ filter?: string;
183
+ /** Called for each matching realtime event. */
184
+ onEvent?: (event: RealtimeEvent<T>) => void;
185
+ /**
186
+ * Whether to automatically invalidate the table's TanStack Query cache
187
+ * when an event is received. Defaults to `true`.
188
+ */
189
+ invalidateQueries?: boolean;
190
+ }
191
+ /**
192
+ * Subscribe to realtime database changes for a table via WebSocket.
193
+ *
194
+ * Creates a `MimDBRealtimeClient` using the connection config from
195
+ * `MimDBClient.getConfig()` and subscribes to the specified table.
196
+ * On each event, the table's TanStack Query cache is invalidated
197
+ * (unless opted out) so queries refetch automatically.
198
+ *
199
+ * The subscription is cleaned up when the component unmounts or when
200
+ * the `table`, `event`, or `filter` options change.
201
+ *
202
+ * @typeParam T - Expected row type for realtime events.
203
+ * @param table - Database table to subscribe to.
204
+ * @param options - Event filters and callbacks.
205
+ * @returns An object containing the current subscription status.
206
+ *
207
+ * @example
208
+ * ```tsx
209
+ * const { status } = useRealtime<Message>('messages', {
210
+ * event: 'INSERT',
211
+ * onEvent: (e) => console.log('New message:', e.new),
212
+ * })
213
+ * ```
214
+ */
215
+ declare function useRealtime<T = Record<string, unknown>>(table: string, options?: UseRealtimeOptions<T>): {
216
+ status: SubscriptionStatus;
217
+ };
218
+
219
+ /**
220
+ * Return type of the {@link useAuth} hook.
221
+ */
222
+ interface UseAuthResult {
223
+ /** The currently authenticated user, or null if signed out. */
224
+ user: User | null;
225
+ /** True while the initial session check is in progress. */
226
+ isLoading: boolean;
227
+ /** Sign in with email and password. */
228
+ signIn: (email: string, password: string) => Promise<void>;
229
+ /** Create a new account with email and password. */
230
+ signUp: (email: string, password: string) => Promise<void>;
231
+ /** Sign out the current user. */
232
+ signOut: () => Promise<void>;
233
+ /** Redirect to an OAuth provider's authorization page. */
234
+ signInWithOAuth: (provider: string, opts: {
235
+ redirectTo: string;
236
+ }) => void;
237
+ }
238
+ /**
239
+ * React hook for authentication state management.
240
+ *
241
+ * On mount, checks for an existing session and fetches the current user.
242
+ * Subscribes to auth state changes so the returned `user` stays in sync
243
+ * with sign-in, sign-out, and token refresh events.
244
+ *
245
+ * @returns An object with the current user, loading state, and auth methods.
246
+ *
247
+ * @example
248
+ * ```tsx
249
+ * function LoginPage() {
250
+ * const { user, isLoading, signIn, signOut } = useAuth()
251
+ *
252
+ * if (isLoading) return <p>Loading...</p>
253
+ * if (user) return <button onClick={signOut}>Sign Out</button>
254
+ *
255
+ * return (
256
+ * <button onClick={() => signIn('user@example.com', 'password')}>
257
+ * Sign In
258
+ * </button>
259
+ * )
260
+ * }
261
+ * ```
262
+ */
263
+ declare function useAuth(): UseAuthResult;
264
+
265
+ /**
266
+ * Return type of the {@link useUpload} hook.
267
+ */
268
+ interface UseUploadResult {
269
+ /** Upload a file to the bucket. Re-throws on failure after setting `error`. */
270
+ upload: (path: string, file: Blob | File, opts?: UploadOptions) => Promise<void>;
271
+ /** True while an upload is in progress. */
272
+ isUploading: boolean;
273
+ /** The error from the most recent failed upload, or null. */
274
+ error: Error | null;
275
+ }
276
+ /**
277
+ * React hook for uploading files to a MimDB storage bucket.
278
+ *
279
+ * Tracks the upload's loading and error state so components can show
280
+ * progress indicators or error messages without manual state management.
281
+ *
282
+ * @param bucket - Name of the storage bucket to upload to.
283
+ * @returns An object with the `upload` function and status flags.
284
+ *
285
+ * @example
286
+ * ```tsx
287
+ * function AvatarUpload() {
288
+ * const { upload, isUploading, error } = useUpload('avatars')
289
+ *
290
+ * const handleFile = (file: File) => {
291
+ * upload(`users/${userId}/avatar.png`, file, { contentType: 'image/png' })
292
+ * }
293
+ *
294
+ * return (
295
+ * <>
296
+ * <input type="file" onChange={(e) => handleFile(e.target.files![0])} />
297
+ * {isUploading && <p>Uploading...</p>}
298
+ * {error && <p>Error: {error.message}</p>}
299
+ * </>
300
+ * )
301
+ * }
302
+ * ```
303
+ */
304
+ declare function useUpload(bucket: string): UseUploadResult;
305
+
306
+ export { MimDBProvider, type MimDBProviderProps, type UpdateInput, type UseAuthResult, type UseQueryOptions, type UseRealtimeOptions, type UseUploadResult, useAuth, useClient, useDelete, useInsert, useQuery, useRealtime, useUpdate, useUpload };
package/dist/index.js ADDED
@@ -0,0 +1,237 @@
1
+ // src/context.ts
2
+ import { createContext, useContext } from "react";
3
+ var MimDBContext = createContext(null);
4
+ function useClient() {
5
+ const client = useContext(MimDBContext);
6
+ if (!client) {
7
+ throw new Error("useClient must be used within <MimDBProvider>");
8
+ }
9
+ return client;
10
+ }
11
+
12
+ // src/provider.tsx
13
+ import { jsx } from "react/jsx-runtime";
14
+ function MimDBProvider({ client, children }) {
15
+ return /* @__PURE__ */ jsx(MimDBContext.Provider, { value: client, children });
16
+ }
17
+
18
+ // src/use-query.ts
19
+ import {
20
+ useQuery as useTanstackQuery
21
+ } from "@tanstack/react-query";
22
+ function useQuery(table, options) {
23
+ const client = useClient();
24
+ return useTanstackQuery({
25
+ queryKey: ["mimdb", table, options],
26
+ queryFn: async () => {
27
+ let query = client.from(table).select(options?.select ?? "*");
28
+ if (options?.eq) {
29
+ for (const [col, val] of Object.entries(options.eq)) {
30
+ query = query.eq(col, val);
31
+ }
32
+ }
33
+ if (options?.neq) {
34
+ for (const [col, val] of Object.entries(options.neq)) {
35
+ query = query.neq(col, val);
36
+ }
37
+ }
38
+ if (options?.order) {
39
+ query = query.order(options.order.column, {
40
+ ascending: options.order.ascending
41
+ });
42
+ }
43
+ if (options?.limit) query = query.limit(options.limit);
44
+ if (options?.offset) query = query.offset(options.offset);
45
+ const { data, error } = await query;
46
+ if (error) throw error;
47
+ return data ?? [];
48
+ },
49
+ enabled: options?.enabled,
50
+ staleTime: options?.staleTime,
51
+ refetchInterval: options?.refetchInterval
52
+ });
53
+ }
54
+
55
+ // src/use-mutation.ts
56
+ import {
57
+ useMutation as useTanstackMutation,
58
+ useQueryClient
59
+ } from "@tanstack/react-query";
60
+ function useInsert(table) {
61
+ const client = useClient();
62
+ const queryClient = useQueryClient();
63
+ return useTanstackMutation({
64
+ mutationFn: async (data) => {
65
+ const { data: result, error } = await client.from(table).insert(data).select().single();
66
+ if (error) throw error;
67
+ return result;
68
+ },
69
+ onSuccess: () => {
70
+ queryClient.invalidateQueries({ queryKey: ["mimdb", table] });
71
+ }
72
+ });
73
+ }
74
+ function useUpdate(table) {
75
+ const client = useClient();
76
+ const queryClient = useQueryClient();
77
+ return useTanstackMutation({
78
+ mutationFn: async ({ data, eq }) => {
79
+ let query = client.from(table).update(data);
80
+ for (const [col, val] of Object.entries(eq)) {
81
+ query = query.eq(col, val);
82
+ }
83
+ const { data: result, error } = await query.select().single();
84
+ if (error) throw error;
85
+ return result;
86
+ },
87
+ onSuccess: () => {
88
+ queryClient.invalidateQueries({ queryKey: ["mimdb", table] });
89
+ }
90
+ });
91
+ }
92
+ function useDelete(table) {
93
+ const client = useClient();
94
+ const queryClient = useQueryClient();
95
+ return useTanstackMutation({
96
+ mutationFn: async (eq) => {
97
+ let query = client.from(table).delete();
98
+ for (const [col, val] of Object.entries(eq)) {
99
+ query = query.eq(col, val);
100
+ }
101
+ const { error } = await query;
102
+ if (error) throw error;
103
+ },
104
+ onSuccess: () => {
105
+ queryClient.invalidateQueries({ queryKey: ["mimdb", table] });
106
+ }
107
+ });
108
+ }
109
+
110
+ // src/use-realtime.ts
111
+ import { useEffect, useRef, useState } from "react";
112
+ import { useQueryClient as useQueryClient2 } from "@tanstack/react-query";
113
+ import {
114
+ MimDBRealtimeClient
115
+ } from "@mimdb/realtime";
116
+ function useRealtime(table, options) {
117
+ const client = useClient();
118
+ const queryClient = useQueryClient2();
119
+ const [status, setStatus] = useState("pending");
120
+ const realtimeRef = useRef(null);
121
+ useEffect(() => {
122
+ const config = client.getConfig();
123
+ if (!realtimeRef.current) {
124
+ realtimeRef.current = new MimDBRealtimeClient({
125
+ url: config.url,
126
+ projectRef: config.ref,
127
+ apiKey: config.apiKey
128
+ });
129
+ }
130
+ const sub = realtimeRef.current.subscribe(table, {
131
+ event: options?.event ?? "*",
132
+ filter: options?.filter,
133
+ onEvent(event) {
134
+ options?.onEvent?.(event);
135
+ if (options?.invalidateQueries !== false) {
136
+ queryClient.invalidateQueries({ queryKey: ["mimdb", table] });
137
+ }
138
+ },
139
+ onSubscribed() {
140
+ setStatus("active");
141
+ },
142
+ onError() {
143
+ setStatus("error");
144
+ }
145
+ });
146
+ setStatus("pending");
147
+ return () => {
148
+ sub.unsubscribe();
149
+ setStatus("closed");
150
+ };
151
+ }, [table, options?.event, options?.filter]);
152
+ return { status };
153
+ }
154
+
155
+ // src/use-auth.ts
156
+ import { useState as useState2, useEffect as useEffect2, useCallback } from "react";
157
+ function useAuth() {
158
+ const client = useClient();
159
+ const [user, setUser] = useState2(null);
160
+ const [isLoading, setIsLoading] = useState2(true);
161
+ useEffect2(() => {
162
+ const session = client.auth.getSession();
163
+ if (session) {
164
+ client.auth.getUser().then(setUser).catch(() => setUser(null)).finally(() => setIsLoading(false));
165
+ } else {
166
+ setIsLoading(false);
167
+ }
168
+ const unsub = client.auth.onAuthStateChange((event, _session) => {
169
+ if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED") {
170
+ client.auth.getUser().then(setUser).catch(() => setUser(null));
171
+ } else if (event === "SIGNED_OUT") {
172
+ setUser(null);
173
+ }
174
+ });
175
+ return unsub;
176
+ }, [client]);
177
+ const signIn = useCallback(
178
+ async (email, password) => {
179
+ await client.auth.signIn(email, password);
180
+ },
181
+ [client]
182
+ );
183
+ const signUp = useCallback(
184
+ async (email, password) => {
185
+ await client.auth.signUp(email, password);
186
+ },
187
+ [client]
188
+ );
189
+ const signOut = useCallback(async () => {
190
+ await client.auth.signOut();
191
+ }, [client]);
192
+ const signInWithOAuth = useCallback(
193
+ (provider, opts) => {
194
+ const url = client.auth.signInWithOAuth(provider, opts);
195
+ window.location.href = url;
196
+ },
197
+ [client]
198
+ );
199
+ return { user, isLoading, signIn, signUp, signOut, signInWithOAuth };
200
+ }
201
+
202
+ // src/use-upload.ts
203
+ import { useState as useState3, useCallback as useCallback2 } from "react";
204
+ function useUpload(bucket) {
205
+ const client = useClient();
206
+ const [isUploading, setIsUploading] = useState3(false);
207
+ const [error, setError] = useState3(null);
208
+ const upload = useCallback2(
209
+ async (path, file, opts) => {
210
+ setIsUploading(true);
211
+ setError(null);
212
+ try {
213
+ await client.storage.from(bucket).upload(path, file, opts);
214
+ } catch (err) {
215
+ const uploadError = err instanceof Error ? err : new Error(String(err));
216
+ setError(uploadError);
217
+ throw uploadError;
218
+ } finally {
219
+ setIsUploading(false);
220
+ }
221
+ },
222
+ [client, bucket]
223
+ );
224
+ return { upload, isUploading, error };
225
+ }
226
+ export {
227
+ MimDBProvider,
228
+ useAuth,
229
+ useClient,
230
+ useDelete,
231
+ useInsert,
232
+ useQuery,
233
+ useRealtime,
234
+ useUpdate,
235
+ useUpload
236
+ };
237
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context.ts","../src/provider.tsx","../src/use-query.ts","../src/use-mutation.ts","../src/use-realtime.ts","../src/use-auth.ts","../src/use-upload.ts"],"sourcesContent":["import { createContext, useContext } from 'react'\nimport type { MimDBClient } from '@mimdb/client'\n\n/**\n * React context that holds the MimDB client instance.\n *\n * Consumers should use the {@link useClient} hook rather than accessing\n * this context directly.\n *\n * @internal\n */\nconst MimDBContext = createContext<MimDBClient | null>(null)\n\n/**\n * Retrieve the MimDB client from the nearest `<MimDBProvider>`.\n *\n * @returns The `MimDBClient` instance provided by the enclosing provider.\n * @throws If called outside of a `<MimDBProvider>` tree.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const client = useClient()\n * // Use client.from(), client.auth, etc.\n * }\n * ```\n */\nexport function useClient(): MimDBClient {\n const client = useContext(MimDBContext)\n if (!client) {\n throw new Error('useClient must be used within <MimDBProvider>')\n }\n return client\n}\n\nexport { MimDBContext }\n","import { type ReactNode } from 'react'\nimport { MimDBContext } from './context'\nimport type { MimDBClient } from '@mimdb/client'\n\n/**\n * Props for the {@link MimDBProvider} component.\n */\nexport interface MimDBProviderProps {\n /** A configured `MimDBClient` instance to make available to child components. */\n client: MimDBClient\n /** The React subtree that will have access to the MimDB client. */\n children: ReactNode\n}\n\n/**\n * Context provider that makes a `MimDBClient` available to all descendant\n * components via the {@link useClient} hook.\n *\n * Wrap your application (or a subtree) with this provider and pass a\n * pre-configured client instance.\n *\n * @param props - Provider props containing the client and children.\n *\n * @example\n * ```tsx\n * import { createClient } from '@mimdb/client'\n * import { MimDBProvider } from '@mimdb/react'\n *\n * const client = createClient('https://api.mimdb.dev', 'ref', 'key')\n *\n * function App() {\n * return (\n * <MimDBProvider client={client}>\n * <MyApp />\n * </MimDBProvider>\n * )\n * }\n * ```\n */\nexport function MimDBProvider({ client, children }: MimDBProviderProps) {\n return <MimDBContext.Provider value={client}>{children}</MimDBContext.Provider>\n}\n","import {\n useQuery as useTanstackQuery,\n type UseQueryResult,\n} from '@tanstack/react-query'\nimport { useClient } from './context'\n\n/**\n * Options for the {@link useQuery} hook.\n */\nexport interface UseQueryOptions {\n /** Column selection string (PostgREST format). Defaults to `'*'`. */\n select?: string\n /** Equality filters applied as `query.eq(column, value)`. */\n eq?: Record<string, string>\n /** Not-equal filters applied as `query.neq(column, value)`. */\n neq?: Record<string, string>\n /** Column ordering configuration. */\n order?: { column: string; ascending?: boolean }\n /** Maximum number of rows to return. */\n limit?: number\n /** Number of rows to skip before returning results. */\n offset?: number\n /** Whether the query should execute. Maps to TanStack Query's `enabled`. */\n enabled?: boolean\n /** Duration in ms before cached data is considered stale. */\n staleTime?: number\n /** Polling interval in ms, or `false` to disable. */\n refetchInterval?: number | false\n}\n\n/**\n * Fetch rows from a MimDB table using the REST API, backed by TanStack Query\n * for caching, deduplication, and background refetching.\n *\n * Automatically derives a stable query key from the table name and options\n * so cache invalidation works out of the box with the mutation hooks.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table to query.\n * @param options - Query filters, modifiers, and TanStack Query settings.\n * @returns A TanStack `UseQueryResult` containing the row array and status flags.\n *\n * @example\n * ```tsx\n * const { data, isLoading } = useQuery<Todo>('todos', {\n * eq: { done: 'false' },\n * order: { column: 'created_at', ascending: false },\n * limit: 20,\n * })\n * ```\n */\nexport function useQuery<T = Record<string, unknown>>(\n table: string,\n options?: UseQueryOptions,\n): UseQueryResult<T[], Error> {\n const client = useClient()\n\n return useTanstackQuery({\n queryKey: ['mimdb', table, options],\n queryFn: async () => {\n let query = client.from<T>(table).select(options?.select ?? '*')\n\n if (options?.eq) {\n for (const [col, val] of Object.entries(options.eq)) {\n query = query.eq(col, val)\n }\n }\n if (options?.neq) {\n for (const [col, val] of Object.entries(options.neq)) {\n query = query.neq(col, val)\n }\n }\n if (options?.order) {\n query = query.order(options.order.column, {\n ascending: options.order.ascending,\n })\n }\n if (options?.limit) query = query.limit(options.limit)\n if (options?.offset) query = query.offset(options.offset)\n\n const { data, error } = await query\n if (error) throw error\n return (data ?? []) as T[]\n },\n enabled: options?.enabled,\n staleTime: options?.staleTime,\n refetchInterval: options?.refetchInterval,\n })\n}\n","import {\n useMutation as useTanstackMutation,\n useQueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query'\nimport { useClient } from './context'\nimport type { MimDBError } from '@mimdb/client'\n\n/**\n * React hook for inserting a row into a MimDB table.\n *\n * On success, all `useQuery` caches for the same table are automatically\n * invalidated so lists stay in sync.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @returns A TanStack `UseMutationResult` whose `mutate` / `mutateAsync`\n * accepts a partial row to insert.\n *\n * @example\n * ```tsx\n * const insert = useInsert<Todo>('todos')\n * insert.mutate({ task: 'Buy milk', done: false })\n * ```\n */\nexport function useInsert<T = Record<string, unknown>>(\n table: string,\n): UseMutationResult<T, MimDBError, Partial<T>> {\n const client = useClient()\n const queryClient = useQueryClient()\n\n return useTanstackMutation({\n mutationFn: async (data: Partial<T>) => {\n const { data: result, error } = await client\n .from<T>(table)\n .insert(data)\n .select()\n .single()\n if (error) throw error\n return result as T\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n },\n })\n}\n\n/**\n * Input shape for the {@link useUpdate} mutation.\n *\n * @typeParam T - Expected row type.\n */\nexport interface UpdateInput<T> {\n /** Fields to update. */\n data: Partial<T>\n /** Equality filters identifying which rows to update. */\n eq: Record<string, string>\n}\n\n/**\n * React hook for updating rows in a MimDB table.\n *\n * The mutation function accepts an object with `data` (fields to set) and\n * `eq` (equality filters to target specific rows). On success, all\n * `useQuery` caches for the same table are invalidated.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @returns A TanStack `UseMutationResult`.\n *\n * @example\n * ```tsx\n * const update = useUpdate<Todo>('todos')\n * update.mutate({ data: { done: true }, eq: { id: '42' } })\n * ```\n */\nexport function useUpdate<T = Record<string, unknown>>(\n table: string,\n): UseMutationResult<T, MimDBError, UpdateInput<T>> {\n const client = useClient()\n const queryClient = useQueryClient()\n\n return useTanstackMutation({\n mutationFn: async ({ data, eq }: UpdateInput<T>) => {\n let query = client.from<T>(table).update(data)\n for (const [col, val] of Object.entries(eq)) {\n query = query.eq(col, val)\n }\n const { data: result, error } = await query.select().single()\n if (error) throw error\n return result as T\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n },\n })\n}\n\n/**\n * React hook for deleting rows from a MimDB table.\n *\n * The mutation function accepts equality filters identifying which rows\n * to delete. On success, all `useQuery` caches for the same table are\n * invalidated.\n *\n * @param table - Name of the database table.\n * @returns A TanStack `UseMutationResult` whose `mutate` accepts equality filters.\n *\n * @example\n * ```tsx\n * const del = useDelete('todos')\n * del.mutate({ id: '42' })\n * ```\n */\nexport function useDelete(\n table: string,\n): UseMutationResult<void, MimDBError, Record<string, string>> {\n const client = useClient()\n const queryClient = useQueryClient()\n\n return useTanstackMutation({\n mutationFn: async (eq: Record<string, string>) => {\n let query = client.from(table).delete()\n for (const [col, val] of Object.entries(eq)) {\n query = query.eq(col, val)\n }\n const { error } = await query\n if (error) throw error\n },\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n },\n })\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport {\n MimDBRealtimeClient,\n type RealtimeEvent,\n type SubscriptionStatus,\n} from '@mimdb/realtime'\nimport { useClient } from './context'\n\n/**\n * Options for the {@link useRealtime} hook.\n *\n * @typeParam T - Expected row type for realtime events.\n */\nexport interface UseRealtimeOptions<T = Record<string, unknown>> {\n /** Event type filter. Defaults to `'*'` (all events). */\n event?: '*' | 'INSERT' | 'UPDATE' | 'DELETE'\n /** Row filter expression (e.g. `'user_id=eq.42'`). */\n filter?: string\n /** Called for each matching realtime event. */\n onEvent?: (event: RealtimeEvent<T>) => void\n /**\n * Whether to automatically invalidate the table's TanStack Query cache\n * when an event is received. Defaults to `true`.\n */\n invalidateQueries?: boolean\n}\n\n/**\n * Subscribe to realtime database changes for a table via WebSocket.\n *\n * Creates a `MimDBRealtimeClient` using the connection config from\n * `MimDBClient.getConfig()` and subscribes to the specified table.\n * On each event, the table's TanStack Query cache is invalidated\n * (unless opted out) so queries refetch automatically.\n *\n * The subscription is cleaned up when the component unmounts or when\n * the `table`, `event`, or `filter` options change.\n *\n * @typeParam T - Expected row type for realtime events.\n * @param table - Database table to subscribe to.\n * @param options - Event filters and callbacks.\n * @returns An object containing the current subscription status.\n *\n * @example\n * ```tsx\n * const { status } = useRealtime<Message>('messages', {\n * event: 'INSERT',\n * onEvent: (e) => console.log('New message:', e.new),\n * })\n * ```\n */\nexport function useRealtime<T = Record<string, unknown>>(\n table: string,\n options?: UseRealtimeOptions<T>,\n): { status: SubscriptionStatus } {\n const client = useClient()\n const queryClient = useQueryClient()\n const [status, setStatus] = useState<SubscriptionStatus>('pending')\n const realtimeRef = useRef<MimDBRealtimeClient | null>(null)\n\n useEffect(() => {\n const config = client.getConfig()\n\n if (!realtimeRef.current) {\n realtimeRef.current = new MimDBRealtimeClient({\n url: config.url,\n projectRef: config.ref,\n apiKey: config.apiKey,\n })\n }\n\n const sub = realtimeRef.current.subscribe<T>(table, {\n event: options?.event ?? '*',\n filter: options?.filter,\n onEvent(event) {\n options?.onEvent?.(event)\n if (options?.invalidateQueries !== false) {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n }\n },\n onSubscribed() {\n setStatus('active')\n },\n onError() {\n setStatus('error')\n },\n })\n\n setStatus('pending')\n\n return () => {\n sub.unsubscribe()\n setStatus('closed')\n }\n }, [table, options?.event, options?.filter]) // eslint-disable-line react-hooks/exhaustive-deps\n\n return { status }\n}\n","import { useState, useEffect, useCallback } from 'react'\nimport { useClient } from './context'\nimport type { User } from '@mimdb/client'\n\n/**\n * Return type of the {@link useAuth} hook.\n */\nexport interface UseAuthResult {\n /** The currently authenticated user, or null if signed out. */\n user: User | null\n /** True while the initial session check is in progress. */\n isLoading: boolean\n /** Sign in with email and password. */\n signIn: (email: string, password: string) => Promise<void>\n /** Create a new account with email and password. */\n signUp: (email: string, password: string) => Promise<void>\n /** Sign out the current user. */\n signOut: () => Promise<void>\n /** Redirect to an OAuth provider's authorization page. */\n signInWithOAuth: (provider: string, opts: { redirectTo: string }) => void\n}\n\n/**\n * React hook for authentication state management.\n *\n * On mount, checks for an existing session and fetches the current user.\n * Subscribes to auth state changes so the returned `user` stays in sync\n * with sign-in, sign-out, and token refresh events.\n *\n * @returns An object with the current user, loading state, and auth methods.\n *\n * @example\n * ```tsx\n * function LoginPage() {\n * const { user, isLoading, signIn, signOut } = useAuth()\n *\n * if (isLoading) return <p>Loading...</p>\n * if (user) return <button onClick={signOut}>Sign Out</button>\n *\n * return (\n * <button onClick={() => signIn('user@example.com', 'password')}>\n * Sign In\n * </button>\n * )\n * }\n * ```\n */\nexport function useAuth(): UseAuthResult {\n const client = useClient()\n const [user, setUser] = useState<User | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n\n useEffect(() => {\n const session = client.auth.getSession()\n if (session) {\n client.auth\n .getUser()\n .then(setUser)\n .catch(() => setUser(null))\n .finally(() => setIsLoading(false))\n } else {\n setIsLoading(false)\n }\n\n const unsub = client.auth.onAuthStateChange((event, _session) => {\n if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') {\n client.auth\n .getUser()\n .then(setUser)\n .catch(() => setUser(null))\n } else if (event === 'SIGNED_OUT') {\n setUser(null)\n }\n })\n\n return unsub\n }, [client])\n\n const signIn = useCallback(\n async (email: string, password: string) => {\n await client.auth.signIn(email, password)\n },\n [client],\n )\n\n const signUp = useCallback(\n async (email: string, password: string) => {\n await client.auth.signUp(email, password)\n },\n [client],\n )\n\n const signOut = useCallback(async () => {\n await client.auth.signOut()\n }, [client])\n\n const signInWithOAuth = useCallback(\n (provider: string, opts: { redirectTo: string }) => {\n const url = client.auth.signInWithOAuth(provider, opts)\n window.location.href = url\n },\n [client],\n )\n\n return { user, isLoading, signIn, signUp, signOut, signInWithOAuth }\n}\n","import { useState, useCallback } from 'react'\nimport { useClient } from './context'\nimport type { UploadOptions } from '@mimdb/client'\n\n/**\n * Return type of the {@link useUpload} hook.\n */\nexport interface UseUploadResult {\n /** Upload a file to the bucket. Re-throws on failure after setting `error`. */\n upload: (path: string, file: Blob | File, opts?: UploadOptions) => Promise<void>\n /** True while an upload is in progress. */\n isUploading: boolean\n /** The error from the most recent failed upload, or null. */\n error: Error | null\n}\n\n/**\n * React hook for uploading files to a MimDB storage bucket.\n *\n * Tracks the upload's loading and error state so components can show\n * progress indicators or error messages without manual state management.\n *\n * @param bucket - Name of the storage bucket to upload to.\n * @returns An object with the `upload` function and status flags.\n *\n * @example\n * ```tsx\n * function AvatarUpload() {\n * const { upload, isUploading, error } = useUpload('avatars')\n *\n * const handleFile = (file: File) => {\n * upload(`users/${userId}/avatar.png`, file, { contentType: 'image/png' })\n * }\n *\n * return (\n * <>\n * <input type=\"file\" onChange={(e) => handleFile(e.target.files![0])} />\n * {isUploading && <p>Uploading...</p>}\n * {error && <p>Error: {error.message}</p>}\n * </>\n * )\n * }\n * ```\n */\nexport function useUpload(bucket: string): UseUploadResult {\n const client = useClient()\n const [isUploading, setIsUploading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n const upload = useCallback(\n async (path: string, file: Blob | File, opts?: UploadOptions) => {\n setIsUploading(true)\n setError(null)\n try {\n await client.storage.from(bucket).upload(path, file, opts)\n } catch (err) {\n const uploadError =\n err instanceof Error ? err : new Error(String(err))\n setError(uploadError)\n throw uploadError\n } finally {\n setIsUploading(false)\n }\n },\n [client, bucket],\n )\n\n return { upload, isUploading, error }\n}\n"],"mappings":"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","names":["useQueryClient","useQueryClient","useState","useEffect","useState","useEffect","useState","useCallback","useState","useCallback"]}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@mimdb/react",
3
+ "version": "0.1.0",
4
+ "description": "React hooks for MimDB",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js",
10
+ "require": "./dist/index.cjs"
11
+ }
12
+ },
13
+ "main": "./dist/index.cjs",
14
+ "module": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "files": ["dist"],
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "lint": "tsc --noEmit"
22
+ },
23
+ "peerDependencies": {
24
+ "react": ">=18.0.0",
25
+ "@tanstack/react-query": ">=5.0.0",
26
+ "@mimdb/client": ">=0.1.0"
27
+ },
28
+ "devDependencies": {
29
+ "tsup": "^8.5.1",
30
+ "vitest": "^4.1.1",
31
+ "typescript": "^6.0.2",
32
+ "react": "^18.3.1",
33
+ "react-dom": "^18.3.1",
34
+ "@types/react": "^18.3.0",
35
+ "@tanstack/react-query": "^5.83.0",
36
+ "@testing-library/react": "^16.3.0",
37
+ "@mimdb/client": "workspace:*",
38
+ "@mimdb/realtime": "workspace:*",
39
+ "jsdom": "^26.1.0"
40
+ },
41
+ "license": "MIT",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "https://github.com/MimDB/SDK",
45
+ "directory": "packages/react"
46
+ },
47
+ "keywords": ["mimdb", "mimisbrunnr", "react", "hooks", "baas"]
48
+ }