@taladb/react 0.8.4 → 0.9.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.d.mts CHANGED
@@ -1,27 +1,52 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { TalaDB, Document, Collection, Filter } from 'taladb';
3
+ import { TalaDB, OpenDBOptions, Document, Collection, Filter } from 'taladb';
4
4
 
5
- interface TalaDBProviderProps {
6
- /** The TalaDB instance returned by `openDB()`. */
7
- db: TalaDB;
5
+ type TalaDBProviderProps = {
8
6
  children: ReactNode;
9
- }
7
+ } & ({
8
+ /** A TalaDB instance you opened yourself with `openDB()`. */
9
+ db: TalaDB;
10
+ name?: never;
11
+ options?: never;
12
+ fallback?: never;
13
+ } | {
14
+ /**
15
+ * Database name — the provider owns the `openDB(name)` lifecycle:
16
+ * it opens lazily on the client (never during SSR), provides the handle
17
+ * once ready, and closes it on unmount. The natural form for Next.js,
18
+ * where `openDB` cannot run during server rendering.
19
+ */
20
+ name: string;
21
+ /** Options forwarded to `openDB(name, options)` (e.g. inline sync config). */
22
+ options?: OpenDBOptions;
23
+ /**
24
+ * Rendered while the database is opening (and during SSR).
25
+ * Defaults to `null`. Children only render once the db is ready, so
26
+ * `useTalaDB()` never observes a missing instance.
27
+ */
28
+ fallback?: ReactNode;
29
+ db?: never;
30
+ });
10
31
  /**
11
32
  * Provides a TalaDB instance to all child hooks.
12
33
  *
13
- * @example
34
+ * Two forms:
35
+ *
36
+ * **Instance form** — you own the lifecycle (plain React, React Native):
37
+ * ```tsx
14
38
  * const db = await openDB('myapp.db')
39
+ * <TalaDBProvider db={db}>…</TalaDBProvider>
40
+ * ```
15
41
  *
16
- * function App() {
17
- * return (
18
- * <TalaDBProvider db={db}>
19
- * <MyComponent />
20
- * </TalaDBProvider>
21
- * )
22
- * }
42
+ * **Name form** — the provider owns the lifecycle (recommended for Next.js):
43
+ * ```tsx
44
+ * <TalaDBProvider name="myapp.db" fallback={<Splash />}>…</TalaDBProvider>
45
+ * ```
46
+ * The database opens client-side only; during SSR (and while opening) the
47
+ * `fallback` renders instead of children, so hooks always see a ready db.
23
48
  */
24
- declare function TalaDBProvider({ db, children }: TalaDBProviderProps): react_jsx_runtime.JSX.Element;
49
+ declare function TalaDBProvider(props: TalaDBProviderProps): react_jsx_runtime.JSX.Element;
25
50
  /**
26
51
  * Returns the TalaDB instance from the nearest `<TalaDBProvider>`.
27
52
  *
@@ -49,6 +74,8 @@ interface FindResult<T> {
49
74
  data: T[];
50
75
  /** True until the first snapshot has been delivered from the database. */
51
76
  loading: boolean;
77
+ /** Most recent subscription error, cleared by the next successful snapshot. */
78
+ error: unknown | null;
52
79
  }
53
80
  /**
54
81
  * Subscribe to a live query. Re-renders whenever the matching documents change.
@@ -72,6 +99,8 @@ interface FindOneResult<T> {
72
99
  data: T | null;
73
100
  /** True until the first snapshot has been delivered from the database. */
74
101
  loading: boolean;
102
+ /** Most recent subscription error, cleared by the next successful snapshot. */
103
+ error: unknown | null;
75
104
  }
76
105
  /**
77
106
  * Subscribe to a single document live query. Re-renders when the matching
@@ -89,4 +118,233 @@ interface FindOneResult<T> {
89
118
  */
90
119
  declare function useFindOne<T extends Document>(collection: Collection<T>, filter: Filter<T>): FindOneResult<T>;
91
120
 
92
- export { type FindOneResult, type FindResult, TalaDBProvider, type TalaDBProviderProps, useCollection, useFind, useFindOne, useTalaDB };
121
+ /** Resolved network configuration for one replicated slice. */
122
+ interface ResolvedReplicationConfig {
123
+ /** Base URL; `/push` and `/pull` are appended by {@link HttpSyncAdapter}. */
124
+ endpoint: string;
125
+ /**
126
+ * Async (or sync) resolver for per-request headers — typically the
127
+ * `Authorization` bearer. Called **once per pass, at send time**, so a token
128
+ * that refreshed while a write sat in the local database is picked up when the
129
+ * write finally flushes.
130
+ */
131
+ getAuth?: () => Promise<Record<string, string>> | Record<string, string>;
132
+ /** `fetch` implementation. Defaults to the global `fetch`. */
133
+ fetch?: typeof fetch;
134
+ /** Override the `/push` and `/pull` sub-paths to match an existing API. */
135
+ paths?: {
136
+ push?: string;
137
+ pull?: string;
138
+ };
139
+ }
140
+
141
+ /** A slice to warm on first run — a collection, optionally on a specific endpoint. */
142
+ type PrefetchSlice = {
143
+ collection: string;
144
+ endpoint?: string;
145
+ };
146
+ /** A prefetch entry: a collection name (shorthand) or a {@link PrefetchSlice}. */
147
+ type PrefetchEntry = string | PrefetchSlice;
148
+ /** `'once'` warms a slice only if it has never synced; `'always'` on every mount. */
149
+ type PrefetchMode = 'once' | 'always';
150
+ /**
151
+ * Replication settings shared by `useQuery` / `useMutation`, supplied once by
152
+ * `<ReplicationProvider>` and overridable per hook.
153
+ *
154
+ * The origin is *your* API — never a database credential. It authorizes the
155
+ * session token from {@link ReplicationConfig.getAuth} and returns only that
156
+ * user's slice, so the auth header doubles as the per-user scope.
157
+ */
158
+ interface ReplicationConfig {
159
+ /** Base sync URL, e.g. `/api/sync`. `/push` and `/pull` are appended. */
160
+ endpoint: string;
161
+ /**
162
+ * Per-request header resolver — typically `{ Authorization: 'Bearer …' }`.
163
+ * Async so it can await a token refresh. Resolved at **send time**, once per
164
+ * pass, so an offline write flushed later carries a current token.
165
+ */
166
+ getAuth?: () => Promise<Record<string, string>> | Record<string, string>;
167
+ /** `fetch` implementation. Defaults to the global `fetch`. */
168
+ fetch?: typeof fetch;
169
+ /** Override the `/push` and `/pull` sub-paths to match an existing API. */
170
+ paths?: {
171
+ push?: string;
172
+ pull?: string;
173
+ };
174
+ /**
175
+ * Default background refresh interval (ms) for `useQuery`. A replication
176
+ * *interval*, not a cache TTL — the local data is never evicted, only
177
+ * refreshed. Omit or set `0` to disable polling by default; a hook can still
178
+ * opt in per query. `30_000` matches the guide's own example cadence.
179
+ */
180
+ pollMs?: number;
181
+ /**
182
+ * Slices to warm into the local replica in the background on first run, so a
183
+ * later `useQuery` for that collection reads local instead of waiting on the
184
+ * network. Best-effort and non-blocking: deferred to browser idle, run in the
185
+ * sync Worker on web, and silently skipped on failure. Each entry is a
186
+ * collection name or a {@link PrefetchSlice}.
187
+ */
188
+ prefetch?: PrefetchEntry[];
189
+ /** How prefetch decides to warm a slice. Default `'once'`. */
190
+ prefetchMode?: PrefetchMode;
191
+ /** Max concurrent prefetch pulls — keeps the active page from starving. Default `2`. */
192
+ prefetchConcurrency?: number;
193
+ }
194
+ interface ReplicationProviderProps extends ReplicationConfig {
195
+ children: ReactNode;
196
+ }
197
+ /**
198
+ * Supplies replication defaults (endpoint, auth, poll interval, prefetch) to the
199
+ * `useQuery` / `useMutation` hooks below it. Compose it inside a
200
+ * `<TalaDBProvider>`:
201
+ *
202
+ * ```tsx
203
+ * <TalaDBProvider name="app.db" fallback={<Splash />}>
204
+ * <ReplicationProvider
205
+ * endpoint="/api/sync"
206
+ * getAuth={async () => ({ Authorization: `Bearer ${await session.token()}` })}
207
+ * pollMs={30_000}
208
+ * prefetch={['products', 'categories']}
209
+ * >
210
+ * <App />
211
+ * </ReplicationProvider>
212
+ * </TalaDBProvider>
213
+ * ```
214
+ */
215
+ declare function ReplicationProvider({ children, ...config }: ReplicationProviderProps): react_jsx_runtime.JSX.Element;
216
+ /**
217
+ * Read the nearest replication config, merged with per-hook overrides.
218
+ * Non-throwing: `config` is `null` when no endpoint is resolvable (valid for
219
+ * `source: 'local-only'`); the caller decides whether that's an error.
220
+ */
221
+ declare function useReplicationConfig(overrides?: Partial<ReplicationConfig>): {
222
+ config: ResolvedReplicationConfig | null;
223
+ pollMs: number;
224
+ };
225
+
226
+ /**
227
+ * How a `useQuery` combines the local replica with the remote origin.
228
+ * *(`remote-only` is a planned addition; the durable-replica model makes it a
229
+ * rare escape hatch.)*
230
+ */
231
+ type ReadSource = 'local-first' | 'remote-first' | 'local-only';
232
+ interface UseQueryOptions<T extends Document> extends Partial<Pick<ReplicationConfig, 'endpoint' | 'getAuth' | 'fetch' | 'paths' | 'pollMs'>> {
233
+ /** Collection name — replicated as a whole; the `filter` narrows locally. */
234
+ collection: string;
235
+ /** Live filter over the local collection. Inline objects are safe. */
236
+ filter?: Filter<T>;
237
+ /**
238
+ * - `local-first` *(default)* — serve local immediately; refresh in the
239
+ * background, and the live query re-renders when the pull lands.
240
+ * - `remote-first` — stay `loading` until the first pull completes, then serve.
241
+ * - `local-only` — never touch the network (no endpoint required).
242
+ */
243
+ source?: ReadSource;
244
+ }
245
+ interface QueryResult<T> {
246
+ /** Current matching documents from the local replica. Reactive. */
247
+ data: T[];
248
+ /** First local snapshot pending — plus the first pull, for `remote-first`. */
249
+ loading: boolean;
250
+ /** Most recent local-read error. */
251
+ error: unknown | null;
252
+ /** A background replication pass is in flight. */
253
+ syncing: boolean;
254
+ /** Most recent replication error (the local data is still served). */
255
+ syncError: unknown | null;
256
+ /** Trigger a pull now. No-op for `local-only`. */
257
+ refetch: () => Promise<void>;
258
+ }
259
+ /**
260
+ * Bind a component to a slice of a remote origin, backed by the local replica.
261
+ *
262
+ * The read is a live query over the local collection (`useFind`); the network
263
+ * pull writes into that same collection, so the live query re-renders on its
264
+ * own — one-way data flow, no `queryKey`, no `invalidateQueries`. See
265
+ * `docs/scoped-replication.md`.
266
+ *
267
+ * @example
268
+ * const { data, loading, syncing } = useQuery<Product>({
269
+ * collection: 'products',
270
+ * filter: { category: 'kitchen' },
271
+ * pollMs: 30_000,
272
+ * })
273
+ */
274
+ declare function useQuery<T extends Document>(options: UseQueryOptions<T>): QueryResult<T>;
275
+
276
+ /**
277
+ * Run several scoped queries at once — one replication + live query per entry,
278
+ * in parallel. The result array is index-aligned with `queries`.
279
+ *
280
+ * Each entry is an independent `useQuery`: its own collection, filter, source,
281
+ * and (optionally) endpoint. This is the multi-slice page case — e.g. a
282
+ * dashboard that needs `orders` and `products` from the same origin. There are
283
+ * no cross-collection joins (TalaDB is a document store); compose in the
284
+ * component.
285
+ *
286
+ * v1 note: entries are typed as `Document`. For a strictly-typed single slice
287
+ * use `useQuery<T>`; per-entry generics (tuple typing) are a follow-up.
288
+ *
289
+ * @example
290
+ * const [orders, products] = useQueries([
291
+ * { collection: 'orders', filter: { open: true } },
292
+ * { collection: 'products' },
293
+ * ])
294
+ */
295
+ declare function useQueries(queries: UseQueryOptions<Document>[]): QueryResult<Document>[];
296
+
297
+ /** A single write intent against the local replica. Discriminated on `type`. */
298
+ type WriteOp<T extends Document> = {
299
+ type: 'insert';
300
+ doc: Omit<T, '_id'>;
301
+ } | {
302
+ type: 'update';
303
+ where: Filter<T>;
304
+ set: Partial<Omit<T, '_id'>>;
305
+ } | {
306
+ type: 'delete';
307
+ where: Filter<T>;
308
+ };
309
+ interface UseMutationOptions extends Partial<Pick<ReplicationConfig, 'endpoint' | 'getAuth' | 'fetch' | 'paths'>> {
310
+ /** Collection the write targets. */
311
+ collection: string;
312
+ /**
313
+ * Replication direction for the drain. `push` *(default)* sends the write;
314
+ * read hooks reconcile the authoritative value on their next pull. `both`
315
+ * also pulls the authoritative echo inline (heavier — replays the collection).
316
+ */
317
+ direction?: 'push' | 'both';
318
+ /**
319
+ * On mount, attempt to flush any local writes left unsent from a previous
320
+ * (offline) session for this collection. Default `true`.
321
+ */
322
+ drainOnMount?: boolean;
323
+ }
324
+ interface MutationResult<T extends Document> {
325
+ /** Fire-and-forget write. Errors surface on `error`, never thrown to render. */
326
+ mutate: (op: WriteOp<T>) => void;
327
+ /** Awaitable write. Resolves once the local write and drain settle; rejects on error. */
328
+ mutateAsync: (op: WriteOp<T>) => Promise<void>;
329
+ /** A write (local + drain) is in flight. */
330
+ pending: boolean;
331
+ /** Most recent write/drain error. The local write is durable regardless. */
332
+ error: unknown | null;
333
+ }
334
+ /**
335
+ * Local-first write hook. A mutation writes the local replica **first**
336
+ * (immediate, durable, reactive — every `useQuery`/`useFind` on the collection
337
+ * re-renders) and then replicates the change outward over the sync-contract with
338
+ * bounded retry. The network step never rolls the local write back: it is
339
+ * already committed, and a later drain still delivers it (write-behind).
340
+ *
341
+ * Write-authority is origin-authoritative by default — the push sends the
342
+ * change and the server is the arbiter; read hooks pull the authoritative value.
343
+ *
344
+ * @example
345
+ * const { mutate, pending } = useMutation<Order>({ collection: 'orders' })
346
+ * mutate({ type: 'update', where: { _id }, set: { status: 'shipped' } })
347
+ */
348
+ declare function useMutation<T extends Document>(options: UseMutationOptions): MutationResult<T>;
349
+
350
+ export { type FindOneResult, type FindResult, type MutationResult, type PrefetchEntry, type PrefetchMode, type PrefetchSlice, type QueryResult, type ReadSource, type ReplicationConfig, ReplicationProvider, type ReplicationProviderProps, TalaDBProvider, type TalaDBProviderProps, type UseMutationOptions, type UseQueryOptions, type WriteOp, useCollection, useFind, useFindOne, useMutation, useQueries, useQuery, useReplicationConfig, useTalaDB };
package/dist/index.d.ts CHANGED
@@ -1,27 +1,52 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { TalaDB, Document, Collection, Filter } from 'taladb';
3
+ import { TalaDB, OpenDBOptions, Document, Collection, Filter } from 'taladb';
4
4
 
5
- interface TalaDBProviderProps {
6
- /** The TalaDB instance returned by `openDB()`. */
7
- db: TalaDB;
5
+ type TalaDBProviderProps = {
8
6
  children: ReactNode;
9
- }
7
+ } & ({
8
+ /** A TalaDB instance you opened yourself with `openDB()`. */
9
+ db: TalaDB;
10
+ name?: never;
11
+ options?: never;
12
+ fallback?: never;
13
+ } | {
14
+ /**
15
+ * Database name — the provider owns the `openDB(name)` lifecycle:
16
+ * it opens lazily on the client (never during SSR), provides the handle
17
+ * once ready, and closes it on unmount. The natural form for Next.js,
18
+ * where `openDB` cannot run during server rendering.
19
+ */
20
+ name: string;
21
+ /** Options forwarded to `openDB(name, options)` (e.g. inline sync config). */
22
+ options?: OpenDBOptions;
23
+ /**
24
+ * Rendered while the database is opening (and during SSR).
25
+ * Defaults to `null`. Children only render once the db is ready, so
26
+ * `useTalaDB()` never observes a missing instance.
27
+ */
28
+ fallback?: ReactNode;
29
+ db?: never;
30
+ });
10
31
  /**
11
32
  * Provides a TalaDB instance to all child hooks.
12
33
  *
13
- * @example
34
+ * Two forms:
35
+ *
36
+ * **Instance form** — you own the lifecycle (plain React, React Native):
37
+ * ```tsx
14
38
  * const db = await openDB('myapp.db')
39
+ * <TalaDBProvider db={db}>…</TalaDBProvider>
40
+ * ```
15
41
  *
16
- * function App() {
17
- * return (
18
- * <TalaDBProvider db={db}>
19
- * <MyComponent />
20
- * </TalaDBProvider>
21
- * )
22
- * }
42
+ * **Name form** — the provider owns the lifecycle (recommended for Next.js):
43
+ * ```tsx
44
+ * <TalaDBProvider name="myapp.db" fallback={<Splash />}>…</TalaDBProvider>
45
+ * ```
46
+ * The database opens client-side only; during SSR (and while opening) the
47
+ * `fallback` renders instead of children, so hooks always see a ready db.
23
48
  */
24
- declare function TalaDBProvider({ db, children }: TalaDBProviderProps): react_jsx_runtime.JSX.Element;
49
+ declare function TalaDBProvider(props: TalaDBProviderProps): react_jsx_runtime.JSX.Element;
25
50
  /**
26
51
  * Returns the TalaDB instance from the nearest `<TalaDBProvider>`.
27
52
  *
@@ -49,6 +74,8 @@ interface FindResult<T> {
49
74
  data: T[];
50
75
  /** True until the first snapshot has been delivered from the database. */
51
76
  loading: boolean;
77
+ /** Most recent subscription error, cleared by the next successful snapshot. */
78
+ error: unknown | null;
52
79
  }
53
80
  /**
54
81
  * Subscribe to a live query. Re-renders whenever the matching documents change.
@@ -72,6 +99,8 @@ interface FindOneResult<T> {
72
99
  data: T | null;
73
100
  /** True until the first snapshot has been delivered from the database. */
74
101
  loading: boolean;
102
+ /** Most recent subscription error, cleared by the next successful snapshot. */
103
+ error: unknown | null;
75
104
  }
76
105
  /**
77
106
  * Subscribe to a single document live query. Re-renders when the matching
@@ -89,4 +118,233 @@ interface FindOneResult<T> {
89
118
  */
90
119
  declare function useFindOne<T extends Document>(collection: Collection<T>, filter: Filter<T>): FindOneResult<T>;
91
120
 
92
- export { type FindOneResult, type FindResult, TalaDBProvider, type TalaDBProviderProps, useCollection, useFind, useFindOne, useTalaDB };
121
+ /** Resolved network configuration for one replicated slice. */
122
+ interface ResolvedReplicationConfig {
123
+ /** Base URL; `/push` and `/pull` are appended by {@link HttpSyncAdapter}. */
124
+ endpoint: string;
125
+ /**
126
+ * Async (or sync) resolver for per-request headers — typically the
127
+ * `Authorization` bearer. Called **once per pass, at send time**, so a token
128
+ * that refreshed while a write sat in the local database is picked up when the
129
+ * write finally flushes.
130
+ */
131
+ getAuth?: () => Promise<Record<string, string>> | Record<string, string>;
132
+ /** `fetch` implementation. Defaults to the global `fetch`. */
133
+ fetch?: typeof fetch;
134
+ /** Override the `/push` and `/pull` sub-paths to match an existing API. */
135
+ paths?: {
136
+ push?: string;
137
+ pull?: string;
138
+ };
139
+ }
140
+
141
+ /** A slice to warm on first run — a collection, optionally on a specific endpoint. */
142
+ type PrefetchSlice = {
143
+ collection: string;
144
+ endpoint?: string;
145
+ };
146
+ /** A prefetch entry: a collection name (shorthand) or a {@link PrefetchSlice}. */
147
+ type PrefetchEntry = string | PrefetchSlice;
148
+ /** `'once'` warms a slice only if it has never synced; `'always'` on every mount. */
149
+ type PrefetchMode = 'once' | 'always';
150
+ /**
151
+ * Replication settings shared by `useQuery` / `useMutation`, supplied once by
152
+ * `<ReplicationProvider>` and overridable per hook.
153
+ *
154
+ * The origin is *your* API — never a database credential. It authorizes the
155
+ * session token from {@link ReplicationConfig.getAuth} and returns only that
156
+ * user's slice, so the auth header doubles as the per-user scope.
157
+ */
158
+ interface ReplicationConfig {
159
+ /** Base sync URL, e.g. `/api/sync`. `/push` and `/pull` are appended. */
160
+ endpoint: string;
161
+ /**
162
+ * Per-request header resolver — typically `{ Authorization: 'Bearer …' }`.
163
+ * Async so it can await a token refresh. Resolved at **send time**, once per
164
+ * pass, so an offline write flushed later carries a current token.
165
+ */
166
+ getAuth?: () => Promise<Record<string, string>> | Record<string, string>;
167
+ /** `fetch` implementation. Defaults to the global `fetch`. */
168
+ fetch?: typeof fetch;
169
+ /** Override the `/push` and `/pull` sub-paths to match an existing API. */
170
+ paths?: {
171
+ push?: string;
172
+ pull?: string;
173
+ };
174
+ /**
175
+ * Default background refresh interval (ms) for `useQuery`. A replication
176
+ * *interval*, not a cache TTL — the local data is never evicted, only
177
+ * refreshed. Omit or set `0` to disable polling by default; a hook can still
178
+ * opt in per query. `30_000` matches the guide's own example cadence.
179
+ */
180
+ pollMs?: number;
181
+ /**
182
+ * Slices to warm into the local replica in the background on first run, so a
183
+ * later `useQuery` for that collection reads local instead of waiting on the
184
+ * network. Best-effort and non-blocking: deferred to browser idle, run in the
185
+ * sync Worker on web, and silently skipped on failure. Each entry is a
186
+ * collection name or a {@link PrefetchSlice}.
187
+ */
188
+ prefetch?: PrefetchEntry[];
189
+ /** How prefetch decides to warm a slice. Default `'once'`. */
190
+ prefetchMode?: PrefetchMode;
191
+ /** Max concurrent prefetch pulls — keeps the active page from starving. Default `2`. */
192
+ prefetchConcurrency?: number;
193
+ }
194
+ interface ReplicationProviderProps extends ReplicationConfig {
195
+ children: ReactNode;
196
+ }
197
+ /**
198
+ * Supplies replication defaults (endpoint, auth, poll interval, prefetch) to the
199
+ * `useQuery` / `useMutation` hooks below it. Compose it inside a
200
+ * `<TalaDBProvider>`:
201
+ *
202
+ * ```tsx
203
+ * <TalaDBProvider name="app.db" fallback={<Splash />}>
204
+ * <ReplicationProvider
205
+ * endpoint="/api/sync"
206
+ * getAuth={async () => ({ Authorization: `Bearer ${await session.token()}` })}
207
+ * pollMs={30_000}
208
+ * prefetch={['products', 'categories']}
209
+ * >
210
+ * <App />
211
+ * </ReplicationProvider>
212
+ * </TalaDBProvider>
213
+ * ```
214
+ */
215
+ declare function ReplicationProvider({ children, ...config }: ReplicationProviderProps): react_jsx_runtime.JSX.Element;
216
+ /**
217
+ * Read the nearest replication config, merged with per-hook overrides.
218
+ * Non-throwing: `config` is `null` when no endpoint is resolvable (valid for
219
+ * `source: 'local-only'`); the caller decides whether that's an error.
220
+ */
221
+ declare function useReplicationConfig(overrides?: Partial<ReplicationConfig>): {
222
+ config: ResolvedReplicationConfig | null;
223
+ pollMs: number;
224
+ };
225
+
226
+ /**
227
+ * How a `useQuery` combines the local replica with the remote origin.
228
+ * *(`remote-only` is a planned addition; the durable-replica model makes it a
229
+ * rare escape hatch.)*
230
+ */
231
+ type ReadSource = 'local-first' | 'remote-first' | 'local-only';
232
+ interface UseQueryOptions<T extends Document> extends Partial<Pick<ReplicationConfig, 'endpoint' | 'getAuth' | 'fetch' | 'paths' | 'pollMs'>> {
233
+ /** Collection name — replicated as a whole; the `filter` narrows locally. */
234
+ collection: string;
235
+ /** Live filter over the local collection. Inline objects are safe. */
236
+ filter?: Filter<T>;
237
+ /**
238
+ * - `local-first` *(default)* — serve local immediately; refresh in the
239
+ * background, and the live query re-renders when the pull lands.
240
+ * - `remote-first` — stay `loading` until the first pull completes, then serve.
241
+ * - `local-only` — never touch the network (no endpoint required).
242
+ */
243
+ source?: ReadSource;
244
+ }
245
+ interface QueryResult<T> {
246
+ /** Current matching documents from the local replica. Reactive. */
247
+ data: T[];
248
+ /** First local snapshot pending — plus the first pull, for `remote-first`. */
249
+ loading: boolean;
250
+ /** Most recent local-read error. */
251
+ error: unknown | null;
252
+ /** A background replication pass is in flight. */
253
+ syncing: boolean;
254
+ /** Most recent replication error (the local data is still served). */
255
+ syncError: unknown | null;
256
+ /** Trigger a pull now. No-op for `local-only`. */
257
+ refetch: () => Promise<void>;
258
+ }
259
+ /**
260
+ * Bind a component to a slice of a remote origin, backed by the local replica.
261
+ *
262
+ * The read is a live query over the local collection (`useFind`); the network
263
+ * pull writes into that same collection, so the live query re-renders on its
264
+ * own — one-way data flow, no `queryKey`, no `invalidateQueries`. See
265
+ * `docs/scoped-replication.md`.
266
+ *
267
+ * @example
268
+ * const { data, loading, syncing } = useQuery<Product>({
269
+ * collection: 'products',
270
+ * filter: { category: 'kitchen' },
271
+ * pollMs: 30_000,
272
+ * })
273
+ */
274
+ declare function useQuery<T extends Document>(options: UseQueryOptions<T>): QueryResult<T>;
275
+
276
+ /**
277
+ * Run several scoped queries at once — one replication + live query per entry,
278
+ * in parallel. The result array is index-aligned with `queries`.
279
+ *
280
+ * Each entry is an independent `useQuery`: its own collection, filter, source,
281
+ * and (optionally) endpoint. This is the multi-slice page case — e.g. a
282
+ * dashboard that needs `orders` and `products` from the same origin. There are
283
+ * no cross-collection joins (TalaDB is a document store); compose in the
284
+ * component.
285
+ *
286
+ * v1 note: entries are typed as `Document`. For a strictly-typed single slice
287
+ * use `useQuery<T>`; per-entry generics (tuple typing) are a follow-up.
288
+ *
289
+ * @example
290
+ * const [orders, products] = useQueries([
291
+ * { collection: 'orders', filter: { open: true } },
292
+ * { collection: 'products' },
293
+ * ])
294
+ */
295
+ declare function useQueries(queries: UseQueryOptions<Document>[]): QueryResult<Document>[];
296
+
297
+ /** A single write intent against the local replica. Discriminated on `type`. */
298
+ type WriteOp<T extends Document> = {
299
+ type: 'insert';
300
+ doc: Omit<T, '_id'>;
301
+ } | {
302
+ type: 'update';
303
+ where: Filter<T>;
304
+ set: Partial<Omit<T, '_id'>>;
305
+ } | {
306
+ type: 'delete';
307
+ where: Filter<T>;
308
+ };
309
+ interface UseMutationOptions extends Partial<Pick<ReplicationConfig, 'endpoint' | 'getAuth' | 'fetch' | 'paths'>> {
310
+ /** Collection the write targets. */
311
+ collection: string;
312
+ /**
313
+ * Replication direction for the drain. `push` *(default)* sends the write;
314
+ * read hooks reconcile the authoritative value on their next pull. `both`
315
+ * also pulls the authoritative echo inline (heavier — replays the collection).
316
+ */
317
+ direction?: 'push' | 'both';
318
+ /**
319
+ * On mount, attempt to flush any local writes left unsent from a previous
320
+ * (offline) session for this collection. Default `true`.
321
+ */
322
+ drainOnMount?: boolean;
323
+ }
324
+ interface MutationResult<T extends Document> {
325
+ /** Fire-and-forget write. Errors surface on `error`, never thrown to render. */
326
+ mutate: (op: WriteOp<T>) => void;
327
+ /** Awaitable write. Resolves once the local write and drain settle; rejects on error. */
328
+ mutateAsync: (op: WriteOp<T>) => Promise<void>;
329
+ /** A write (local + drain) is in flight. */
330
+ pending: boolean;
331
+ /** Most recent write/drain error. The local write is durable regardless. */
332
+ error: unknown | null;
333
+ }
334
+ /**
335
+ * Local-first write hook. A mutation writes the local replica **first**
336
+ * (immediate, durable, reactive — every `useQuery`/`useFind` on the collection
337
+ * re-renders) and then replicates the change outward over the sync-contract with
338
+ * bounded retry. The network step never rolls the local write back: it is
339
+ * already committed, and a later drain still delivers it (write-behind).
340
+ *
341
+ * Write-authority is origin-authoritative by default — the push sends the
342
+ * change and the server is the arbiter; read hooks pull the authoritative value.
343
+ *
344
+ * @example
345
+ * const { mutate, pending } = useMutation<Order>({ collection: 'orders' })
346
+ * mutate({ type: 'update', where: { _id }, set: { status: 'shipped' } })
347
+ */
348
+ declare function useMutation<T extends Document>(options: UseMutationOptions): MutationResult<T>;
349
+
350
+ export { type FindOneResult, type FindResult, type MutationResult, type PrefetchEntry, type PrefetchMode, type PrefetchSlice, type QueryResult, type ReadSource, type ReplicationConfig, ReplicationProvider, type ReplicationProviderProps, TalaDBProvider, type TalaDBProviderProps, type UseMutationOptions, type UseQueryOptions, type WriteOp, useCollection, useFind, useFindOne, useMutation, useQueries, useQuery, useReplicationConfig, useTalaDB };