pbtsdb 0.11.0 → 2.0.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/README.md CHANGED
@@ -1,13 +1,12 @@
1
1
  # pbtsdb: PocketBase TanStack Database Integration
2
2
 
3
- > Type-safe PocketBase integration with TanStack Query and TanStack DB
3
+ > Type-safe PocketBase integration with TanStack DB
4
4
 
5
- A TypeScript library that seamlessly integrates [PocketBase](https://pocketbase.io) with [TanStack Query](https://tanstack.com/query) and [TanStack DB](https://tanstack.com/db), providing:
5
+ A TypeScript library that seamlessly integrates [PocketBase](https://pocketbase.io) with [TanStack DB](https://tanstack.com/db), providing:
6
6
 
7
7
  - 🔥 **Real-time subscriptions** with automatic synchronization
8
8
  - 🎯 **Full TypeScript type safety** for queries and relations
9
9
  - ⚡ **Reactive collections** with TanStack DB
10
- - 🔄 **Automatic caching** via TanStack Query
11
10
  - ✨ **Optimistic mutations** with insert/update/delete support
12
11
  - 🎨 **React hooks** for easy component integration
13
12
  - 🔗 **Type-safe joins** and relation fetching into their own collections
@@ -22,6 +21,7 @@ A TypeScript library that seamlessly integrates [PocketBase](https://pocketbase.
22
21
  - [Related data](#related-data)
23
22
  - [React Integration](#react-integration)
24
23
  - [Subscriptions](#subscriptions)
24
+ - [Sync Status API](#sync-status-api)
25
25
  - [Utility Functions](#utility-functions)
26
26
  - [Usage Examples](#usage-examples)
27
27
  - [Includes (Nested Subqueries)](#includes-nested-subqueries)
@@ -32,16 +32,14 @@ A TypeScript library that seamlessly integrates [PocketBase](https://pocketbase.
32
32
  ## Installation
33
33
 
34
34
  ```bash
35
- npm install pbtsdb pocketbase @tanstack/db @tanstack/query-db-collection @tanstack/react-query @tanstack/react-db
35
+ npm install pbtsdb pocketbase @tanstack/db @tanstack/react-db
36
36
  ```
37
37
 
38
38
  ### Peer Dependencies
39
39
 
40
40
  - `pocketbase` >= 0.22.0
41
- - `@tanstack/db` >= 0.6.0
42
- - `@tanstack/query-db-collection` >= 1.0.40
43
- - `@tanstack/react-query` >= 5.0.0
44
- - `@tanstack/react-db` >= 0.1.86 (optional; only for `createReactProvider`)
41
+ - `@tanstack/db` >= 0.12.1
42
+ - `@tanstack/react-db` >= 0.5.5 (optional; only for `createReactProvider`)
45
43
  - `react` and `react-dom` >= 18.0.0 (optional)
46
44
 
47
45
  All peer dependencies use minimum version constraints; newer versions should work. The
@@ -110,18 +108,12 @@ type BlogSchema = {
110
108
  ```typescript
111
109
  // app.tsx
112
110
  import PocketBase from 'pocketbase';
113
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
114
111
  import { createCollection, createReactProvider } from 'pbtsdb';
115
112
 
116
113
  const pb = new PocketBase('http://localhost:8090');
117
- const queryClient = new QueryClient({
118
- defaultOptions: {
119
- queries: { staleTime: 60_000 } // Cache for 1 minute
120
- }
121
- });
122
114
 
123
115
  // Create collections with automatic type inference
124
- const c = createCollection<BlogSchema>(pb, queryClient);
116
+ const c = createCollection<BlogSchema>(pb);
125
117
  const users = c('users', {});
126
118
  export const { Provider, useStore } = createReactProvider({
127
119
  users,
@@ -139,11 +131,9 @@ export const { Provider, useStore } = createReactProvider({
139
131
 
140
132
  export function App() {
141
133
  return (
142
- <QueryClientProvider client={queryClient}>
143
- <Provider>
144
- <BlogDashboard />
145
- </Provider>
146
- </QueryClientProvider>
134
+ <Provider>
135
+ <BlogDashboard />
136
+ </Provider>
147
137
  );
148
138
  }
149
139
  ```
@@ -253,14 +243,13 @@ Collections are reactive data stores that automatically sync with PocketBase:
253
243
 
254
244
  ```typescript
255
245
  // Create a collection using the curried API
256
- const c = createCollection<MySchema>(pb, queryClient);
246
+ const c = createCollection<MySchema>(pb);
257
247
  const booksCollection = c('books', {});
258
248
 
259
249
  // Collections automatically:
260
250
  // - Fetch data from PocketBase
261
251
  // - Subscribe to real-time updates
262
252
  // - Update React components when data changes
263
- // - Cache data via TanStack Query
264
253
  ```
265
254
 
266
255
  ### Real-time Subscriptions
@@ -269,7 +258,7 @@ Collections manage subscriptions **automatically** based on query lifecycle:
269
258
 
270
259
  ```typescript
271
260
  // Collections are lazy - no subscription until queried
272
- const c = createCollection<MySchema>(pb, queryClient);
261
+ const c = createCollection<MySchema>(pb);
273
262
  const booksCollection = c('books', {});
274
263
 
275
264
  // Subscription starts automatically when query becomes active
@@ -286,6 +275,74 @@ const { data } = useLiveQuery((q) =>
286
275
  - **Shared:** Multiple components using the same collection share one subscription
287
276
  - **No manual control needed:** The collection handles all subscription management internally
288
277
 
278
+ ### Reconnects
279
+
280
+ pbtsdb runs its own realtime connection. When the connection drops, it reconnects with backoff and refetches every live query, because PocketBase does not replay events missed during the gap. A server that supports pbtsdb's resume extension (`?resume=<clientId>&after=<seq>` on the SSE URL, `resumed: true` in `PB_CONNECT`, `seq` on each event) replays the gap instead, and no refetch runs.
281
+
282
+ pbtsdb's connection is independent of `pb.realtime`. When `pb.authStore` changes to another auth record (login, logout, switching users), pbtsdb forgets the connection's server-side session and reconnects at once, re-sending every subscribed topic under the new auth; every ready collection reloads once that POST succeeds, the same as a non-resumed reconnect. A token refresh for the same record changes nothing. PocketBase would otherwise answer the next subscriptions POST with a 403, or keep serving the previous user's data.
283
+
284
+ Call `resetRealtime(pb)` yourself for a change the auth store cannot see, such as pointing `pb` at another server:
285
+
286
+ ```typescript
287
+ import { disconnectRealtime, resetRealtime } from 'pbtsdb';
288
+
289
+ resetRealtime(pb); // forget the session and re-subscribe every open topic now
290
+
291
+ disconnectRealtime(pb); // close the connection and keep it closed
292
+ resetRealtime(pb); // open it again; every ready collection reloads
293
+ ```
294
+
295
+ `disconnectRealtime(pb)` closes the connection and keeps it closed until `resetRealtime(pb)`. Collections keep working over REST and keep their subscriptions registered. Use it at logout, or at startup where realtime is not wanted, such as an embedded view.
296
+
297
+ ### Sync Status
298
+
299
+ Two problems are visible only to pbtsdb: the realtime stream dropping while REST still works, so lists look fine but stop updating; and a query sleeping in its load retry backoff, so a list sits in "loading" with no reason shown. `getSyncStatus(pb)` reports both, for every collection of one client:
300
+
301
+ ```typescript
302
+ import { getSyncStatus, subscribeSyncStatus } from 'pbtsdb';
303
+
304
+ const status = getSyncStatus(pb);
305
+ // {
306
+ // realtime:
307
+ // | { state: 'disabled' } // disconnectRealtime(pb), or no collection has subscribed yet
308
+ // | { state: 'connecting' } // the first connection of a session is opening
309
+ // | { state: 'connected' } // stream open, PB_CONNECT received
310
+ // | { state: 'reconnecting'; attempt: number; nextRetryAt: number; since: number },
311
+ // loads: {
312
+ // retrying: number, // live queries sleeping in loadRetryDelays backoff
313
+ // failingSince?: number, // when the oldest of them first failed, epoch ms
314
+ // failed: number, // live queries whose load ended in a 4xx that is not retried
315
+ // },
316
+ // }
317
+
318
+ const stop = subscribeSyncStatus(pb, status => console.log(status));
319
+ ```
320
+
321
+ `reconnecting` means the stream was up and dropped, or a retry never came up, and the next retry is scheduled; the first connection of a session reports `connecting` instead. `nextRetryAt` and `since` are epoch milliseconds, and `nextRetryAt` changes only when a new retry is scheduled. `disabled` is not a problem state: it is what `disconnectRealtime(pb)` asks for, and what an app sees before login.
322
+
323
+ `retrying` counts only demands a live query still holds; a parked subset or an unmounted query is never counted. `failed` is separate because a 403 or 404 is an answer, not an outage; the count drops when the query reloads or unmounts.
324
+
325
+ The snapshot is stable: `getSyncStatus(pb)` returns the same object, with the same nested objects, until a value changes. The React entry point wraps it in `useSyncStatus(pb)`:
326
+
327
+ ```tsx
328
+ import { useSyncStatus } from 'pbtsdb';
329
+
330
+ function SyncNotice() {
331
+ const { realtime, loads } = useSyncStatus(pb);
332
+ if (realtime.state === 'reconnecting') return <p>Live updates paused, reconnecting…</p>;
333
+ if (loads.retrying > 0) return <p>Retrying {loads.retrying} queries…</p>;
334
+ return null;
335
+ }
336
+ ```
337
+
338
+ The shape of `SyncStatus` is public and changes only in a major release.
339
+
340
+ ### Subset Lifetime
341
+
342
+ In on-demand mode a live query's subset is released when the last subscriber unmounts, after a grace window of `subsetGcTime` milliseconds (default 5000). A query with an equal request that mounts within the window reuses the rows with no request. Realtime keeps the parked rows fresh, and rows a parent filed through a relation stay for the same window, so a panel that mounts and unmounts quickly costs no refetch. `collection.reload()` releases every parked subset. An auth change releases every waiting subset and every accepted row at once and reloads every live subset under the new auth, whether or not realtime is connected, so a load right after a logout never reuses the previous user's rows and the order of `authStore.clear()` and `disconnectRealtime(pb)` does not matter. Set `subsetGcTime: 0` to release a subset as soon as it unloads; `0` also keeps accepted rows until a reload or idle instead of expiring them.
343
+
344
+ A subset load that fails is retried with backoff (`loadRetryDelays`, default 1, 2, 4, 8, 15 and then every 30 seconds) until it succeeds, so a live query stays loading through an outage instead of entering an error state it cannot leave. A `collection.reload()` or a realtime reconnect retries at once, also while another reload is running. A response the server gave on purpose, a 4xx other than 401, 408 or 429, is not retried and reports its error. A 401 waits for the next auth change and then retries. Delays carry a little jitter so many queries do not retry in lockstep.
345
+
289
346
  ### Sync Modes
290
347
 
291
348
  Every collection is either **eager** (the default) or **on-demand**:
@@ -331,9 +388,9 @@ builder still loads the first `n + limit` rows. Put a page boundary in the
331
388
 
332
389
  ### Mutations and Refetch
333
390
 
334
- By default, pbtsdb does **not** refetch the entire collection after a successful insert, update, or delete. The realtime subscription delivers server-confirmed rows — including server-assigned fields like `id`, `created`, `updated`, and any values rewritten by PocketBase hooks — and TanStack DB's optimistic write keeps the UI consistent in the meantime. The post-mutation refetch is therefore redundant.
391
+ The built-in handlers write PocketBase's response into the collection before they return: server-assigned fields like `created` and `updated`, and any values rewritten by PocketBase hooks. A built-in delete removes the row the same way. TanStack DB drops a mutation's optimistic state when its handler settles, and rows written while the handler runs publish together with that drop, so the settled row is the server's row with no gap. The realtime echo that follows changes nothing.
335
392
 
336
- Set `refetchOnMutation: true` to opt back into the previous behavior — for example, when realtime is unreliable in your environment, or when a server-side hook produces a field you must read synchronously after the mutation resolves:
393
+ By default, pbtsdb does **not** refetch after a successful insert, update, or delete. Set `refetchOnMutation: true` to refetch the collection's active queries before the handler settles — for example, when a server-side hook changes other rows you must read right after the mutation:
337
394
 
338
395
  ```typescript
339
396
  const collection = c('books', {
@@ -341,7 +398,23 @@ const collection = c('books', {
341
398
  });
342
399
  ```
343
400
 
344
- The option only affects the built-in default handlers. If you supply your own `onInsert`, `onUpdate`, or `onDelete`, you control its return value yourself — return `{ refetch: false }` (or omit a return) to skip the refetch, return `{ refetch: true }` to force one.
401
+ The option only affects the built-in default handlers. A custom `onInsert`, `onUpdate`, or `onDelete` controls write-back itself:
402
+
403
+ - TanStack DB drops the optimistic state when your handler returns. Until the realtime echo arrives, the row shows its previous server value: an updated row reverts, an inserted row disappears, and a deleted row comes back.
404
+ - For an insert or an update, `await collection.accept(serverRows)` before you return. This closes the gap.
405
+ - For a delete, `await collection.evict(ids)` before you return. Without it, the deleted row shows again until the delete echo arrives.
406
+ - In on-demand mode, when realtime goes idle (no live query on the collection), rows held only by an accepted write-back are released. A row written back while nothing is mounted is fetched again on the next mount.
407
+ - The handler returns `void`. Core no longer reads a `{ refetch }` result; call `collection.reload()` yourself if the handler needs a refetch.
408
+
409
+ ### Writing server rows yourself
410
+
411
+ `collection.accept(rows)` lands rows the server returned, for example the response of a custom endpoint, as confirmed state. A row older than the stored one is ignored. Use it when the screen must update before the realtime echo arrives. It resolves when the rows are accepted, so a custom mutation handler can await it.
412
+
413
+ `collection.evict(ids)` removes rows the server deleted, for example after a custom endpoint deleted them. The rows leave every holder, and a fetch in flight does not put them back. It resolves when the removal is accepted, so a custom delete handler can await it.
414
+
415
+ `collection.reload()` refetches every live query's subset. Then it releases the realtime-topic and accepted holders of the rows the results do not confirm. A row that a parent filed through a relation stays. Use it when the server state changed with no realtime event, such as after a user loses access to rows.
416
+
417
+ All three are also on `collection.utils`.
345
418
 
346
419
  ### Type Safety
347
420
 
@@ -367,7 +440,6 @@ The main function for creating type-safe collections. Uses a curried API for bet
367
440
  ```typescript
368
441
  const c = createCollection<Schema>(
369
442
  pb: PocketBase,
370
- queryClient: QueryClient,
371
443
  factoryOptions?: CreateCollectionFactoryOptions
372
444
  );
373
445
  const collection = c(collectionName: string, options?: CreateCollectionOptions);
@@ -375,7 +447,6 @@ const collection = c(collectionName: string, options?: CreateCollectionOptions);
375
447
 
376
448
  **Parameters:**
377
449
  - `pb` - PocketBase instance
378
- - `queryClient` - TanStack Query QueryClient instance
379
450
  - `factoryOptions` - Optional configuration applied to every collection this factory builds (see [Subscription Options](#subscription-options))
380
451
  - `collectionName` - Name of the PocketBase collection
381
452
  - `options` - Optional configuration
@@ -390,7 +461,6 @@ const collection = c(collectionName: string, options?: CreateCollectionOptions);
390
461
  - `onUpdate?: UpdateMutationFn | false` - Custom update handler or `false` to disable
391
462
  - `onDelete?: DeleteMutationFn | false` - Custom delete handler or `false` to disable
392
463
  - `refetchOnMutation?: boolean` - Refetch the collection after a built-in insert/update/delete succeeds (default: `false`; see [Mutations and Refetch](#mutations-and-refetch))
393
- - `ignoreAutoCancellation?: boolean` - Ignore PocketBase auto-cancellation errors (default: `true`)
394
464
  - `collectionOptions?: object` - Additional TanStack DB collection options passed through directly (see [Collection Options Passthrough](#collection-options-passthrough))
395
465
 
396
466
  **Returns:** Fully-typed Collection instance with subscription capabilities
@@ -399,7 +469,7 @@ const collection = c(collectionName: string, options?: CreateCollectionOptions);
399
469
 
400
470
  Basic collection (lazy, subscribes automatically on first query):
401
471
  ```typescript
402
- const c = createCollection<MySchema>(pb, queryClient);
472
+ const c = createCollection<MySchema>(pb);
403
473
  const booksCollection = c('books', {});
404
474
  ```
405
475
 
@@ -410,7 +480,7 @@ collections. Rows never carry `expand`; read related records from the target
410
480
  collection.
411
481
 
412
482
  ```typescript
413
- const c = createCollection<MySchema>(pb, queryClient);
483
+ const c = createCollection<MySchema>(pb);
414
484
  const authors = c('authors', { syncMode: 'on-demand' });
415
485
  const tags = c('tags', { syncMode: 'on-demand' });
416
486
  const books = c('books', {
@@ -421,8 +491,8 @@ const books = c('books', {
421
491
 
422
492
  Every books request expands `author`; the expanded authors are filed into
423
493
  `authors` (an on-demand target has its sync started) and removed from the
424
- book rows. Read them through `materialize()` in a query, a join, or
425
- `authors.get(book.author)`:
494
+ book rows. Read them through `materialize()` in a query or through a join,
495
+ inside the `useLiveQuery` that needs them:
426
496
 
427
497
  ```typescript
428
498
  import { eq } from '@tanstack/db';
@@ -446,6 +516,14 @@ reads through a `fetchRelations()` view, whose fetch goes to PocketBase so its
446
516
  paths get filed; anything else is fetched in one batched request. An empty
447
517
  `inArray(id, [])` yields no rows and no request.
448
518
 
519
+ Do not read a related row with `authors.get(book.author)` in a component. A
520
+ `get()` is a one-time read: the component does not re-render when the author
521
+ changes, and the row can leave the store while the component still shows it,
522
+ because a filed row stays only as long as a live query holds the parent row
523
+ that filed it. A `useLiveQuery` with `materialize()` or a join holds the rows
524
+ it reads and re-renders when they change. `get()` is for code outside React
525
+ that needs a value right now, such as a mutation handler or a test.
526
+
449
527
  Fetch a relation for one query only with `fetchRelations()`; the view shares the
450
528
  collection's store, realtime subscription, and mutations, and only its fetches
451
529
  add the `expand` parameter:
@@ -490,7 +568,7 @@ never treated as complete.
490
568
  Pass any [TanStack DB `BaseCollectionConfig`](https://tanstack.com/db/latest/docs/overview) option directly via `collectionOptions`. This is useful for configuring indexing, garbage collection, and other collection-level settings:
491
569
 
492
570
  ```typescript
493
- const c = createCollection<MySchema>(pb, queryClient);
571
+ const c = createCollection<MySchema>(pb);
494
572
  const booksCollection = c('books', {
495
573
  collectionOptions: {
496
574
  gcTime: 60000, // 1 minute GC
@@ -504,7 +582,7 @@ pbtsdb defaults `autoIndex` to `'eager'` with `defaultIndexType: BTreeIndex`, so
504
582
  TanStack DB does not warn about a missing index). Pass `autoIndex: 'off'` or a
505
583
  different `defaultIndexType` in `collectionOptions` to change that per collection.
506
584
 
507
- The following fields are managed by pbtsdb and excluded from `collectionOptions`: `getKey`, `syncMode`, `onInsert`, `onUpdate`, `onDelete`, `schema`.
585
+ The following fields are managed by pbtsdb and excluded from `collectionOptions`: `getKey`, `syncMode`, `onInsert`, `onUpdate`, `onDelete`, `schema`, `utils`.
508
586
 
509
587
  ### React Integration
510
588
 
@@ -527,7 +605,7 @@ const { Provider, useStore } = createReactProvider(collections: CollectionsMap);
527
605
  ```typescript
528
606
  import { createCollection, createReactProvider } from 'pbtsdb';
529
607
 
530
- const c = createCollection<MySchema>(pb, queryClient);
608
+ const c = createCollection<MySchema>(pb);
531
609
  const collections = {
532
610
  authors: c('authors', {}),
533
611
  books: c('books', {
@@ -685,7 +763,7 @@ options — `headers`, `filter`, `expand`, `fields` — to every real-time
685
763
  subscription the factory creates.
686
764
 
687
765
  ```typescript
688
- const c = createCollection<Schema>(pb, queryClient, {
766
+ const c = createCollection<Schema>(pb, {
689
767
  subscribeOptions: () => {
690
768
  const token = getShareToken();
691
769
  return token ? { headers: { 'X-Share-Token': token } } : undefined;
@@ -717,6 +795,32 @@ An `expand` you add here is yours: pbtsdb strips only the paths it requested
717
795
  through `alwaysFetchRelations` and `fetchRelations()`, so records expanded by
718
796
  this option stay on the echoed rows, untyped.
719
797
 
798
+ ### Sync Status API
799
+
800
+ #### getSyncStatus()
801
+
802
+ ```typescript
803
+ getSyncStatus(pb: PocketBase): SyncStatus
804
+ ```
805
+
806
+ The current [sync status](#sync-status) of `pb`'s collections. The returned object is stable until a value changes.
807
+
808
+ #### subscribeSyncStatus()
809
+
810
+ ```typescript
811
+ subscribeSyncStatus(pb: PocketBase, listener: (status: SyncStatus) => void): () => void
812
+ ```
813
+
814
+ Calls `listener` with each new snapshot. Returns the unsubscribe function.
815
+
816
+ #### useSyncStatus()
817
+
818
+ ```typescript
819
+ useSyncStatus(pb: PocketBase): SyncStatus
820
+ ```
821
+
822
+ React hook over the two functions above, built on `useSyncExternalStore`. Exported from `pbtsdb`, not from `pbtsdb/core`.
823
+
720
824
  ### Utility Functions
721
825
 
722
826
  #### newRecordId()
@@ -968,7 +1072,7 @@ export function CreateBookForm() {
968
1072
  try {
969
1073
  // Optimistic insert - appears instantly
970
1074
  const tx = books.insert({ id: newRecordId(), title, author: 'author_id' });
971
- await tx.isPersisted.promise;
1075
+ await tx.when('settled');
972
1076
 
973
1077
  if (tx.state === 'completed') setTitle('');
974
1078
  else setError('Failed to create book');
@@ -1143,7 +1247,7 @@ Always create collections with proper type parameters:
1143
1247
 
1144
1248
  ```typescript
1145
1249
  // ✅ Good - full type safety
1146
- const c = createCollection<MySchema>(pb, queryClient);
1250
+ const c = createCollection<MySchema>(pb);
1147
1251
  const books = c('books', {
1148
1252
  omitOnInsert: ['created', 'updated'] as const
1149
1253
  });
@@ -1164,7 +1268,7 @@ Define all collections once at app initialization:
1164
1268
 
1165
1269
  ```typescript
1166
1270
  // ✅ Do this - centralized, type-safe
1167
- const c = createCollection<MySchema>(pb, queryClient);
1271
+ const c = createCollection<MySchema>(pb);
1168
1272
 
1169
1273
  export const { Provider, useStore } = createReactProvider({
1170
1274
  posts: c('posts', { omitOnInsert: ['created', 'updated'] as const }),
@@ -1179,7 +1283,7 @@ When declaring `relations`, create the target collection first:
1179
1283
 
1180
1284
  ```typescript
1181
1285
  // ✅ Good - authors exists before books references it
1182
- const c = createCollection<MySchema>(pb, queryClient);
1286
+ const c = createCollection<MySchema>(pb);
1183
1287
  const authors = c('authors', {});
1184
1288
  const books = c('books', {
1185
1289
  relations: { author: authors }, // authors is already created
@@ -1230,7 +1334,7 @@ return <PostsList posts={data} />;
1230
1334
  per parent row, on every fetch of the parent:
1231
1335
 
1232
1336
  ```typescript
1233
- const c = createCollection<MySchema>(pb, queryClient);
1337
+ const c = createCollection<MySchema>(pb);
1234
1338
  const authors = c('authors', {});
1235
1339
  const posts = c('posts', {
1236
1340
  relations: { author: authors },
@@ -1246,20 +1350,6 @@ it) and, once the rows are filed, subsequent queries make no request at all.
1246
1350
  Prefer `alwaysFetchRelations` when the parent is the only path by which those
1247
1351
  rows enter an on-demand collection; otherwise let the query load them.
1248
1352
 
1249
- ### 6. Configure QueryClient Defaults
1250
-
1251
- ```typescript
1252
- const queryClient = new QueryClient({
1253
- defaultOptions: {
1254
- queries: {
1255
- staleTime: 60_000, // 1 minute
1256
- gcTime: 300_000, // 5 minutes
1257
- refetchOnWindowFocus: false
1258
- }
1259
- }
1260
- });
1261
- ```
1262
-
1263
1353
  ## Configuration
1264
1354
 
1265
1355
  ### Custom Logger Integration
@@ -1381,6 +1471,5 @@ npm run typecheck # TypeScript only
1381
1471
 
1382
1472
  **Built with:**
1383
1473
  - [PocketBase](https://pocketbase.io) - Backend-as-a-Service
1384
- - [TanStack Query](https://tanstack.com/query) - Powerful data fetching
1385
1474
  - [TanStack DB](https://tanstack.com/db) - Reactive database
1386
1475
  - [TypeScript](https://www.typescriptlang.org) - Type safety