pbtsdb 0.9.0 → 0.9.2

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
@@ -431,6 +431,32 @@ Paths can be nested through a target collection's own `relations`
431
431
  (`'book.author'`). While a query fetches into a target, that target keeps its
432
432
  realtime subscription, so `get()` reads stay fresh.
433
433
 
434
+ Back-relations work the same way and go one step further. PocketBase names them
435
+ `<collection>_via_<field>`; fetching one files every child that references the
436
+ parent, and pbtsdb records that the child subset for that parent is complete,
437
+ so a child query filtered by the foreign key is served from the store:
438
+
439
+ ```typescript
440
+ const comments = c('comments', { syncMode: 'on-demand' });
441
+ const cards = c('cards', { syncMode: 'on-demand', relations: { comments_via_card: comments } });
442
+
443
+ const { data } = useLiveQuery((q) =>
444
+ q.from({ card: cards.fetchRelations('comments_via_card') })
445
+ .where(({ card }) => eq(card.id, cardId))
446
+ .select(({ card }) => ({
447
+ ...card,
448
+ comments: materialize(q.from({ cm: comments }).where(({ cm }) => eq(cm.card, card.id))),
449
+ }))
450
+ );
451
+ // one request; the comments include reads from the store
452
+ ```
453
+
454
+ A subset stays marked while the child collection is subscribed (the parent holds
455
+ it live) and is forgotten when a child row is pruned from the store, when the
456
+ child's realtime subscription stops, or when the collection is cleaned up.
457
+ PocketBase caps a back-relation expand at 1000 records, and a capped expand is
458
+ never treated as complete.
459
+
434
460
  #### Collection Options Passthrough
435
461
 
436
462
  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:
@@ -20,6 +20,18 @@ function joinPaths(paths) {
20
20
  const normalized = normalizePaths(paths);
21
21
  return normalized.length > 0 ? normalized.join(",") : void 0;
22
22
  }
23
+ var BACK_RELATION_EXPAND_CAP = 1e3;
24
+ function parseViaKey(key) {
25
+ const index = key.indexOf("_via_");
26
+ if (index < 0) return void 0;
27
+ const field = key.slice(index + "_via_".length);
28
+ return field ? { field } : void 0;
29
+ }
30
+ function markFiledSubset(target, key, values, parentId) {
31
+ const via = parseViaKey(key);
32
+ if (!via || values.length >= BACK_RELATION_EXPAND_CAP) return;
33
+ target.markSubsetLoaded?.(via.field, parentId);
34
+ }
23
35
  function validateExpandPath(collectionName, targets, path) {
24
36
  if (!targets) {
25
37
  throw new Error(
@@ -39,30 +51,33 @@ function validateExpandPath(collectionName, targets, path) {
39
51
  }
40
52
 
41
53
  // src/keyed-where.ts
42
- function isIdRef(node) {
43
- return node?.type === "ref" && node.path?.length === 1 && node.path[0] === "id";
54
+ function fieldRef(node) {
55
+ return node?.type === "ref" && node.path?.length === 1 ? node.path[0] : void 0;
44
56
  }
45
57
  function stringValue(node) {
46
58
  return node?.type === "val" && typeof node.value === "string" ? node.value : void 0;
47
59
  }
48
60
  function collectEq(a, b) {
49
- const other = isIdRef(a) ? b : isIdRef(b) ? a : void 0;
50
- if (!other) return void 0;
51
- const value = stringValue(other);
52
- return value === void 0 ? void 0 : [value];
61
+ const field = fieldRef(a) ?? fieldRef(b);
62
+ if (field === void 0) return void 0;
63
+ const value = stringValue(fieldRef(a) !== void 0 ? b : a);
64
+ return value === void 0 ? void 0 : { field, values: [value] };
53
65
  }
54
66
  function collectIn(a, b) {
55
- if (!isIdRef(a) || b?.type !== "val" || !Array.isArray(b.value)) return void 0;
56
- return b.value.every((v) => typeof v === "string") ? b.value : void 0;
67
+ const field = fieldRef(a);
68
+ if (field === void 0 || b?.type !== "val" || !Array.isArray(b.value)) return void 0;
69
+ return b.value.every((v) => typeof v === "string") ? { field, values: b.value } : void 0;
57
70
  }
58
71
  function collectOr(args) {
59
- const ids = [];
72
+ let field;
73
+ const values = [];
60
74
  for (const arg of args) {
61
75
  const sub = collect(arg);
62
- if (!sub) return void 0;
63
- ids.push(...sub);
76
+ if (!sub || field !== void 0 && sub.field !== field) return void 0;
77
+ field = sub.field;
78
+ values.push(...sub.values);
64
79
  }
65
- return ids;
80
+ return field === void 0 ? void 0 : { field, values };
66
81
  }
67
82
  function collect(node) {
68
83
  if (node.type !== "func" || !node.args) return void 0;
@@ -78,10 +93,17 @@ function collect(node) {
78
93
  return void 0;
79
94
  }
80
95
  }
81
- function idsFromWhere(where) {
96
+ function subsetFromWhere(where) {
82
97
  if (!where) return void 0;
83
- const ids = collect(where);
84
- return ids ? [...new Set(ids)].sort() : void 0;
98
+ const subset = collect(where);
99
+ return subset ? { field: subset.field, values: [...new Set(subset.values)].sort() } : void 0;
100
+ }
101
+ function matchesSubset(row, field, wanted) {
102
+ const value = row[field];
103
+ if (typeof value === "string") return wanted.has(value);
104
+ if (Array.isArray(value))
105
+ return value.some((item) => typeof item === "string" && wanted.has(item));
106
+ return false;
85
107
  }
86
108
 
87
109
  // src/logger.ts
@@ -213,6 +235,37 @@ function convertToPocketBaseSort(orderBy) {
213
235
 
214
236
  // src/build-collection.ts
215
237
  var viewPaths = /* @__PURE__ */ new WeakMap();
238
+ var pendingFilings = /* @__PURE__ */ new WeakMap();
239
+ function registerPendingFiling(target, field, settles) {
240
+ let byField = pendingFilings.get(target);
241
+ if (!byField) {
242
+ byField = /* @__PURE__ */ new Map();
243
+ pendingFilings.set(target, byField);
244
+ }
245
+ let pending = byField.get(field);
246
+ if (!pending) {
247
+ pending = [];
248
+ byField.set(field, pending);
249
+ }
250
+ pending.push(settles);
251
+ return () => {
252
+ const index = pending.indexOf(settles);
253
+ if (index !== -1) pending.splice(index, 1);
254
+ if (pending.length === 0) byField.delete(field);
255
+ if (byField.size === 0) pendingFilings.delete(target);
256
+ };
257
+ }
258
+ async function awaitPendingFiling(target, field) {
259
+ const pending = pendingFilings.get(target)?.get(field);
260
+ if (!pending || pending.length === 0) return;
261
+ await Promise.all(pending);
262
+ }
263
+ function registerMarkInvalidationEvents(collection, clearMarks) {
264
+ collection.onStatusChange((event) => {
265
+ if (event.status === "cleaned-up") clearMarks();
266
+ });
267
+ collection.onTruncate(() => clearMarks());
268
+ }
216
269
  function buildCollection(input) {
217
270
  const { pb, queryClient, factoryOptions, collectionName, options } = input;
218
271
  const relationTargets = options?.relations;
@@ -222,11 +275,11 @@ function buildCollection(input) {
222
275
  const requestedExpand = /* @__PURE__ */ new Set();
223
276
  function toRequest(opts) {
224
277
  const request = {};
225
- const ids = idsFromWhere(opts?.where);
226
- const filter = ids ? void 0 : convertToPocketBaseFilter(opts?.where);
278
+ const subset = subsetFromWhere(opts?.where);
279
+ const filter = subset ? void 0 : convertToPocketBaseFilter(opts?.where);
227
280
  const sort = convertToPocketBaseSort(opts?.orderBy);
228
281
  const expand = joinPaths(opts?.expand ?? []);
229
- if (ids) request.ids = ids;
282
+ if (subset) request.subset = subset;
230
283
  if (filter) request.filter = filter;
231
284
  if (sort) request.sort = sort;
232
285
  if (opts?.limit) request.limit = opts.limit;
@@ -244,6 +297,16 @@ function buildCollection(input) {
244
297
  ...syncMode === "eager" ? requestedExpand : []
245
298
  ]);
246
299
  }
300
+ function backRelationTargetsFor(request) {
301
+ if (!relationTargets) return [];
302
+ const results = [];
303
+ for (const key of splitPaths(activeExpand(request)).map((path) => path.split(".")[0])) {
304
+ const target = relationTargets[key];
305
+ const via = target && parseViaKey(key);
306
+ if (target && via) results.push({ target, key, field: via.field });
307
+ }
308
+ return results;
309
+ }
247
310
  function stripFetchedRelations(items, expandString) {
248
311
  const heads = new Set(splitPaths(expandString).map((path) => path.split(".")[0]));
249
312
  if (heads.size === 0) return items;
@@ -268,7 +331,7 @@ function buildCollection(input) {
268
331
  });
269
332
  }
270
333
  async function upsertInto(key, target, values) {
271
- if (!target.utils) return;
334
+ if (!target.utils) return false;
272
335
  if (!target.isReady()) {
273
336
  if (target.config?.syncMode === "on-demand") {
274
337
  await target._sync.startSync();
@@ -278,33 +341,103 @@ function buildCollection(input) {
278
341
  logger.warn(
279
342
  `not syncing ${key} on ${collectionName} because store is not yet ready`
280
343
  );
281
- return;
344
+ return false;
282
345
  }
283
346
  }
284
347
  target.utils.writeUpsert(withoutExpand(values));
348
+ return true;
285
349
  }
286
- async function upsertExpandedField(key, value, targets) {
350
+ async function upsertExpandedField(key, value, targets, parentId) {
287
351
  const target = targets[key];
288
352
  if (!target) {
289
353
  logger.debug("No relation target for expanded field", { collectionName, key });
290
354
  return;
291
355
  }
292
356
  const values = Array.isArray(value) ? value : [value];
293
- await upsertInto(key, target, values);
357
+ const filed = await upsertInto(key, target, values);
294
358
  await upsertExpanded(values, target.relationTargets);
359
+ if (filed && parentId !== void 0) markFiledSubset(target, key, values, parentId);
295
360
  }
296
361
  async function upsertExpanded(records, targets) {
297
362
  if (!targets) return;
298
363
  for (const record of records) {
299
364
  const expandData = record.expand;
300
365
  if (!expandData) continue;
366
+ const id = record.id;
367
+ const parentId = typeof id === "string" ? id : void 0;
301
368
  for (const [key, value] of Object.entries(expandData)) {
302
- await upsertExpandedField(key, value, targets);
369
+ await upsertExpandedField(key, value, targets, parentId);
370
+ }
371
+ }
372
+ }
373
+ function markEmptyBackRelations(items, request) {
374
+ const heads = backRelationTargetsFor(request);
375
+ if (heads.length === 0) return;
376
+ for (const item of items) {
377
+ const { id, expand } = item;
378
+ if (typeof id !== "string") continue;
379
+ for (const { target, key, field } of heads) {
380
+ if (expand?.[key] === void 0) target.markSubsetLoaded?.(field, id);
303
381
  }
304
382
  }
305
383
  }
306
- function idFilter(ids) {
307
- return ids.map((id) => `id = "${id.replace(/"/g, '\\"')}"`).join(" || ");
384
+ function subsetFilter({ field, values }) {
385
+ return values.map((value) => `${field} = "${value.replace(/"/g, '\\"')}"`).join(" || ");
386
+ }
387
+ const loadedSubsets = /* @__PURE__ */ new Map();
388
+ function markSubsetLoaded(field, value) {
389
+ let values = loadedSubsets.get(field);
390
+ if (!values) {
391
+ values = /* @__PURE__ */ new Set();
392
+ loadedSubsets.set(field, values);
393
+ }
394
+ values.add(value);
395
+ }
396
+ function loadedSubsetCount() {
397
+ let count = 0;
398
+ for (const values of loadedSubsets.values()) count += values.size;
399
+ return count;
400
+ }
401
+ function subsetIsLoaded({ field, values }) {
402
+ const marked = loadedSubsets.get(field);
403
+ return marked !== void 0 && values.every((value) => marked.has(value));
404
+ }
405
+ function forgetMarkedValue(marked, value) {
406
+ if (typeof value === "string") return marked.delete(value) ? [value] : [];
407
+ if (!Array.isArray(value)) return [];
408
+ return value.filter((item) => typeof item === "string" && marked.delete(item));
409
+ }
410
+ function matchesMarkedSubset(query, isMarked) {
411
+ if (query.queryKey[0] !== collectionName) return false;
412
+ const request = query.queryKey[1];
413
+ if (!request?.subset) return false;
414
+ const { field, values } = request.subset;
415
+ return values.some((value) => isMarked(field, value));
416
+ }
417
+ function invalidateMarkedQueries(isMarked) {
418
+ void queryClient.invalidateQueries({ predicate: (query) => matchesMarkedSubset(query, isMarked) }).catch(
419
+ (error) => logger.error("Failed to invalidate marked subset queries", {
420
+ collectionName,
421
+ error
422
+ })
423
+ );
424
+ }
425
+ function invalidateForgottenSubset(field, values) {
426
+ invalidateMarkedQueries(
427
+ (queryField, value) => queryField === field && values.includes(value)
428
+ );
429
+ }
430
+ function invalidateAllMarkedSubsets() {
431
+ invalidateMarkedQueries((field, value) => loadedSubsets.get(field)?.has(value) ?? false);
432
+ }
433
+ function forgetMarksFor(row) {
434
+ if (!row || typeof row !== "object") return;
435
+ for (const [field, marked] of loadedSubsets) {
436
+ const forgotten = forgetMarkedValue(marked, row[field]);
437
+ if (forgotten.length > 0) {
438
+ queueMicrotask(() => invalidateForgottenSubset(field, forgotten));
439
+ }
440
+ }
308
441
  }
309
442
  function rowsFromStore(ids) {
310
443
  const rows = [];
@@ -315,21 +448,37 @@ function buildCollection(input) {
315
448
  }
316
449
  return rows;
317
450
  }
451
+ function idSubsetFromStore(subset, limit) {
452
+ const present = rowsFromStore(subset.values);
453
+ if (!present) return void 0;
454
+ return limit ? present.slice(0, limit) : present;
455
+ }
456
+ function fieldSubsetFromStore(subset, limit) {
457
+ if (!subsetIsLoaded(subset)) return void 0;
458
+ const wanted = new Set(subset.values);
459
+ const rows = [...collection._state.syncedData.values()].filter(
460
+ (row) => matchesSubset(row, subset.field, wanted)
461
+ );
462
+ return limit ? rows.slice(0, limit) : rows;
463
+ }
318
464
  function servedFromStore(request) {
319
- const { ids, sort, limit } = request;
320
- if (!ids) return void 0;
321
- if (ids.length === 0) return [];
465
+ const { subset, sort, limit } = request;
466
+ if (!subset) return void 0;
467
+ if (subset.values.length === 0) return [];
322
468
  if (request.expand) return void 0;
323
469
  if (sort && limit) return void 0;
324
- const present = rowsFromStore(ids);
325
- if (!present) return void 0;
326
- return limit ? present.slice(0, limit) : present;
470
+ return subset.field === "id" ? idSubsetFromStore(subset, limit) : fieldSubsetFromStore(subset, limit);
327
471
  }
328
472
  async function fetchItems(request) {
329
473
  const served = servedFromStore(request);
330
474
  if (served) return served;
331
- const { sort, limit, ids } = request;
332
- const filter = ids ? idFilter(ids) : request.filter;
475
+ if (request.subset && request.subset.field !== "id" && backRelationTargetsFor(request).length === 0) {
476
+ await awaitPendingFiling(collection, request.subset.field);
477
+ const servedAfterFiling = servedFromStore(request);
478
+ if (servedAfterFiling) return servedAfterFiling;
479
+ }
480
+ const { sort, limit, subset } = request;
481
+ const filter = subset ? subsetFilter(subset) : request.filter;
333
482
  const expand = activeExpand(request);
334
483
  if (limit) {
335
484
  const result = await pb.collection(collectionName).getList(1, limit, {
@@ -339,13 +488,17 @@ function buildCollection(input) {
339
488
  // Optimize by skipping total count
340
489
  expand
341
490
  });
342
- return result.items;
491
+ const items2 = result.items;
492
+ markEmptyBackRelations(items2, request);
493
+ return items2;
343
494
  }
344
- return await pb.collection(collectionName).getFullList({
495
+ const items = await pb.collection(collectionName).getFullList({
345
496
  filter,
346
497
  sort,
347
498
  expand
348
499
  });
500
+ markEmptyBackRelations(items, request);
501
+ return items;
349
502
  }
350
503
  const inFlightConfirmedIds = /* @__PURE__ */ new Set();
351
504
  function markConfirmedPresent(records) {
@@ -377,6 +530,13 @@ function buildCollection(input) {
377
530
  async function fetchRecords(request, queryKey) {
378
531
  const confirmedMidFlight = /* @__PURE__ */ new Set();
379
532
  inFlightConfirmedIds.add(confirmedMidFlight);
533
+ let settleFiling = () => void 0;
534
+ const filed = new Promise((resolve) => {
535
+ settleFiling = resolve;
536
+ });
537
+ const unregisterFilings = backRelationTargetsFor(request).map(
538
+ ({ target, field }) => registerPendingFiling(target, field, filed)
539
+ );
380
540
  try {
381
541
  let items;
382
542
  try {
@@ -397,6 +557,8 @@ function buildCollection(input) {
397
557
  );
398
558
  } finally {
399
559
  inFlightConfirmedIds.delete(confirmedMidFlight);
560
+ settleFiling();
561
+ for (const unregister of unregisterFilings) unregister();
400
562
  }
401
563
  }
402
564
  const queryCollectionConfig = queryCollectionOptions({
@@ -512,6 +674,7 @@ function buildCollection(input) {
512
674
  sync: (params) => {
513
675
  const guardedWrite = (message) => {
514
676
  const op = message;
677
+ if (op.type === "delete" && !applyingOwnWrite) forgetMarksFor(op.value);
515
678
  if (shouldDropSyncedWrite(op)) return;
516
679
  return params.write(message);
517
680
  };
@@ -730,7 +893,11 @@ function buildCollection(input) {
730
893
  }
731
894
  };
732
895
  const doStopSubscription = async (releaseTargets = true) => {
733
- if (releaseTargets) syncHeldSubscriptions(/* @__PURE__ */ new Set());
896
+ if (releaseTargets) {
897
+ syncHeldSubscriptions(/* @__PURE__ */ new Set());
898
+ invalidateAllMarkedSubsets();
899
+ loadedSubsets.clear();
900
+ }
734
901
  if (!isSubscribed || !unsubscribeFn) return;
735
902
  try {
736
903
  await unsubscribeFn();
@@ -818,12 +985,21 @@ function buildCollection(input) {
818
985
  }
819
986
  }
820
987
  );
988
+ registerMarkInvalidationEvents(
989
+ {
990
+ onStatusChange: (callback) => collection.on("status:change", callback),
991
+ onTruncate: (callback) => collection.on("truncate", callback)
992
+ },
993
+ () => loadedSubsets.clear()
994
+ );
821
995
  Object.assign(collection, {
822
996
  collectionName,
823
997
  relationTargets,
824
998
  waitForSubscription,
825
999
  isSubscribed: () => isSubscribed,
826
1000
  heldRelationTargetCount: () => heldTargetSubscriptions.size,
1001
+ markSubsetLoaded,
1002
+ loadedSubsetCount,
827
1003
  fetchRelations
828
1004
  });
829
1005
  return collection;
@@ -853,5 +1029,5 @@ function newRecordId() {
853
1029
  }
854
1030
 
855
1031
  export { createCollection, newRecordId, resetLogger, setLogger };
856
- //# sourceMappingURL=chunk-YWTU6QXM.js.map
857
- //# sourceMappingURL=chunk-YWTU6QXM.js.map
1032
+ //# sourceMappingURL=chunk-I6UWXRAH.js.map
1033
+ //# sourceMappingURL=chunk-I6UWXRAH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/expand-paths.ts","../src/keyed-where.ts","../src/logger.ts","../src/pocketbase-query-converter.ts","../src/build-collection.ts","../src/collection.ts","../src/util.ts"],"names":["items","createTanStackCollection"],"mappings":"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","file":"chunk-I6UWXRAH.js","sourcesContent":["import type { ExpandTargetCollection } from './types'\n\nexport type RelationTargets = Record<string, ExpandTargetCollection>\n\nexport function normalizePaths(paths: Iterable<string>): string[] {\n const set = new Set<string>()\n for (const path of paths) {\n const trimmed = path.trim()\n if (trimmed) set.add(trimmed)\n }\n return [...set].sort()\n}\n\nexport function splitPaths(csv: string | undefined): string[] {\n return csv ? normalizePaths(csv.split(',')) : []\n}\n\nexport function joinPaths(paths: Iterable<string>): string | undefined {\n const normalized = normalizePaths(paths)\n return normalized.length > 0 ? normalized.join(',') : undefined\n}\n\nexport const BACK_RELATION_EXPAND_CAP = 1000\n\n/** `<collection>_via_<field>` → `{ field }`, split at the first `_via_`. */\nexport function parseViaKey(key: string): { field: string } | undefined {\n const index = key.indexOf('_via_')\n if (index < 0) return undefined\n const field = key.slice(index + '_via_'.length)\n return field ? { field } : undefined\n}\n\n/**\n * After a parent filed the values expanded under `key`, record on the target\n * that the subset `field = parentId` is complete — unless the key is a forward\n * relation or PocketBase may have capped the expand.\n */\nexport function markFiledSubset(\n target: ExpandTargetCollection,\n key: string,\n values: readonly object[],\n parentId: string\n): void {\n const via = parseViaKey(key)\n if (!via || values.length >= BACK_RELATION_EXPAND_CAP) return\n target.markSubsetLoaded?.(via.field, parentId)\n}\n\nexport function validateExpandPath(\n collectionName: string,\n targets: RelationTargets | undefined,\n path: string\n): void {\n if (!targets) {\n throw new Error(\n `Cannot expand \"${path}\" on collection \"${collectionName}\": no relations declared`\n )\n }\n let current: RelationTargets | undefined = targets\n for (const segment of path.split('.')) {\n const next: ExpandTargetCollection | undefined = current?.[segment]\n if (!next) {\n throw new Error(\n `Cannot expand \"${path}\" on collection \"${collectionName}\": segment \"${segment}\" is not a declared relation`\n )\n }\n current = next.relationTargets\n }\n}\n","import type { IR } from '@tanstack/db'\n\nexport type WhereSubset = { field: string; values: string[] }\n\ntype Node = { type: string; name?: string; args?: Node[]; path?: string[]; value?: unknown }\n\nfunction fieldRef(node: Node | undefined): string | undefined {\n return node?.type === 'ref' && node.path?.length === 1 ? node.path[0] : undefined\n}\n\nfunction stringValue(node: Node | undefined): string | undefined {\n return node?.type === 'val' && typeof node.value === 'string' ? node.value : undefined\n}\n\nfunction collectEq(a: Node | undefined, b: Node | undefined): WhereSubset | undefined {\n const field = fieldRef(a) ?? fieldRef(b)\n if (field === undefined) return undefined\n const value = stringValue(fieldRef(a) !== undefined ? b : a)\n return value === undefined ? undefined : { field, values: [value] }\n}\n\nfunction collectIn(a: Node | undefined, b: Node | undefined): WhereSubset | undefined {\n const field = fieldRef(a)\n if (field === undefined || b?.type !== 'val' || !Array.isArray(b.value)) return undefined\n return b.value.every(v => typeof v === 'string')\n ? { field, values: b.value as string[] }\n : undefined\n}\n\nfunction collectOr(args: Node[]): WhereSubset | undefined {\n let field: string | undefined\n const values: string[] = []\n for (const arg of args) {\n const sub = collect(arg)\n if (!sub || (field !== undefined && sub.field !== field)) return undefined\n field = sub.field\n values.push(...sub.values)\n }\n return field === undefined ? undefined : { field, values }\n}\n\nfunction collect(node: Node): WhereSubset | undefined {\n if (node.type !== 'func' || !node.args) return undefined\n const [a, b] = node.args\n switch (node.name) {\n case 'eq':\n return collectEq(a, b)\n case 'in':\n return collectIn(a, b)\n case 'or':\n return collectOr(node.args)\n default:\n return undefined\n }\n}\n\n/**\n * The single-field subset a `where` selects when it is nothing but equalities on\n * one top-level field: `eq(field, x)`, `in(field, [...])`, or an `or` of those.\n * Anything else returns `undefined`.\n */\nexport function subsetFromWhere(\n where: IR.BasicExpression<boolean> | undefined | null\n): WhereSubset | undefined {\n if (!where) return undefined\n const subset = collect(where as unknown as Node)\n return subset ? { field: subset.field, values: [...new Set(subset.values)].sort() } : undefined\n}\n\n/** Whether a row's `field` is one of `wanted` (a multiple relation matches by containment). */\nexport function matchesSubset(row: object, field: string, wanted: ReadonlySet<string>): boolean {\n const value = (row as Record<string, unknown>)[field]\n if (typeof value === 'string') return wanted.has(value)\n if (Array.isArray(value))\n return value.some(item => typeof item === 'string' && wanted.has(item))\n return false\n}\n","/**\n * Logger interface for subscription events and internal operations.\n * Users can provide their own implementation to integrate with external logging services.\n */\nexport interface Logger {\n /**\n * Log debug-level messages (typically only shown in development).\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n debug: (msg: string, context?: object) => void\n\n /**\n * Log info-level messages.\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n info: (msg: string, context?: object) => void\n\n /**\n * Log warning-level messages.\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n warn: (msg: string, context?: object) => void\n\n /**\n * Log error-level messages.\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n error: (msg: string, context?: object) => void\n}\n\n/**\n * Default console-based logger implementation.\n * Only logs debug messages in development mode.\n */\nconst defaultLogger: Logger = {\n debug: (msg: string, context?: object) => {\n if (process.env.NODE_ENV === 'development') {\n console.debug(`[pbtsdb] ${msg}`, context || '')\n }\n },\n info: (msg: string, context?: object) => {\n console.info(`[pbtsdb] ${msg}`, context || '')\n },\n warn: (msg: string, context?: object) => {\n console.warn(`[pbtsdb] ${msg}`, context || '')\n },\n error: (msg: string, context?: object) => {\n console.error(`[pbtsdb] ${msg}`, context || '')\n },\n}\n\n/**\n * Current logger instance (can be replaced by users).\n */\nlet currentLogger: Logger = defaultLogger\n\n/**\n * Internal logger instance used by the library.\n */\nexport const logger: Logger = {\n debug: (msg: string, context?: object) => currentLogger.debug(msg, context),\n info: (msg: string, context?: object) => currentLogger.info(msg, context),\n warn: (msg: string, context?: object) => currentLogger.warn(msg, context),\n error: (msg: string, context?: object) => currentLogger.error(msg, context),\n}\n\n/**\n * Set a custom logger implementation.\n * This allows users to integrate with their own logging services (e.g., Sentry, LogRocket, etc.).\n *\n * @param customLogger - The custom logger implementation\n *\n * @example\n * ```ts\n * import { setLogger } from 'pbtsdb';\n *\n * // Integration with a custom logging service\n * setLogger({\n * debug: (msg, context) => myLogger.debug(msg, context),\n * warn: (msg, context) => myLogger.warn(msg, context),\n * error: (msg, context) => {\n * myLogger.error(msg, context);\n * Sentry.captureMessage(msg, { level: 'error', extra: context });\n * },\n * });\n * ```\n *\n * @example\n * ```ts\n * // Disable all logging\n * setLogger({\n * debug: () => {},\n * warn: () => {},\n * error: () => {},\n * });\n * ```\n */\nexport function setLogger(customLogger: Logger): void {\n currentLogger = customLogger\n}\n\n/**\n * Reset the logger to the default implementation.\n */\nexport function resetLogger(): void {\n currentLogger = defaultLogger\n}\n","import type { IR } from '@tanstack/db'\nimport {\n type FieldPath,\n type ParsedOrderBy,\n parseOrderByExpression,\n parseWhereExpression,\n} from '@tanstack/db'\n\ntype BasicExpression<T = unknown> = IR.BasicExpression<T>\n\nfunction escapeValue(value: unknown): string {\n if (value === null) {\n return 'null'\n }\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false'\n }\n if (typeof value === 'number') {\n return value.toString()\n }\n if (typeof value === 'string') {\n return `\"${value.replace(/\"/g, '\\\\\"')}\"`\n }\n if (value instanceof Date) {\n return `\"${value.toISOString()}\"`\n }\n if (Array.isArray(value)) {\n return `[${value.map(escapeValue).join(',')}]`\n }\n return `\"${String(value)}\"`\n}\n\nfunction fieldPathToString(path: FieldPath): string {\n return path.join('.')\n}\n\nexport function convertToPocketBaseFilter(\n where: BasicExpression<boolean> | undefined | null\n): string | undefined {\n if (!where) {\n return undefined\n }\n\n const result = parseWhereExpression(where, {\n handlers: {\n eq: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} = ${escapeValue(value)}`\n },\n gt: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} > ${escapeValue(value)}`\n },\n gte: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} >= ${escapeValue(value)}`\n },\n lt: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} < ${escapeValue(value)}`\n },\n lte: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} <= ${escapeValue(value)}`\n },\n and: (...conditions: string[]) => {\n if (conditions.length === 0) return ''\n if (conditions.length === 1) return conditions[0]\n return `(${conditions.join(' && ')})`\n },\n or: (...conditions: string[]) => {\n if (conditions.length === 0) return ''\n if (conditions.length === 1) return conditions[0]\n return `(${conditions.join(' || ')})`\n },\n not: (condition: string) => {\n return `!(${condition})`\n },\n in: (field: FieldPath, values: unknown) => {\n const valueArray = Array.isArray(values) ? values : [values]\n const uniqueValues = [...new Set(valueArray)]\n const fieldStr = fieldPathToString(field)\n const conditions = uniqueValues.map(v => `${fieldStr} = ${escapeValue(v)}`)\n return conditions.length > 1 ? `(${conditions.join(' || ')})` : conditions[0]\n },\n like: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} ~ ${escapeValue(value)}`\n },\n isNull: (field: FieldPath) => {\n return `${fieldPathToString(field)} = null`\n },\n isUndefined: (field: FieldPath) => {\n return `${fieldPathToString(field)} = null`\n },\n },\n onUnknownOperator: (operator: string, _args: unknown[]) => {\n throw new Error(\n `Unsupported operator '${operator}' for PocketBase filter conversion. ` +\n `Supported operators: eq, gt, gte, lt, lte, in, like, and, or, not, isNull, isUndefined`\n )\n },\n })\n\n return result || undefined\n}\n\nexport function convertToPocketBaseSort(\n orderBy: IR.OrderBy | undefined | null\n): string | undefined {\n if (!orderBy) {\n return undefined\n }\n\n const sorts = parseOrderByExpression(orderBy)\n\n if (sorts.length === 0) {\n return undefined\n }\n\n return sorts\n .map((sort: ParsedOrderBy) => {\n const field = fieldPathToString(sort.field)\n return sort.direction === 'desc' ? `-${field}` : field\n })\n .join(',')\n}\n","import {\n BTreeIndex,\n type Collection,\n createCollection as createTanStackCollection,\n type LoadSubsetOptions,\n} from '@tanstack/db'\nimport {\n DeleteOperationItemNotFoundError,\n type QueryCollectionUtils,\n queryCollectionOptions,\n} from '@tanstack/query-db-collection'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type PocketBase from 'pocketbase'\nimport type { RecordSubscribeOptions, RecordSubscription } from 'pocketbase'\nimport type { RelationTargets } from './expand-paths'\nimport {\n joinPaths,\n markFiledSubset,\n normalizePaths,\n parseViaKey,\n splitPaths,\n validateExpandPath,\n} from './expand-paths'\nimport { matchesSubset, subsetFromWhere, type WhereSubset } from './keyed-where'\nimport { logger } from './logger'\nimport { convertToPocketBaseFilter, convertToPocketBaseSort } from './pocketbase-query-converter'\nimport type {\n CreateCollectionOptions,\n ExpandTargetCollection,\n ExtractRecordType,\n SchemaDeclaration,\n} from './types'\n\n// Subscriptions created through a view, mapped to the view's expand paths. Keyed\n// by the subscription object TanStack hands back to loadSubset/unloadSubset.\nconst viewPaths = new WeakMap<object, string[]>()\n\n// A correlated subquery over a relation target (e.g. a `materialize` include\n// keyed off the parent row's id) can have its own `loadSubset` dispatched by\n// TanStack DB's query planner before the parent's own fetch — the one that\n// would file and mark this exact subset — has resolved. Keyed by the target\n// collection instance and via-field, this lets the target's own fetch wait\n// for a same-tick parent fetch that might satisfy it instead of racing it.\nconst pendingFilings = new WeakMap<object, Map<string, Promise<void>[]>>()\n\n// Called by a PARENT collection's own fetch, on the relation TARGET instance,\n// to register that it might mark `field` once that fetch's upsertExpanded\n// settles. The target's own fetchItems awaits these (see awaitPendingFiling)\n// before issuing a request for a not-yet-loaded subset on that field. Returns\n// an unregister function the caller runs once its fetch settles, so a\n// long-lived target never accumulates promises for fetches that finished.\nfunction registerPendingFiling(target: object, field: string, settles: Promise<void>): () => void {\n let byField = pendingFilings.get(target)\n if (!byField) {\n byField = new Map()\n pendingFilings.set(target, byField)\n }\n let pending = byField.get(field)\n if (!pending) {\n pending = []\n byField.set(field, pending)\n }\n pending.push(settles)\n return () => {\n const index = pending.indexOf(settles)\n if (index !== -1) pending.splice(index, 1)\n if (pending.length === 0) byField.delete(field)\n if (byField.size === 0) pendingFilings.delete(target)\n }\n}\n\nasync function awaitPendingFiling(target: object, field: string): Promise<void> {\n const pending = pendingFilings.get(target)?.get(field)\n if (!pending || pending.length === 0) return\n await Promise.all(pending)\n}\n\n/**\n * Minimal shape of the two collection events that invalidate every loaded-subset\n * mark: `status:change` (cleared on reaching `cleaned-up`) and `truncate`\n * (cleared unconditionally). Extracted so the wiring itself is unit-testable\n * against a fake emitter, independent of a real `Collection` instance.\n * @internal\n */\nexport type MarkInvalidatingCollection = {\n onStatusChange: (callback: (event: { status: string }) => void) => () => void\n onTruncate: (callback: () => void) => () => void\n}\n\n/**\n * Without a live subscription, back-relation children can appear server-side\n * unseen, so every mark is stale once the collection cleans up or truncates.\n * @internal\n */\nexport function registerMarkInvalidationEvents(\n collection: MarkInvalidatingCollection,\n clearMarks: () => void\n): void {\n collection.onStatusChange(event => {\n if (event.status === 'cleaned-up') clearMarks()\n })\n collection.onTruncate(() => clearMarks())\n}\n\n/**\n * Options applied to every collection built by a {@link createCollection} factory.\n */\nexport interface CreateCollectionFactoryOptions {\n /**\n * Extra options passed to every real-time subscription this factory creates,\n * such as `headers`, `filter`, `expand` or `fields`.\n *\n * Invoked at subscribe time rather than read once, because a subscription is\n * re-established on reconnect and whenever the subscriber count rises from\n * zero — a value captured at build time would go stale exactly then.\n *\n * Returning `undefined` subscribes with no extra options.\n */\n subscribeOptions?: () => RecordSubscribeOptions | undefined\n}\n\n/**\n * Subscription helpers added to collection instances.\n * @internal\n */\nexport interface CollectionSubscriptionHelpers {\n /** The PocketBase collection name */\n collectionName: string\n /** Wait for subscription to be established (useful in tests) */\n waitForSubscription: (timeout?: number) => Promise<void>\n /** Check if collection has an active subscription */\n isSubscribed: () => boolean\n /** Relation targets declared through `relations` */\n relationTargets: RelationTargets | undefined\n /** Number of relation targets currently held live */\n heldRelationTargetCount: () => number\n /** Record that every row with `field === value` is now in this collection's store */\n markSubsetLoaded: (field: string, value: string) => void\n /** Number of field/value pairs currently marked loaded */\n loadedSubsetCount: () => number\n}\n\n/**\n * Runtime shape of a built collection, before the public factory narrows it.\n * @internal\n */\nexport type BuiltCollection<T extends object> = Collection<\n T,\n string | number,\n QueryCollectionUtils<T, string | number, T>,\n never,\n T\n> &\n CollectionSubscriptionHelpers\n\n/** @internal */\nexport interface BuildCollectionInput<\n Schema extends SchemaDeclaration,\n C extends keyof Schema & string,\n> {\n pb: PocketBase\n queryClient: QueryClient\n factoryOptions: CreateCollectionFactoryOptions | undefined\n collectionName: C\n options: CreateCollectionOptions<Schema, C> | undefined\n}\n\n/** @internal */\nexport function buildCollection<Schema extends SchemaDeclaration, C extends keyof Schema & string>(\n input: BuildCollectionInput<Schema, C>\n): BuiltCollection<ExtractRecordType<Schema, C>> {\n const { pb, queryClient, factoryOptions, collectionName, options } = input\n type RecordType = ExtractRecordType<Schema, C>\n\n const relationTargets = options?.relations as RelationTargets | undefined\n const alwaysFetch = normalizePaths(options?.alwaysFetchRelations ?? [])\n for (const path of alwaysFetch) validateExpandPath(collectionName, relationTargets, path)\n const syncMode = options?.syncMode ?? 'eager'\n\n // Paths requested by views that have subscribed at least once. Eager fetches\n // read it because they cannot receive per-subset options; the realtime\n // subscription reads it so echoes carry every relation in use.\n const requestedExpand = new Set<string>()\n\n type LoadOptions = LoadSubsetOptions & { expand?: readonly string[] }\n type PbRequest = {\n filter?: string\n sort?: string\n limit?: number\n expand?: string\n subset?: WhereSubset\n }\n\n function toRequest(opts: LoadSubsetOptions | undefined): PbRequest {\n const request: PbRequest = {}\n const subset = subsetFromWhere(opts?.where)\n const filter = subset ? undefined : convertToPocketBaseFilter(opts?.where)\n const sort = convertToPocketBaseSort(opts?.orderBy)\n const expand = joinPaths((opts as LoadOptions | undefined)?.expand ?? [])\n if (subset) request.subset = subset\n if (filter) request.filter = filter\n if (sort) request.sort = sort\n if (opts?.limit) request.limit = opts.limit\n if (expand) request.expand = expand\n return request\n }\n\n function queryKeyFor(opts?: LoadSubsetOptions): [C] | [C, PbRequest] {\n const request = toRequest(opts)\n return Object.keys(request).length === 0 ? [collectionName] : [collectionName, request]\n }\n\n function activeExpand(request: PbRequest): string | undefined {\n return joinPaths([\n ...alwaysFetch,\n ...splitPaths(request.expand),\n ...(syncMode === 'eager' ? requestedExpand : []),\n ])\n }\n\n // The declared relation targets this request's top-level expand keys will\n // file into, for each key that is a back-relation (`<collection>_via_<field>`).\n // Used to give a same-tick correlated subquery on one of those targets a\n // chance to be served from the store instead of racing this fetch.\n function backRelationTargetsFor(\n request: PbRequest\n ): Array<{ target: ExpandTargetCollection; key: string; field: string }> {\n if (!relationTargets) return []\n const results: Array<{ target: ExpandTargetCollection; key: string; field: string }> = []\n for (const key of splitPaths(activeExpand(request)).map(path => path.split('.')[0])) {\n const target = relationTargets[key]\n const via = target && parseViaKey(key)\n if (target && via) results.push({ target, key, field: via.field })\n }\n return results\n }\n\n // pbtsdb asked PocketBase for these relations only to file them into their\n // target collections; the copies never reach a row in any cache.\n function stripFetchedRelations(\n items: RecordType[],\n expandString: string | undefined\n ): RecordType[] {\n const heads = new Set(splitPaths(expandString).map(path => path.split('.')[0]))\n if (heads.size === 0) return items\n return items.map(item => {\n const { expand, ...plain } = item as RecordType & {\n expand?: Record<string, unknown>\n }\n if (!expand) return item\n const kept = Object.fromEntries(\n Object.entries(expand).filter(([key]) => !heads.has(key))\n )\n return (Object.keys(kept).length > 0 ? { ...plain, expand: kept } : plain) as RecordType\n })\n }\n\n const ignoreAutoCancellation = options?.ignoreAutoCancellation ?? true\n const refetchOnMutation = options?.refetchOnMutation ?? false\n\n function eagerSyncInFlight(target: ExpandTargetCollection): boolean {\n return (\n target.status !== undefined &&\n target.status !== 'idle' &&\n target.status !== 'cleaned-up'\n )\n }\n\n // A filed copy never carries `expand`: any part of it with a declared\n // target was filed by the recursive upsertExpanded call right after\n // upsertInto, and any part without one has nowhere to go and is dropped.\n function withoutExpand(values: object[]): object[] {\n return values.map(value => {\n const { expand: _expand, ...plain } = value as { expand?: unknown }\n return plain\n })\n }\n\n // Returns whether a write actually happened. A silent no-op (no utils, or\n // not ready with no way to become ready) must never be treated as a filing:\n // the caller uses this to decide whether the values just upserted can be\n // trusted to mark a subset complete.\n async function upsertInto(\n key: string,\n target: ExpandTargetCollection,\n values: object[]\n ): Promise<boolean> {\n if (!target.utils) return false\n if (!target.isReady()) {\n if (target.config?.syncMode === 'on-demand') {\n await target._sync.startSync()\n } else if (target.preload && eagerSyncInFlight(target)) {\n // An eager target whose full load is already running (a held\n // subscription started it) becomes ready shortly; wait rather\n // than drop the records or race the load.\n await target.preload()\n } else {\n logger.warn(\n `not syncing ${key} on ${collectionName} because store is not yet ready`\n )\n return false\n }\n }\n target.utils.writeUpsert(withoutExpand(values))\n return true\n }\n\n async function upsertExpandedField(\n key: string,\n value: object | object[],\n targets: RelationTargets,\n parentId: string | undefined\n ): Promise<void> {\n const target = targets[key]\n if (!target) {\n logger.debug('No relation target for expanded field', { collectionName, key })\n return\n }\n const values = Array.isArray(value) ? value : [value]\n const filed = await upsertInto(key, target, values)\n await upsertExpanded(values, target.relationTargets)\n if (filed && parentId !== undefined) markFiledSubset(target, key, values, parentId)\n }\n\n async function upsertExpanded(\n records: object[],\n targets: RelationTargets | undefined\n ): Promise<void> {\n if (!targets) return\n for (const record of records) {\n const expandData = (record as { expand?: Record<string, object | object[]> }).expand\n if (!expandData) continue\n const id = (record as { id?: unknown }).id\n const parentId = typeof id === 'string' ? id : undefined\n for (const [key, value] of Object.entries(expandData)) {\n await upsertExpandedField(key, value, targets, parentId)\n }\n }\n }\n\n // PocketBase omits the expand key entirely when a back-relation has no\n // records, so absence after a server fetch means zero children for that parent.\n function markEmptyBackRelations(items: readonly object[], request: PbRequest): void {\n const heads = backRelationTargetsFor(request)\n if (heads.length === 0) return\n for (const item of items) {\n const { id, expand } = item as { id?: unknown; expand?: Record<string, unknown> }\n if (typeof id !== 'string') continue\n for (const { target, key, field } of heads) {\n if (expand?.[key] === undefined) target.markSubsetLoaded?.(field, id)\n }\n }\n }\n\n function subsetFilter({ field, values }: WhereSubset): string {\n return values.map(value => `${field} = \"${value.replace(/\"/g, '\\\\\"')}\"`).join(' || ')\n }\n\n // Field → parent ids whose child subset is known complete in the store,\n // recorded when a parent files a back-relation expand for that parent id.\n // Grows with the distinct parents filed while this target is held live,\n // pairs with rows the store already retains, and is cleared on stop,\n // cleanup, or truncate.\n const loadedSubsets = new Map<string, Set<string>>()\n\n function markSubsetLoaded(field: string, value: string): void {\n let values = loadedSubsets.get(field)\n if (!values) {\n values = new Set()\n loadedSubsets.set(field, values)\n }\n values.add(value)\n }\n\n function loadedSubsetCount(): number {\n let count = 0\n for (const values of loadedSubsets.values()) count += values.size\n return count\n }\n\n function subsetIsLoaded({ field, values }: WhereSubset): boolean {\n const marked = loadedSubsets.get(field)\n return marked !== undefined && values.every(value => marked.has(value))\n }\n\n function forgetMarkedValue(marked: Set<string>, value: unknown): string[] {\n if (typeof value === 'string') return marked.delete(value) ? [value] : []\n if (!Array.isArray(value)) return []\n return value.filter(item => typeof item === 'string' && marked.delete(item))\n }\n\n // True when `query` reads a subset of this collection keyed on a field the\n // caller marks, with at least one value the caller marks. Shared by\n // invalidateForgottenSubset (one field, the values just forgotten) and\n // invalidateMarkedSubsets (every field/value currently marked).\n function matchesMarkedSubset(\n query: { queryKey: readonly unknown[] },\n isMarked: (field: string, value: string) => boolean\n ): boolean {\n if (query.queryKey[0] !== collectionName) return false\n const request = query.queryKey[1] as PbRequest | undefined\n if (!request?.subset) return false\n const { field, values } = request.subset\n return values.some(value => isMarked(field, value))\n }\n\n function invalidateMarkedQueries(isMarked: (field: string, value: string) => boolean): void {\n void queryClient\n .invalidateQueries({ predicate: query => matchesMarkedSubset(query, isMarked) })\n .catch(error =>\n logger.error('Failed to invalidate marked subset queries', {\n collectionName,\n error,\n })\n )\n }\n\n // A subset query that already resolved successfully is served from\n // query-db-collection's own observer cache on the next mount regardless of\n // our own marks, so forgetting a mark must also invalidate that cached\n // query for a fresh fetch to actually happen.\n function invalidateForgottenSubset(field: string, values: readonly string[]): void {\n invalidateMarkedQueries(\n (queryField, value) => queryField === field && values.includes(value)\n )\n }\n\n // Every mark held for this target justified serving some subset query from\n // the store; releasing them on a real stop (see doStopSubscription) must\n // invalidate those queries too, or a later mount reads the same cached\n // result instead of re-checking with a live subscription.\n function invalidateAllMarkedSubsets(): void {\n invalidateMarkedQueries((field, value) => loadedSubsets.get(field)?.has(value) ?? false)\n }\n\n // A row leaving the store other than by a server-confirmed delete means the\n // subsets it belonged to are no longer complete. Deferred with\n // queueMicrotask: this runs inside the guarded sync write, i.e. inside\n // TanStack's write batch, and invalidateQueries can start a queryFn\n // synchronously up to its first await — which must not re-enter\n // fetchRecords/registerPendingFiling mid-batch.\n function forgetMarksFor(row: unknown): void {\n if (!row || typeof row !== 'object') return\n for (const [field, marked] of loadedSubsets) {\n const forgotten = forgetMarkedValue(marked, (row as Record<string, unknown>)[field])\n if (forgotten.length > 0) {\n queueMicrotask(() => invalidateForgottenSubset(field, forgotten))\n }\n }\n }\n\n // Rows already in the synced store are as fresh as realtime keeps them;\n // an id-only request whose ids are all present needs no round trip.\n function rowsFromStore(ids: readonly string[]): RecordType[] | undefined {\n const rows: RecordType[] = []\n for (const id of ids) {\n const row = collection._state.syncedData.get(id) as RecordType | undefined\n if (!row) return undefined\n rows.push(row)\n }\n return rows\n }\n\n // A row already in the store was fetched (and filed) with this collection's own\n // alwaysFetchRelations, so that part of `expand` is already reflected. Only\n // `request.expand` — the extra paths a fetchRelations() view adds — may not have\n // been filed for this row yet, so only that forces a real fetch. An empty subset\n // (e.g. `in(id, [])`) selects nothing and must never fall through to a request,\n // which an empty id filter would turn into \"fetch everything\".\n function idSubsetFromStore(\n subset: WhereSubset,\n limit: number | undefined\n ): RecordType[] | undefined {\n const present = rowsFromStore(subset.values)\n if (!present) return undefined\n return limit ? present.slice(0, limit) : present\n }\n\n function fieldSubsetFromStore(\n subset: WhereSubset,\n limit: number | undefined\n ): RecordType[] | undefined {\n if (!subsetIsLoaded(subset)) return undefined\n const wanted = new Set(subset.values)\n const rows = [...collection._state.syncedData.values()].filter(row =>\n matchesSubset(row as object, subset.field, wanted)\n ) as RecordType[]\n return limit ? rows.slice(0, limit) : rows\n }\n\n function servedFromStore(request: PbRequest): RecordType[] | undefined {\n const { subset, sort, limit } = request\n if (!subset) return undefined\n if (subset.values.length === 0) return []\n if (request.expand) return undefined\n // A sorted + limited request must be sliced in that order; the store\n // holds rows in id order, so slicing here could return the wrong subset.\n // TanStack passes neither for id-only loads today, so this only guards\n // against a future caller combining them.\n if (sort && limit) return undefined\n return subset.field === 'id'\n ? idSubsetFromStore(subset, limit)\n : fieldSubsetFromStore(subset, limit)\n }\n\n async function fetchItems(request: PbRequest): Promise<RecordType[]> {\n const served = servedFromStore(request)\n if (served) return served\n // A same-tick parent fetch may be about to file and mark exactly this\n // subset (see pendingFilings above); give it the chance before fetching.\n // Invariant: a registering fetch never waits. This fetch's own active\n // expand (alwaysFetchRelations included, not just request.expand) may\n // itself register pending filings on other targets (backRelationTargetsFor\n // below, in fetchRecords); waiting here too would let two mutually\n // back-related collections each register before either awaits, and then\n // await each other forever.\n if (\n request.subset &&\n request.subset.field !== 'id' &&\n backRelationTargetsFor(request).length === 0\n ) {\n await awaitPendingFiling(collection, request.subset.field)\n const servedAfterFiling = servedFromStore(request)\n if (servedAfterFiling) return servedAfterFiling\n }\n const { sort, limit, subset } = request\n const filter = subset ? subsetFilter(subset) : request.filter\n const expand = activeExpand(request)\n\n if (limit) {\n // Use getList when limit is specified to avoid fetching all records\n const result = await pb.collection(collectionName).getList(1, limit, {\n filter,\n sort,\n skipTotal: true, // Optimize by skipping total count\n expand,\n })\n const items = result.items as unknown as RecordType[]\n markEmptyBackRelations(items, request)\n return items\n }\n // Use getFullList to fetch all records with automatic pagination\n const items = (await pb.collection(collectionName).getFullList({\n filter,\n sort,\n expand,\n })) as unknown as RecordType[]\n markEmptyBackRelations(items, request)\n return items\n }\n\n // Each in-flight fetch registers a set here before its request goes out;\n // authoritative local writes (mutation write-backs and realtime echoes)\n // add the confirmed record ids to every registered set. An id added\n // after a fetch was issued is newer than that fetch's view of the\n // server, so the result cannot speak to the id's absence. The merge\n // deliberately ignores the fetch's filter: the manual-write cache push\n // grants every active query ownership of every synced row, so even a\n // row outside this subset's filter must be shielded from its reconcile.\n //\n // Why this exists: @tanstack/query-db-collection's applySuccessfulResult\n // reconcile-DELETES every row a query owns that its result omits, and the\n // synced-write guard below deliberately exempts deletes. A subset read\n // issued before a row existed can therefore resolve late and delete the\n // just-confirmed row (rows a query owns include rows pushed into its\n // cache by the manual-write path that runs on every write-back). The fix\n // is applied to the RESULT rather than the delete: fetchRecords merges\n // such rows back in, which both prevents the delete and keeps the row\n // owned by the query — a dropped delete alone would still strip\n // ownership and leave the row to a later GC pass.\n const inFlightConfirmedIds = new Set<Set<string>>()\n\n function markConfirmedPresent(records: RecordType[]): void {\n if (inFlightConfirmedIds.size === 0) return\n for (const record of records) {\n const id = (record as { id?: unknown } | null | undefined)?.id\n if (typeof id !== 'string') continue\n for (const confirmed of inFlightConfirmedIds) confirmed.add(id)\n }\n }\n\n function withRowsConfirmedMidFlight(\n items: RecordType[],\n confirmedMidFlight: Set<string>\n ): RecordType[] {\n if (confirmedMidFlight.size === 0) return items\n const resultIds = new Set(\n items.map(item => (item as { id?: unknown } | null | undefined)?.id)\n )\n // Ids absent from the synced store (deleted mid-flight, or never\n // landed) have nothing to protect and drop out of the merge.\n const mergedIds = [...confirmedMidFlight].filter(\n id => !resultIds.has(id) && collection._state.syncedData.has(id)\n )\n if (mergedIds.length === 0) return items\n logger.debug('Merging rows confirmed while fetch was in flight', {\n collectionName,\n ids: mergedIds,\n })\n return [\n ...items,\n ...mergedIds.map(id => collection._state.syncedData.get(id) as RecordType),\n ]\n }\n\n async function fetchRecords(\n request: PbRequest,\n queryKey: readonly unknown[]\n ): Promise<RecordType[]> {\n const confirmedMidFlight = new Set<string>()\n inFlightConfirmedIds.add(confirmedMidFlight)\n // Registered up front, before fetchItems runs, so a target's own\n // fetchItems — dispatched the same tick by a correlated subquery — can\n // await this fetch's filing instead of racing it. Resolves once filing\n // settles either way (including on an error/autocancel path below), so\n // a waiter is never left hanging on a subset this fetch never files.\n let settleFiling: () => void = () => undefined\n const filed = new Promise<void>(resolve => {\n settleFiling = resolve\n })\n const unregisterFilings = backRelationTargetsFor(request).map(({ target, field }) =>\n registerPendingFiling(target, field, filed)\n )\n try {\n let items: RecordType[]\n try {\n items = await fetchItems(request)\n } catch (error) {\n if (\n ignoreAutoCancellation &&\n error instanceof Error &&\n error.message.includes('autocancelled')\n ) {\n // PocketBase auto-cancelled this in-flight read because a newer\n // request superseded it. Resolve to THIS subset's own cached rows\n // (keyed by the full query key) so the reconcile is a no-op for the\n // subset. The base key ([collectionName]) holds the full-collection\n // snapshot — returning that here would let applySuccessfulResult\n // reconcile foreign rows into a filtered subset (re-introducing rows\n // the subset's filter excludes). Re-throwing instead would error the\n // subset and empty/retry it.\n return withRowsConfirmedMidFlight(\n queryClient.getQueryData<RecordType[]>(queryKey) ?? [],\n confirmedMidFlight\n )\n }\n throw error\n }\n\n await upsertExpanded(items, relationTargets)\n return withRowsConfirmedMidFlight(\n stripFetchedRelations(items, activeExpand(request)),\n confirmedMidFlight\n )\n } finally {\n inFlightConfirmedIds.delete(confirmedMidFlight)\n settleFiling()\n for (const unregister of unregisterFilings) unregister()\n }\n }\n\n // TanStack DB 0.6 turned auto-indexing off by default; without an index an\n // orderBy+limit query loads the whole subset instead of paging lazily and\n // warns on every compile. Restore the earlier default; callers can override\n // both settings through collectionOptions.\n const queryCollectionConfig = queryCollectionOptions({\n autoIndex: 'eager',\n defaultIndexType: BTreeIndex,\n ...options?.collectionOptions,\n queryClient,\n queryKey: queryKeyFor,\n syncMode,\n queryFn: async (ctx): Promise<RecordType[]> => {\n const request = (ctx.queryKey[1] as PbRequest | undefined) ?? {}\n return fetchRecords(request, ctx.queryKey)\n },\n getKey: (item: RecordType) => {\n const record = item as unknown as Record<string, unknown>\n if (!record || typeof record !== 'object' || !('id' in record)) {\n throw new Error(\n `Record in collection '${collectionName}' is missing required 'id' field. Received: ${JSON.stringify(item)}`\n )\n }\n return record.id as string\n },\n onInsert:\n options?.onInsert === false\n ? undefined\n : (options?.onInsert ??\n (async ({ transaction }) => {\n const created = await Promise.all(\n transaction.mutations.map(async mutation => {\n const {\n created: _created,\n updated: _updated,\n collectionId: _collectionId,\n collectionName: _collectionName,\n ...data\n } = mutation.modified as unknown as Record<string, unknown>\n return pb.collection(collectionName).create(data)\n })\n )\n writeBackAfterPersisted(transaction, created)\n return { refetch: refetchOnMutation }\n })),\n onUpdate:\n options?.onUpdate === false\n ? undefined\n : (options?.onUpdate ??\n (async ({ transaction }) => {\n const updated = await Promise.all(\n transaction.mutations.map(async mutation => {\n const recordWithId = mutation.original as { id: string }\n return pb\n .collection(collectionName)\n .update(recordWithId.id, mutation.changes)\n })\n )\n writeBackAfterPersisted(transaction, updated)\n return { refetch: refetchOnMutation }\n })),\n onDelete:\n options?.onDelete === false\n ? undefined\n : (options?.onDelete ??\n (async ({ transaction }) => {\n await Promise.all(\n transaction.mutations.map(async mutation => {\n const recordWithId = mutation.original as { id: string }\n await pb.collection(collectionName).delete(recordWithId.id)\n })\n )\n return { refetch: refetchOnMutation }\n })),\n })\n\n // queryCollectionOptions consumes `gcTime` for the underlying react-query\n // observer and never forwards it to the collection options it returns, so\n // the DB collection's own lifecycle GC (what controls when an idle\n // collection reaches 'cleaned-up') would silently fall back to its\n // 5-minute default. Re-apply it explicitly so a caller-supplied value\n // reaches both layers.\n const collectionOptions =\n options?.collectionOptions?.gcTime === undefined\n ? queryCollectionConfig\n : { ...queryCollectionConfig, gcTime: options.collectionOptions.gcTime }\n\n // Write the server's copy of a mutation's rows back AFTER the transaction\n // has persisted — never from inside its handler.\n //\n // TanStack DB keeps a completed transaction's optimistic draft visible\n // until a synced write for the key arrives, so a record the server\n // fills in (a number, a timestamp) reaches the screen only through that\n // later synced write. A write-back issued from inside the handler lands\n // while the transaction is still `persisting`; TanStack applies it,\n // then on completion re-adds the draft as a \"confirmed but unsynced\"\n // overlay and waits for a synced write that already happened. If the\n // realtime echo has ALSO already been consumed (it arrives before the\n // create resolves under load, and an echo carrying the same `updated`\n // as the write-back is dropped as stale), nothing ever clears the\n // overlay: the row shows the draft — minus every server-assigned field\n // — until a reload. Deferring the write-back to after persistence makes\n // it the synced write TanStack is waiting for.\n //\n // `markConfirmedPresent` still runs immediately: the in-flight fetch\n // bookkeeping needs to know the rows are confirmed the moment the\n // server said so, not a tick later.\n //\n // The deferred write itself: a no-op until the collection is ready\n // (writing into the synced store before sync has initialized throws,\n // and with no live query there is nothing to keep in sync — the next\n // query fetches the already-persisted state; the transaction can\n // outlive the last subscriber), and it drops any row the store already\n // supersedes — a realtime echo may have landed a newer copy while the\n // transaction was settling, and writing the response over it would\n // revert the row.\n function writeBackAfterPersisted(\n transaction: { isPersisted: { promise: Promise<unknown> } },\n records: RecordType[]\n ): void {\n markConfirmedPresent(records)\n void transaction.isPersisted.promise.then(\n () => {\n if (!collection.utils || !collection.isReady()) return\n const fresh = records.filter(record => !isStaleServerRecord(record))\n if (fresh.length === 0) return\n writeOwn(() => collection.utils.writeUpsert(fresh))\n },\n // A rejected transaction rolled its draft back; there is\n // nothing to write and nothing to report here.\n () => undefined\n )\n }\n\n // Set while pbtsdb performs its own authoritative writes (mutation-response\n // write-backs and realtime echoes) through collection.utils.*. Those writes\n // share the same sync `write` primitive as the query-result reconcile path\n // (see the sync.sync wrapper below), so the guard uses this flag to tell them\n // apart: pbtsdb's own writes are exempt from the optimistic-pending arm of the\n // guard (the mutation-response write-back intentionally lands the confirmed\n // value while that very mutation's optimistic overlay is still in flight).\n let applyingOwnWrite = false\n function writeOwn(fn: () => void): void {\n applyingOwnWrite = true\n try {\n fn()\n } finally {\n applyingOwnWrite = false\n }\n }\n\n // The record id a synced insert/update targets, or null when the op is a delete\n // (terminal — never guarded) or carries no usable key.\n function syncedWriteKey(op: { type: string; value?: unknown; key?: unknown }): string | null {\n if (op.type !== 'insert' && op.type !== 'update') return null\n if (typeof op.key === 'string') return op.key\n const id = (op.value as { id?: unknown } | undefined)?.id\n return typeof id === 'string' ? id : null\n }\n\n // Guard the synced write path that pbtsdb does not otherwise control:\n // @tanstack/query-db-collection's applySuccessfulResult reconciles every query\n // result into the synced store via this same `write`, with no recency or\n // optimistic check. Under on-demand contention a single-row/subset read can\n // resolve with a pre-mutation row and land here after the row already moved on,\n // reverting it. We drop such a synced insert/update when either it targets a key\n // with a pending optimistic mutation (see the arm below) or it is strictly older\n // than the synced row (an out-of-order read). pbtsdb's own writes\n // (applyingOwnWrite) skip the optimistic arm; they are staleness-filtered\n // upstream by writeBackAfterPersisted/isStaleEcho.\n function shouldDropSyncedWrite(op: { type: string; value?: unknown; key?: unknown }): boolean {\n const key = syncedWriteKey(op)\n if (key === null) return false\n // Optimistic arm: only guard a key already present in the synced store. A\n // write to a key the synced store doesn't yet hold is populating it (e.g. the\n // initial fetch landing a row the user just optimistically inserted) and must\n // pass — dropping it would leave the row absent once the overlay clears. A\n // write to a key already synced, while an optimistic mutation is pending, is a\n // racing read that would revert the in-flight value, so drop it.\n if (\n !applyingOwnWrite &&\n hasPendingOptimisticMutation(key) &&\n collection._state.syncedData.has(key)\n ) {\n logger.debug('Dropping synced write for optimistically-pending row', {\n collectionName,\n id: key,\n })\n return true\n }\n if (isStaleServerRecord(op.value)) {\n logger.debug('Dropping stale synced write', { collectionName, id: key })\n return true\n }\n return false\n }\n\n // A view's subscription is tagged in viewPaths (see createView below); this\n // adds the view's expand paths to load options for a tagged subscription so\n // loadSubset/unloadSubset fetch (and later untrack) with the right `expand`.\n // A subscription's initial snapshot loads synchronously inside\n // collection.subscribeChanges, before that call returns the subscription\n // object a view tags in viewPaths — so that first loadSubset cannot yet be\n // looked up by identity. While a view's subscribeChanges call is on the\n // stack, its paths are used for load options with no tagged subscription;\n // every later call (untracked demand growth, unloadSubset) is tagged by then.\n let subscribingViewPaths: string[] | undefined\n\n function withViewExpand(opts: LoadSubsetOptions): LoadOptions {\n const paths =\n (opts.subscription && viewPaths.get(opts.subscription)) ?? subscribingViewPaths\n return paths ? { ...opts, expand: paths } : opts\n }\n\n // Wrap the sync factory so every synced `write` flows through the guard above,\n // and every loadSubset/unloadSubset call is tagged with a view's expand paths.\n // @tanstack/db invokes sync.sync with the write primitives; we hand back the\n // same params with a filtered `write`. begin/commit/markReady/etc. pass through.\n const innerSync = collectionOptions.sync.sync\n collectionOptions.sync = {\n ...collectionOptions.sync,\n sync: (params: Parameters<typeof innerSync>[0]) => {\n const guardedWrite: typeof params.write = message => {\n const op = message as { type: string; value?: unknown; key?: unknown }\n if (op.type === 'delete' && !applyingOwnWrite) forgetMarksFor(op.value)\n if (shouldDropSyncedWrite(op)) return\n return params.write(message)\n }\n const res = innerSync({ ...params, write: guardedWrite })\n if (!res || typeof res === 'function') return res\n const { loadSubset, unloadSubset } = res\n return {\n ...res,\n loadSubset: loadSubset\n ? (opts: LoadSubsetOptions) => loadSubset(withViewExpand(opts))\n : undefined,\n unloadSubset: unloadSubset\n ? (opts: LoadSubsetOptions) => unloadSubset(withViewExpand(opts))\n : undefined,\n }\n },\n }\n\n const collection = createTanStackCollection(collectionOptions)\n\n const views = new Map<string, object>()\n\n function createView(paths: string[]): object {\n const view = Object.create(collection)\n Object.defineProperties(view, {\n id: { value: `${collectionName}?expand=${paths.join(',')}` },\n subscribeChanges: {\n value: (...args: Parameters<typeof collection.subscribeChanges>) => {\n noteViewSubscribed(paths)\n subscribingViewPaths = paths\n try {\n const subscription = collection.subscribeChanges(...args)\n viewPaths.set(subscription, paths)\n return subscription\n } finally {\n subscribingViewPaths = undefined\n }\n },\n },\n fetchRelations: {\n value: () => {\n throw new Error(`A view of \"${collectionName}\" cannot fetch further relations`)\n },\n },\n })\n return view\n }\n\n function fetchRelations(...paths: string[]): object {\n for (const path of paths) validateExpandPath(collectionName, relationTargets, path)\n const all = normalizePaths([...alwaysFetch, ...paths])\n if (all.every(path => alwaysFetch.includes(path))) return collection\n const key = all.join(',')\n let view = views.get(key)\n if (!view) {\n view = createView(all)\n views.set(key, view)\n }\n return view\n }\n\n // True when the key has an in-flight (not yet settled) optimistic mutation.\n // While pending, the optimistic overlay — not syncedData — is the visible value,\n // so any synced write would only take effect once the overlay collapses, and an\n // older/racing read landing here is exactly what reverts a just-applied move.\n function hasPendingOptimisticMutation(key: string): boolean {\n const state = collection._state as unknown as {\n optimisticUpserts: { has: (k: string) => boolean }\n optimisticDeletes: { has: (k: string) => boolean }\n }\n return state.optimisticUpserts.has(key) || state.optimisticDeletes.has(key)\n }\n\n // Read the PocketBase `updated` autodate from a record, if present.\n // Collections without an `updated` field opt out of staleness checks.\n function recordUpdatedAt(record: unknown): string | undefined {\n const updated = (record as { updated?: unknown } | null | undefined)?.updated\n return typeof updated === 'string' && updated !== '' ? updated : undefined\n }\n\n // A server record is stale relative to the synced store when an entry for\n // the same key already holds a newer `updated` timestamp. PocketBase can\n // redeliver or reorder realtime echoes (and a slow mutation response can\n // resolve after a newer echo), so applying an older write would revert the\n // row. ISO 8601 timestamps sort lexicographically, so string comparison is\n // chronological. When either side lacks a comparable timestamp we cannot\n // tell, so we treat the write as fresh and let it through.\n //\n // Strictly older, never equal. PocketBase stamps `updated` to the\n // millisecond and bumps it on every write, so an equal timestamp is the\n // same version of the row: re-landing it changes nothing, and it is what\n // lets a confirmed value clear a lingering optimistic overlay. (An earlier\n // `<=` variant on the query-result path guarded against a read carrying\n // old content under a new timestamp, which a real server cannot produce;\n // the revert it chased was the write-back racing its own transaction,\n // fixed in writeBackAfterPersisted.)\n function isStaleServerRecord(record: unknown): boolean {\n const id = (record as { id?: unknown } | null | undefined)?.id\n if (typeof id !== 'string') return false\n const incoming = recordUpdatedAt(record)\n if (!incoming) return false\n const current = recordUpdatedAt(\n collection._state.syncedData.get(id) as RecordType | undefined\n )\n if (current === undefined) return false\n return incoming < current\n }\n\n // Decide whether a realtime echo should be dropped as stale. Under realtime\n // contention PocketBase can redeliver or reorder events, so an echo carrying\n // a pre-mutation value can arrive after the row already moved on (e.g. the\n // local mutation that just wrote the fresh value back). Applying a\n // strictly-older create/update echo would revert the row, so it is ignored.\n // Deletes are terminal and not timestamp-guarded.\n function isStaleEcho(event: RecordSubscription<RecordType>): boolean {\n if (event.action !== 'create' && event.action !== 'update') return false\n if (!isStaleServerRecord(event.record)) return false\n logger.debug('Ignoring stale realtime echo', {\n collectionName,\n id: (event.record as { id?: string } | undefined)?.id,\n })\n return true\n }\n\n // Real-time subscription state\n let unsubscribeFn: (() => Promise<void>) | null = null\n let isSubscribed = false\n let subscriptionPromise: Promise<void> | null = null\n let subscriptionResolve: (() => void) | null = null\n // The `expand` string sent with the currently live subscription, so a\n // caller that widened requestedExpand mid-flight can tell whether the\n // subscription that just landed already covers it.\n let subscribedExpand: string | undefined\n\n // All start/stop/restart work is serialized onto this promise tail so\n // overlapping callers (two views created back-to-back, a reconnect\n // racing a widened expand) never run startSubscription/stopSubscription\n // concurrently — the tail is what lets a later caller's restart observe\n // the outcome of an earlier caller's in-flight start. Errors are caught\n // and logged so a failed step never poisons the tail for later work.\n let subscriptionWork: Promise<void> = Promise.resolve()\n function enqueueSubscriptionWork(fn: () => Promise<void>): Promise<void> {\n const run = subscriptionWork.then(fn, fn).catch(error => {\n logger.error('Subscription work failed', { collectionName, error })\n })\n subscriptionWork = run\n return run\n }\n\n // Handle real-time events from PocketBase.\n //\n // The write primitives differ in how they treat a key that is absent from\n // the *synced* store (collection._state.syncedData, which is what they\n // validate against — not the optimistic view exposed by collection.has()):\n // - writeInsert / writeUpsert: idempotent, never throw on an absent key.\n // - writeDelete: throws DeleteOperationItemNotFoundError on an absent key.\n // So only the delete branch can throw, and we make it idempotent below.\n // Runs BEFORE the stale-echo filter: even a stale create/update echo\n // proves the server holds the row. Delete echoes need no marking — the\n // merge checks the synced store, which the delete's writeDelete empties.\n function markEchoPresence(event: RecordSubscription<RecordType>): void {\n if (event.action !== 'delete') markConfirmedPresent([event.record])\n }\n\n const handleRealtimeEvent = (event: RecordSubscription<RecordType>) => {\n if (!collection.utils) return\n markEchoPresence(event)\n if (isStaleEcho(event)) return\n\n const [stored] = stripFetchedRelations([event.record], pendingSubscribeExpand())\n try {\n writeOwn(() =>\n collection.utils.writeBatch(() => {\n switch (event.action) {\n case 'create':\n collection.utils.writeInsert(stored)\n break\n case 'update':\n collection.utils.writeUpsert(stored)\n break\n case 'delete':\n if (event.record && 'id' in event.record) {\n // Throws DeleteOperationItemNotFoundError if the key\n // is no longer in the synced store (see catch below).\n collection.utils.writeDelete((event.record as { id: string }).id)\n }\n break\n }\n })\n )\n } catch (error) {\n // How a delete echo throws: writeDelete fails when its key is already\n // gone from the synced store. That happens when something removed it\n // before the echo arrived:\n // 1. on-demand sync — each useLiveQuery refetches with a server\n // filter, and query-db-collection prunes rows no longer owned by\n // any active query out of the synced store. If that prune (or a\n // concurrent query's reconcile) runs before this client's own\n // delete echo lands, the key is already gone -> throw. This is\n // the on-demand-only race; eager collections have no such second\n // writer to the synced store, so they cannot hit it.\n // 2. a re-delivered SSE delete (e.g. after a reconnect) for a key\n // that was already deleted -> throw on the second echo.\n // In both cases the record is already in its intended end state\n // (gone), so the echo is a no-op and the error is safe to ignore.\n // Anything that is NOT a missing-key delete is a real error: rethrow.\n if (error instanceof DeleteOperationItemNotFoundError) {\n logger.debug('Ignoring delete echo for already-removed record', {\n collectionName,\n id: (event.record as { id?: string } | undefined)?.id,\n })\n } else {\n throw error\n }\n }\n\n if (event.action !== 'delete') {\n upsertExpanded([event.record], relationTargets).catch(error =>\n logger.error('Failed to upsert expanded records from realtime echo', {\n collectionName,\n error,\n })\n )\n }\n }\n\n // The union of expand paths the next (re)subscribe should carry:\n // alwaysFetch plus every path a view has requested. Pure and\n // side-effect-free (unlike realtimeSubscribeOptions below), so it is\n // safe to call more than once per subscribe attempt to detect drift.\n function pendingSubscribeExpand(): string | undefined {\n return joinPaths([...alwaysFetch, ...requestedExpand])\n }\n\n // Collections along every active expand path. Held live (below) so their\n // stores stay fresh for keyed reads (materialize, joins, get()) and for\n // the store-served short circuit.\n function activeExpandTargets(): Set<ExpandTargetCollection> {\n const targets = new Set<ExpandTargetCollection>()\n for (const path of splitPaths(pendingSubscribeExpand())) {\n let current: RelationTargets | undefined = relationTargets\n for (const segment of path.split('.')) {\n const target: ExpandTargetCollection | undefined = current?.[segment]\n if (!target) break\n targets.add(target)\n current = target.relationTargets\n }\n }\n return targets\n }\n\n // The only place held target subscriptions are added or removed, so the\n // map always mirrors the last desired set exactly.\n const heldTargetSubscriptions = new Map<ExpandTargetCollection, { unsubscribe: () => void }>()\n\n function releaseHeldTarget(target: ExpandTargetCollection): void {\n const held = heldTargetSubscriptions.get(target)\n if (!held) return\n heldTargetSubscriptions.delete(target)\n try {\n held.unsubscribe()\n } catch (error) {\n logger.error('Failed to release relation target subscription', {\n collectionName,\n error,\n })\n }\n }\n\n function holdTarget(target: ExpandTargetCollection): void {\n if (heldTargetSubscriptions.has(target) || !target.subscribeChanges) return\n try {\n const held = target.subscribeChanges(() => {}, { includeInitialState: false })\n heldTargetSubscriptions.set(target, held)\n } catch (error) {\n logger.error('Failed to hold relation target subscription', { collectionName, error })\n }\n }\n\n function syncHeldSubscriptions(desired: Set<ExpandTargetCollection>): void {\n for (const target of [...heldTargetSubscriptions.keys()]) {\n if (!desired.has(target)) releaseHeldTarget(target)\n }\n for (const target of desired) holdTarget(target)\n }\n\n // Options for the next (re)subscribe: the expand union above, merged\n // with whatever the factory's own subscribeOptions() supplies rather\n // than overridden by it. Calls the factory callback, so it is invoked\n // exactly once per subscribe attempt (never re-derived afterward).\n function realtimeSubscribeOptions(): RecordSubscribeOptions | undefined {\n const base = factoryOptions?.subscribeOptions?.()\n const expand = joinPaths([\n ...splitPaths(pendingSubscribeExpand()),\n ...splitPaths(base?.expand),\n ])\n return expand ? { ...base, expand } : base\n }\n\n // Start PocketBase real-time subscription. Only ever run through\n // enqueueSubscriptionWork so it never overlaps a stop/restart.\n const doStartSubscription = async () => {\n if (isSubscribed) return\n\n // Create promise before starting so waiters can await it\n if (!subscriptionPromise) {\n subscriptionPromise = new Promise<void>(resolve => {\n subscriptionResolve = resolve\n })\n }\n\n const pendingExpand = pendingSubscribeExpand()\n try {\n unsubscribeFn = await pb\n .collection(collectionName)\n .subscribe('*', handleRealtimeEvent, realtimeSubscribeOptions())\n isSubscribed = true\n subscribedExpand = pendingExpand\n syncHeldSubscriptions(activeExpandTargets())\n logger.debug('Subscription started', { collectionName })\n // Resolve the promise to notify waiters\n if (subscriptionResolve) {\n subscriptionResolve()\n }\n } catch (error) {\n logger.error('Failed to start subscription', { collectionName, error })\n }\n\n // requestedExpand can grow while the subscribe() call above was in\n // flight (a view mounted mid-round-trip sees no live subscription\n // yet, and would otherwise never schedule a restart). Comparing\n // against the pure expand union (not realtimeSubscribeOptions,\n // which would re-invoke the factory's own subscribeOptions()\n // callback) lets this check run after every start with no\n // observable side effect.\n if (pendingSubscribeExpand() !== subscribedExpand) {\n enqueueSubscriptionWork(doRestartSubscription).catch(() => {})\n }\n }\n\n // Stop PocketBase real-time subscription. Only ever run through\n // enqueueSubscriptionWork so it never overlaps a start/restart.\n const doStopSubscription = async (releaseTargets = true) => {\n // Before the guard below: a restart whose subscribe() threw leaves\n // isSubscribed false with targets still held, and this real stop is\n // the only remaining chance to release them.\n if (releaseTargets) {\n syncHeldSubscriptions(new Set())\n invalidateAllMarkedSubsets()\n loadedSubsets.clear()\n }\n if (!isSubscribed || !unsubscribeFn) return\n\n try {\n await unsubscribeFn()\n logger.debug('Subscription stopped', { collectionName })\n } catch (error) {\n logger.debug('Unsubscribe failed (expected if connection closed)', {\n collectionName,\n error,\n })\n } finally {\n // Unconditional: a throwing unsubscribe must not leave the state\n // machine believing it is still subscribed after targets were\n // released, or the next start would return early and never re-hold.\n unsubscribeFn = null\n isSubscribed = false\n subscribedExpand = undefined\n subscriptionPromise = null\n subscriptionResolve = null\n }\n }\n\n // Restart the live subscription, e.g. after the requested expand union\n // grows. A no-op when there is no live subscription to restart — the\n // next first-subscriber start already picks up the current union.\n const doRestartSubscription = async () => {\n if (!isSubscribed) return\n await doStopSubscription(false)\n await doStartSubscription()\n }\n\n const startSubscription = () => enqueueSubscriptionWork(doStartSubscription)\n const stopSubscription = () => enqueueSubscriptionWork(() => doStopSubscription())\n const restartSubscription = () => enqueueSubscriptionWork(doRestartSubscription)\n\n // Record which expand paths a view has subscribed with at least once.\n // Eager collections cannot request per-subset options, so a wider union\n // needs a refetch to pick up the new expand; a live realtime subscription\n // needs restarting so its own expand union grows too.\n function noteViewSubscribed(paths: string[]): void {\n let grew = false\n for (const path of paths) {\n if (requestedExpand.has(path)) continue\n requestedExpand.add(path)\n grew = true\n }\n if (!grew) return\n if (\n syncMode === 'eager' &&\n collection.status !== 'idle' &&\n collection.status !== 'cleaned-up'\n ) {\n void collection.utils.refetch().catch(error =>\n logger.error('Failed to refetch after widening expand', {\n collectionName,\n error,\n })\n )\n }\n // Enqueued unconditionally (not gated on isSubscribed): the tail\n // guarantees this runs after any in-flight start/stop, and\n // doRestartSubscription itself no-ops when nothing is live.\n restartSubscription().catch(error =>\n logger.error('Failed to restart subscription with wider expand', {\n collectionName,\n error,\n })\n )\n }\n\n // Wait for subscription to be established (for testing)\n const waitForSubscription = async (timeout = 5000): Promise<void> => {\n if (isSubscribed) return\n\n if (!subscriptionPromise) {\n // No subscription in progress, wait for one to start\n await new Promise<void>(resolve => {\n const checkInterval = setInterval(() => {\n if (subscriptionPromise) {\n clearInterval(checkInterval)\n resolve()\n }\n }, 10)\n setTimeout(() => {\n clearInterval(checkInterval)\n resolve()\n }, timeout)\n })\n }\n\n if (subscriptionPromise) {\n await Promise.race([\n subscriptionPromise,\n new Promise<void>((_, reject) =>\n setTimeout(() => reject(new Error('Subscription timeout')), timeout)\n ),\n ])\n }\n }\n\n // Manage subscription based on collection subscriber count\n collection.on(\n 'subscribers:change',\n (event: { subscriberCount: number; previousSubscriberCount: number }) => {\n const newCount = event.subscriberCount\n const previousCount = event.previousSubscriberCount\n\n if (newCount > 0 && previousCount === 0) {\n // First subscriber - start real-time subscription\n startSubscription().catch(() => {})\n } else if (newCount === 0 && previousCount > 0) {\n // Last subscriber removed - stop real-time subscription\n stopSubscription().catch(() => {})\n }\n }\n )\n\n registerMarkInvalidationEvents(\n {\n onStatusChange: callback => collection.on('status:change', callback),\n onTruncate: callback => collection.on('truncate', callback),\n },\n () => loadedSubsets.clear()\n )\n\n // Add collectionName and subscription helpers\n Object.assign(collection, {\n collectionName,\n relationTargets,\n waitForSubscription,\n isSubscribed: () => isSubscribed,\n heldRelationTargetCount: () => heldTargetSubscriptions.size,\n markSubsetLoaded,\n loadedSubsetCount,\n fetchRelations,\n })\n\n return collection as unknown as BuiltCollection<RecordType>\n}\n","import type { Collection } from '@tanstack/db'\nimport type { QueryCollectionUtils } from '@tanstack/query-db-collection'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type PocketBase from 'pocketbase'\nimport { buildCollection, type CreateCollectionFactoryOptions } from './build-collection'\nimport type {\n CreateCollectionOptions,\n ExpandPath,\n ExtractRecordType,\n InsertInputOf,\n PbMeta,\n RelationsOf,\n SchemaDeclaration,\n} from './types'\n\nexport type { CreateCollectionFactoryOptions } from './build-collection'\nexport type { BaseRecord, CreateCollectionOptions, SchemaDeclaration } from './types'\n\n/**\n * A pbtsdb collection or view: a TanStack DB collection over\n * `ExtractRecordType<Schema, C>` rows, plus pbtsdb's subscription helpers.\n * Views are created by {@link PbCollection.fetchRelations} and are leaves:\n * they have no further `fetchRelations()`.\n */\nexport type PbCollectionView<\n Schema extends SchemaDeclaration,\n C extends keyof Schema & string,\n Opts,\n> = Collection<\n ExtractRecordType<Schema, C>,\n string | number,\n QueryCollectionUtils<\n ExtractRecordType<Schema, C>,\n string | number,\n ExtractRecordType<Schema, C>\n >,\n never,\n InsertInputOf<Schema, C, Opts>\n> & {\n /** The PocketBase collection name */\n readonly collectionName: C\n /** Wait for the real-time subscription to be established (useful in tests) */\n waitForSubscription: (timeout?: number) => Promise<void>\n /** Whether the collection has an active real-time subscription */\n isSubscribed: () => boolean\n /** @internal relation targets declared through `relations` */\n readonly relationTargets: Record<string, unknown> | undefined\n /** @internal number of relation targets currently held live */\n readonly heldRelationTargetCount: () => number\n /** @internal record that every row with `field === value` is now in this collection's store */\n readonly markSubsetLoaded: (field: string, value: string) => void\n /** @internal number of field/value pairs currently marked loaded */\n readonly loadedSubsetCount: () => number\n /** @internal phantom; never present at runtime */\n readonly __pbtsdb: PbMeta<Schema, C, RelationsOf<Opts>>\n}\n\n/**\n * The collection returned by {@link createCollection}: a {@link PbCollectionView}\n * plus `fetchRelations()` for per-query views.\n */\nexport type PbCollection<\n Schema extends SchemaDeclaration,\n C extends keyof Schema & string,\n Opts,\n> = PbCollectionView<Schema, C, Opts> & {\n /**\n * A view of this collection whose queries also fetch `paths` and file the\n * expanded records into their target collections. Rows are unchanged; read\n * related records through `materialize()`, a join, or the target's `get()`.\n */\n fetchRelations<const P extends readonly ExpandPath<RelationsOf<Opts>>[]>(\n ...paths: P\n ): PbCollectionView<Schema, C, Opts>\n}\n\ntype AlwaysFetchRelationsCheck<Opts> = {\n alwaysFetchRelations?: readonly ExpandPath<RelationsOf<Opts>>[]\n}\n\n/**\n * Creates a type-safe TanStack DB collection backed by PocketBase.\n * Use this when you need fine-grained control or need to create collections with dependencies.\n *\n * @param pb - PocketBase client instance\n * @param queryClient - TanStack Query client\n * @returns A curried function that takes collection name and options\n *\n * @example\n * Basic usage:\n * ```ts\n * const booksCollection = createCollection<Schema>(pb, queryClient)('books', {});\n *\n * // Use directly\n * const books = await booksCollection.getFullList();\n * ```\n *\n * @example\n * With relations fetched on every request:\n * ```ts\n * const authorsCollection = createCollection<Schema>(pb, queryClient)('authors', {});\n * const booksCollection = createCollection<Schema>(pb, queryClient)('books', {\n * relations: { author: authorsCollection },\n * alwaysFetchRelations: ['author'],\n * });\n *\n * const { data } = useLiveQuery((q) => q.from({ books: booksCollection }));\n * // The expanded author is filed into authorsCollection, not kept on the row.\n * authorsCollection.get(data[0].author)?.name\n * ```\n *\n * @example\n * With a per-query fetchRelations view:\n * ```ts\n * const booksCollection = createCollection<Schema>(pb, queryClient)('books', {\n * relations: { author: authorsCollection },\n * });\n *\n * const view = booksCollection.fetchRelations('author');\n * const { data } = useLiveQuery((q) => q.from({ books: view }));\n * // Same target collection as above; the view only affects what gets fetched.\n * authorsCollection.get(data[0].author)?.name\n * ```\n */\nexport function createCollection<Schema extends SchemaDeclaration>(\n pb: PocketBase,\n queryClient: QueryClient,\n factoryOptions?: CreateCollectionFactoryOptions\n) {\n return <C extends keyof Schema & string, const Opts extends CreateCollectionOptions<Schema, C>>(\n collectionName: C,\n options?: Opts & AlwaysFetchRelationsCheck<Opts>\n ): PbCollection<Schema, C, Opts> => {\n return buildCollection<Schema, C>({\n pb,\n queryClient,\n factoryOptions,\n collectionName,\n options,\n }) as unknown as PbCollection<Schema, C, Opts>\n }\n}\n","/**\n * Generates a new PocketBase-compatible record ID.\n * Returns a 15-character alphanumeric string (lowercase letters and numbers).\n *\n * PocketBase uses 15-character IDs for records, formatted as lowercase alphanumeric.\n *\n * @returns A 15-character alphanumeric string suitable for use as a PocketBase record ID\n *\n * @example\n * ```ts\n * const id = newRecordId(); // \"a1b2c3d4e5f6g7h\"\n * ```\n */\nexport function newRecordId(): string {\n const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'\n let result = ''\n for (let i = 0; i < 15; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length))\n }\n return result\n}\n"]}
package/dist/core.d.ts CHANGED
@@ -410,6 +410,10 @@ type PbCollectionView<Schema extends SchemaDeclaration, C extends keyof Schema &
410
410
  readonly relationTargets: Record<string, unknown> | undefined;
411
411
  /** @internal number of relation targets currently held live */
412
412
  readonly heldRelationTargetCount: () => number;
413
+ /** @internal record that every row with `field === value` is now in this collection's store */
414
+ readonly markSubsetLoaded: (field: string, value: string) => void;
415
+ /** @internal number of field/value pairs currently marked loaded */
416
+ readonly loadedSubsetCount: () => number;
413
417
  /** @internal phantom; never present at runtime */
414
418
  readonly __pbtsdb: PbMeta<Schema, C, RelationsOf<Opts>>;
415
419
  };
package/dist/core.js CHANGED
@@ -1,3 +1,3 @@
1
- export { BTreeIndex, BasicIndex, ReverseIndex, createCollection, createEffect, materialize, newRecordId, resetLogger, setLogger, toArray } from './chunk-YWTU6QXM.js';
1
+ export { BTreeIndex, BasicIndex, ReverseIndex, createCollection, createEffect, materialize, newRecordId, resetLogger, setLogger, toArray } from './chunk-I6UWXRAH.js';
2
2
  //# sourceMappingURL=core.js.map
3
3
  //# sourceMappingURL=core.js.map
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { BTreeIndex, BasicIndex, ReverseIndex, createCollection, createEffect, materialize, newRecordId, resetLogger, setLogger, toArray } from './chunk-YWTU6QXM.js';
1
+ export { BTreeIndex, BasicIndex, ReverseIndex, createCollection, createEffect, materialize, newRecordId, resetLogger, setLogger, toArray } from './chunk-I6UWXRAH.js';
2
2
  import { createContext, useContext } from 'react';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pbtsdb",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Type-safe PocketBase integration with TanStack Query and TanStack DB",
5
5
  "keywords": [
6
6
  "pocketbase",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/expand-paths.ts","../src/keyed-where.ts","../src/logger.ts","../src/pocketbase-query-converter.ts","../src/build-collection.ts","../src/collection.ts","../src/util.ts"],"names":["createTanStackCollection"],"mappings":"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","file":"chunk-YWTU6QXM.js","sourcesContent":["import type { ExpandTargetCollection } from './types'\n\nexport type RelationTargets = Record<string, ExpandTargetCollection>\n\nexport function normalizePaths(paths: Iterable<string>): string[] {\n const set = new Set<string>()\n for (const path of paths) {\n const trimmed = path.trim()\n if (trimmed) set.add(trimmed)\n }\n return [...set].sort()\n}\n\nexport function splitPaths(csv: string | undefined): string[] {\n return csv ? normalizePaths(csv.split(',')) : []\n}\n\nexport function joinPaths(paths: Iterable<string>): string | undefined {\n const normalized = normalizePaths(paths)\n return normalized.length > 0 ? normalized.join(',') : undefined\n}\n\nexport function validateExpandPath(\n collectionName: string,\n targets: RelationTargets | undefined,\n path: string\n): void {\n if (!targets) {\n throw new Error(\n `Cannot expand \"${path}\" on collection \"${collectionName}\": no relations declared`\n )\n }\n let current: RelationTargets | undefined = targets\n for (const segment of path.split('.')) {\n const next: ExpandTargetCollection | undefined = current?.[segment]\n if (!next) {\n throw new Error(\n `Cannot expand \"${path}\" on collection \"${collectionName}\": segment \"${segment}\" is not a declared relation`\n )\n }\n current = next.relationTargets\n }\n}\n","import type { IR } from '@tanstack/db'\n\ntype Node = { type: string; name?: string; args?: Node[]; path?: string[]; value?: unknown }\n\nfunction isIdRef(node: Node | undefined): boolean {\n return node?.type === 'ref' && node.path?.length === 1 && node.path[0] === 'id'\n}\n\nfunction stringValue(node: Node | undefined): string | undefined {\n return node?.type === 'val' && typeof node.value === 'string' ? node.value : undefined\n}\n\nfunction collectEq(a: Node | undefined, b: Node | undefined): string[] | undefined {\n const other = isIdRef(a) ? b : isIdRef(b) ? a : undefined\n if (!other) return undefined\n const value = stringValue(other)\n return value === undefined ? undefined : [value]\n}\n\nfunction collectIn(a: Node | undefined, b: Node | undefined): string[] | undefined {\n if (!isIdRef(a) || b?.type !== 'val' || !Array.isArray(b.value)) return undefined\n return b.value.every(v => typeof v === 'string') ? (b.value as string[]) : undefined\n}\n\nfunction collectOr(args: Node[]): string[] | undefined {\n const ids: string[] = []\n for (const arg of args) {\n const sub = collect(arg)\n if (!sub) return undefined\n ids.push(...sub)\n }\n return ids\n}\n\nfunction collect(node: Node): string[] | undefined {\n if (node.type !== 'func' || !node.args) return undefined\n const [a, b] = node.args\n switch (node.name) {\n case 'eq':\n return collectEq(a, b)\n case 'in':\n return collectIn(a, b)\n case 'or':\n return collectOr(node.args)\n default:\n return undefined\n }\n}\n\n/**\n * The ids a `where` selects when it is nothing but `id` equalities: `eq(id, x)`,\n * `in(id, [...])`, or an `or` of those. Anything else returns `undefined`.\n */\nexport function idsFromWhere(\n where: IR.BasicExpression<boolean> | undefined | null\n): string[] | undefined {\n if (!where) return undefined\n const ids = collect(where as unknown as Node)\n return ids ? [...new Set(ids)].sort() : undefined\n}\n","/**\n * Logger interface for subscription events and internal operations.\n * Users can provide their own implementation to integrate with external logging services.\n */\nexport interface Logger {\n /**\n * Log debug-level messages (typically only shown in development).\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n debug: (msg: string, context?: object) => void\n\n /**\n * Log info-level messages.\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n info: (msg: string, context?: object) => void\n\n /**\n * Log warning-level messages.\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n warn: (msg: string, context?: object) => void\n\n /**\n * Log error-level messages.\n * @param msg - The message to log\n * @param context - Optional context object with additional information\n */\n error: (msg: string, context?: object) => void\n}\n\n/**\n * Default console-based logger implementation.\n * Only logs debug messages in development mode.\n */\nconst defaultLogger: Logger = {\n debug: (msg: string, context?: object) => {\n if (process.env.NODE_ENV === 'development') {\n console.debug(`[pbtsdb] ${msg}`, context || '')\n }\n },\n info: (msg: string, context?: object) => {\n console.info(`[pbtsdb] ${msg}`, context || '')\n },\n warn: (msg: string, context?: object) => {\n console.warn(`[pbtsdb] ${msg}`, context || '')\n },\n error: (msg: string, context?: object) => {\n console.error(`[pbtsdb] ${msg}`, context || '')\n },\n}\n\n/**\n * Current logger instance (can be replaced by users).\n */\nlet currentLogger: Logger = defaultLogger\n\n/**\n * Internal logger instance used by the library.\n */\nexport const logger: Logger = {\n debug: (msg: string, context?: object) => currentLogger.debug(msg, context),\n info: (msg: string, context?: object) => currentLogger.info(msg, context),\n warn: (msg: string, context?: object) => currentLogger.warn(msg, context),\n error: (msg: string, context?: object) => currentLogger.error(msg, context),\n}\n\n/**\n * Set a custom logger implementation.\n * This allows users to integrate with their own logging services (e.g., Sentry, LogRocket, etc.).\n *\n * @param customLogger - The custom logger implementation\n *\n * @example\n * ```ts\n * import { setLogger } from 'pbtsdb';\n *\n * // Integration with a custom logging service\n * setLogger({\n * debug: (msg, context) => myLogger.debug(msg, context),\n * warn: (msg, context) => myLogger.warn(msg, context),\n * error: (msg, context) => {\n * myLogger.error(msg, context);\n * Sentry.captureMessage(msg, { level: 'error', extra: context });\n * },\n * });\n * ```\n *\n * @example\n * ```ts\n * // Disable all logging\n * setLogger({\n * debug: () => {},\n * warn: () => {},\n * error: () => {},\n * });\n * ```\n */\nexport function setLogger(customLogger: Logger): void {\n currentLogger = customLogger\n}\n\n/**\n * Reset the logger to the default implementation.\n */\nexport function resetLogger(): void {\n currentLogger = defaultLogger\n}\n","import type { IR } from '@tanstack/db'\nimport {\n type FieldPath,\n type ParsedOrderBy,\n parseOrderByExpression,\n parseWhereExpression,\n} from '@tanstack/db'\n\ntype BasicExpression<T = unknown> = IR.BasicExpression<T>\n\nfunction escapeValue(value: unknown): string {\n if (value === null) {\n return 'null'\n }\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false'\n }\n if (typeof value === 'number') {\n return value.toString()\n }\n if (typeof value === 'string') {\n return `\"${value.replace(/\"/g, '\\\\\"')}\"`\n }\n if (value instanceof Date) {\n return `\"${value.toISOString()}\"`\n }\n if (Array.isArray(value)) {\n return `[${value.map(escapeValue).join(',')}]`\n }\n return `\"${String(value)}\"`\n}\n\nfunction fieldPathToString(path: FieldPath): string {\n return path.join('.')\n}\n\nexport function convertToPocketBaseFilter(\n where: BasicExpression<boolean> | undefined | null\n): string | undefined {\n if (!where) {\n return undefined\n }\n\n const result = parseWhereExpression(where, {\n handlers: {\n eq: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} = ${escapeValue(value)}`\n },\n gt: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} > ${escapeValue(value)}`\n },\n gte: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} >= ${escapeValue(value)}`\n },\n lt: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} < ${escapeValue(value)}`\n },\n lte: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} <= ${escapeValue(value)}`\n },\n and: (...conditions: string[]) => {\n if (conditions.length === 0) return ''\n if (conditions.length === 1) return conditions[0]\n return `(${conditions.join(' && ')})`\n },\n or: (...conditions: string[]) => {\n if (conditions.length === 0) return ''\n if (conditions.length === 1) return conditions[0]\n return `(${conditions.join(' || ')})`\n },\n not: (condition: string) => {\n return `!(${condition})`\n },\n in: (field: FieldPath, values: unknown) => {\n const valueArray = Array.isArray(values) ? values : [values]\n const uniqueValues = [...new Set(valueArray)]\n const fieldStr = fieldPathToString(field)\n const conditions = uniqueValues.map(v => `${fieldStr} = ${escapeValue(v)}`)\n return conditions.length > 1 ? `(${conditions.join(' || ')})` : conditions[0]\n },\n like: (field: FieldPath, value: unknown) => {\n return `${fieldPathToString(field)} ~ ${escapeValue(value)}`\n },\n isNull: (field: FieldPath) => {\n return `${fieldPathToString(field)} = null`\n },\n isUndefined: (field: FieldPath) => {\n return `${fieldPathToString(field)} = null`\n },\n },\n onUnknownOperator: (operator: string, _args: unknown[]) => {\n throw new Error(\n `Unsupported operator '${operator}' for PocketBase filter conversion. ` +\n `Supported operators: eq, gt, gte, lt, lte, in, like, and, or, not, isNull, isUndefined`\n )\n },\n })\n\n return result || undefined\n}\n\nexport function convertToPocketBaseSort(\n orderBy: IR.OrderBy | undefined | null\n): string | undefined {\n if (!orderBy) {\n return undefined\n }\n\n const sorts = parseOrderByExpression(orderBy)\n\n if (sorts.length === 0) {\n return undefined\n }\n\n return sorts\n .map((sort: ParsedOrderBy) => {\n const field = fieldPathToString(sort.field)\n return sort.direction === 'desc' ? `-${field}` : field\n })\n .join(',')\n}\n","import {\n BTreeIndex,\n type Collection,\n createCollection as createTanStackCollection,\n type LoadSubsetOptions,\n} from '@tanstack/db'\nimport {\n DeleteOperationItemNotFoundError,\n type QueryCollectionUtils,\n queryCollectionOptions,\n} from '@tanstack/query-db-collection'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type PocketBase from 'pocketbase'\nimport type { RecordSubscribeOptions, RecordSubscription } from 'pocketbase'\nimport type { RelationTargets } from './expand-paths'\nimport { joinPaths, normalizePaths, splitPaths, validateExpandPath } from './expand-paths'\nimport { idsFromWhere } from './keyed-where'\nimport { logger } from './logger'\nimport { convertToPocketBaseFilter, convertToPocketBaseSort } from './pocketbase-query-converter'\nimport type {\n CreateCollectionOptions,\n ExpandTargetCollection,\n ExtractRecordType,\n SchemaDeclaration,\n} from './types'\n\n// Subscriptions created through a view, mapped to the view's expand paths. Keyed\n// by the subscription object TanStack hands back to loadSubset/unloadSubset.\nconst viewPaths = new WeakMap<object, string[]>()\n\n/**\n * Options applied to every collection built by a {@link createCollection} factory.\n */\nexport interface CreateCollectionFactoryOptions {\n /**\n * Extra options passed to every real-time subscription this factory creates,\n * such as `headers`, `filter`, `expand` or `fields`.\n *\n * Invoked at subscribe time rather than read once, because a subscription is\n * re-established on reconnect and whenever the subscriber count rises from\n * zero — a value captured at build time would go stale exactly then.\n *\n * Returning `undefined` subscribes with no extra options.\n */\n subscribeOptions?: () => RecordSubscribeOptions | undefined\n}\n\n/**\n * Subscription helpers added to collection instances.\n * @internal\n */\nexport interface CollectionSubscriptionHelpers {\n /** The PocketBase collection name */\n collectionName: string\n /** Wait for subscription to be established (useful in tests) */\n waitForSubscription: (timeout?: number) => Promise<void>\n /** Check if collection has an active subscription */\n isSubscribed: () => boolean\n /** Relation targets declared through `relations` */\n relationTargets: RelationTargets | undefined\n /** Number of relation targets currently held live */\n heldRelationTargetCount: () => number\n}\n\n/**\n * Runtime shape of a built collection, before the public factory narrows it.\n * @internal\n */\nexport type BuiltCollection<T extends object> = Collection<\n T,\n string | number,\n QueryCollectionUtils<T, string | number, T>,\n never,\n T\n> &\n CollectionSubscriptionHelpers\n\n/** @internal */\nexport interface BuildCollectionInput<\n Schema extends SchemaDeclaration,\n C extends keyof Schema & string,\n> {\n pb: PocketBase\n queryClient: QueryClient\n factoryOptions: CreateCollectionFactoryOptions | undefined\n collectionName: C\n options: CreateCollectionOptions<Schema, C> | undefined\n}\n\n/** @internal */\nexport function buildCollection<Schema extends SchemaDeclaration, C extends keyof Schema & string>(\n input: BuildCollectionInput<Schema, C>\n): BuiltCollection<ExtractRecordType<Schema, C>> {\n const { pb, queryClient, factoryOptions, collectionName, options } = input\n type RecordType = ExtractRecordType<Schema, C>\n\n const relationTargets = options?.relations as RelationTargets | undefined\n const alwaysFetch = normalizePaths(options?.alwaysFetchRelations ?? [])\n for (const path of alwaysFetch) validateExpandPath(collectionName, relationTargets, path)\n const syncMode = options?.syncMode ?? 'eager'\n\n // Paths requested by views that have subscribed at least once. Eager fetches\n // read it because they cannot receive per-subset options; the realtime\n // subscription reads it so echoes carry every relation in use.\n const requestedExpand = new Set<string>()\n\n type LoadOptions = LoadSubsetOptions & { expand?: readonly string[] }\n type PbRequest = {\n filter?: string\n sort?: string\n limit?: number\n expand?: string\n ids?: string[]\n }\n\n function toRequest(opts: LoadSubsetOptions | undefined): PbRequest {\n const request: PbRequest = {}\n const ids = idsFromWhere(opts?.where)\n const filter = ids ? undefined : convertToPocketBaseFilter(opts?.where)\n const sort = convertToPocketBaseSort(opts?.orderBy)\n const expand = joinPaths((opts as LoadOptions | undefined)?.expand ?? [])\n if (ids) request.ids = ids\n if (filter) request.filter = filter\n if (sort) request.sort = sort\n if (opts?.limit) request.limit = opts.limit\n if (expand) request.expand = expand\n return request\n }\n\n function queryKeyFor(opts?: LoadSubsetOptions): [C] | [C, PbRequest] {\n const request = toRequest(opts)\n return Object.keys(request).length === 0 ? [collectionName] : [collectionName, request]\n }\n\n function activeExpand(request: PbRequest): string | undefined {\n return joinPaths([\n ...alwaysFetch,\n ...splitPaths(request.expand),\n ...(syncMode === 'eager' ? requestedExpand : []),\n ])\n }\n\n // pbtsdb asked PocketBase for these relations only to file them into their\n // target collections; the copies never reach a row in any cache.\n function stripFetchedRelations(\n items: RecordType[],\n expandString: string | undefined\n ): RecordType[] {\n const heads = new Set(splitPaths(expandString).map(path => path.split('.')[0]))\n if (heads.size === 0) return items\n return items.map(item => {\n const { expand, ...plain } = item as RecordType & {\n expand?: Record<string, unknown>\n }\n if (!expand) return item\n const kept = Object.fromEntries(\n Object.entries(expand).filter(([key]) => !heads.has(key))\n )\n return (Object.keys(kept).length > 0 ? { ...plain, expand: kept } : plain) as RecordType\n })\n }\n\n const ignoreAutoCancellation = options?.ignoreAutoCancellation ?? true\n const refetchOnMutation = options?.refetchOnMutation ?? false\n\n function eagerSyncInFlight(target: ExpandTargetCollection): boolean {\n return (\n target.status !== undefined &&\n target.status !== 'idle' &&\n target.status !== 'cleaned-up'\n )\n }\n\n // A filed copy never carries `expand`: any part of it with a declared\n // target was filed by the recursive upsertExpanded call right after\n // upsertInto, and any part without one has nowhere to go and is dropped.\n function withoutExpand(values: object[]): object[] {\n return values.map(value => {\n const { expand: _expand, ...plain } = value as { expand?: unknown }\n return plain\n })\n }\n\n async function upsertInto(\n key: string,\n target: ExpandTargetCollection,\n values: object[]\n ): Promise<void> {\n if (!target.utils) return\n if (!target.isReady()) {\n if (target.config?.syncMode === 'on-demand') {\n await target._sync.startSync()\n } else if (target.preload && eagerSyncInFlight(target)) {\n // An eager target whose full load is already running (a held\n // subscription started it) becomes ready shortly; wait rather\n // than drop the records or race the load.\n await target.preload()\n } else {\n logger.warn(\n `not syncing ${key} on ${collectionName} because store is not yet ready`\n )\n return\n }\n }\n target.utils.writeUpsert(withoutExpand(values))\n }\n\n async function upsertExpandedField(\n key: string,\n value: object | object[],\n targets: RelationTargets\n ): Promise<void> {\n const target = targets[key]\n if (!target) {\n logger.debug('No relation target for expanded field', { collectionName, key })\n return\n }\n const values = Array.isArray(value) ? value : [value]\n await upsertInto(key, target, values)\n await upsertExpanded(values, target.relationTargets)\n }\n\n async function upsertExpanded(\n records: object[],\n targets: RelationTargets | undefined\n ): Promise<void> {\n if (!targets) return\n for (const record of records) {\n const expandData = (record as { expand?: Record<string, object | object[]> }).expand\n if (!expandData) continue\n for (const [key, value] of Object.entries(expandData)) {\n await upsertExpandedField(key, value, targets)\n }\n }\n }\n\n function idFilter(ids: readonly string[]): string {\n return ids.map(id => `id = \"${id.replace(/\"/g, '\\\\\"')}\"`).join(' || ')\n }\n\n // Rows already in the synced store are as fresh as realtime keeps them;\n // an id-only request whose ids are all present needs no round trip.\n function rowsFromStore(ids: readonly string[]): RecordType[] | undefined {\n const rows: RecordType[] = []\n for (const id of ids) {\n const row = collection._state.syncedData.get(id) as RecordType | undefined\n if (!row) return undefined\n rows.push(row)\n }\n return rows\n }\n\n // A row already in the store was fetched (and filed) with this collection's own\n // alwaysFetchRelations, so that part of `expand` is already reflected. Only\n // `request.expand` — the extra paths a fetchRelations() view adds — may not have\n // been filed for this row yet, so only that forces a real fetch. An empty `ids`\n // (e.g. `in(id, [])`) selects nothing and must never fall through to a request,\n // which an empty id filter would turn into \"fetch everything\".\n function servedFromStore(request: PbRequest): RecordType[] | undefined {\n const { ids, sort, limit } = request\n if (!ids) return undefined\n if (ids.length === 0) return []\n if (request.expand) return undefined\n // A sorted + limited request must be sliced in that order; the store\n // holds rows in id order, so slicing here could return the wrong subset.\n // TanStack passes neither for id-only loads today, so this only guards\n // against a future caller combining them.\n if (sort && limit) return undefined\n const present = rowsFromStore(ids)\n if (!present) return undefined\n return limit ? present.slice(0, limit) : present\n }\n\n async function fetchItems(request: PbRequest): Promise<RecordType[]> {\n const served = servedFromStore(request)\n if (served) return served\n const { sort, limit, ids } = request\n const filter = ids ? idFilter(ids) : request.filter\n const expand = activeExpand(request)\n\n if (limit) {\n // Use getList when limit is specified to avoid fetching all records\n const result = await pb.collection(collectionName).getList(1, limit, {\n filter,\n sort,\n skipTotal: true, // Optimize by skipping total count\n expand,\n })\n return result.items as unknown as RecordType[]\n }\n // Use getFullList to fetch all records with automatic pagination\n return (await pb.collection(collectionName).getFullList({\n filter,\n sort,\n expand,\n })) as unknown as RecordType[]\n }\n\n // Each in-flight fetch registers a set here before its request goes out;\n // authoritative local writes (mutation write-backs and realtime echoes)\n // add the confirmed record ids to every registered set. An id added\n // after a fetch was issued is newer than that fetch's view of the\n // server, so the result cannot speak to the id's absence. The merge\n // deliberately ignores the fetch's filter: the manual-write cache push\n // grants every active query ownership of every synced row, so even a\n // row outside this subset's filter must be shielded from its reconcile.\n //\n // Why this exists: @tanstack/query-db-collection's applySuccessfulResult\n // reconcile-DELETES every row a query owns that its result omits, and the\n // synced-write guard below deliberately exempts deletes. A subset read\n // issued before a row existed can therefore resolve late and delete the\n // just-confirmed row (rows a query owns include rows pushed into its\n // cache by the manual-write path that runs on every write-back). The fix\n // is applied to the RESULT rather than the delete: fetchRecords merges\n // such rows back in, which both prevents the delete and keeps the row\n // owned by the query — a dropped delete alone would still strip\n // ownership and leave the row to a later GC pass.\n const inFlightConfirmedIds = new Set<Set<string>>()\n\n function markConfirmedPresent(records: RecordType[]): void {\n if (inFlightConfirmedIds.size === 0) return\n for (const record of records) {\n const id = (record as { id?: unknown } | null | undefined)?.id\n if (typeof id !== 'string') continue\n for (const confirmed of inFlightConfirmedIds) confirmed.add(id)\n }\n }\n\n function withRowsConfirmedMidFlight(\n items: RecordType[],\n confirmedMidFlight: Set<string>\n ): RecordType[] {\n if (confirmedMidFlight.size === 0) return items\n const resultIds = new Set(\n items.map(item => (item as { id?: unknown } | null | undefined)?.id)\n )\n // Ids absent from the synced store (deleted mid-flight, or never\n // landed) have nothing to protect and drop out of the merge.\n const mergedIds = [...confirmedMidFlight].filter(\n id => !resultIds.has(id) && collection._state.syncedData.has(id)\n )\n if (mergedIds.length === 0) return items\n logger.debug('Merging rows confirmed while fetch was in flight', {\n collectionName,\n ids: mergedIds,\n })\n return [\n ...items,\n ...mergedIds.map(id => collection._state.syncedData.get(id) as RecordType),\n ]\n }\n\n async function fetchRecords(\n request: PbRequest,\n queryKey: readonly unknown[]\n ): Promise<RecordType[]> {\n const confirmedMidFlight = new Set<string>()\n inFlightConfirmedIds.add(confirmedMidFlight)\n try {\n let items: RecordType[]\n try {\n items = await fetchItems(request)\n } catch (error) {\n if (\n ignoreAutoCancellation &&\n error instanceof Error &&\n error.message.includes('autocancelled')\n ) {\n // PocketBase auto-cancelled this in-flight read because a newer\n // request superseded it. Resolve to THIS subset's own cached rows\n // (keyed by the full query key) so the reconcile is a no-op for the\n // subset. The base key ([collectionName]) holds the full-collection\n // snapshot — returning that here would let applySuccessfulResult\n // reconcile foreign rows into a filtered subset (re-introducing rows\n // the subset's filter excludes). Re-throwing instead would error the\n // subset and empty/retry it.\n return withRowsConfirmedMidFlight(\n queryClient.getQueryData<RecordType[]>(queryKey) ?? [],\n confirmedMidFlight\n )\n }\n throw error\n }\n\n await upsertExpanded(items, relationTargets)\n return withRowsConfirmedMidFlight(\n stripFetchedRelations(items, activeExpand(request)),\n confirmedMidFlight\n )\n } finally {\n inFlightConfirmedIds.delete(confirmedMidFlight)\n }\n }\n\n // TanStack DB 0.6 turned auto-indexing off by default; without an index an\n // orderBy+limit query loads the whole subset instead of paging lazily and\n // warns on every compile. Restore the earlier default; callers can override\n // both settings through collectionOptions.\n const queryCollectionConfig = queryCollectionOptions({\n autoIndex: 'eager',\n defaultIndexType: BTreeIndex,\n ...options?.collectionOptions,\n queryClient,\n queryKey: queryKeyFor,\n syncMode,\n queryFn: async (ctx): Promise<RecordType[]> => {\n const request = (ctx.queryKey[1] as PbRequest | undefined) ?? {}\n return fetchRecords(request, ctx.queryKey)\n },\n getKey: (item: RecordType) => {\n const record = item as unknown as Record<string, unknown>\n if (!record || typeof record !== 'object' || !('id' in record)) {\n throw new Error(\n `Record in collection '${collectionName}' is missing required 'id' field. Received: ${JSON.stringify(item)}`\n )\n }\n return record.id as string\n },\n onInsert:\n options?.onInsert === false\n ? undefined\n : (options?.onInsert ??\n (async ({ transaction }) => {\n const created = await Promise.all(\n transaction.mutations.map(async mutation => {\n const {\n created: _created,\n updated: _updated,\n collectionId: _collectionId,\n collectionName: _collectionName,\n ...data\n } = mutation.modified as unknown as Record<string, unknown>\n return pb.collection(collectionName).create(data)\n })\n )\n writeBackAfterPersisted(transaction, created)\n return { refetch: refetchOnMutation }\n })),\n onUpdate:\n options?.onUpdate === false\n ? undefined\n : (options?.onUpdate ??\n (async ({ transaction }) => {\n const updated = await Promise.all(\n transaction.mutations.map(async mutation => {\n const recordWithId = mutation.original as { id: string }\n return pb\n .collection(collectionName)\n .update(recordWithId.id, mutation.changes)\n })\n )\n writeBackAfterPersisted(transaction, updated)\n return { refetch: refetchOnMutation }\n })),\n onDelete:\n options?.onDelete === false\n ? undefined\n : (options?.onDelete ??\n (async ({ transaction }) => {\n await Promise.all(\n transaction.mutations.map(async mutation => {\n const recordWithId = mutation.original as { id: string }\n await pb.collection(collectionName).delete(recordWithId.id)\n })\n )\n return { refetch: refetchOnMutation }\n })),\n })\n\n // queryCollectionOptions consumes `gcTime` for the underlying react-query\n // observer and never forwards it to the collection options it returns, so\n // the DB collection's own lifecycle GC (what controls when an idle\n // collection reaches 'cleaned-up') would silently fall back to its\n // 5-minute default. Re-apply it explicitly so a caller-supplied value\n // reaches both layers.\n const collectionOptions =\n options?.collectionOptions?.gcTime === undefined\n ? queryCollectionConfig\n : { ...queryCollectionConfig, gcTime: options.collectionOptions.gcTime }\n\n // Write the server's copy of a mutation's rows back AFTER the transaction\n // has persisted — never from inside its handler.\n //\n // TanStack DB keeps a completed transaction's optimistic draft visible\n // until a synced write for the key arrives, so a record the server\n // fills in (a number, a timestamp) reaches the screen only through that\n // later synced write. A write-back issued from inside the handler lands\n // while the transaction is still `persisting`; TanStack applies it,\n // then on completion re-adds the draft as a \"confirmed but unsynced\"\n // overlay and waits for a synced write that already happened. If the\n // realtime echo has ALSO already been consumed (it arrives before the\n // create resolves under load, and an echo carrying the same `updated`\n // as the write-back is dropped as stale), nothing ever clears the\n // overlay: the row shows the draft — minus every server-assigned field\n // — until a reload. Deferring the write-back to after persistence makes\n // it the synced write TanStack is waiting for.\n //\n // `markConfirmedPresent` still runs immediately: the in-flight fetch\n // bookkeeping needs to know the rows are confirmed the moment the\n // server said so, not a tick later.\n //\n // The deferred write itself: a no-op until the collection is ready\n // (writing into the synced store before sync has initialized throws,\n // and with no live query there is nothing to keep in sync — the next\n // query fetches the already-persisted state; the transaction can\n // outlive the last subscriber), and it drops any row the store already\n // supersedes — a realtime echo may have landed a newer copy while the\n // transaction was settling, and writing the response over it would\n // revert the row.\n function writeBackAfterPersisted(\n transaction: { isPersisted: { promise: Promise<unknown> } },\n records: RecordType[]\n ): void {\n markConfirmedPresent(records)\n void transaction.isPersisted.promise.then(\n () => {\n if (!collection.utils || !collection.isReady()) return\n const fresh = records.filter(record => !isStaleServerRecord(record))\n if (fresh.length === 0) return\n writeOwn(() => collection.utils.writeUpsert(fresh))\n },\n // A rejected transaction rolled its draft back; there is\n // nothing to write and nothing to report here.\n () => undefined\n )\n }\n\n // Set while pbtsdb performs its own authoritative writes (mutation-response\n // write-backs and realtime echoes) through collection.utils.*. Those writes\n // share the same sync `write` primitive as the query-result reconcile path\n // (see the sync.sync wrapper below), so the guard uses this flag to tell them\n // apart: pbtsdb's own writes are exempt from the optimistic-pending arm of the\n // guard (the mutation-response write-back intentionally lands the confirmed\n // value while that very mutation's optimistic overlay is still in flight).\n let applyingOwnWrite = false\n function writeOwn(fn: () => void): void {\n applyingOwnWrite = true\n try {\n fn()\n } finally {\n applyingOwnWrite = false\n }\n }\n\n // The record id a synced insert/update targets, or null when the op is a delete\n // (terminal — never guarded) or carries no usable key.\n function syncedWriteKey(op: { type: string; value?: unknown; key?: unknown }): string | null {\n if (op.type !== 'insert' && op.type !== 'update') return null\n if (typeof op.key === 'string') return op.key\n const id = (op.value as { id?: unknown } | undefined)?.id\n return typeof id === 'string' ? id : null\n }\n\n // Guard the synced write path that pbtsdb does not otherwise control:\n // @tanstack/query-db-collection's applySuccessfulResult reconciles every query\n // result into the synced store via this same `write`, with no recency or\n // optimistic check. Under on-demand contention a single-row/subset read can\n // resolve with a pre-mutation row and land here after the row already moved on,\n // reverting it. We drop such a synced insert/update when either it targets a key\n // with a pending optimistic mutation (see the arm below) or it is strictly older\n // than the synced row (an out-of-order read). pbtsdb's own writes\n // (applyingOwnWrite) skip the optimistic arm; they are staleness-filtered\n // upstream by writeBackAfterPersisted/isStaleEcho.\n function shouldDropSyncedWrite(op: { type: string; value?: unknown; key?: unknown }): boolean {\n const key = syncedWriteKey(op)\n if (key === null) return false\n // Optimistic arm: only guard a key already present in the synced store. A\n // write to a key the synced store doesn't yet hold is populating it (e.g. the\n // initial fetch landing a row the user just optimistically inserted) and must\n // pass — dropping it would leave the row absent once the overlay clears. A\n // write to a key already synced, while an optimistic mutation is pending, is a\n // racing read that would revert the in-flight value, so drop it.\n if (\n !applyingOwnWrite &&\n hasPendingOptimisticMutation(key) &&\n collection._state.syncedData.has(key)\n ) {\n logger.debug('Dropping synced write for optimistically-pending row', {\n collectionName,\n id: key,\n })\n return true\n }\n if (isStaleServerRecord(op.value)) {\n logger.debug('Dropping stale synced write', { collectionName, id: key })\n return true\n }\n return false\n }\n\n // A view's subscription is tagged in viewPaths (see createView below); this\n // adds the view's expand paths to load options for a tagged subscription so\n // loadSubset/unloadSubset fetch (and later untrack) with the right `expand`.\n // A subscription's initial snapshot loads synchronously inside\n // collection.subscribeChanges, before that call returns the subscription\n // object a view tags in viewPaths — so that first loadSubset cannot yet be\n // looked up by identity. While a view's subscribeChanges call is on the\n // stack, its paths are used for load options with no tagged subscription;\n // every later call (untracked demand growth, unloadSubset) is tagged by then.\n let subscribingViewPaths: string[] | undefined\n\n function withViewExpand(opts: LoadSubsetOptions): LoadOptions {\n const paths =\n (opts.subscription && viewPaths.get(opts.subscription)) ?? subscribingViewPaths\n return paths ? { ...opts, expand: paths } : opts\n }\n\n // Wrap the sync factory so every synced `write` flows through the guard above,\n // and every loadSubset/unloadSubset call is tagged with a view's expand paths.\n // @tanstack/db invokes sync.sync with the write primitives; we hand back the\n // same params with a filtered `write`. begin/commit/markReady/etc. pass through.\n const innerSync = collectionOptions.sync.sync\n collectionOptions.sync = {\n ...collectionOptions.sync,\n sync: (params: Parameters<typeof innerSync>[0]) => {\n const guardedWrite: typeof params.write = message => {\n const op = message as { type: string; value?: unknown; key?: unknown }\n if (shouldDropSyncedWrite(op)) return\n return params.write(message)\n }\n const res = innerSync({ ...params, write: guardedWrite })\n if (!res || typeof res === 'function') return res\n const { loadSubset, unloadSubset } = res\n return {\n ...res,\n loadSubset: loadSubset\n ? (opts: LoadSubsetOptions) => loadSubset(withViewExpand(opts))\n : undefined,\n unloadSubset: unloadSubset\n ? (opts: LoadSubsetOptions) => unloadSubset(withViewExpand(opts))\n : undefined,\n }\n },\n }\n\n const collection = createTanStackCollection(collectionOptions)\n\n const views = new Map<string, object>()\n\n function createView(paths: string[]): object {\n const view = Object.create(collection)\n Object.defineProperties(view, {\n id: { value: `${collectionName}?expand=${paths.join(',')}` },\n subscribeChanges: {\n value: (...args: Parameters<typeof collection.subscribeChanges>) => {\n noteViewSubscribed(paths)\n subscribingViewPaths = paths\n try {\n const subscription = collection.subscribeChanges(...args)\n viewPaths.set(subscription, paths)\n return subscription\n } finally {\n subscribingViewPaths = undefined\n }\n },\n },\n fetchRelations: {\n value: () => {\n throw new Error(`A view of \"${collectionName}\" cannot fetch further relations`)\n },\n },\n })\n return view\n }\n\n function fetchRelations(...paths: string[]): object {\n for (const path of paths) validateExpandPath(collectionName, relationTargets, path)\n const all = normalizePaths([...alwaysFetch, ...paths])\n if (all.every(path => alwaysFetch.includes(path))) return collection\n const key = all.join(',')\n let view = views.get(key)\n if (!view) {\n view = createView(all)\n views.set(key, view)\n }\n return view\n }\n\n // True when the key has an in-flight (not yet settled) optimistic mutation.\n // While pending, the optimistic overlay — not syncedData — is the visible value,\n // so any synced write would only take effect once the overlay collapses, and an\n // older/racing read landing here is exactly what reverts a just-applied move.\n function hasPendingOptimisticMutation(key: string): boolean {\n const state = collection._state as unknown as {\n optimisticUpserts: { has: (k: string) => boolean }\n optimisticDeletes: { has: (k: string) => boolean }\n }\n return state.optimisticUpserts.has(key) || state.optimisticDeletes.has(key)\n }\n\n // Read the PocketBase `updated` autodate from a record, if present.\n // Collections without an `updated` field opt out of staleness checks.\n function recordUpdatedAt(record: unknown): string | undefined {\n const updated = (record as { updated?: unknown } | null | undefined)?.updated\n return typeof updated === 'string' && updated !== '' ? updated : undefined\n }\n\n // A server record is stale relative to the synced store when an entry for\n // the same key already holds a newer `updated` timestamp. PocketBase can\n // redeliver or reorder realtime echoes (and a slow mutation response can\n // resolve after a newer echo), so applying an older write would revert the\n // row. ISO 8601 timestamps sort lexicographically, so string comparison is\n // chronological. When either side lacks a comparable timestamp we cannot\n // tell, so we treat the write as fresh and let it through.\n //\n // Strictly older, never equal. PocketBase stamps `updated` to the\n // millisecond and bumps it on every write, so an equal timestamp is the\n // same version of the row: re-landing it changes nothing, and it is what\n // lets a confirmed value clear a lingering optimistic overlay. (An earlier\n // `<=` variant on the query-result path guarded against a read carrying\n // old content under a new timestamp, which a real server cannot produce;\n // the revert it chased was the write-back racing its own transaction,\n // fixed in writeBackAfterPersisted.)\n function isStaleServerRecord(record: unknown): boolean {\n const id = (record as { id?: unknown } | null | undefined)?.id\n if (typeof id !== 'string') return false\n const incoming = recordUpdatedAt(record)\n if (!incoming) return false\n const current = recordUpdatedAt(\n collection._state.syncedData.get(id) as RecordType | undefined\n )\n if (current === undefined) return false\n return incoming < current\n }\n\n // Decide whether a realtime echo should be dropped as stale. Under realtime\n // contention PocketBase can redeliver or reorder events, so an echo carrying\n // a pre-mutation value can arrive after the row already moved on (e.g. the\n // local mutation that just wrote the fresh value back). Applying a\n // strictly-older create/update echo would revert the row, so it is ignored.\n // Deletes are terminal and not timestamp-guarded.\n function isStaleEcho(event: RecordSubscription<RecordType>): boolean {\n if (event.action !== 'create' && event.action !== 'update') return false\n if (!isStaleServerRecord(event.record)) return false\n logger.debug('Ignoring stale realtime echo', {\n collectionName,\n id: (event.record as { id?: string } | undefined)?.id,\n })\n return true\n }\n\n // Real-time subscription state\n let unsubscribeFn: (() => Promise<void>) | null = null\n let isSubscribed = false\n let subscriptionPromise: Promise<void> | null = null\n let subscriptionResolve: (() => void) | null = null\n // The `expand` string sent with the currently live subscription, so a\n // caller that widened requestedExpand mid-flight can tell whether the\n // subscription that just landed already covers it.\n let subscribedExpand: string | undefined\n\n // All start/stop/restart work is serialized onto this promise tail so\n // overlapping callers (two views created back-to-back, a reconnect\n // racing a widened expand) never run startSubscription/stopSubscription\n // concurrently — the tail is what lets a later caller's restart observe\n // the outcome of an earlier caller's in-flight start. Errors are caught\n // and logged so a failed step never poisons the tail for later work.\n let subscriptionWork: Promise<void> = Promise.resolve()\n function enqueueSubscriptionWork(fn: () => Promise<void>): Promise<void> {\n const run = subscriptionWork.then(fn, fn).catch(error => {\n logger.error('Subscription work failed', { collectionName, error })\n })\n subscriptionWork = run\n return run\n }\n\n // Handle real-time events from PocketBase.\n //\n // The write primitives differ in how they treat a key that is absent from\n // the *synced* store (collection._state.syncedData, which is what they\n // validate against — not the optimistic view exposed by collection.has()):\n // - writeInsert / writeUpsert: idempotent, never throw on an absent key.\n // - writeDelete: throws DeleteOperationItemNotFoundError on an absent key.\n // So only the delete branch can throw, and we make it idempotent below.\n // Runs BEFORE the stale-echo filter: even a stale create/update echo\n // proves the server holds the row. Delete echoes need no marking — the\n // merge checks the synced store, which the delete's writeDelete empties.\n function markEchoPresence(event: RecordSubscription<RecordType>): void {\n if (event.action !== 'delete') markConfirmedPresent([event.record])\n }\n\n const handleRealtimeEvent = (event: RecordSubscription<RecordType>) => {\n if (!collection.utils) return\n markEchoPresence(event)\n if (isStaleEcho(event)) return\n\n const [stored] = stripFetchedRelations([event.record], pendingSubscribeExpand())\n try {\n writeOwn(() =>\n collection.utils.writeBatch(() => {\n switch (event.action) {\n case 'create':\n collection.utils.writeInsert(stored)\n break\n case 'update':\n collection.utils.writeUpsert(stored)\n break\n case 'delete':\n if (event.record && 'id' in event.record) {\n // Throws DeleteOperationItemNotFoundError if the key\n // is no longer in the synced store (see catch below).\n collection.utils.writeDelete((event.record as { id: string }).id)\n }\n break\n }\n })\n )\n } catch (error) {\n // How a delete echo throws: writeDelete fails when its key is already\n // gone from the synced store. That happens when something removed it\n // before the echo arrived:\n // 1. on-demand sync — each useLiveQuery refetches with a server\n // filter, and query-db-collection prunes rows no longer owned by\n // any active query out of the synced store. If that prune (or a\n // concurrent query's reconcile) runs before this client's own\n // delete echo lands, the key is already gone -> throw. This is\n // the on-demand-only race; eager collections have no such second\n // writer to the synced store, so they cannot hit it.\n // 2. a re-delivered SSE delete (e.g. after a reconnect) for a key\n // that was already deleted -> throw on the second echo.\n // In both cases the record is already in its intended end state\n // (gone), so the echo is a no-op and the error is safe to ignore.\n // Anything that is NOT a missing-key delete is a real error: rethrow.\n if (error instanceof DeleteOperationItemNotFoundError) {\n logger.debug('Ignoring delete echo for already-removed record', {\n collectionName,\n id: (event.record as { id?: string } | undefined)?.id,\n })\n } else {\n throw error\n }\n }\n\n if (event.action !== 'delete') {\n upsertExpanded([event.record], relationTargets).catch(error =>\n logger.error('Failed to upsert expanded records from realtime echo', {\n collectionName,\n error,\n })\n )\n }\n }\n\n // The union of expand paths the next (re)subscribe should carry:\n // alwaysFetch plus every path a view has requested. Pure and\n // side-effect-free (unlike realtimeSubscribeOptions below), so it is\n // safe to call more than once per subscribe attempt to detect drift.\n function pendingSubscribeExpand(): string | undefined {\n return joinPaths([...alwaysFetch, ...requestedExpand])\n }\n\n // Collections along every active expand path. Held live (below) so their\n // stores stay fresh for keyed reads (materialize, joins, get()) and for\n // the store-served short circuit.\n function activeExpandTargets(): Set<ExpandTargetCollection> {\n const targets = new Set<ExpandTargetCollection>()\n for (const path of splitPaths(pendingSubscribeExpand())) {\n let current: RelationTargets | undefined = relationTargets\n for (const segment of path.split('.')) {\n const target: ExpandTargetCollection | undefined = current?.[segment]\n if (!target) break\n targets.add(target)\n current = target.relationTargets\n }\n }\n return targets\n }\n\n // The only place held target subscriptions are added or removed, so the\n // map always mirrors the last desired set exactly.\n const heldTargetSubscriptions = new Map<ExpandTargetCollection, { unsubscribe: () => void }>()\n\n function releaseHeldTarget(target: ExpandTargetCollection): void {\n const held = heldTargetSubscriptions.get(target)\n if (!held) return\n heldTargetSubscriptions.delete(target)\n try {\n held.unsubscribe()\n } catch (error) {\n logger.error('Failed to release relation target subscription', {\n collectionName,\n error,\n })\n }\n }\n\n function holdTarget(target: ExpandTargetCollection): void {\n if (heldTargetSubscriptions.has(target) || !target.subscribeChanges) return\n try {\n const held = target.subscribeChanges(() => {}, { includeInitialState: false })\n heldTargetSubscriptions.set(target, held)\n } catch (error) {\n logger.error('Failed to hold relation target subscription', { collectionName, error })\n }\n }\n\n function syncHeldSubscriptions(desired: Set<ExpandTargetCollection>): void {\n for (const target of [...heldTargetSubscriptions.keys()]) {\n if (!desired.has(target)) releaseHeldTarget(target)\n }\n for (const target of desired) holdTarget(target)\n }\n\n // Options for the next (re)subscribe: the expand union above, merged\n // with whatever the factory's own subscribeOptions() supplies rather\n // than overridden by it. Calls the factory callback, so it is invoked\n // exactly once per subscribe attempt (never re-derived afterward).\n function realtimeSubscribeOptions(): RecordSubscribeOptions | undefined {\n const base = factoryOptions?.subscribeOptions?.()\n const expand = joinPaths([\n ...splitPaths(pendingSubscribeExpand()),\n ...splitPaths(base?.expand),\n ])\n return expand ? { ...base, expand } : base\n }\n\n // Start PocketBase real-time subscription. Only ever run through\n // enqueueSubscriptionWork so it never overlaps a stop/restart.\n const doStartSubscription = async () => {\n if (isSubscribed) return\n\n // Create promise before starting so waiters can await it\n if (!subscriptionPromise) {\n subscriptionPromise = new Promise<void>(resolve => {\n subscriptionResolve = resolve\n })\n }\n\n const pendingExpand = pendingSubscribeExpand()\n try {\n unsubscribeFn = await pb\n .collection(collectionName)\n .subscribe('*', handleRealtimeEvent, realtimeSubscribeOptions())\n isSubscribed = true\n subscribedExpand = pendingExpand\n syncHeldSubscriptions(activeExpandTargets())\n logger.debug('Subscription started', { collectionName })\n // Resolve the promise to notify waiters\n if (subscriptionResolve) {\n subscriptionResolve()\n }\n } catch (error) {\n logger.error('Failed to start subscription', { collectionName, error })\n }\n\n // requestedExpand can grow while the subscribe() call above was in\n // flight (a view mounted mid-round-trip sees no live subscription\n // yet, and would otherwise never schedule a restart). Comparing\n // against the pure expand union (not realtimeSubscribeOptions,\n // which would re-invoke the factory's own subscribeOptions()\n // callback) lets this check run after every start with no\n // observable side effect.\n if (pendingSubscribeExpand() !== subscribedExpand) {\n enqueueSubscriptionWork(doRestartSubscription).catch(() => {})\n }\n }\n\n // Stop PocketBase real-time subscription. Only ever run through\n // enqueueSubscriptionWork so it never overlaps a start/restart.\n const doStopSubscription = async (releaseTargets = true) => {\n // Before the guard below: a restart whose subscribe() threw leaves\n // isSubscribed false with targets still held, and this real stop is\n // the only remaining chance to release them.\n if (releaseTargets) syncHeldSubscriptions(new Set())\n if (!isSubscribed || !unsubscribeFn) return\n\n try {\n await unsubscribeFn()\n logger.debug('Subscription stopped', { collectionName })\n } catch (error) {\n logger.debug('Unsubscribe failed (expected if connection closed)', {\n collectionName,\n error,\n })\n } finally {\n // Unconditional: a throwing unsubscribe must not leave the state\n // machine believing it is still subscribed after targets were\n // released, or the next start would return early and never re-hold.\n unsubscribeFn = null\n isSubscribed = false\n subscribedExpand = undefined\n subscriptionPromise = null\n subscriptionResolve = null\n }\n }\n\n // Restart the live subscription, e.g. after the requested expand union\n // grows. A no-op when there is no live subscription to restart — the\n // next first-subscriber start already picks up the current union.\n const doRestartSubscription = async () => {\n if (!isSubscribed) return\n await doStopSubscription(false)\n await doStartSubscription()\n }\n\n const startSubscription = () => enqueueSubscriptionWork(doStartSubscription)\n const stopSubscription = () => enqueueSubscriptionWork(() => doStopSubscription())\n const restartSubscription = () => enqueueSubscriptionWork(doRestartSubscription)\n\n // Record which expand paths a view has subscribed with at least once.\n // Eager collections cannot request per-subset options, so a wider union\n // needs a refetch to pick up the new expand; a live realtime subscription\n // needs restarting so its own expand union grows too.\n function noteViewSubscribed(paths: string[]): void {\n let grew = false\n for (const path of paths) {\n if (requestedExpand.has(path)) continue\n requestedExpand.add(path)\n grew = true\n }\n if (!grew) return\n if (\n syncMode === 'eager' &&\n collection.status !== 'idle' &&\n collection.status !== 'cleaned-up'\n ) {\n void collection.utils.refetch().catch(error =>\n logger.error('Failed to refetch after widening expand', {\n collectionName,\n error,\n })\n )\n }\n // Enqueued unconditionally (not gated on isSubscribed): the tail\n // guarantees this runs after any in-flight start/stop, and\n // doRestartSubscription itself no-ops when nothing is live.\n restartSubscription().catch(error =>\n logger.error('Failed to restart subscription with wider expand', {\n collectionName,\n error,\n })\n )\n }\n\n // Wait for subscription to be established (for testing)\n const waitForSubscription = async (timeout = 5000): Promise<void> => {\n if (isSubscribed) return\n\n if (!subscriptionPromise) {\n // No subscription in progress, wait for one to start\n await new Promise<void>(resolve => {\n const checkInterval = setInterval(() => {\n if (subscriptionPromise) {\n clearInterval(checkInterval)\n resolve()\n }\n }, 10)\n setTimeout(() => {\n clearInterval(checkInterval)\n resolve()\n }, timeout)\n })\n }\n\n if (subscriptionPromise) {\n await Promise.race([\n subscriptionPromise,\n new Promise<void>((_, reject) =>\n setTimeout(() => reject(new Error('Subscription timeout')), timeout)\n ),\n ])\n }\n }\n\n // Manage subscription based on collection subscriber count\n collection.on(\n 'subscribers:change',\n (event: { subscriberCount: number; previousSubscriberCount: number }) => {\n const newCount = event.subscriberCount\n const previousCount = event.previousSubscriberCount\n\n if (newCount > 0 && previousCount === 0) {\n // First subscriber - start real-time subscription\n startSubscription().catch(() => {})\n } else if (newCount === 0 && previousCount > 0) {\n // Last subscriber removed - stop real-time subscription\n stopSubscription().catch(() => {})\n }\n }\n )\n\n // Add collectionName and subscription helpers\n Object.assign(collection, {\n collectionName,\n relationTargets,\n waitForSubscription,\n isSubscribed: () => isSubscribed,\n heldRelationTargetCount: () => heldTargetSubscriptions.size,\n fetchRelations,\n })\n\n return collection as unknown as BuiltCollection<RecordType>\n}\n","import type { Collection } from '@tanstack/db'\nimport type { QueryCollectionUtils } from '@tanstack/query-db-collection'\nimport type { QueryClient } from '@tanstack/react-query'\nimport type PocketBase from 'pocketbase'\nimport { buildCollection, type CreateCollectionFactoryOptions } from './build-collection'\nimport type {\n CreateCollectionOptions,\n ExpandPath,\n ExtractRecordType,\n InsertInputOf,\n PbMeta,\n RelationsOf,\n SchemaDeclaration,\n} from './types'\n\nexport type { CreateCollectionFactoryOptions } from './build-collection'\nexport type { BaseRecord, CreateCollectionOptions, SchemaDeclaration } from './types'\n\n/**\n * A pbtsdb collection or view: a TanStack DB collection over\n * `ExtractRecordType<Schema, C>` rows, plus pbtsdb's subscription helpers.\n * Views are created by {@link PbCollection.fetchRelations} and are leaves:\n * they have no further `fetchRelations()`.\n */\nexport type PbCollectionView<\n Schema extends SchemaDeclaration,\n C extends keyof Schema & string,\n Opts,\n> = Collection<\n ExtractRecordType<Schema, C>,\n string | number,\n QueryCollectionUtils<\n ExtractRecordType<Schema, C>,\n string | number,\n ExtractRecordType<Schema, C>\n >,\n never,\n InsertInputOf<Schema, C, Opts>\n> & {\n /** The PocketBase collection name */\n readonly collectionName: C\n /** Wait for the real-time subscription to be established (useful in tests) */\n waitForSubscription: (timeout?: number) => Promise<void>\n /** Whether the collection has an active real-time subscription */\n isSubscribed: () => boolean\n /** @internal relation targets declared through `relations` */\n readonly relationTargets: Record<string, unknown> | undefined\n /** @internal number of relation targets currently held live */\n readonly heldRelationTargetCount: () => number\n /** @internal phantom; never present at runtime */\n readonly __pbtsdb: PbMeta<Schema, C, RelationsOf<Opts>>\n}\n\n/**\n * The collection returned by {@link createCollection}: a {@link PbCollectionView}\n * plus `fetchRelations()` for per-query views.\n */\nexport type PbCollection<\n Schema extends SchemaDeclaration,\n C extends keyof Schema & string,\n Opts,\n> = PbCollectionView<Schema, C, Opts> & {\n /**\n * A view of this collection whose queries also fetch `paths` and file the\n * expanded records into their target collections. Rows are unchanged; read\n * related records through `materialize()`, a join, or the target's `get()`.\n */\n fetchRelations<const P extends readonly ExpandPath<RelationsOf<Opts>>[]>(\n ...paths: P\n ): PbCollectionView<Schema, C, Opts>\n}\n\ntype AlwaysFetchRelationsCheck<Opts> = {\n alwaysFetchRelations?: readonly ExpandPath<RelationsOf<Opts>>[]\n}\n\n/**\n * Creates a type-safe TanStack DB collection backed by PocketBase.\n * Use this when you need fine-grained control or need to create collections with dependencies.\n *\n * @param pb - PocketBase client instance\n * @param queryClient - TanStack Query client\n * @returns A curried function that takes collection name and options\n *\n * @example\n * Basic usage:\n * ```ts\n * const booksCollection = createCollection<Schema>(pb, queryClient)('books', {});\n *\n * // Use directly\n * const books = await booksCollection.getFullList();\n * ```\n *\n * @example\n * With relations fetched on every request:\n * ```ts\n * const authorsCollection = createCollection<Schema>(pb, queryClient)('authors', {});\n * const booksCollection = createCollection<Schema>(pb, queryClient)('books', {\n * relations: { author: authorsCollection },\n * alwaysFetchRelations: ['author'],\n * });\n *\n * const { data } = useLiveQuery((q) => q.from({ books: booksCollection }));\n * // The expanded author is filed into authorsCollection, not kept on the row.\n * authorsCollection.get(data[0].author)?.name\n * ```\n *\n * @example\n * With a per-query fetchRelations view:\n * ```ts\n * const booksCollection = createCollection<Schema>(pb, queryClient)('books', {\n * relations: { author: authorsCollection },\n * });\n *\n * const view = booksCollection.fetchRelations('author');\n * const { data } = useLiveQuery((q) => q.from({ books: view }));\n * // Same target collection as above; the view only affects what gets fetched.\n * authorsCollection.get(data[0].author)?.name\n * ```\n */\nexport function createCollection<Schema extends SchemaDeclaration>(\n pb: PocketBase,\n queryClient: QueryClient,\n factoryOptions?: CreateCollectionFactoryOptions\n) {\n return <C extends keyof Schema & string, const Opts extends CreateCollectionOptions<Schema, C>>(\n collectionName: C,\n options?: Opts & AlwaysFetchRelationsCheck<Opts>\n ): PbCollection<Schema, C, Opts> => {\n return buildCollection<Schema, C>({\n pb,\n queryClient,\n factoryOptions,\n collectionName,\n options,\n }) as unknown as PbCollection<Schema, C, Opts>\n }\n}\n","/**\n * Generates a new PocketBase-compatible record ID.\n * Returns a 15-character alphanumeric string (lowercase letters and numbers).\n *\n * PocketBase uses 15-character IDs for records, formatted as lowercase alphanumeric.\n *\n * @returns A 15-character alphanumeric string suitable for use as a PocketBase record ID\n *\n * @example\n * ```ts\n * const id = newRecordId(); // \"a1b2c3d4e5f6g7h\"\n * ```\n */\nexport function newRecordId(): string {\n const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'\n let result = ''\n for (let i = 0; i < 15; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length))\n }\n return result\n}\n"]}