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 +146 -57
- package/dist/chunk-TTENGDS3.js +3142 -0
- package/dist/chunk-TTENGDS3.js.map +1 -0
- package/dist/core.d.ts +232 -86
- package/dist/core.js +1 -1
- package/dist/index.d.ts +25 -11
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/llms.txt +29 -25
- package/package.json +6 -11
- package/dist/chunk-OBDOVDCI.js +0 -1596
- package/dist/chunk-OBDOVDCI.js.map +0 -1
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pbtsdb
|
|
2
2
|
|
|
3
|
-
> Type-safe PocketBase integration with TanStack
|
|
3
|
+
> Type-safe PocketBase integration with TanStack DB for React applications. Provides reactive collections with automatic real-time subscriptions, optimistic mutations, full TypeScript type safety, and minimal boilerplate.
|
|
4
4
|
|
|
5
5
|
This library connects PocketBase (backend-as-a-service) to TanStack's reactive database tools. Use it when building React applications that need real-time data synchronization with PocketBase while maintaining strict type safety.
|
|
6
6
|
|
|
@@ -26,7 +26,7 @@ export type Schema = {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// 2. Create collections using curried createCollection
|
|
29
|
-
const c = createCollection<Schema>(pb
|
|
29
|
+
const c = createCollection<Schema>(pb);
|
|
30
30
|
const collections = {
|
|
31
31
|
books: c('books', {}),
|
|
32
32
|
authors: c('authors', {}),
|
|
@@ -72,7 +72,7 @@ const [myBooks] = useStore('myBooks');
|
|
|
72
72
|
|
|
73
73
|
## Key Concepts
|
|
74
74
|
|
|
75
|
-
- **createCollection**: Curried function `createCollection<Schema>(pb,
|
|
75
|
+
- **createCollection**: Curried function `createCollection<Schema>(pb, factoryOptions?)` returns `(collectionName, options) => Collection`
|
|
76
76
|
- **createReactProvider**: Wraps collections for React, returns `{ Provider, useStore }`
|
|
77
77
|
- **Collections are lazy**: No network activity until first query
|
|
78
78
|
- **Subscriptions are automatic**: Start when component mounts, stop 5s after unmount
|
|
@@ -86,7 +86,7 @@ For non-React environments, use `createCollection` directly:
|
|
|
86
86
|
```typescript
|
|
87
87
|
import { createCollection } from 'pbtsdb';
|
|
88
88
|
|
|
89
|
-
const c = createCollection<Schema>(pb
|
|
89
|
+
const c = createCollection<Schema>(pb);
|
|
90
90
|
const booksCollection = c('books', {});
|
|
91
91
|
|
|
92
92
|
// Collections have TanStack DB interface
|
|
@@ -95,12 +95,12 @@ const booksCollection = c('books', {});
|
|
|
95
95
|
|
|
96
96
|
## Real-time Subscription Options
|
|
97
97
|
|
|
98
|
-
The
|
|
98
|
+
The second `createCollection` argument applies to every collection the factory
|
|
99
99
|
builds. `subscribeOptions` is a getter invoked at subscribe time, so the value
|
|
100
100
|
may change across reconnects:
|
|
101
101
|
|
|
102
102
|
```typescript
|
|
103
|
-
const c = createCollection<Schema>(pb,
|
|
103
|
+
const c = createCollection<Schema>(pb, {
|
|
104
104
|
subscribeOptions: () => {
|
|
105
105
|
const token = getShareToken();
|
|
106
106
|
return token ? { headers: { 'X-Share-Token': token } } : undefined;
|
|
@@ -142,7 +142,7 @@ Collections support insert, update, and delete with automatic PocketBase sync:
|
|
|
142
142
|
import { newRecordId, createCollection, createReactProvider } from 'pbtsdb';
|
|
143
143
|
|
|
144
144
|
// Setup with custom mutation handlers (optional)
|
|
145
|
-
const c = createCollection<Schema>(pb
|
|
145
|
+
const c = createCollection<Schema>(pb);
|
|
146
146
|
const collections = {
|
|
147
147
|
books: c('books', {
|
|
148
148
|
onInsert: async ({ transaction }) => { /* custom logic */ },
|
|
@@ -176,37 +176,38 @@ function BooksList() {
|
|
|
176
176
|
// Delete with optimistic update
|
|
177
177
|
books.delete('record_id');
|
|
178
178
|
|
|
179
|
-
//
|
|
180
|
-
|
|
181
|
-
books.update('id1', (draft) => { draft.field1 = 'value1' });
|
|
182
|
-
books.update('id1', (draft) => { draft.field2 = 'value2' }); // Merged!
|
|
183
|
-
books.update('id2', (draft) => { draft.field = 'value' });
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
// Wait for persistence
|
|
187
|
-
await tx.isPersisted.promise; // States: pending → persisting → completed
|
|
179
|
+
// Wait for persistence (isPersisted.promise is deprecated)
|
|
180
|
+
await tx.when('settled'); // States: pending → persisting → completed
|
|
188
181
|
}
|
|
189
182
|
```
|
|
190
183
|
|
|
191
184
|
**Key Points:**
|
|
192
185
|
- Mutations are optimistic by default (UI updates immediately)
|
|
193
186
|
- Auto-syncs to PocketBase in background
|
|
194
|
-
-
|
|
187
|
+
- The built-in handlers write the server response into the collection before they settle, so the settled row is the server's row (`created`, `updated`, hook-rewritten values)
|
|
195
188
|
- Transaction states: pending → persisting → completed
|
|
196
189
|
- Use `newRecordId()` to generate PocketBase-compatible IDs
|
|
190
|
+
- `row.$hasPendingWrites` is true while a row has an unsettled optimistic change (`$synced` is deprecated)
|
|
191
|
+
- A custom `onInsert`/`onUpdate` should `await collection.accept(serverRows)` and a custom `onDelete` should `await collection.evict(ids)` before it returns `void`; otherwise the row shows its previous server value from settle until the realtime echo
|
|
192
|
+
- `collection.accept(rows)` lands server-returned rows as confirmed state; `collection.evict(ids)` removes rows the server deleted; `collection.reload()` refetches every live query's subset and drops rows the results do not confirm. All three resolve on acceptance and are also on `collection.utils`
|
|
197
193
|
|
|
198
194
|
## Common Patterns
|
|
199
195
|
|
|
200
196
|
**Approach 1: Related data (Recommended)**
|
|
201
197
|
|
|
202
198
|
PocketBase `expand` only files related records into their own collections;
|
|
203
|
-
rows never carry `expand`. Read related records from the target collection
|
|
199
|
+
rows never carry `expand`. Read related records from the target collection
|
|
200
|
+
through `materialize()` or a join inside the `useLiveQuery` that needs them.
|
|
201
|
+
Do not read them with `collection.get(id)` in a component: a `get()` does not
|
|
202
|
+
re-render when the row changes, and the row can leave the store while the
|
|
203
|
+
component still shows it. `get()` is for code outside React, such as a mutation
|
|
204
|
+
handler.
|
|
204
205
|
|
|
205
206
|
```typescript
|
|
206
207
|
import { eq } from '@tanstack/db';
|
|
207
208
|
import { materialize } from 'pbtsdb';
|
|
208
209
|
|
|
209
|
-
const c = createCollection<Schema>(pb
|
|
210
|
+
const c = createCollection<Schema>(pb);
|
|
210
211
|
const authors = c('authors', { syncMode: 'on-demand' });
|
|
211
212
|
const books = c('books', {
|
|
212
213
|
relations: { author: authors }, // where expanded records are filed
|
|
@@ -245,7 +246,7 @@ const { data } = useLiveQuery((q) => q.from({ books: books.fetchRelations('tags'
|
|
|
245
246
|
|
|
246
247
|
**Approach 2: TanStack Joins**
|
|
247
248
|
```typescript
|
|
248
|
-
const c = createCollection<Schema>(pb
|
|
249
|
+
const c = createCollection<Schema>(pb);
|
|
249
250
|
const collections = {
|
|
250
251
|
jobs: c('jobs', {}),
|
|
251
252
|
customers: c('customers', {}),
|
|
@@ -271,13 +272,16 @@ const [jobs, customers] = useStore('jobs', 'customers');
|
|
|
271
272
|
|
|
272
273
|
- Simple CRUD without real-time (PocketBase SDK is simpler)
|
|
273
274
|
- Very large collections (>10k records - use pagination)
|
|
274
|
-
- Non-PocketBase backends (use
|
|
275
|
+
- Non-PocketBase backends (use `@tanstack/db` directly)
|
|
275
276
|
- Server-side only Node.js (use PocketBase SDK directly)
|
|
276
277
|
|
|
277
278
|
### Package Details
|
|
278
279
|
|
|
279
|
-
- Requires React 18+, TypeScript 5.0+, PocketBase 0.
|
|
280
|
-
-
|
|
281
|
-
-
|
|
282
|
-
-
|
|
280
|
+
- Requires React 18+, TypeScript 5.0+, PocketBase 0.22.0+
|
|
281
|
+
- Requires `@tanstack/db` 0.12.1+, `@tanstack/react-db` 0.5.5+
|
|
282
|
+
- Collections use TanStack DB's core sync API, with pbtsdb's own membership ledger
|
|
283
|
+
- Real-time via PocketBase Server-Sent Events (SSE), through pbtsdb's own client
|
|
284
|
+
- Automatic reconnection with exponential backoff; a reconnect the server did
|
|
285
|
+
not resume refetches every live query, since PocketBase does not replay
|
|
286
|
+
events missed during the gap
|
|
283
287
|
- Default syncMode is 'eager' (matches TanStack DB default)
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pbtsdb",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Type-safe PocketBase integration with TanStack
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "Type-safe PocketBase integration with TanStack DB",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pocketbase",
|
|
7
7
|
"tanstack",
|
|
8
|
-
"tanstack-query",
|
|
9
8
|
"tanstack-db",
|
|
10
9
|
"database",
|
|
11
10
|
"react",
|
|
@@ -57,10 +56,8 @@
|
|
|
57
56
|
"test:server:migrate": "pocketbase migrate --dir ./pb_data"
|
|
58
57
|
},
|
|
59
58
|
"peerDependencies": {
|
|
60
|
-
"@tanstack/db": ">=0.
|
|
61
|
-
"@tanstack/
|
|
62
|
-
"@tanstack/react-db": ">=0.3.8",
|
|
63
|
-
"@tanstack/react-query": ">=5.0.0",
|
|
59
|
+
"@tanstack/db": ">=0.12.1",
|
|
60
|
+
"@tanstack/react-db": ">=0.5.5",
|
|
64
61
|
"pocketbase": ">=0.22.0",
|
|
65
62
|
"react": ">=18.0.0",
|
|
66
63
|
"react-dom": ">=18.0.0"
|
|
@@ -78,10 +75,8 @@
|
|
|
78
75
|
},
|
|
79
76
|
"devDependencies": {
|
|
80
77
|
"@biomejs/biome": "^2.5.0",
|
|
81
|
-
"@tanstack/db": ">=0.
|
|
82
|
-
"@tanstack/
|
|
83
|
-
"@tanstack/react-db": ">=0.3.8",
|
|
84
|
-
"@tanstack/react-query": ">=5.101.0",
|
|
78
|
+
"@tanstack/db": ">=0.12.1",
|
|
79
|
+
"@tanstack/react-db": ">=0.5.5",
|
|
85
80
|
"@testing-library/react": ">=16.3.2",
|
|
86
81
|
"@types/node": ">=25.0.10",
|
|
87
82
|
"@types/react": ">=19.2.10",
|