pbtsdb 0.10.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -57
- package/dist/chunk-4CRCARB3.js +2954 -0
- package/dist/chunk-4CRCARB3.js.map +1 -0
- package/dist/core.d.ts +184 -86
- package/dist/core.js +1 -1
- package/dist/index.d.ts +6 -10
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/llms.txt +29 -25
- package/package.json +6 -11
- package/dist/chunk-X7ZGPVG2.js +0 -1543
- package/dist/chunk-X7ZGPVG2.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
# pbtsdb: PocketBase TanStack Database Integration
|
|
2
2
|
|
|
3
|
-
> Type-safe PocketBase integration with TanStack
|
|
3
|
+
> Type-safe PocketBase integration with TanStack DB
|
|
4
4
|
|
|
5
|
-
A TypeScript library that seamlessly integrates [PocketBase](https://pocketbase.io) with [TanStack
|
|
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
|
|
@@ -32,16 +31,14 @@ A TypeScript library that seamlessly integrates [PocketBase](https://pocketbase.
|
|
|
32
31
|
## Installation
|
|
33
32
|
|
|
34
33
|
```bash
|
|
35
|
-
npm install pbtsdb pocketbase @tanstack/db @tanstack/
|
|
34
|
+
npm install pbtsdb pocketbase @tanstack/db @tanstack/react-db
|
|
36
35
|
```
|
|
37
36
|
|
|
38
37
|
### Peer Dependencies
|
|
39
38
|
|
|
40
39
|
- `pocketbase` >= 0.22.0
|
|
41
|
-
- `@tanstack/db` >= 0.
|
|
42
|
-
- `@tanstack/
|
|
43
|
-
- `@tanstack/react-query` >= 5.0.0
|
|
44
|
-
- `@tanstack/react-db` >= 0.1.86 (optional; only for `createReactProvider`)
|
|
40
|
+
- `@tanstack/db` >= 0.12.1
|
|
41
|
+
- `@tanstack/react-db` >= 0.5.5 (optional; only for `createReactProvider`)
|
|
45
42
|
- `react` and `react-dom` >= 18.0.0 (optional)
|
|
46
43
|
|
|
47
44
|
All peer dependencies use minimum version constraints; newer versions should work. The
|
|
@@ -110,18 +107,12 @@ type BlogSchema = {
|
|
|
110
107
|
```typescript
|
|
111
108
|
// app.tsx
|
|
112
109
|
import PocketBase from 'pocketbase';
|
|
113
|
-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
114
110
|
import { createCollection, createReactProvider } from 'pbtsdb';
|
|
115
111
|
|
|
116
112
|
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
113
|
|
|
123
114
|
// Create collections with automatic type inference
|
|
124
|
-
const c = createCollection<BlogSchema>(pb
|
|
115
|
+
const c = createCollection<BlogSchema>(pb);
|
|
125
116
|
const users = c('users', {});
|
|
126
117
|
export const { Provider, useStore } = createReactProvider({
|
|
127
118
|
users,
|
|
@@ -139,11 +130,9 @@ export const { Provider, useStore } = createReactProvider({
|
|
|
139
130
|
|
|
140
131
|
export function App() {
|
|
141
132
|
return (
|
|
142
|
-
<
|
|
143
|
-
<
|
|
144
|
-
|
|
145
|
-
</Provider>
|
|
146
|
-
</QueryClientProvider>
|
|
133
|
+
<Provider>
|
|
134
|
+
<BlogDashboard />
|
|
135
|
+
</Provider>
|
|
147
136
|
);
|
|
148
137
|
}
|
|
149
138
|
```
|
|
@@ -253,14 +242,13 @@ Collections are reactive data stores that automatically sync with PocketBase:
|
|
|
253
242
|
|
|
254
243
|
```typescript
|
|
255
244
|
// Create a collection using the curried API
|
|
256
|
-
const c = createCollection<MySchema>(pb
|
|
245
|
+
const c = createCollection<MySchema>(pb);
|
|
257
246
|
const booksCollection = c('books', {});
|
|
258
247
|
|
|
259
248
|
// Collections automatically:
|
|
260
249
|
// - Fetch data from PocketBase
|
|
261
250
|
// - Subscribe to real-time updates
|
|
262
251
|
// - Update React components when data changes
|
|
263
|
-
// - Cache data via TanStack Query
|
|
264
252
|
```
|
|
265
253
|
|
|
266
254
|
### Real-time Subscriptions
|
|
@@ -269,7 +257,7 @@ Collections manage subscriptions **automatically** based on query lifecycle:
|
|
|
269
257
|
|
|
270
258
|
```typescript
|
|
271
259
|
// Collections are lazy - no subscription until queried
|
|
272
|
-
const c = createCollection<MySchema>(pb
|
|
260
|
+
const c = createCollection<MySchema>(pb);
|
|
273
261
|
const booksCollection = c('books', {});
|
|
274
262
|
|
|
275
263
|
// Subscription starts automatically when query becomes active
|
|
@@ -286,6 +274,31 @@ const { data } = useLiveQuery((q) =>
|
|
|
286
274
|
- **Shared:** Multiple components using the same collection share one subscription
|
|
287
275
|
- **No manual control needed:** The collection handles all subscription management internally
|
|
288
276
|
|
|
277
|
+
### Reconnects
|
|
278
|
+
|
|
279
|
+
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.
|
|
280
|
+
|
|
281
|
+
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.
|
|
282
|
+
|
|
283
|
+
Call `resetRealtime(pb)` yourself for a change the auth store cannot see, such as pointing `pb` at another server:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
import { disconnectRealtime, resetRealtime } from 'pbtsdb';
|
|
287
|
+
|
|
288
|
+
resetRealtime(pb); // forget the session and re-subscribe every open topic now
|
|
289
|
+
|
|
290
|
+
disconnectRealtime(pb); // close the connection and keep it closed
|
|
291
|
+
resetRealtime(pb); // open it again; every ready collection reloads
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`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.
|
|
295
|
+
|
|
296
|
+
### Subset Lifetime
|
|
297
|
+
|
|
298
|
+
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.
|
|
299
|
+
|
|
300
|
+
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.
|
|
301
|
+
|
|
289
302
|
### Sync Modes
|
|
290
303
|
|
|
291
304
|
Every collection is either **eager** (the default) or **on-demand**:
|
|
@@ -302,11 +315,38 @@ for enter the store, and different filters are cached under different keys.
|
|
|
302
315
|
Use on-demand for large collections; realtime keeps both modes current once rows
|
|
303
316
|
are loaded.
|
|
304
317
|
|
|
318
|
+
#### Paging
|
|
319
|
+
|
|
320
|
+
An on-demand query with `orderBy` and `limit` fetches one page of that size.
|
|
321
|
+
When TanStack DB needs more rows (`setWindow`, or a window past what is loaded)
|
|
322
|
+
it hands the sync layer a cursor on the sort field and the count of rows it
|
|
323
|
+
already has. pbtsdb conjoins the cursor to the fetch filter and fetches only the
|
|
324
|
+
delta; an offset without a cursor becomes a PocketBase page.
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
const { data, collection } = useLiveQuery((q) =>
|
|
328
|
+
q.from({ b: books }).where(({ b }) => eq(b.author, id)).orderBy(({ b }) => b.page_count).limit(20)
|
|
329
|
+
);
|
|
330
|
+
// fetches only the rows past what is loaded: one cursor request plus a boundary tie-check
|
|
331
|
+
collection.utils.setWindow({ offset: 20, limit: 20 });
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Realtime stays on the base `where`: every page of one query shares one
|
|
335
|
+
subscription, and a new row that sorts into the window arrives on its own. A
|
|
336
|
+
query whose `where` holds its own boundary (`lt(b.page_count, cursor)`)
|
|
337
|
+
subscribes to that slice only, which is the shape for numbered pages: page one
|
|
338
|
+
has no boundary and receives every new row. A join's or include's key batch
|
|
339
|
+
keeps its own filter, so lazily loaded rows stay covered.
|
|
340
|
+
|
|
341
|
+
TanStack applies `offset` in memory after loading, so `.offset(n)` on the
|
|
342
|
+
builder still loads the first `n + limit` rows. Put a page boundary in the
|
|
343
|
+
`where` when a deep page must not load what comes before it.
|
|
344
|
+
|
|
305
345
|
### Mutations and Refetch
|
|
306
346
|
|
|
307
|
-
|
|
347
|
+
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.
|
|
308
348
|
|
|
309
|
-
Set `refetchOnMutation: true` to
|
|
349
|
+
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:
|
|
310
350
|
|
|
311
351
|
```typescript
|
|
312
352
|
const collection = c('books', {
|
|
@@ -314,7 +354,23 @@ const collection = c('books', {
|
|
|
314
354
|
});
|
|
315
355
|
```
|
|
316
356
|
|
|
317
|
-
The option only affects the built-in default handlers.
|
|
357
|
+
The option only affects the built-in default handlers. A custom `onInsert`, `onUpdate`, or `onDelete` controls write-back itself:
|
|
358
|
+
|
|
359
|
+
- 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.
|
|
360
|
+
- For an insert or an update, `await collection.accept(serverRows)` before you return. This closes the gap.
|
|
361
|
+
- For a delete, `await collection.evict(ids)` before you return. Without it, the deleted row shows again until the delete echo arrives.
|
|
362
|
+
- 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.
|
|
363
|
+
- The handler returns `void`. Core no longer reads a `{ refetch }` result; call `collection.reload()` yourself if the handler needs a refetch.
|
|
364
|
+
|
|
365
|
+
### Writing server rows yourself
|
|
366
|
+
|
|
367
|
+
`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.
|
|
368
|
+
|
|
369
|
+
`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.
|
|
370
|
+
|
|
371
|
+
`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.
|
|
372
|
+
|
|
373
|
+
All three are also on `collection.utils`.
|
|
318
374
|
|
|
319
375
|
### Type Safety
|
|
320
376
|
|
|
@@ -340,7 +396,6 @@ The main function for creating type-safe collections. Uses a curried API for bet
|
|
|
340
396
|
```typescript
|
|
341
397
|
const c = createCollection<Schema>(
|
|
342
398
|
pb: PocketBase,
|
|
343
|
-
queryClient: QueryClient,
|
|
344
399
|
factoryOptions?: CreateCollectionFactoryOptions
|
|
345
400
|
);
|
|
346
401
|
const collection = c(collectionName: string, options?: CreateCollectionOptions);
|
|
@@ -348,7 +403,6 @@ const collection = c(collectionName: string, options?: CreateCollectionOptions);
|
|
|
348
403
|
|
|
349
404
|
**Parameters:**
|
|
350
405
|
- `pb` - PocketBase instance
|
|
351
|
-
- `queryClient` - TanStack Query QueryClient instance
|
|
352
406
|
- `factoryOptions` - Optional configuration applied to every collection this factory builds (see [Subscription Options](#subscription-options))
|
|
353
407
|
- `collectionName` - Name of the PocketBase collection
|
|
354
408
|
- `options` - Optional configuration
|
|
@@ -363,7 +417,6 @@ const collection = c(collectionName: string, options?: CreateCollectionOptions);
|
|
|
363
417
|
- `onUpdate?: UpdateMutationFn | false` - Custom update handler or `false` to disable
|
|
364
418
|
- `onDelete?: DeleteMutationFn | false` - Custom delete handler or `false` to disable
|
|
365
419
|
- `refetchOnMutation?: boolean` - Refetch the collection after a built-in insert/update/delete succeeds (default: `false`; see [Mutations and Refetch](#mutations-and-refetch))
|
|
366
|
-
- `ignoreAutoCancellation?: boolean` - Ignore PocketBase auto-cancellation errors (default: `true`)
|
|
367
420
|
- `collectionOptions?: object` - Additional TanStack DB collection options passed through directly (see [Collection Options Passthrough](#collection-options-passthrough))
|
|
368
421
|
|
|
369
422
|
**Returns:** Fully-typed Collection instance with subscription capabilities
|
|
@@ -372,7 +425,7 @@ const collection = c(collectionName: string, options?: CreateCollectionOptions);
|
|
|
372
425
|
|
|
373
426
|
Basic collection (lazy, subscribes automatically on first query):
|
|
374
427
|
```typescript
|
|
375
|
-
const c = createCollection<MySchema>(pb
|
|
428
|
+
const c = createCollection<MySchema>(pb);
|
|
376
429
|
const booksCollection = c('books', {});
|
|
377
430
|
```
|
|
378
431
|
|
|
@@ -383,7 +436,7 @@ collections. Rows never carry `expand`; read related records from the target
|
|
|
383
436
|
collection.
|
|
384
437
|
|
|
385
438
|
```typescript
|
|
386
|
-
const c = createCollection<MySchema>(pb
|
|
439
|
+
const c = createCollection<MySchema>(pb);
|
|
387
440
|
const authors = c('authors', { syncMode: 'on-demand' });
|
|
388
441
|
const tags = c('tags', { syncMode: 'on-demand' });
|
|
389
442
|
const books = c('books', {
|
|
@@ -394,8 +447,8 @@ const books = c('books', {
|
|
|
394
447
|
|
|
395
448
|
Every books request expands `author`; the expanded authors are filed into
|
|
396
449
|
`authors` (an on-demand target has its sync started) and removed from the
|
|
397
|
-
book rows. Read them through `materialize()` in a query
|
|
398
|
-
`
|
|
450
|
+
book rows. Read them through `materialize()` in a query or through a join,
|
|
451
|
+
inside the `useLiveQuery` that needs them:
|
|
399
452
|
|
|
400
453
|
```typescript
|
|
401
454
|
import { eq } from '@tanstack/db';
|
|
@@ -419,6 +472,14 @@ reads through a `fetchRelations()` view, whose fetch goes to PocketBase so its
|
|
|
419
472
|
paths get filed; anything else is fetched in one batched request. An empty
|
|
420
473
|
`inArray(id, [])` yields no rows and no request.
|
|
421
474
|
|
|
475
|
+
Do not read a related row with `authors.get(book.author)` in a component. A
|
|
476
|
+
`get()` is a one-time read: the component does not re-render when the author
|
|
477
|
+
changes, and the row can leave the store while the component still shows it,
|
|
478
|
+
because a filed row stays only as long as a live query holds the parent row
|
|
479
|
+
that filed it. A `useLiveQuery` with `materialize()` or a join holds the rows
|
|
480
|
+
it reads and re-renders when they change. `get()` is for code outside React
|
|
481
|
+
that needs a value right now, such as a mutation handler or a test.
|
|
482
|
+
|
|
422
483
|
Fetch a relation for one query only with `fetchRelations()`; the view shares the
|
|
423
484
|
collection's store, realtime subscription, and mutations, and only its fetches
|
|
424
485
|
add the `expand` parameter:
|
|
@@ -463,7 +524,7 @@ never treated as complete.
|
|
|
463
524
|
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:
|
|
464
525
|
|
|
465
526
|
```typescript
|
|
466
|
-
const c = createCollection<MySchema>(pb
|
|
527
|
+
const c = createCollection<MySchema>(pb);
|
|
467
528
|
const booksCollection = c('books', {
|
|
468
529
|
collectionOptions: {
|
|
469
530
|
gcTime: 60000, // 1 minute GC
|
|
@@ -477,7 +538,7 @@ pbtsdb defaults `autoIndex` to `'eager'` with `defaultIndexType: BTreeIndex`, so
|
|
|
477
538
|
TanStack DB does not warn about a missing index). Pass `autoIndex: 'off'` or a
|
|
478
539
|
different `defaultIndexType` in `collectionOptions` to change that per collection.
|
|
479
540
|
|
|
480
|
-
The following fields are managed by pbtsdb and excluded from `collectionOptions`: `getKey`, `syncMode`, `onInsert`, `onUpdate`, `onDelete`, `schema`.
|
|
541
|
+
The following fields are managed by pbtsdb and excluded from `collectionOptions`: `getKey`, `syncMode`, `onInsert`, `onUpdate`, `onDelete`, `schema`, `utils`.
|
|
481
542
|
|
|
482
543
|
### React Integration
|
|
483
544
|
|
|
@@ -500,7 +561,7 @@ const { Provider, useStore } = createReactProvider(collections: CollectionsMap);
|
|
|
500
561
|
```typescript
|
|
501
562
|
import { createCollection, createReactProvider } from 'pbtsdb';
|
|
502
563
|
|
|
503
|
-
const c = createCollection<MySchema>(pb
|
|
564
|
+
const c = createCollection<MySchema>(pb);
|
|
504
565
|
const collections = {
|
|
505
566
|
authors: c('authors', {}),
|
|
506
567
|
books: c('books', {
|
|
@@ -658,7 +719,7 @@ options — `headers`, `filter`, `expand`, `fields` — to every real-time
|
|
|
658
719
|
subscription the factory creates.
|
|
659
720
|
|
|
660
721
|
```typescript
|
|
661
|
-
const c = createCollection<Schema>(pb,
|
|
722
|
+
const c = createCollection<Schema>(pb, {
|
|
662
723
|
subscribeOptions: () => {
|
|
663
724
|
const token = getShareToken();
|
|
664
725
|
return token ? { headers: { 'X-Share-Token': token } } : undefined;
|
|
@@ -941,7 +1002,7 @@ export function CreateBookForm() {
|
|
|
941
1002
|
try {
|
|
942
1003
|
// Optimistic insert - appears instantly
|
|
943
1004
|
const tx = books.insert({ id: newRecordId(), title, author: 'author_id' });
|
|
944
|
-
await tx.
|
|
1005
|
+
await tx.when('settled');
|
|
945
1006
|
|
|
946
1007
|
if (tx.state === 'completed') setTitle('');
|
|
947
1008
|
else setError('Failed to create book');
|
|
@@ -1116,7 +1177,7 @@ Always create collections with proper type parameters:
|
|
|
1116
1177
|
|
|
1117
1178
|
```typescript
|
|
1118
1179
|
// ✅ Good - full type safety
|
|
1119
|
-
const c = createCollection<MySchema>(pb
|
|
1180
|
+
const c = createCollection<MySchema>(pb);
|
|
1120
1181
|
const books = c('books', {
|
|
1121
1182
|
omitOnInsert: ['created', 'updated'] as const
|
|
1122
1183
|
});
|
|
@@ -1137,7 +1198,7 @@ Define all collections once at app initialization:
|
|
|
1137
1198
|
|
|
1138
1199
|
```typescript
|
|
1139
1200
|
// ✅ Do this - centralized, type-safe
|
|
1140
|
-
const c = createCollection<MySchema>(pb
|
|
1201
|
+
const c = createCollection<MySchema>(pb);
|
|
1141
1202
|
|
|
1142
1203
|
export const { Provider, useStore } = createReactProvider({
|
|
1143
1204
|
posts: c('posts', { omitOnInsert: ['created', 'updated'] as const }),
|
|
@@ -1152,7 +1213,7 @@ When declaring `relations`, create the target collection first:
|
|
|
1152
1213
|
|
|
1153
1214
|
```typescript
|
|
1154
1215
|
// ✅ Good - authors exists before books references it
|
|
1155
|
-
const c = createCollection<MySchema>(pb
|
|
1216
|
+
const c = createCollection<MySchema>(pb);
|
|
1156
1217
|
const authors = c('authors', {});
|
|
1157
1218
|
const books = c('books', {
|
|
1158
1219
|
relations: { author: authors }, // authors is already created
|
|
@@ -1203,7 +1264,7 @@ return <PostsList posts={data} />;
|
|
|
1203
1264
|
per parent row, on every fetch of the parent:
|
|
1204
1265
|
|
|
1205
1266
|
```typescript
|
|
1206
|
-
const c = createCollection<MySchema>(pb
|
|
1267
|
+
const c = createCollection<MySchema>(pb);
|
|
1207
1268
|
const authors = c('authors', {});
|
|
1208
1269
|
const posts = c('posts', {
|
|
1209
1270
|
relations: { author: authors },
|
|
@@ -1219,20 +1280,6 @@ it) and, once the rows are filed, subsequent queries make no request at all.
|
|
|
1219
1280
|
Prefer `alwaysFetchRelations` when the parent is the only path by which those
|
|
1220
1281
|
rows enter an on-demand collection; otherwise let the query load them.
|
|
1221
1282
|
|
|
1222
|
-
### 6. Configure QueryClient Defaults
|
|
1223
|
-
|
|
1224
|
-
```typescript
|
|
1225
|
-
const queryClient = new QueryClient({
|
|
1226
|
-
defaultOptions: {
|
|
1227
|
-
queries: {
|
|
1228
|
-
staleTime: 60_000, // 1 minute
|
|
1229
|
-
gcTime: 300_000, // 5 minutes
|
|
1230
|
-
refetchOnWindowFocus: false
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
});
|
|
1234
|
-
```
|
|
1235
|
-
|
|
1236
1283
|
## Configuration
|
|
1237
1284
|
|
|
1238
1285
|
### Custom Logger Integration
|
|
@@ -1354,6 +1401,5 @@ npm run typecheck # TypeScript only
|
|
|
1354
1401
|
|
|
1355
1402
|
**Built with:**
|
|
1356
1403
|
- [PocketBase](https://pocketbase.io) - Backend-as-a-Service
|
|
1357
|
-
- [TanStack Query](https://tanstack.com/query) - Powerful data fetching
|
|
1358
1404
|
- [TanStack DB](https://tanstack.com/db) - Reactive database
|
|
1359
1405
|
- [TypeScript](https://www.typescriptlang.org) - Type safety
|