@tanstack/db 0.5.24 → 0.5.26

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.
Files changed (82) hide show
  1. package/dist/cjs/collection/change-events.cjs +1 -1
  2. package/dist/cjs/collection/change-events.cjs.map +1 -1
  3. package/dist/cjs/collection/changes.cjs +6 -1
  4. package/dist/cjs/collection/changes.cjs.map +1 -1
  5. package/dist/cjs/collection/lifecycle.cjs +11 -0
  6. package/dist/cjs/collection/lifecycle.cjs.map +1 -1
  7. package/dist/cjs/collection/subscription.cjs +18 -5
  8. package/dist/cjs/collection/subscription.cjs.map +1 -1
  9. package/dist/cjs/collection/subscription.d.cts +7 -1
  10. package/dist/cjs/indexes/base-index.cjs.map +1 -1
  11. package/dist/cjs/indexes/base-index.d.cts +10 -6
  12. package/dist/cjs/indexes/btree-index.cjs +64 -24
  13. package/dist/cjs/indexes/btree-index.cjs.map +1 -1
  14. package/dist/cjs/indexes/btree-index.d.cts +31 -9
  15. package/dist/cjs/indexes/reverse-index.cjs +6 -0
  16. package/dist/cjs/indexes/reverse-index.cjs.map +1 -1
  17. package/dist/cjs/indexes/reverse-index.d.cts +4 -2
  18. package/dist/cjs/query/builder/index.cjs.map +1 -1
  19. package/dist/cjs/query/builder/index.d.cts +1 -1
  20. package/dist/cjs/query/compiler/evaluators.cjs +2 -2
  21. package/dist/cjs/query/compiler/evaluators.cjs.map +1 -1
  22. package/dist/cjs/query/compiler/joins.cjs +3 -2
  23. package/dist/cjs/query/compiler/joins.cjs.map +1 -1
  24. package/dist/cjs/query/index.d.cts +1 -1
  25. package/dist/cjs/query/live/collection-config-builder.cjs +9 -1
  26. package/dist/cjs/query/live/collection-config-builder.cjs.map +1 -1
  27. package/dist/cjs/query/live/collection-subscriber.cjs +111 -30
  28. package/dist/cjs/query/live/collection-subscriber.cjs.map +1 -1
  29. package/dist/cjs/query/live/collection-subscriber.d.cts +5 -0
  30. package/dist/cjs/types.d.cts +16 -0
  31. package/dist/cjs/utils/comparison.cjs +16 -0
  32. package/dist/cjs/utils/comparison.cjs.map +1 -1
  33. package/dist/cjs/utils/comparison.d.cts +21 -0
  34. package/dist/esm/collection/change-events.js +1 -1
  35. package/dist/esm/collection/change-events.js.map +1 -1
  36. package/dist/esm/collection/changes.js +6 -1
  37. package/dist/esm/collection/changes.js.map +1 -1
  38. package/dist/esm/collection/lifecycle.js +11 -0
  39. package/dist/esm/collection/lifecycle.js.map +1 -1
  40. package/dist/esm/collection/subscription.d.ts +7 -1
  41. package/dist/esm/collection/subscription.js +18 -5
  42. package/dist/esm/collection/subscription.js.map +1 -1
  43. package/dist/esm/indexes/base-index.d.ts +10 -6
  44. package/dist/esm/indexes/base-index.js.map +1 -1
  45. package/dist/esm/indexes/btree-index.d.ts +31 -9
  46. package/dist/esm/indexes/btree-index.js +65 -25
  47. package/dist/esm/indexes/btree-index.js.map +1 -1
  48. package/dist/esm/indexes/reverse-index.d.ts +4 -2
  49. package/dist/esm/indexes/reverse-index.js +6 -0
  50. package/dist/esm/indexes/reverse-index.js.map +1 -1
  51. package/dist/esm/query/builder/index.d.ts +1 -1
  52. package/dist/esm/query/builder/index.js.map +1 -1
  53. package/dist/esm/query/compiler/evaluators.js +2 -2
  54. package/dist/esm/query/compiler/evaluators.js.map +1 -1
  55. package/dist/esm/query/compiler/joins.js +3 -2
  56. package/dist/esm/query/compiler/joins.js.map +1 -1
  57. package/dist/esm/query/index.d.ts +1 -1
  58. package/dist/esm/query/live/collection-config-builder.js +9 -1
  59. package/dist/esm/query/live/collection-config-builder.js.map +1 -1
  60. package/dist/esm/query/live/collection-subscriber.d.ts +5 -0
  61. package/dist/esm/query/live/collection-subscriber.js +112 -31
  62. package/dist/esm/query/live/collection-subscriber.js.map +1 -1
  63. package/dist/esm/types.d.ts +16 -0
  64. package/dist/esm/utils/comparison.d.ts +21 -0
  65. package/dist/esm/utils/comparison.js +16 -0
  66. package/dist/esm/utils/comparison.js.map +1 -1
  67. package/package.json +2 -2
  68. package/src/collection/change-events.ts +1 -1
  69. package/src/collection/changes.ts +6 -1
  70. package/src/collection/lifecycle.ts +14 -0
  71. package/src/collection/subscription.ts +38 -10
  72. package/src/indexes/base-index.ts +19 -6
  73. package/src/indexes/btree-index.ts +101 -30
  74. package/src/indexes/reverse-index.ts +13 -2
  75. package/src/query/builder/index.ts +18 -0
  76. package/src/query/compiler/evaluators.ts +2 -2
  77. package/src/query/compiler/joins.ts +3 -2
  78. package/src/query/index.ts +17 -0
  79. package/src/query/live/collection-config-builder.ts +13 -5
  80. package/src/query/live/collection-subscriber.ts +173 -50
  81. package/src/types.ts +16 -0
  82. package/src/utils/comparison.ts +34 -0
@@ -1,6 +1,10 @@
1
1
  import { compareKeys } from '@tanstack/db-ivm'
2
2
  import { BTree } from '../utils/btree.js'
3
- import { defaultComparator, normalizeValue } from '../utils/comparison.js'
3
+ import {
4
+ defaultComparator,
5
+ denormalizeUndefined,
6
+ normalizeForBTree,
7
+ } from '../utils/comparison.js'
4
8
  import { BaseIndex } from './base-index.js'
5
9
  import type { CompareOptions } from '../query/builder/types.js'
6
10
  import type { BasicExpression } from '../query/ir.js'
@@ -29,7 +33,7 @@ export interface RangeQueryOptions {
29
33
  * This maintains items in sorted order and provides efficient range operations
30
34
  */
31
35
  export class BTreeIndex<
32
- TKey extends string | number = string | number,
36
+ TKey extends string | number | undefined = string | number | undefined,
33
37
  > extends BaseIndex<TKey> {
34
38
  public readonly supportedOperations = new Set<IndexOperation>([
35
39
  `eq`,
@@ -55,7 +59,16 @@ export class BTreeIndex<
55
59
  options?: any,
56
60
  ) {
57
61
  super(id, expression, name, options)
58
- this.compareFn = options?.compareFn ?? defaultComparator
62
+
63
+ // Get the base compare function
64
+ const baseCompareFn = options?.compareFn ?? defaultComparator
65
+
66
+ // Wrap it to denormalize sentinels before comparison
67
+ // This ensures UNDEFINED_SENTINEL is converted back to undefined
68
+ // before being passed to the baseCompareFn (which can be user-provided and is unaware of the UNDEFINED_SENTINEL)
69
+ this.compareFn = (a: any, b: any) =>
70
+ baseCompareFn(denormalizeUndefined(a), denormalizeUndefined(b))
71
+
59
72
  if (options?.compareOptions) {
60
73
  this.compareOptions = options!.compareOptions
61
74
  }
@@ -78,7 +91,7 @@ export class BTreeIndex<
78
91
  }
79
92
 
80
93
  // Normalize the value for Map key usage
81
- const normalizedValue = normalizeValue(indexedValue)
94
+ const normalizedValue = normalizeForBTree(indexedValue)
82
95
 
83
96
  // Check if this value already exists
84
97
  if (this.valueMap.has(normalizedValue)) {
@@ -111,7 +124,7 @@ export class BTreeIndex<
111
124
  }
112
125
 
113
126
  // Normalize the value for Map key usage
114
- const normalizedValue = normalizeValue(indexedValue)
127
+ const normalizedValue = normalizeForBTree(indexedValue)
115
128
 
116
129
  if (this.valueMap.has(normalizedValue)) {
117
130
  const keySet = this.valueMap.get(normalizedValue)!
@@ -207,7 +220,7 @@ export class BTreeIndex<
207
220
  * Performs an equality lookup
208
221
  */
209
222
  equalityLookup(value: any): Set<TKey> {
210
- const normalizedValue = normalizeValue(value)
223
+ const normalizedValue = normalizeForBTree(value)
211
224
  return new Set(this.valueMap.get(normalizedValue) ?? [])
212
225
  }
213
226
 
@@ -219,10 +232,15 @@ export class BTreeIndex<
219
232
  const { from, to, fromInclusive = true, toInclusive = true } = options
220
233
  const result = new Set<TKey>()
221
234
 
222
- const normalizedFrom = normalizeValue(from)
223
- const normalizedTo = normalizeValue(to)
224
- const fromKey = normalizedFrom ?? this.orderedEntries.minKey()
225
- const toKey = normalizedTo ?? this.orderedEntries.maxKey()
235
+ // Check if from/to were explicitly provided (even if undefined)
236
+ // vs not provided at all (should use min/max key)
237
+ const hasFrom = `from` in options
238
+ const hasTo = `to` in options
239
+
240
+ const fromKey = hasFrom
241
+ ? normalizeForBTree(from)
242
+ : this.orderedEntries.minKey()
243
+ const toKey = hasTo ? normalizeForBTree(to) : this.orderedEntries.maxKey()
226
244
 
227
245
  this.orderedEntries.forRange(
228
246
  fromKey,
@@ -250,29 +268,43 @@ export class BTreeIndex<
250
268
  */
251
269
  rangeQueryReversed(options: RangeQueryOptions = {}): Set<TKey> {
252
270
  const { from, to, fromInclusive = true, toInclusive = true } = options
271
+ const hasFrom = `from` in options
272
+ const hasTo = `to` in options
273
+
274
+ // Swap from/to for reversed query, respecting explicit undefined values
253
275
  return this.rangeQuery({
254
- from: to ?? this.orderedEntries.maxKey(),
255
- to: from ?? this.orderedEntries.minKey(),
276
+ from: hasTo ? to : this.orderedEntries.maxKey(),
277
+ to: hasFrom ? from : this.orderedEntries.minKey(),
256
278
  fromInclusive: toInclusive,
257
279
  toInclusive: fromInclusive,
258
280
  })
259
281
  }
260
282
 
283
+ /**
284
+ * Internal method for taking items from the index.
285
+ * @param n - The number of items to return
286
+ * @param nextPair - Function to get the next pair from the BTree
287
+ * @param from - Already normalized! undefined means "start from beginning/end", sentinel means "start from the key undefined"
288
+ * @param filterFn - Optional filter function
289
+ * @param reversed - Whether to reverse the order of keys within each value
290
+ */
261
291
  private takeInternal(
262
292
  n: number,
263
293
  nextPair: (k?: any) => [any, any] | undefined,
264
- from?: any,
294
+ from: any,
265
295
  filterFn?: (key: TKey) => boolean,
266
296
  reversed: boolean = false,
267
297
  ): Array<TKey> {
268
298
  const keysInResult: Set<TKey> = new Set()
269
299
  const result: Array<TKey> = []
270
300
  let pair: [any, any] | undefined
271
- let key = normalizeValue(from)
301
+ let key = from // Use as-is - it's already normalized by the caller
272
302
 
273
303
  while ((pair = nextPair(key)) !== undefined && result.length < n) {
274
304
  key = pair[0]
275
- const keys = this.valueMap.get(key)
305
+ const keys = this.valueMap.get(key) as
306
+ | Set<Exclude<TKey, undefined>>
307
+ | undefined
276
308
  if (keys && keys.size > 0) {
277
309
  // Sort keys for deterministic order, reverse if needed
278
310
  const sorted = Array.from(keys).sort(compareKeys)
@@ -291,29 +323,60 @@ export class BTreeIndex<
291
323
  }
292
324
 
293
325
  /**
294
- * Returns the next n items after the provided item or the first n items if no from item is provided.
326
+ * Returns the next n items after the provided item.
295
327
  * @param n - The number of items to return
296
- * @param from - The item to start from (exclusive). Starts from the smallest item (inclusive) if not provided.
297
- * @returns The next n items after the provided key. Returns the first n items if no from item is provided.
328
+ * @param from - The item to start from (exclusive).
329
+ * @returns The next n items after the provided key.
298
330
  */
299
- take(n: number, from?: any, filterFn?: (key: TKey) => boolean): Array<TKey> {
331
+ take(n: number, from: any, filterFn?: (key: TKey) => boolean): Array<TKey> {
300
332
  const nextPair = (k?: any) => this.orderedEntries.nextHigherPair(k)
301
- return this.takeInternal(n, nextPair, from, filterFn)
333
+ // Normalize the from value
334
+ const normalizedFrom = normalizeForBTree(from)
335
+ return this.takeInternal(n, nextPair, normalizedFrom, filterFn)
302
336
  }
303
337
 
304
338
  /**
305
- * Returns the next n items **before** the provided item (in descending order) or the last n items if no from item is provided.
339
+ * Returns the first n items from the beginning.
306
340
  * @param n - The number of items to return
307
- * @param from - The item to start from (exclusive). Starts from the largest item (inclusive) if not provided.
308
- * @returns The next n items **before** the provided key. Returns the last n items if no from item is provided.
341
+ * @param filterFn - Optional filter function
342
+ * @returns The first n items
343
+ */
344
+ takeFromStart(n: number, filterFn?: (key: TKey) => boolean): Array<TKey> {
345
+ const nextPair = (k?: any) => this.orderedEntries.nextHigherPair(k)
346
+ // Pass undefined to mean "start from beginning" (BTree's native behavior)
347
+ return this.takeInternal(n, nextPair, undefined, filterFn)
348
+ }
349
+
350
+ /**
351
+ * Returns the next n items **before** the provided item (in descending order).
352
+ * @param n - The number of items to return
353
+ * @param from - The item to start from (exclusive). Required.
354
+ * @returns The next n items **before** the provided key.
309
355
  */
310
356
  takeReversed(
311
357
  n: number,
312
- from?: any,
358
+ from: any,
359
+ filterFn?: (key: TKey) => boolean,
360
+ ): Array<TKey> {
361
+ const nextPair = (k?: any) => this.orderedEntries.nextLowerPair(k)
362
+ // Normalize the from value
363
+ const normalizedFrom = normalizeForBTree(from)
364
+ return this.takeInternal(n, nextPair, normalizedFrom, filterFn, true)
365
+ }
366
+
367
+ /**
368
+ * Returns the last n items from the end.
369
+ * @param n - The number of items to return
370
+ * @param filterFn - Optional filter function
371
+ * @returns The last n items
372
+ */
373
+ takeReversedFromEnd(
374
+ n: number,
313
375
  filterFn?: (key: TKey) => boolean,
314
376
  ): Array<TKey> {
315
377
  const nextPair = (k?: any) => this.orderedEntries.nextLowerPair(k)
316
- return this.takeInternal(n, nextPair, from, filterFn, true)
378
+ // Pass undefined to mean "start from end" (BTree's native behavior)
379
+ return this.takeInternal(n, nextPair, undefined, filterFn, true)
317
380
  }
318
381
 
319
382
  /**
@@ -323,7 +386,7 @@ export class BTreeIndex<
323
386
  const result = new Set<TKey>()
324
387
 
325
388
  for (const value of values) {
326
- const normalizedValue = normalizeValue(value)
389
+ const normalizedValue = normalizeForBTree(value)
327
390
  const keys = this.valueMap.get(normalizedValue)
328
391
  if (keys) {
329
392
  keys.forEach((key) => result.add(key))
@@ -341,17 +404,25 @@ export class BTreeIndex<
341
404
  get orderedEntriesArray(): Array<[any, Set<TKey>]> {
342
405
  return this.orderedEntries
343
406
  .keysArray()
344
- .map((key) => [key, this.valueMap.get(key) ?? new Set()])
407
+ .map((key) => [
408
+ denormalizeUndefined(key),
409
+ this.valueMap.get(key) ?? new Set(),
410
+ ])
345
411
  }
346
412
 
347
413
  get orderedEntriesArrayReversed(): Array<[any, Set<TKey>]> {
348
- return this.takeReversed(this.orderedEntries.size).map((key) => [
349
- key,
414
+ return this.takeReversedFromEnd(this.orderedEntries.size).map((key) => [
415
+ denormalizeUndefined(key),
350
416
  this.valueMap.get(key) ?? new Set(),
351
417
  ])
352
418
  }
353
419
 
354
420
  get valueMapData(): Map<any, Set<TKey>> {
355
- return this.valueMap
421
+ // Return a new Map with denormalized keys
422
+ const result = new Map<any, Set<TKey>>()
423
+ for (const [key, value] of this.valueMap) {
424
+ result.set(denormalizeUndefined(key), value)
425
+ }
426
+ return result
356
427
  }
357
428
  }
@@ -36,18 +36,29 @@ export class ReverseIndex<
36
36
  return this.originalIndex.rangeQuery(options)
37
37
  }
38
38
 
39
- take(n: number, from?: any, filterFn?: (key: TKey) => boolean): Array<TKey> {
39
+ take(n: number, from: any, filterFn?: (key: TKey) => boolean): Array<TKey> {
40
40
  return this.originalIndex.takeReversed(n, from, filterFn)
41
41
  }
42
42
 
43
+ takeFromStart(n: number, filterFn?: (key: TKey) => boolean): Array<TKey> {
44
+ return this.originalIndex.takeReversedFromEnd(n, filterFn)
45
+ }
46
+
43
47
  takeReversed(
44
48
  n: number,
45
- from?: any,
49
+ from: any,
46
50
  filterFn?: (key: TKey) => boolean,
47
51
  ): Array<TKey> {
48
52
  return this.originalIndex.take(n, from, filterFn)
49
53
  }
50
54
 
55
+ takeReversedFromEnd(
56
+ n: number,
57
+ filterFn?: (key: TKey) => boolean,
58
+ ): Array<TKey> {
59
+ return this.originalIndex.takeFromStart(n, filterFn)
60
+ }
61
+
51
62
  get orderedEntriesArray(): Array<[any, Set<TKey>]> {
52
63
  return this.originalIndex.orderedEntriesArrayReversed
53
64
  }
@@ -910,8 +910,26 @@ export type QueryResult<T> = GetResult<ExtractContext<T>>
910
910
  // Export the types from types.ts for convenience
911
911
  export type {
912
912
  Context,
913
+ ContextSchema,
913
914
  Source,
914
915
  GetResult,
915
916
  RefLeaf as Ref,
916
917
  InferResultType,
918
+ // Types used in public method signatures that must be exported
919
+ // for declaration emit to work (see https://github.com/TanStack/db/issues/1012)
920
+ SchemaFromSource,
921
+ InferCollectionType,
922
+ MergeContextWithJoinType,
923
+ MergeContextForJoinCallback,
924
+ ApplyJoinOptionalityToMergedSchema,
925
+ ResultTypeFromSelect,
926
+ WithResult,
927
+ JoinOnCallback,
928
+ RefsForContext,
929
+ WhereCallback,
930
+ OrderByCallback,
931
+ GroupByCallback,
932
+ SelectObject,
933
+ FunctionalHavingRow,
934
+ Prettify,
917
935
  } from './types.js'
@@ -336,7 +336,7 @@ function compileFunction(func: Func, isSingleRow: boolean): (data: any) => any {
336
336
  const valueEvaluator = compiledArgs[0]!
337
337
  const arrayEvaluator = compiledArgs[1]!
338
338
  return (data) => {
339
- const value = valueEvaluator(data)
339
+ const value = normalizeValue(valueEvaluator(data))
340
340
  const array = arrayEvaluator(data)
341
341
  // In 3-valued logic, if the value is null/undefined, return UNKNOWN
342
342
  if (isUnknown(value)) {
@@ -345,7 +345,7 @@ function compileFunction(func: Func, isSingleRow: boolean): (data: any) => any {
345
345
  if (!Array.isArray(array)) {
346
346
  return false
347
347
  }
348
- return array.includes(value)
348
+ return array.some((item) => normalizeValue(item) === value)
349
349
  }
350
350
  }
351
351
 
@@ -11,6 +11,7 @@ import {
11
11
  UnsupportedJoinSourceTypeError,
12
12
  UnsupportedJoinTypeError,
13
13
  } from '../../errors.js'
14
+ import { normalizeValue } from '../../utils/comparison.js'
14
15
  import { ensureIndexForField } from '../../indexes/auto-index.js'
15
16
  import { PropRef, followRef } from '../ir.js'
16
17
  import { inArray } from '../builder/functions.js'
@@ -188,7 +189,7 @@ function processJoin(
188
189
  let mainPipeline = pipeline.pipe(
189
190
  map(([currentKey, namespacedRow]) => {
190
191
  // Extract the join key from the main source expression
191
- const mainKey = compiledMainExpr(namespacedRow)
192
+ const mainKey = normalizeValue(compiledMainExpr(namespacedRow))
192
193
 
193
194
  // Return [joinKey, [originalKey, namespacedRow]]
194
195
  return [mainKey, [currentKey, namespacedRow]] as [
@@ -205,7 +206,7 @@ function processJoin(
205
206
  const namespacedRow: NamespacedRow = { [joinedSource]: row }
206
207
 
207
208
  // Extract the join key from the joined source expression
208
- const joinedKey = compiledJoinedExpr(namespacedRow)
209
+ const joinedKey = normalizeValue(compiledJoinedExpr(namespacedRow))
209
210
 
210
211
  // Return [joinKey, [originalKey, namespacedRow]]
211
212
  return [joinedKey, [currentKey, namespacedRow]] as [
@@ -7,11 +7,28 @@ export {
7
7
  type InitialQueryBuilder,
8
8
  type QueryBuilder,
9
9
  type Context,
10
+ type ContextSchema,
10
11
  type Source,
11
12
  type GetResult,
12
13
  type InferResultType,
13
14
  type ExtractContext,
14
15
  type QueryResult,
16
+ // Types needed for declaration emit (https://github.com/TanStack/db/issues/1012)
17
+ type SchemaFromSource,
18
+ type InferCollectionType,
19
+ type MergeContextWithJoinType,
20
+ type MergeContextForJoinCallback,
21
+ type ApplyJoinOptionalityToMergedSchema,
22
+ type ResultTypeFromSelect,
23
+ type WithResult,
24
+ type JoinOnCallback,
25
+ type RefsForContext,
26
+ type WhereCallback,
27
+ type OrderByCallback,
28
+ type GroupByCallback,
29
+ type SelectObject,
30
+ type FunctionalHavingRow,
31
+ type Prettify,
15
32
  } from './builder/index.js'
16
33
 
17
34
  // Expression functions exports
@@ -336,6 +336,7 @@ export class CollectionConfigBuilder<
336
336
 
337
337
  // Always run the graph if subscribed (eager execution)
338
338
  if (syncState.subscribedToAllCollections) {
339
+ let callbackCalled = false
339
340
  while (syncState.graph.pendingWork()) {
340
341
  syncState.graph.run()
341
342
  // Flush accumulated changes after each graph step to commit them as one transaction.
@@ -343,6 +344,14 @@ export class CollectionConfigBuilder<
343
344
  // duplicate key errors when the full join result arrives in the same step.
344
345
  syncState.flushPendingChanges?.()
345
346
  callback?.()
347
+ callbackCalled = true
348
+ }
349
+
350
+ // Ensure the callback runs at least once even when the graph has no pending work.
351
+ // This handles lazy loading scenarios where setWindow() increases the limit or
352
+ // an async loadSubset completes and we need to re-check if more data is needed.
353
+ if (!callbackCalled) {
354
+ callback?.()
346
355
  }
347
356
 
348
357
  // On the initial run, we may need to do an empty commit to ensure that
@@ -830,17 +839,16 @@ export class CollectionConfigBuilder<
830
839
  return
831
840
  }
832
841
 
842
+ const subscribedToAll = this.currentSyncState?.subscribedToAllCollections
843
+ const allReady = this.allCollectionsReady()
844
+ const isLoading = this.liveQueryCollection?.isLoadingSubset
833
845
  // Mark ready when:
834
846
  // 1. All subscriptions are set up (subscribedToAllCollections)
835
847
  // 2. All source collections are ready
836
848
  // 3. The live query collection is not loading subset data
837
849
  // This prevents marking the live query ready before its data is processed
838
850
  // (fixes issue where useLiveQuery returns isReady=true with empty data)
839
- if (
840
- this.currentSyncState?.subscribedToAllCollections &&
841
- this.allCollectionsReady() &&
842
- !this.liveQueryCollection?.isLoadingSubset
843
- ) {
851
+ if (subscribedToAll && allReady && !isLoading) {
844
852
  markReady()
845
853
  }
846
854
  }