@mimdb/react 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -99,16 +99,18 @@ function useInsert(table, options) {
99
99
  },
100
100
  onMutate: options?.optimistic ? async (newData) => {
101
101
  await queryClient.cancelQueries({ queryKey: ["mimdb", table] });
102
- const previous = queryClient.getQueryData(["mimdb", table]);
103
- queryClient.setQueryData(["mimdb", table], (old) => [
102
+ const previous = queryClient.getQueriesData({ queryKey: ["mimdb", table] });
103
+ queryClient.setQueriesData({ queryKey: ["mimdb", table] }, (old) => [
104
104
  ...old ?? [],
105
105
  newData
106
106
  ]);
107
107
  return { previous };
108
108
  } : void 0,
109
109
  onError: options?.optimistic ? (_err, _data, context) => {
110
- if (context?.previous !== void 0) {
111
- queryClient.setQueryData(["mimdb", table], context.previous);
110
+ if (context?.previous) {
111
+ for (const [key, data] of context.previous) {
112
+ queryClient.setQueryData(key, data);
113
+ }
112
114
  }
113
115
  } : void 0,
114
116
  onSettled: () => {
@@ -131,9 +133,9 @@ function useUpdate(table, options) {
131
133
  },
132
134
  onMutate: options?.optimistic ? async ({ data, eq }) => {
133
135
  await queryClient.cancelQueries({ queryKey: ["mimdb", table] });
134
- const previous = queryClient.getQueryData(["mimdb", table]);
135
- queryClient.setQueryData(
136
- ["mimdb", table],
136
+ const previous = queryClient.getQueriesData({ queryKey: ["mimdb", table] });
137
+ queryClient.setQueriesData(
138
+ { queryKey: ["mimdb", table] },
137
139
  (old) => (old ?? []).map((row) => {
138
140
  const record = row;
139
141
  const matches = Object.entries(eq).every(
@@ -145,8 +147,10 @@ function useUpdate(table, options) {
145
147
  return { previous };
146
148
  } : void 0,
147
149
  onError: options?.optimistic ? (_err, _data, context) => {
148
- if (context?.previous !== void 0) {
149
- queryClient.setQueryData(["mimdb", table], context.previous);
150
+ if (context?.previous) {
151
+ for (const [key, data] of context.previous) {
152
+ queryClient.setQueryData(key, data);
153
+ }
150
154
  }
151
155
  } : void 0,
152
156
  onSettled: () => {
@@ -168,9 +172,9 @@ function useDelete(table, options) {
168
172
  },
169
173
  onMutate: options?.optimistic ? async (eq) => {
170
174
  await queryClient.cancelQueries({ queryKey: ["mimdb", table] });
171
- const previous = queryClient.getQueryData(["mimdb", table]);
172
- queryClient.setQueryData(
173
- ["mimdb", table],
175
+ const previous = queryClient.getQueriesData({ queryKey: ["mimdb", table] });
176
+ queryClient.setQueriesData(
177
+ { queryKey: ["mimdb", table] },
174
178
  (old) => (old ?? []).filter(
175
179
  (row) => !Object.entries(eq).every(
176
180
  ([col, val]) => String(row[col]) === val
@@ -180,8 +184,10 @@ function useDelete(table, options) {
180
184
  return { previous };
181
185
  } : void 0,
182
186
  onError: options?.optimistic ? (_err, _data, context) => {
183
- if (context?.previous !== void 0) {
184
- queryClient.setQueryData(["mimdb", table], context.previous);
187
+ if (context?.previous) {
188
+ for (const [key, data] of context.previous) {
189
+ queryClient.setQueryData(key, data);
190
+ }
185
191
  }
186
192
  } : void 0,
187
193
  onSettled: () => {
@@ -1 +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-subscription.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 {\n useInsert,\n useUpdate,\n useDelete,\n type UpdateInput,\n type UseInsertOptions,\n type UseUpdateOptions,\n type UseDeleteOptions,\n} from './use-mutation'\nexport { useRealtime, type UseRealtimeOptions } from './use-realtime'\nexport { useSubscription, type UseSubscriptionResult } from './use-subscription'\nexport { useAuth, type UseAuthResult } from './use-auth'\nexport { useUpload, type UseUploadResult } from './use-upload'\n\n// Re-export createServerClient for convenience\nexport { createServerClient } from '@mimdb/client'\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 * Options for the {@link useInsert} hook.\n */\nexport interface UseInsertOptions {\n /**\n * Enable optimistic updates. When true, the new row is appended to\n * the query cache immediately and rolled back on error.\n */\n optimistic?: boolean\n}\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 * When `optimistic` is enabled, the new row is appended to the cache\n * before the server responds. On error the cache is rolled back.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @param options - Insert hook options.\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', { optimistic: true })\n * insert.mutate({ task: 'Buy milk', done: false })\n * ```\n */\nexport function useInsert<T = Record<string, unknown>>(\n table: string,\n options?: UseInsertOptions,\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 onMutate: options?.optimistic\n ? async (newData) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueryData<T[]>(['mimdb', table])\n queryClient.setQueryData<T[]>(['mimdb', table], (old) => [\n ...(old ?? []),\n newData as T,\n ])\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: T[] } | undefined) => {\n if (context?.previous !== undefined) {\n queryClient.setQueryData(['mimdb', table], context.previous)\n }\n }\n : undefined,\n onSettled: () => {\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 * Options for the {@link useUpdate} hook.\n */\nexport interface UseUpdateOptions {\n /**\n * Enable optimistic updates. When true, matching rows in the cache\n * are updated immediately and rolled back on error.\n */\n optimistic?: boolean\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 * When `optimistic` is enabled, matching rows in the cache are updated\n * in-place before the server responds and rolled back on error.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @param options - Update hook options.\n * @returns A TanStack `UseMutationResult`.\n *\n * @example\n * ```tsx\n * const update = useUpdate<Todo>('todos', { optimistic: true })\n * update.mutate({ data: { done: true }, eq: { id: '42' } })\n * ```\n */\nexport function useUpdate<T = Record<string, unknown>>(\n table: string,\n options?: UseUpdateOptions,\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 onMutate: options?.optimistic\n ? async ({ data, eq }) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueryData<T[]>(['mimdb', table])\n queryClient.setQueryData<T[]>(['mimdb', table], (old) =>\n (old ?? []).map((row) => {\n const record = row as Record<string, unknown>\n const matches = Object.entries(eq).every(\n ([col, val]) => String(record[col]) === val,\n )\n return matches ? { ...row, ...data } : row\n }),\n )\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: T[] } | undefined) => {\n if (context?.previous !== undefined) {\n queryClient.setQueryData(['mimdb', table], context.previous)\n }\n }\n : undefined,\n onSettled: () => {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n },\n })\n}\n\n/**\n * Options for the {@link useDelete} hook.\n */\nexport interface UseDeleteOptions {\n /**\n * Enable optimistic updates. When true, matching rows are removed\n * from the cache immediately and restored on error.\n */\n optimistic?: boolean\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 * When `optimistic` is enabled, matching rows are removed from the cache\n * before the server responds and restored on error.\n *\n * @param table - Name of the database table.\n * @param options - Delete hook options.\n * @returns A TanStack `UseMutationResult` whose `mutate` accepts equality filters.\n *\n * @example\n * ```tsx\n * const del = useDelete('todos', { optimistic: true })\n * del.mutate({ id: '42' })\n * ```\n */\nexport function useDelete(\n table: string,\n options?: UseDeleteOptions,\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 onMutate: options?.optimistic\n ? async (eq) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueryData<Record<string, unknown>[]>(['mimdb', table])\n queryClient.setQueryData<Record<string, unknown>[]>(['mimdb', table], (old) =>\n (old ?? []).filter((row) =>\n !Object.entries(eq).every(\n ([col, val]) => String(row[col]) === val,\n ),\n ),\n )\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: Record<string, unknown>[] } | undefined) => {\n if (context?.previous !== undefined) {\n queryClient.setQueryData(['mimdb', table], context.previous)\n }\n }\n : undefined,\n onSettled: () => {\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 // Skip WebSocket connections during SSR\n if (typeof window === 'undefined') return\n\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 } from 'react'\nimport type { RealtimeEvent, SubscriptionStatus } from '@mimdb/realtime'\nimport { useClient } from './context'\n\n/**\n * Return type of the {@link useSubscription} hook.\n *\n * @typeParam T - Expected row type for realtime events.\n */\nexport interface UseSubscriptionResult<T> {\n /** The most recently received realtime event, or null if none yet. */\n lastEvent: RealtimeEvent<T> | null\n /** Current subscription lifecycle status. */\n status: SubscriptionStatus\n}\n\n/**\n * Subscribe to a table and maintain the latest event in React state.\n *\n * Unlike {@link useRealtime} (which fires callbacks), this hook returns\n * the most recent event directly as component state, making it ideal\n * for rendering the latest change inline.\n *\n * Uses `client.realtime` (the lazy realtime accessor on MimDBClient)\n * so no separate realtime client setup is needed.\n *\n * The subscription is cleaned up when the component unmounts or when\n * `table`, `event`, or `filter` change.\n *\n * @typeParam T - Expected row type for realtime events.\n * @param table - Database table to subscribe to.\n * @param options - Event type and filter configuration.\n * @returns The latest event and subscription status.\n *\n * @example\n * ```tsx\n * const { lastEvent, status } = useSubscription<Message>('messages', {\n * event: 'INSERT',\n * })\n *\n * if (lastEvent) {\n * console.log('Latest insert:', lastEvent.new)\n * }\n * ```\n */\nexport function useSubscription<T = Record<string, unknown>>(\n table: string,\n options?: {\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 },\n): UseSubscriptionResult<T> {\n const client = useClient()\n const [lastEvent, setLastEvent] = useState<RealtimeEvent<T> | null>(null)\n const [status, setStatus] = useState<SubscriptionStatus>('pending')\n\n useEffect(() => {\n // Skip WebSocket connections during SSR\n if (typeof window === 'undefined') return\n\n const sub = client.realtime.subscribe<T>(table, {\n event: options?.event ?? '*',\n filter: options?.filter,\n onEvent(event) {\n setLastEvent(event)\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 { lastEvent, 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' || event === 'TOKEN_REFRESH_FAILED') {\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 if (typeof window !== 'undefined') {\n window.location.href = url\n }\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","import_react"]}
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-subscription.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 {\n useInsert,\n useUpdate,\n useDelete,\n type UpdateInput,\n type UseInsertOptions,\n type UseUpdateOptions,\n type UseDeleteOptions,\n} from './use-mutation'\nexport { useRealtime, type UseRealtimeOptions } from './use-realtime'\nexport { useSubscription, type UseSubscriptionResult } from './use-subscription'\nexport { useAuth, type UseAuthResult } from './use-auth'\nexport { useUpload, type UseUploadResult } from './use-upload'\n\n// Re-export createServerClient for convenience\nexport { createServerClient } from '@mimdb/client'\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 * Options for the {@link useInsert} hook.\n */\nexport interface UseInsertOptions {\n /**\n * Enable optimistic updates. When true, the new row is appended to\n * the query cache immediately and rolled back on error.\n */\n optimistic?: boolean\n}\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 * When `optimistic` is enabled, the new row is appended to the cache\n * before the server responds. On error the cache is rolled back.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @param options - Insert hook options.\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', { optimistic: true })\n * insert.mutate({ task: 'Buy milk', done: false })\n * ```\n */\nexport function useInsert<T = Record<string, unknown>>(\n table: string,\n options?: UseInsertOptions,\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 onMutate: options?.optimistic\n ? async (newData) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueriesData<T[]>({ queryKey: ['mimdb', table] })\n queryClient.setQueriesData<T[]>({ queryKey: ['mimdb', table] }, (old) => [\n ...(old ?? []),\n newData as T,\n ])\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: [readonly unknown[], T[] | undefined][] } | undefined) => {\n if (context?.previous) {\n for (const [key, data] of context.previous) {\n queryClient.setQueryData(key as unknown[], data)\n }\n }\n }\n : undefined,\n onSettled: () => {\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 * Options for the {@link useUpdate} hook.\n */\nexport interface UseUpdateOptions {\n /**\n * Enable optimistic updates. When true, matching rows in the cache\n * are updated immediately and rolled back on error.\n */\n optimistic?: boolean\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 * When `optimistic` is enabled, matching rows in the cache are updated\n * in-place before the server responds and rolled back on error.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @param options - Update hook options.\n * @returns A TanStack `UseMutationResult`.\n *\n * @example\n * ```tsx\n * const update = useUpdate<Todo>('todos', { optimistic: true })\n * update.mutate({ data: { done: true }, eq: { id: '42' } })\n * ```\n */\nexport function useUpdate<T = Record<string, unknown>>(\n table: string,\n options?: UseUpdateOptions,\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 onMutate: options?.optimistic\n ? async ({ data, eq }) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueriesData<T[]>({ queryKey: ['mimdb', table] })\n queryClient.setQueriesData<T[]>({ queryKey: ['mimdb', table] }, (old) =>\n (old ?? []).map((row) => {\n const record = row as Record<string, unknown>\n const matches = Object.entries(eq).every(\n ([col, val]) => String(record[col]) === val,\n )\n return matches ? { ...row, ...data } : row\n }),\n )\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: [readonly unknown[], T[] | undefined][] } | undefined) => {\n if (context?.previous) {\n for (const [key, data] of context.previous) {\n queryClient.setQueryData(key as unknown[], data)\n }\n }\n }\n : undefined,\n onSettled: () => {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n },\n })\n}\n\n/**\n * Options for the {@link useDelete} hook.\n */\nexport interface UseDeleteOptions {\n /**\n * Enable optimistic updates. When true, matching rows are removed\n * from the cache immediately and restored on error.\n */\n optimistic?: boolean\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 * When `optimistic` is enabled, matching rows are removed from the cache\n * before the server responds and restored on error.\n *\n * @param table - Name of the database table.\n * @param options - Delete hook options.\n * @returns A TanStack `UseMutationResult` whose `mutate` accepts equality filters.\n *\n * @example\n * ```tsx\n * const del = useDelete('todos', { optimistic: true })\n * del.mutate({ id: '42' })\n * ```\n */\nexport function useDelete(\n table: string,\n options?: UseDeleteOptions,\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 onMutate: options?.optimistic\n ? async (eq) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueriesData<Record<string, unknown>[]>({ queryKey: ['mimdb', table] })\n queryClient.setQueriesData<Record<string, unknown>[]>({ queryKey: ['mimdb', table] }, (old) =>\n (old ?? []).filter((row) =>\n !Object.entries(eq).every(\n ([col, val]) => String(row[col]) === val,\n ),\n ),\n )\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: [readonly unknown[], Record<string, unknown>[] | undefined][] } | undefined) => {\n if (context?.previous) {\n for (const [key, data] of context.previous) {\n queryClient.setQueryData(key as unknown[], data)\n }\n }\n }\n : undefined,\n onSettled: () => {\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 // Skip WebSocket connections during SSR\n if (typeof window === 'undefined') return\n\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 } from 'react'\nimport type { RealtimeEvent, SubscriptionStatus } from '@mimdb/realtime'\nimport { useClient } from './context'\n\n/**\n * Return type of the {@link useSubscription} hook.\n *\n * @typeParam T - Expected row type for realtime events.\n */\nexport interface UseSubscriptionResult<T> {\n /** The most recently received realtime event, or null if none yet. */\n lastEvent: RealtimeEvent<T> | null\n /** Current subscription lifecycle status. */\n status: SubscriptionStatus\n}\n\n/**\n * Subscribe to a table and maintain the latest event in React state.\n *\n * Unlike {@link useRealtime} (which fires callbacks), this hook returns\n * the most recent event directly as component state, making it ideal\n * for rendering the latest change inline.\n *\n * Uses `client.realtime` (the lazy realtime accessor on MimDBClient)\n * so no separate realtime client setup is needed.\n *\n * The subscription is cleaned up when the component unmounts or when\n * `table`, `event`, or `filter` change.\n *\n * @typeParam T - Expected row type for realtime events.\n * @param table - Database table to subscribe to.\n * @param options - Event type and filter configuration.\n * @returns The latest event and subscription status.\n *\n * @example\n * ```tsx\n * const { lastEvent, status } = useSubscription<Message>('messages', {\n * event: 'INSERT',\n * })\n *\n * if (lastEvent) {\n * console.log('Latest insert:', lastEvent.new)\n * }\n * ```\n */\nexport function useSubscription<T = Record<string, unknown>>(\n table: string,\n options?: {\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 },\n): UseSubscriptionResult<T> {\n const client = useClient()\n const [lastEvent, setLastEvent] = useState<RealtimeEvent<T> | null>(null)\n const [status, setStatus] = useState<SubscriptionStatus>('pending')\n\n useEffect(() => {\n // Skip WebSocket connections during SSR\n if (typeof window === 'undefined') return\n\n const sub = client.realtime.subscribe<T>(table, {\n event: options?.event ?? '*',\n filter: options?.filter,\n onEvent(event) {\n setLastEvent(event)\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 { lastEvent, 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' || event === 'TOKEN_REFRESH_FAILED') {\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 if (typeof window !== 'undefined') {\n window.location.href = url\n }\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAA0C;AAW1C,IAAM,mBAAe,4BAAkC,IAAI;AAgBpD,SAAS,YAAyB;AACvC,QAAM,aAAS,yBAAW,YAAY;AACtC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AACA,SAAO;AACT;;;ACOS;AADF,SAAS,cAAc,EAAE,QAAQ,SAAS,GAAuB;AACtE,SAAO,4CAAC,aAAa,UAAb,EAAsB,OAAO,QAAS,UAAS;AACzD;;;ACzCA,yBAGO;AAgDA,SAAS,SACd,OACA,SAC4B;AAC5B,QAAM,SAAS,UAAU;AAEzB,aAAO,mBAAAA,UAAiB;AAAA,IACtB,UAAU,CAAC,SAAS,OAAO,OAAO;AAAA,IAClC,SAAS,YAAY;AACnB,UAAI,QAAQ,OAAO,KAAQ,KAAK,EAAE,OAAO,SAAS,UAAU,GAAG;AAE/D,UAAI,SAAS,IAAI;AACf,mBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,QAAQ,EAAE,GAAG;AACnD,kBAAQ,MAAM,GAAG,KAAK,GAAG;AAAA,QAC3B;AAAA,MACF;AACA,UAAI,SAAS,KAAK;AAChB,mBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,QAAQ,GAAG,GAAG;AACpD,kBAAQ,MAAM,IAAI,KAAK,GAAG;AAAA,QAC5B;AAAA,MACF;AACA,UAAI,SAAS,OAAO;AAClB,gBAAQ,MAAM,MAAM,QAAQ,MAAM,QAAQ;AAAA,UACxC,WAAW,QAAQ,MAAM;AAAA,QAC3B,CAAC;AAAA,MACH;AACA,UAAI,SAAS,MAAO,SAAQ,MAAM,MAAM,QAAQ,KAAK;AACrD,UAAI,SAAS,OAAQ,SAAQ,MAAM,OAAO,QAAQ,MAAM;AAExD,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM;AAC9B,UAAI,MAAO,OAAM;AACjB,aAAQ,QAAQ,CAAC;AAAA,IACnB;AAAA,IACA,SAAS,SAAS;AAAA,IAClB,WAAW,SAAS;AAAA,IACpB,iBAAiB,SAAS;AAAA,EAC5B,CAAC;AACH;;;ACxFA,IAAAC,sBAIO;AAoCA,SAAS,UACd,OACA,SAC8C;AAC9C,QAAM,SAAS,UAAU;AACzB,QAAM,kBAAc,oCAAe;AAEnC,aAAO,oBAAAC,aAAoB;AAAA,IACzB,YAAY,OAAO,SAAqB;AACtC,YAAM,EAAE,MAAM,QAAQ,MAAM,IAAI,MAAM,OACnC,KAAQ,KAAK,EACb,OAAO,IAAI,EACX,OAAO,EACP,OAAO;AACV,UAAI,MAAO,OAAM;AACjB,aAAO;AAAA,IACT;AAAA,IACA,UAAU,SAAS,aACf,OAAO,YAAY;AACjB,YAAM,YAAY,cAAc,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE,CAAC;AAC9D,YAAM,WAAW,YAAY,eAAoB,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE,CAAC;AAC/E,kBAAY,eAAoB,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE,GAAG,CAAC,QAAQ;AAAA,QACvE,GAAI,OAAO,CAAC;AAAA,QACZ;AAAA,MACF,CAAC;AACD,aAAO,EAAE,SAAS;AAAA,IACpB,IACA;AAAA,IACJ,SAAS,SAAS,aACd,CAAC,MAAM,OAAO,YAAgF;AAC5F,UAAI,SAAS,UAAU;AACrB,mBAAW,CAAC,KAAK,IAAI,KAAK,QAAQ,UAAU;AAC1C,sBAAY,aAAa,KAAkB,IAAI;AAAA,QACjD;AAAA,MACF;AAAA,IACF,IACA;AAAA,IACJ,WAAW,MAAM;AACf,kBAAY,kBAAkB,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE,CAAC;AAAA,IAC9D;AAAA,EACF,CAAC;AACH;AA8CO,SAAS,UACd,OACA,SACkD;AAClD,QAAM,SAAS,UAAU;AACzB,QAAM,kBAAc,oCAAe;AAEnC,aAAO,oBAAAA,aAAoB;AAAA,IACzB,YAAY,OAAO,EAAE,MAAM,GAAG,MAAsB;AAClD,UAAI,QAAQ,OAAO,KAAQ,KAAK,EAAE,OAAO,IAAI;AAC7C,iBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,EAAE,GAAG;AAC3C,gBAAQ,MAAM,GAAG,KAAK,GAAG;AAAA,MAC3B;AACA,YAAM,EAAE,MAAM,QAAQ,MAAM,IAAI,MAAM,MAAM,OAAO,EAAE,OAAO;AAC5D,UAAI,MAAO,OAAM;AACjB,aAAO;AAAA,IACT;AAAA,IACA,UAAU,SAAS,aACf,OAAO,EAAE,MAAM,GAAG,MAAM;AACtB,YAAM,YAAY,cAAc,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE,CAAC;AAC9D,YAAM,WAAW,YAAY,eAAoB,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE,CAAC;AAC/E,kBAAY;AAAA,QAAoB,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE;AAAA,QAAG,CAAC,SAC9D,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ;AACvB,gBAAM,SAAS;AACf,gBAAM,UAAU,OAAO,QAAQ,EAAE,EAAE;AAAA,YACjC,CAAC,CAAC,KAAK,GAAG,MAAM,OAAO,OAAO,GAAG,CAAC,MAAM;AAAA,UAC1C;AACA,iBAAO,UAAU,EAAE,GAAG,KAAK,GAAG,KAAK,IAAI;AAAA,QACzC,CAAC;AAAA,MACH;AACA,aAAO,EAAE,SAAS;AAAA,IACpB,IACA;AAAA,IACJ,SAAS,SAAS,aACd,CAAC,MAAM,OAAO,YAAgF;AAC5F,UAAI,SAAS,UAAU;AACrB,mBAAW,CAAC,KAAK,IAAI,KAAK,QAAQ,UAAU;AAC1C,sBAAY,aAAa,KAAkB,IAAI;AAAA,QACjD;AAAA,MACF;AAAA,IACF,IACA;AAAA,IACJ,WAAW,MAAM;AACf,kBAAY,kBAAkB,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE,CAAC;AAAA,IAC9D;AAAA,EACF,CAAC;AACH;AAiCO,SAAS,UACd,OACA,SAC6D;AAC7D,QAAM,SAAS,UAAU;AACzB,QAAM,kBAAc,oCAAe;AAEnC,aAAO,oBAAAA,aAAoB;AAAA,IACzB,YAAY,OAAO,OAA+B;AAChD,UAAI,QAAQ,OAAO,KAAK,KAAK,EAAE,OAAO;AACtC,iBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,EAAE,GAAG;AAC3C,gBAAQ,MAAM,GAAG,KAAK,GAAG;AAAA,MAC3B;AACA,YAAM,EAAE,MAAM,IAAI,MAAM;AACxB,UAAI,MAAO,OAAM;AAAA,IACnB;AAAA,IACA,UAAU,SAAS,aACf,OAAO,OAAO;AACZ,YAAM,YAAY,cAAc,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE,CAAC;AAC9D,YAAM,WAAW,YAAY,eAA0C,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE,CAAC;AACrG,kBAAY;AAAA,QAA0C,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE;AAAA,QAAG,CAAC,SACpF,OAAO,CAAC,GAAG;AAAA,UAAO,CAAC,QAClB,CAAC,OAAO,QAAQ,EAAE,EAAE;AAAA,YAClB,CAAC,CAAC,KAAK,GAAG,MAAM,OAAO,IAAI,GAAG,CAAC,MAAM;AAAA,UACvC;AAAA,QACF;AAAA,MACF;AACA,aAAO,EAAE,SAAS;AAAA,IACpB,IACA;AAAA,IACJ,SAAS,SAAS,aACd,CAAC,MAAM,OAAO,YAAsG;AAClH,UAAI,SAAS,UAAU;AACrB,mBAAW,CAAC,KAAK,IAAI,KAAK,QAAQ,UAAU;AAC1C,sBAAY,aAAa,KAAkB,IAAI;AAAA,QACjD;AAAA,MACF;AAAA,IACF,IACA;AAAA,IACJ,WAAW,MAAM;AACf,kBAAY,kBAAkB,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE,CAAC;AAAA,IAC9D;AAAA,EACF,CAAC;AACH;;;ACzPA,IAAAC,gBAA4C;AAC5C,IAAAC,sBAA+B;AAC/B,sBAIO;AA8CA,SAAS,YACd,OACA,SACgC;AAChC,QAAM,SAAS,UAAU;AACzB,QAAM,kBAAc,oCAAe;AACnC,QAAM,CAAC,QAAQ,SAAS,QAAI,wBAA6B,SAAS;AAClE,QAAM,kBAAc,sBAAmC,IAAI;AAE3D,+BAAU,MAAM;AAEd,QAAI,OAAO,WAAW,YAAa;AAEnC,UAAM,SAAS,OAAO,UAAU;AAEhC,QAAI,CAAC,YAAY,SAAS;AACxB,kBAAY,UAAU,IAAI,oCAAoB;AAAA,QAC5C,KAAK,OAAO;AAAA,QACZ,YAAY,OAAO;AAAA,QACnB,QAAQ,OAAO;AAAA,MACjB,CAAC;AAAA,IACH;AAEA,UAAM,MAAM,YAAY,QAAQ,UAAa,OAAO;AAAA,MAClD,OAAO,SAAS,SAAS;AAAA,MACzB,QAAQ,SAAS;AAAA,MACjB,QAAQ,OAAO;AACb,iBAAS,UAAU,KAAK;AACxB,YAAI,SAAS,sBAAsB,OAAO;AACxC,sBAAY,kBAAkB,EAAE,UAAU,CAAC,SAAS,KAAK,EAAE,CAAC;AAAA,QAC9D;AAAA,MACF;AAAA,MACA,eAAe;AACb,kBAAU,QAAQ;AAAA,MACpB;AAAA,MACA,UAAU;AACR,kBAAU,OAAO;AAAA,MACnB;AAAA,IACF,CAAC;AAED,cAAU,SAAS;AAEnB,WAAO,MAAM;AACX,UAAI,YAAY;AAChB,gBAAU,QAAQ;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,SAAS,OAAO,SAAS,MAAM,CAAC;AAE3C,SAAO,EAAE,OAAO;AAClB;;;ACrGA,IAAAC,gBAAoC;AA6C7B,SAAS,gBACd,OACA,SAM0B;AAC1B,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAkC,IAAI;AACxE,QAAM,CAAC,QAAQ,SAAS,QAAI,wBAA6B,SAAS;AAElE,+BAAU,MAAM;AAEd,QAAI,OAAO,WAAW,YAAa;AAEnC,UAAM,MAAM,OAAO,SAAS,UAAa,OAAO;AAAA,MAC9C,OAAO,SAAS,SAAS;AAAA,MACzB,QAAQ,SAAS;AAAA,MACjB,QAAQ,OAAO;AACb,qBAAa,KAAK;AAAA,MACpB;AAAA,MACA,eAAe;AACb,kBAAU,QAAQ;AAAA,MACpB;AAAA,MACA,UAAU;AACR,kBAAU,OAAO;AAAA,MACnB;AAAA,IACF,CAAC;AAED,cAAU,SAAS;AAEnB,WAAO,MAAM;AACX,UAAI,YAAY;AAChB,gBAAU,QAAQ;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,OAAO,SAAS,OAAO,SAAS,MAAM,CAAC;AAE3C,SAAO,EAAE,WAAW,OAAO;AAC7B;;;ACrFA,IAAAC,gBAAiD;AA+C1C,SAAS,UAAyB;AACvC,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAsB,IAAI;AAClD,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,IAAI;AAE/C,+BAAU,MAAM;AACd,UAAM,UAAU,OAAO,KAAK,WAAW;AACvC,QAAI,SAAS;AACX,aAAO,KACJ,QAAQ,EACR,KAAK,OAAO,EACZ,MAAM,MAAM,QAAQ,IAAI,CAAC,EACzB,QAAQ,MAAM,aAAa,KAAK,CAAC;AAAA,IACtC,OAAO;AACL,mBAAa,KAAK;AAAA,IACpB;AAEA,UAAM,QAAQ,OAAO,KAAK,kBAAkB,CAAC,OAAO,aAAa;AAC/D,UAAI,UAAU,eAAe,UAAU,mBAAmB;AACxD,eAAO,KACJ,QAAQ,EACR,KAAK,OAAO,EACZ,MAAM,MAAM,QAAQ,IAAI,CAAC;AAAA,MAC9B,WAAW,UAAU,gBAAgB,UAAU,wBAAwB;AACrE,gBAAQ,IAAI;AAAA,MACd;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,aAAS;AAAA,IACb,OAAO,OAAe,aAAqB;AACzC,YAAM,OAAO,KAAK,OAAO,OAAO,QAAQ;AAAA,IAC1C;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,aAAS;AAAA,IACb,OAAO,OAAe,aAAqB;AACzC,YAAM,OAAO,KAAK,OAAO,OAAO,QAAQ;AAAA,IAC1C;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,cAAU,2BAAY,YAAY;AACtC,UAAM,OAAO,KAAK,QAAQ;AAAA,EAC5B,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,sBAAkB;AAAA,IACtB,CAAC,UAAkB,SAAiC;AAClD,YAAM,MAAM,OAAO,KAAK,gBAAgB,UAAU,IAAI;AACtD,UAAI,OAAO,WAAW,aAAa;AACjC,eAAO,SAAS,OAAO;AAAA,MACzB;AAAA,IACF;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,SAAO,EAAE,MAAM,WAAW,QAAQ,QAAQ,SAAS,gBAAgB;AACrE;;;AC3GA,IAAAC,gBAAsC;AA4C/B,SAAS,UAAU,QAAiC;AACzD,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,aAAa,cAAc,QAAI,wBAAS,KAAK;AACpD,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AAErD,QAAM,aAAS;AAAA,IACb,OAAO,MAAc,MAAmB,SAAyB;AAC/D,qBAAe,IAAI;AACnB,eAAS,IAAI;AACb,UAAI;AACF,cAAM,OAAO,QAAQ,KAAK,MAAM,EAAE,OAAO,MAAM,MAAM,IAAI;AAAA,MAC3D,SAAS,KAAK;AACZ,cAAM,cACJ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AACpD,iBAAS,WAAW;AACpB,cAAM;AAAA,MACR,UAAE;AACA,uBAAe,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,MAAM;AAAA,EACjB;AAEA,SAAO,EAAE,QAAQ,aAAa,MAAM;AACtC;;;ARlDA,oBAAmC;","names":["useTanstackQuery","import_react_query","useTanstackMutation","import_react","import_react_query","import_react","import_react","import_react"]}
package/dist/index.js CHANGED
@@ -68,16 +68,18 @@ function useInsert(table, options) {
68
68
  },
69
69
  onMutate: options?.optimistic ? async (newData) => {
70
70
  await queryClient.cancelQueries({ queryKey: ["mimdb", table] });
71
- const previous = queryClient.getQueryData(["mimdb", table]);
72
- queryClient.setQueryData(["mimdb", table], (old) => [
71
+ const previous = queryClient.getQueriesData({ queryKey: ["mimdb", table] });
72
+ queryClient.setQueriesData({ queryKey: ["mimdb", table] }, (old) => [
73
73
  ...old ?? [],
74
74
  newData
75
75
  ]);
76
76
  return { previous };
77
77
  } : void 0,
78
78
  onError: options?.optimistic ? (_err, _data, context) => {
79
- if (context?.previous !== void 0) {
80
- queryClient.setQueryData(["mimdb", table], context.previous);
79
+ if (context?.previous) {
80
+ for (const [key, data] of context.previous) {
81
+ queryClient.setQueryData(key, data);
82
+ }
81
83
  }
82
84
  } : void 0,
83
85
  onSettled: () => {
@@ -100,9 +102,9 @@ function useUpdate(table, options) {
100
102
  },
101
103
  onMutate: options?.optimistic ? async ({ data, eq }) => {
102
104
  await queryClient.cancelQueries({ queryKey: ["mimdb", table] });
103
- const previous = queryClient.getQueryData(["mimdb", table]);
104
- queryClient.setQueryData(
105
- ["mimdb", table],
105
+ const previous = queryClient.getQueriesData({ queryKey: ["mimdb", table] });
106
+ queryClient.setQueriesData(
107
+ { queryKey: ["mimdb", table] },
106
108
  (old) => (old ?? []).map((row) => {
107
109
  const record = row;
108
110
  const matches = Object.entries(eq).every(
@@ -114,8 +116,10 @@ function useUpdate(table, options) {
114
116
  return { previous };
115
117
  } : void 0,
116
118
  onError: options?.optimistic ? (_err, _data, context) => {
117
- if (context?.previous !== void 0) {
118
- queryClient.setQueryData(["mimdb", table], context.previous);
119
+ if (context?.previous) {
120
+ for (const [key, data] of context.previous) {
121
+ queryClient.setQueryData(key, data);
122
+ }
119
123
  }
120
124
  } : void 0,
121
125
  onSettled: () => {
@@ -137,9 +141,9 @@ function useDelete(table, options) {
137
141
  },
138
142
  onMutate: options?.optimistic ? async (eq) => {
139
143
  await queryClient.cancelQueries({ queryKey: ["mimdb", table] });
140
- const previous = queryClient.getQueryData(["mimdb", table]);
141
- queryClient.setQueryData(
142
- ["mimdb", table],
144
+ const previous = queryClient.getQueriesData({ queryKey: ["mimdb", table] });
145
+ queryClient.setQueriesData(
146
+ { queryKey: ["mimdb", table] },
143
147
  (old) => (old ?? []).filter(
144
148
  (row) => !Object.entries(eq).every(
145
149
  ([col, val]) => String(row[col]) === val
@@ -149,8 +153,10 @@ function useDelete(table, options) {
149
153
  return { previous };
150
154
  } : void 0,
151
155
  onError: options?.optimistic ? (_err, _data, context) => {
152
- if (context?.previous !== void 0) {
153
- queryClient.setQueryData(["mimdb", table], context.previous);
156
+ if (context?.previous) {
157
+ for (const [key, data] of context.previous) {
158
+ queryClient.setQueryData(key, data);
159
+ }
154
160
  }
155
161
  } : void 0,
156
162
  onSettled: () => {
package/dist/index.js.map CHANGED
@@ -1 +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-subscription.ts","../src/use-auth.ts","../src/use-upload.ts","../src/index.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 * Options for the {@link useInsert} hook.\n */\nexport interface UseInsertOptions {\n /**\n * Enable optimistic updates. When true, the new row is appended to\n * the query cache immediately and rolled back on error.\n */\n optimistic?: boolean\n}\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 * When `optimistic` is enabled, the new row is appended to the cache\n * before the server responds. On error the cache is rolled back.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @param options - Insert hook options.\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', { optimistic: true })\n * insert.mutate({ task: 'Buy milk', done: false })\n * ```\n */\nexport function useInsert<T = Record<string, unknown>>(\n table: string,\n options?: UseInsertOptions,\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 onMutate: options?.optimistic\n ? async (newData) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueryData<T[]>(['mimdb', table])\n queryClient.setQueryData<T[]>(['mimdb', table], (old) => [\n ...(old ?? []),\n newData as T,\n ])\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: T[] } | undefined) => {\n if (context?.previous !== undefined) {\n queryClient.setQueryData(['mimdb', table], context.previous)\n }\n }\n : undefined,\n onSettled: () => {\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 * Options for the {@link useUpdate} hook.\n */\nexport interface UseUpdateOptions {\n /**\n * Enable optimistic updates. When true, matching rows in the cache\n * are updated immediately and rolled back on error.\n */\n optimistic?: boolean\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 * When `optimistic` is enabled, matching rows in the cache are updated\n * in-place before the server responds and rolled back on error.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @param options - Update hook options.\n * @returns A TanStack `UseMutationResult`.\n *\n * @example\n * ```tsx\n * const update = useUpdate<Todo>('todos', { optimistic: true })\n * update.mutate({ data: { done: true }, eq: { id: '42' } })\n * ```\n */\nexport function useUpdate<T = Record<string, unknown>>(\n table: string,\n options?: UseUpdateOptions,\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 onMutate: options?.optimistic\n ? async ({ data, eq }) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueryData<T[]>(['mimdb', table])\n queryClient.setQueryData<T[]>(['mimdb', table], (old) =>\n (old ?? []).map((row) => {\n const record = row as Record<string, unknown>\n const matches = Object.entries(eq).every(\n ([col, val]) => String(record[col]) === val,\n )\n return matches ? { ...row, ...data } : row\n }),\n )\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: T[] } | undefined) => {\n if (context?.previous !== undefined) {\n queryClient.setQueryData(['mimdb', table], context.previous)\n }\n }\n : undefined,\n onSettled: () => {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n },\n })\n}\n\n/**\n * Options for the {@link useDelete} hook.\n */\nexport interface UseDeleteOptions {\n /**\n * Enable optimistic updates. When true, matching rows are removed\n * from the cache immediately and restored on error.\n */\n optimistic?: boolean\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 * When `optimistic` is enabled, matching rows are removed from the cache\n * before the server responds and restored on error.\n *\n * @param table - Name of the database table.\n * @param options - Delete hook options.\n * @returns A TanStack `UseMutationResult` whose `mutate` accepts equality filters.\n *\n * @example\n * ```tsx\n * const del = useDelete('todos', { optimistic: true })\n * del.mutate({ id: '42' })\n * ```\n */\nexport function useDelete(\n table: string,\n options?: UseDeleteOptions,\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 onMutate: options?.optimistic\n ? async (eq) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueryData<Record<string, unknown>[]>(['mimdb', table])\n queryClient.setQueryData<Record<string, unknown>[]>(['mimdb', table], (old) =>\n (old ?? []).filter((row) =>\n !Object.entries(eq).every(\n ([col, val]) => String(row[col]) === val,\n ),\n ),\n )\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: Record<string, unknown>[] } | undefined) => {\n if (context?.previous !== undefined) {\n queryClient.setQueryData(['mimdb', table], context.previous)\n }\n }\n : undefined,\n onSettled: () => {\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 // Skip WebSocket connections during SSR\n if (typeof window === 'undefined') return\n\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 } from 'react'\nimport type { RealtimeEvent, SubscriptionStatus } from '@mimdb/realtime'\nimport { useClient } from './context'\n\n/**\n * Return type of the {@link useSubscription} hook.\n *\n * @typeParam T - Expected row type for realtime events.\n */\nexport interface UseSubscriptionResult<T> {\n /** The most recently received realtime event, or null if none yet. */\n lastEvent: RealtimeEvent<T> | null\n /** Current subscription lifecycle status. */\n status: SubscriptionStatus\n}\n\n/**\n * Subscribe to a table and maintain the latest event in React state.\n *\n * Unlike {@link useRealtime} (which fires callbacks), this hook returns\n * the most recent event directly as component state, making it ideal\n * for rendering the latest change inline.\n *\n * Uses `client.realtime` (the lazy realtime accessor on MimDBClient)\n * so no separate realtime client setup is needed.\n *\n * The subscription is cleaned up when the component unmounts or when\n * `table`, `event`, or `filter` change.\n *\n * @typeParam T - Expected row type for realtime events.\n * @param table - Database table to subscribe to.\n * @param options - Event type and filter configuration.\n * @returns The latest event and subscription status.\n *\n * @example\n * ```tsx\n * const { lastEvent, status } = useSubscription<Message>('messages', {\n * event: 'INSERT',\n * })\n *\n * if (lastEvent) {\n * console.log('Latest insert:', lastEvent.new)\n * }\n * ```\n */\nexport function useSubscription<T = Record<string, unknown>>(\n table: string,\n options?: {\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 },\n): UseSubscriptionResult<T> {\n const client = useClient()\n const [lastEvent, setLastEvent] = useState<RealtimeEvent<T> | null>(null)\n const [status, setStatus] = useState<SubscriptionStatus>('pending')\n\n useEffect(() => {\n // Skip WebSocket connections during SSR\n if (typeof window === 'undefined') return\n\n const sub = client.realtime.subscribe<T>(table, {\n event: options?.event ?? '*',\n filter: options?.filter,\n onEvent(event) {\n setLastEvent(event)\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 { lastEvent, 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' || event === 'TOKEN_REFRESH_FAILED') {\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 if (typeof window !== 'undefined') {\n window.location.href = url\n }\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","export { MimDBProvider, type MimDBProviderProps } from './provider'\nexport { useClient } from './context'\nexport { useQuery, type UseQueryOptions } from './use-query'\nexport {\n useInsert,\n useUpdate,\n useDelete,\n type UpdateInput,\n type UseInsertOptions,\n type UseUpdateOptions,\n type UseDeleteOptions,\n} from './use-mutation'\nexport { useRealtime, type UseRealtimeOptions } from './use-realtime'\nexport { useSubscription, type UseSubscriptionResult } from './use-subscription'\nexport { useAuth, type UseAuthResult } from './use-auth'\nexport { useUpload, type UseUploadResult } from './use-upload'\n\n// Re-export createServerClient for convenience\nexport { createServerClient } from '@mimdb/client'\n"],"mappings":"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","names":["useQueryClient","useQueryClient","useState","useEffect","useState","useEffect","useState","useEffect","useState","useEffect","useState","useCallback","useState","useCallback"]}
1
+ {"version":3,"sources":["../src/context.ts","../src/provider.tsx","../src/use-query.ts","../src/use-mutation.ts","../src/use-realtime.ts","../src/use-subscription.ts","../src/use-auth.ts","../src/use-upload.ts","../src/index.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 * Options for the {@link useInsert} hook.\n */\nexport interface UseInsertOptions {\n /**\n * Enable optimistic updates. When true, the new row is appended to\n * the query cache immediately and rolled back on error.\n */\n optimistic?: boolean\n}\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 * When `optimistic` is enabled, the new row is appended to the cache\n * before the server responds. On error the cache is rolled back.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @param options - Insert hook options.\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', { optimistic: true })\n * insert.mutate({ task: 'Buy milk', done: false })\n * ```\n */\nexport function useInsert<T = Record<string, unknown>>(\n table: string,\n options?: UseInsertOptions,\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 onMutate: options?.optimistic\n ? async (newData) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueriesData<T[]>({ queryKey: ['mimdb', table] })\n queryClient.setQueriesData<T[]>({ queryKey: ['mimdb', table] }, (old) => [\n ...(old ?? []),\n newData as T,\n ])\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: [readonly unknown[], T[] | undefined][] } | undefined) => {\n if (context?.previous) {\n for (const [key, data] of context.previous) {\n queryClient.setQueryData(key as unknown[], data)\n }\n }\n }\n : undefined,\n onSettled: () => {\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 * Options for the {@link useUpdate} hook.\n */\nexport interface UseUpdateOptions {\n /**\n * Enable optimistic updates. When true, matching rows in the cache\n * are updated immediately and rolled back on error.\n */\n optimistic?: boolean\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 * When `optimistic` is enabled, matching rows in the cache are updated\n * in-place before the server responds and rolled back on error.\n *\n * @typeParam T - Expected row type. Defaults to a generic record.\n * @param table - Name of the database table.\n * @param options - Update hook options.\n * @returns A TanStack `UseMutationResult`.\n *\n * @example\n * ```tsx\n * const update = useUpdate<Todo>('todos', { optimistic: true })\n * update.mutate({ data: { done: true }, eq: { id: '42' } })\n * ```\n */\nexport function useUpdate<T = Record<string, unknown>>(\n table: string,\n options?: UseUpdateOptions,\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 onMutate: options?.optimistic\n ? async ({ data, eq }) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueriesData<T[]>({ queryKey: ['mimdb', table] })\n queryClient.setQueriesData<T[]>({ queryKey: ['mimdb', table] }, (old) =>\n (old ?? []).map((row) => {\n const record = row as Record<string, unknown>\n const matches = Object.entries(eq).every(\n ([col, val]) => String(record[col]) === val,\n )\n return matches ? { ...row, ...data } : row\n }),\n )\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: [readonly unknown[], T[] | undefined][] } | undefined) => {\n if (context?.previous) {\n for (const [key, data] of context.previous) {\n queryClient.setQueryData(key as unknown[], data)\n }\n }\n }\n : undefined,\n onSettled: () => {\n queryClient.invalidateQueries({ queryKey: ['mimdb', table] })\n },\n })\n}\n\n/**\n * Options for the {@link useDelete} hook.\n */\nexport interface UseDeleteOptions {\n /**\n * Enable optimistic updates. When true, matching rows are removed\n * from the cache immediately and restored on error.\n */\n optimistic?: boolean\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 * When `optimistic` is enabled, matching rows are removed from the cache\n * before the server responds and restored on error.\n *\n * @param table - Name of the database table.\n * @param options - Delete hook options.\n * @returns A TanStack `UseMutationResult` whose `mutate` accepts equality filters.\n *\n * @example\n * ```tsx\n * const del = useDelete('todos', { optimistic: true })\n * del.mutate({ id: '42' })\n * ```\n */\nexport function useDelete(\n table: string,\n options?: UseDeleteOptions,\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 onMutate: options?.optimistic\n ? async (eq) => {\n await queryClient.cancelQueries({ queryKey: ['mimdb', table] })\n const previous = queryClient.getQueriesData<Record<string, unknown>[]>({ queryKey: ['mimdb', table] })\n queryClient.setQueriesData<Record<string, unknown>[]>({ queryKey: ['mimdb', table] }, (old) =>\n (old ?? []).filter((row) =>\n !Object.entries(eq).every(\n ([col, val]) => String(row[col]) === val,\n ),\n ),\n )\n return { previous }\n }\n : undefined,\n onError: options?.optimistic\n ? (_err, _data, context: { previous?: [readonly unknown[], Record<string, unknown>[] | undefined][] } | undefined) => {\n if (context?.previous) {\n for (const [key, data] of context.previous) {\n queryClient.setQueryData(key as unknown[], data)\n }\n }\n }\n : undefined,\n onSettled: () => {\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 // Skip WebSocket connections during SSR\n if (typeof window === 'undefined') return\n\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 } from 'react'\nimport type { RealtimeEvent, SubscriptionStatus } from '@mimdb/realtime'\nimport { useClient } from './context'\n\n/**\n * Return type of the {@link useSubscription} hook.\n *\n * @typeParam T - Expected row type for realtime events.\n */\nexport interface UseSubscriptionResult<T> {\n /** The most recently received realtime event, or null if none yet. */\n lastEvent: RealtimeEvent<T> | null\n /** Current subscription lifecycle status. */\n status: SubscriptionStatus\n}\n\n/**\n * Subscribe to a table and maintain the latest event in React state.\n *\n * Unlike {@link useRealtime} (which fires callbacks), this hook returns\n * the most recent event directly as component state, making it ideal\n * for rendering the latest change inline.\n *\n * Uses `client.realtime` (the lazy realtime accessor on MimDBClient)\n * so no separate realtime client setup is needed.\n *\n * The subscription is cleaned up when the component unmounts or when\n * `table`, `event`, or `filter` change.\n *\n * @typeParam T - Expected row type for realtime events.\n * @param table - Database table to subscribe to.\n * @param options - Event type and filter configuration.\n * @returns The latest event and subscription status.\n *\n * @example\n * ```tsx\n * const { lastEvent, status } = useSubscription<Message>('messages', {\n * event: 'INSERT',\n * })\n *\n * if (lastEvent) {\n * console.log('Latest insert:', lastEvent.new)\n * }\n * ```\n */\nexport function useSubscription<T = Record<string, unknown>>(\n table: string,\n options?: {\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 },\n): UseSubscriptionResult<T> {\n const client = useClient()\n const [lastEvent, setLastEvent] = useState<RealtimeEvent<T> | null>(null)\n const [status, setStatus] = useState<SubscriptionStatus>('pending')\n\n useEffect(() => {\n // Skip WebSocket connections during SSR\n if (typeof window === 'undefined') return\n\n const sub = client.realtime.subscribe<T>(table, {\n event: options?.event ?? '*',\n filter: options?.filter,\n onEvent(event) {\n setLastEvent(event)\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 { lastEvent, 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' || event === 'TOKEN_REFRESH_FAILED') {\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 if (typeof window !== 'undefined') {\n window.location.href = url\n }\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","export { MimDBProvider, type MimDBProviderProps } from './provider'\nexport { useClient } from './context'\nexport { useQuery, type UseQueryOptions } from './use-query'\nexport {\n useInsert,\n useUpdate,\n useDelete,\n type UpdateInput,\n type UseInsertOptions,\n type UseUpdateOptions,\n type UseDeleteOptions,\n} from './use-mutation'\nexport { useRealtime, type UseRealtimeOptions } from './use-realtime'\nexport { useSubscription, type UseSubscriptionResult } from './use-subscription'\nexport { useAuth, type UseAuthResult } from './use-auth'\nexport { useUpload, type UseUploadResult } from './use-upload'\n\n// Re-export createServerClient for convenience\nexport { createServerClient } from '@mimdb/client'\n"],"mappings":"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","names":["useQueryClient","useQueryClient","useState","useEffect","useState","useEffect","useState","useEffect","useState","useEffect","useState","useCallback","useState","useCallback"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mimdb/react",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "React hooks for MimDB",
5
5
  "type": "module",
6
6
  "exports": {
@@ -23,7 +23,8 @@
23
23
  "peerDependencies": {
24
24
  "react": ">=18.0.0",
25
25
  "@tanstack/react-query": ">=5.0.0",
26
- "@mimdb/client": ">=0.1.0"
26
+ "@mimdb/client": ">=0.2.0",
27
+ "@mimdb/realtime": ">=0.1.1"
27
28
  },
28
29
  "devDependencies": {
29
30
  "tsup": "^8.5.1",