@tanstack/db 0.5.32 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (287) hide show
  1. package/dist/cjs/collection/change-events.cjs.map +1 -1
  2. package/dist/cjs/collection/change-events.d.cts +3 -2
  3. package/dist/cjs/collection/changes.cjs +13 -4
  4. package/dist/cjs/collection/changes.cjs.map +1 -1
  5. package/dist/cjs/collection/changes.d.cts +10 -1
  6. package/dist/cjs/collection/cleanup-queue.cjs +89 -0
  7. package/dist/cjs/collection/cleanup-queue.cjs.map +1 -0
  8. package/dist/cjs/collection/cleanup-queue.d.cts +30 -0
  9. package/dist/cjs/collection/events.cjs +14 -0
  10. package/dist/cjs/collection/events.cjs.map +1 -1
  11. package/dist/cjs/collection/events.d.cts +39 -1
  12. package/dist/cjs/collection/index.cjs +66 -28
  13. package/dist/cjs/collection/index.cjs.map +1 -1
  14. package/dist/cjs/collection/index.d.cts +49 -36
  15. package/dist/cjs/collection/indexes.cjs +211 -62
  16. package/dist/cjs/collection/indexes.cjs.map +1 -1
  17. package/dist/cjs/collection/indexes.d.cts +27 -17
  18. package/dist/cjs/collection/lifecycle.cjs +5 -22
  19. package/dist/cjs/collection/lifecycle.cjs.map +1 -1
  20. package/dist/cjs/collection/lifecycle.d.cts +0 -1
  21. package/dist/cjs/collection/mutations.cjs +18 -0
  22. package/dist/cjs/collection/mutations.cjs.map +1 -1
  23. package/dist/cjs/collection/mutations.d.cts +1 -0
  24. package/dist/cjs/collection/state.cjs +381 -53
  25. package/dist/cjs/collection/state.cjs.map +1 -1
  26. package/dist/cjs/collection/state.d.cts +65 -1
  27. package/dist/cjs/collection/subscription.cjs +6 -0
  28. package/dist/cjs/collection/subscription.cjs.map +1 -1
  29. package/dist/cjs/collection/subscription.d.cts +4 -0
  30. package/dist/cjs/collection/sync.cjs +108 -1
  31. package/dist/cjs/collection/sync.cjs.map +1 -1
  32. package/dist/cjs/collection/sync.d.cts +2 -0
  33. package/dist/cjs/collection/transaction-metadata.cjs +5 -0
  34. package/dist/cjs/collection/transaction-metadata.cjs.map +1 -0
  35. package/dist/cjs/collection/transaction-metadata.d.cts +1 -0
  36. package/dist/cjs/errors.cjs +8 -0
  37. package/dist/cjs/errors.cjs.map +1 -1
  38. package/dist/cjs/errors.d.cts +3 -0
  39. package/dist/cjs/index.cjs +24 -4
  40. package/dist/cjs/index.cjs.map +1 -1
  41. package/dist/cjs/index.d.cts +12 -3
  42. package/dist/cjs/indexes/auto-index.cjs +13 -6
  43. package/dist/cjs/indexes/auto-index.cjs.map +1 -1
  44. package/dist/cjs/indexes/base-index.cjs +0 -3
  45. package/dist/cjs/indexes/base-index.cjs.map +1 -1
  46. package/dist/cjs/indexes/base-index.d.cts +2 -6
  47. package/dist/cjs/indexes/basic-index.cjs +361 -0
  48. package/dist/cjs/indexes/basic-index.cjs.map +1 -0
  49. package/dist/cjs/indexes/basic-index.d.cts +102 -0
  50. package/dist/cjs/indexes/btree-index.cjs.map +1 -1
  51. package/dist/cjs/indexes/btree-index.d.cts +1 -1
  52. package/dist/cjs/indexes/index-options.d.cts +8 -9
  53. package/dist/cjs/indexes/index-registry.cjs +89 -0
  54. package/dist/cjs/indexes/index-registry.cjs.map +1 -0
  55. package/dist/cjs/indexes/index-registry.d.cts +61 -0
  56. package/dist/cjs/local-only.cjs +5 -0
  57. package/dist/cjs/local-only.cjs.map +1 -1
  58. package/dist/cjs/query/builder/functions.cjs +27 -11
  59. package/dist/cjs/query/builder/functions.cjs.map +1 -1
  60. package/dist/cjs/query/builder/functions.d.cts +25 -3
  61. package/dist/cjs/query/builder/index.cjs +200 -39
  62. package/dist/cjs/query/builder/index.cjs.map +1 -1
  63. package/dist/cjs/query/builder/index.d.cts +4 -3
  64. package/dist/cjs/query/builder/ref-proxy.cjs.map +1 -1
  65. package/dist/cjs/query/builder/ref-proxy.d.cts +14 -3
  66. package/dist/cjs/query/builder/types.d.cts +84 -19
  67. package/dist/cjs/query/compiler/evaluators.cjs +51 -0
  68. package/dist/cjs/query/compiler/evaluators.cjs.map +1 -1
  69. package/dist/cjs/query/compiler/group-by.cjs +100 -28
  70. package/dist/cjs/query/compiler/group-by.cjs.map +1 -1
  71. package/dist/cjs/query/compiler/group-by.d.cts +4 -2
  72. package/dist/cjs/query/compiler/index.cjs +283 -11
  73. package/dist/cjs/query/compiler/index.cjs.map +1 -1
  74. package/dist/cjs/query/compiler/index.d.cts +30 -2
  75. package/dist/cjs/query/compiler/order-by.cjs +29 -10
  76. package/dist/cjs/query/compiler/order-by.cjs.map +1 -1
  77. package/dist/cjs/query/compiler/order-by.d.cts +1 -1
  78. package/dist/cjs/query/compiler/select.cjs +8 -0
  79. package/dist/cjs/query/compiler/select.cjs.map +1 -1
  80. package/dist/cjs/query/effect.cjs +602 -0
  81. package/dist/cjs/query/effect.cjs.map +1 -0
  82. package/dist/cjs/query/effect.d.cts +94 -0
  83. package/dist/cjs/query/index.d.cts +2 -1
  84. package/dist/cjs/query/ir.cjs +18 -1
  85. package/dist/cjs/query/ir.cjs.map +1 -1
  86. package/dist/cjs/query/ir.d.cts +21 -1
  87. package/dist/cjs/query/live/collection-config-builder.cjs +493 -66
  88. package/dist/cjs/query/live/collection-config-builder.cjs.map +1 -1
  89. package/dist/cjs/query/live/collection-config-builder.d.cts +7 -0
  90. package/dist/cjs/query/live/collection-subscriber.cjs +33 -100
  91. package/dist/cjs/query/live/collection-subscriber.cjs.map +1 -1
  92. package/dist/cjs/query/live/collection-subscriber.d.cts +0 -1
  93. package/dist/cjs/query/live/types.d.cts +3 -3
  94. package/dist/cjs/query/live/utils.cjs +219 -0
  95. package/dist/cjs/query/live/utils.cjs.map +1 -0
  96. package/dist/cjs/query/live/utils.d.cts +110 -0
  97. package/dist/cjs/query/live-query-collection.cjs.map +1 -1
  98. package/dist/cjs/query/live-query-collection.d.cts +9 -6
  99. package/dist/cjs/query/query-once.cjs.map +1 -1
  100. package/dist/cjs/query/query-once.d.cts +7 -5
  101. package/dist/cjs/query/subset-dedupe.cjs +9 -3
  102. package/dist/cjs/query/subset-dedupe.cjs.map +1 -1
  103. package/dist/cjs/types.d.cts +42 -8
  104. package/dist/cjs/utils/array-utils.cjs +27 -0
  105. package/dist/cjs/utils/array-utils.cjs.map +1 -0
  106. package/dist/cjs/utils/array-utils.d.cts +16 -0
  107. package/dist/cjs/utils/comparison.cjs +11 -0
  108. package/dist/cjs/utils/comparison.cjs.map +1 -1
  109. package/dist/cjs/utils/index-optimization.cjs +4 -0
  110. package/dist/cjs/utils/index-optimization.cjs.map +1 -1
  111. package/dist/cjs/utils.cjs +7 -9
  112. package/dist/cjs/utils.cjs.map +1 -1
  113. package/dist/cjs/utils.d.cts +6 -1
  114. package/dist/cjs/virtual-props.cjs +33 -0
  115. package/dist/cjs/virtual-props.cjs.map +1 -0
  116. package/dist/cjs/virtual-props.d.cts +196 -0
  117. package/dist/esm/collection/change-events.d.ts +3 -2
  118. package/dist/esm/collection/change-events.js.map +1 -1
  119. package/dist/esm/collection/changes.d.ts +10 -1
  120. package/dist/esm/collection/changes.js +13 -4
  121. package/dist/esm/collection/changes.js.map +1 -1
  122. package/dist/esm/collection/cleanup-queue.d.ts +30 -0
  123. package/dist/esm/collection/cleanup-queue.js +89 -0
  124. package/dist/esm/collection/cleanup-queue.js.map +1 -0
  125. package/dist/esm/collection/events.d.ts +39 -1
  126. package/dist/esm/collection/events.js +14 -0
  127. package/dist/esm/collection/events.js.map +1 -1
  128. package/dist/esm/collection/index.d.ts +49 -36
  129. package/dist/esm/collection/index.js +67 -29
  130. package/dist/esm/collection/index.js.map +1 -1
  131. package/dist/esm/collection/indexes.d.ts +27 -17
  132. package/dist/esm/collection/indexes.js +211 -62
  133. package/dist/esm/collection/indexes.js.map +1 -1
  134. package/dist/esm/collection/lifecycle.d.ts +0 -1
  135. package/dist/esm/collection/lifecycle.js +5 -22
  136. package/dist/esm/collection/lifecycle.js.map +1 -1
  137. package/dist/esm/collection/mutations.d.ts +1 -0
  138. package/dist/esm/collection/mutations.js +18 -0
  139. package/dist/esm/collection/mutations.js.map +1 -1
  140. package/dist/esm/collection/state.d.ts +65 -1
  141. package/dist/esm/collection/state.js +381 -53
  142. package/dist/esm/collection/state.js.map +1 -1
  143. package/dist/esm/collection/subscription.d.ts +4 -0
  144. package/dist/esm/collection/subscription.js +6 -0
  145. package/dist/esm/collection/subscription.js.map +1 -1
  146. package/dist/esm/collection/sync.d.ts +2 -0
  147. package/dist/esm/collection/sync.js +108 -1
  148. package/dist/esm/collection/sync.js.map +1 -1
  149. package/dist/esm/collection/transaction-metadata.d.ts +1 -0
  150. package/dist/esm/collection/transaction-metadata.js +5 -0
  151. package/dist/esm/collection/transaction-metadata.js.map +1 -0
  152. package/dist/esm/errors.d.ts +3 -0
  153. package/dist/esm/errors.js +8 -0
  154. package/dist/esm/errors.js.map +1 -1
  155. package/dist/esm/index.d.ts +12 -3
  156. package/dist/esm/index.js +27 -7
  157. package/dist/esm/index.js.map +1 -1
  158. package/dist/esm/indexes/auto-index.js +13 -6
  159. package/dist/esm/indexes/auto-index.js.map +1 -1
  160. package/dist/esm/indexes/base-index.d.ts +2 -6
  161. package/dist/esm/indexes/base-index.js +1 -4
  162. package/dist/esm/indexes/base-index.js.map +1 -1
  163. package/dist/esm/indexes/basic-index.d.ts +102 -0
  164. package/dist/esm/indexes/basic-index.js +361 -0
  165. package/dist/esm/indexes/basic-index.js.map +1 -0
  166. package/dist/esm/indexes/btree-index.d.ts +1 -1
  167. package/dist/esm/indexes/btree-index.js.map +1 -1
  168. package/dist/esm/indexes/index-options.d.ts +8 -9
  169. package/dist/esm/indexes/index-registry.d.ts +61 -0
  170. package/dist/esm/indexes/index-registry.js +89 -0
  171. package/dist/esm/indexes/index-registry.js.map +1 -0
  172. package/dist/esm/local-only.js +5 -0
  173. package/dist/esm/local-only.js.map +1 -1
  174. package/dist/esm/query/builder/functions.d.ts +25 -3
  175. package/dist/esm/query/builder/functions.js +27 -11
  176. package/dist/esm/query/builder/functions.js.map +1 -1
  177. package/dist/esm/query/builder/index.d.ts +4 -3
  178. package/dist/esm/query/builder/index.js +201 -40
  179. package/dist/esm/query/builder/index.js.map +1 -1
  180. package/dist/esm/query/builder/ref-proxy.d.ts +14 -3
  181. package/dist/esm/query/builder/ref-proxy.js.map +1 -1
  182. package/dist/esm/query/builder/types.d.ts +84 -19
  183. package/dist/esm/query/compiler/evaluators.js +51 -0
  184. package/dist/esm/query/compiler/evaluators.js.map +1 -1
  185. package/dist/esm/query/compiler/group-by.d.ts +4 -2
  186. package/dist/esm/query/compiler/group-by.js +101 -29
  187. package/dist/esm/query/compiler/group-by.js.map +1 -1
  188. package/dist/esm/query/compiler/index.d.ts +30 -2
  189. package/dist/esm/query/compiler/index.js +285 -13
  190. package/dist/esm/query/compiler/index.js.map +1 -1
  191. package/dist/esm/query/compiler/order-by.d.ts +1 -1
  192. package/dist/esm/query/compiler/order-by.js +30 -11
  193. package/dist/esm/query/compiler/order-by.js.map +1 -1
  194. package/dist/esm/query/compiler/select.js +8 -0
  195. package/dist/esm/query/compiler/select.js.map +1 -1
  196. package/dist/esm/query/effect.d.ts +94 -0
  197. package/dist/esm/query/effect.js +602 -0
  198. package/dist/esm/query/effect.js.map +1 -0
  199. package/dist/esm/query/index.d.ts +2 -1
  200. package/dist/esm/query/ir.d.ts +21 -1
  201. package/dist/esm/query/ir.js +18 -1
  202. package/dist/esm/query/ir.js.map +1 -1
  203. package/dist/esm/query/live/collection-config-builder.d.ts +7 -0
  204. package/dist/esm/query/live/collection-config-builder.js +492 -65
  205. package/dist/esm/query/live/collection-config-builder.js.map +1 -1
  206. package/dist/esm/query/live/collection-subscriber.d.ts +0 -1
  207. package/dist/esm/query/live/collection-subscriber.js +31 -98
  208. package/dist/esm/query/live/collection-subscriber.js.map +1 -1
  209. package/dist/esm/query/live/types.d.ts +3 -3
  210. package/dist/esm/query/live/utils.d.ts +110 -0
  211. package/dist/esm/query/live/utils.js +219 -0
  212. package/dist/esm/query/live/utils.js.map +1 -0
  213. package/dist/esm/query/live-query-collection.d.ts +9 -6
  214. package/dist/esm/query/live-query-collection.js.map +1 -1
  215. package/dist/esm/query/query-once.d.ts +7 -5
  216. package/dist/esm/query/query-once.js.map +1 -1
  217. package/dist/esm/query/subset-dedupe.js +9 -3
  218. package/dist/esm/query/subset-dedupe.js.map +1 -1
  219. package/dist/esm/types.d.ts +42 -8
  220. package/dist/esm/utils/array-utils.d.ts +16 -0
  221. package/dist/esm/utils/array-utils.js +27 -0
  222. package/dist/esm/utils/array-utils.js.map +1 -0
  223. package/dist/esm/utils/comparison.js +11 -0
  224. package/dist/esm/utils/comparison.js.map +1 -1
  225. package/dist/esm/utils/index-optimization.js +4 -0
  226. package/dist/esm/utils/index-optimization.js.map +1 -1
  227. package/dist/esm/utils.d.ts +6 -1
  228. package/dist/esm/utils.js +7 -9
  229. package/dist/esm/utils.js.map +1 -1
  230. package/dist/esm/virtual-props.d.ts +196 -0
  231. package/dist/esm/virtual-props.js +33 -0
  232. package/dist/esm/virtual-props.js.map +1 -0
  233. package/package.json +2 -2
  234. package/skills/db-core/collection-setup/references/electric-adapter.md +1 -1
  235. package/src/collection/change-events.ts +13 -9
  236. package/src/collection/changes.ts +30 -7
  237. package/src/collection/cleanup-queue.ts +105 -0
  238. package/src/collection/events.ts +65 -0
  239. package/src/collection/index.ts +110 -45
  240. package/src/collection/indexes.ts +283 -76
  241. package/src/collection/lifecycle.ts +5 -26
  242. package/src/collection/mutations.ts +21 -0
  243. package/src/collection/state.ts +545 -71
  244. package/src/collection/subscription.ts +7 -0
  245. package/src/collection/sync.ts +137 -0
  246. package/src/collection/transaction-metadata.ts +1 -0
  247. package/src/errors.ts +9 -0
  248. package/src/index.ts +57 -3
  249. package/src/indexes/auto-index.ts +18 -8
  250. package/src/indexes/base-index.ts +2 -10
  251. package/src/indexes/basic-index.ts +507 -0
  252. package/src/indexes/btree-index.ts +1 -1
  253. package/src/indexes/index-options.ts +17 -37
  254. package/src/indexes/index-registry.ts +174 -0
  255. package/src/local-only.ts +7 -0
  256. package/src/query/builder/functions.ts +84 -7
  257. package/src/query/builder/index.ts +329 -9
  258. package/src/query/builder/ref-proxy.ts +22 -4
  259. package/src/query/builder/types.ts +257 -62
  260. package/src/query/compiler/evaluators.ts +57 -0
  261. package/src/query/compiler/group-by.ts +156 -35
  262. package/src/query/compiler/index.ts +445 -15
  263. package/src/query/compiler/order-by.ts +51 -12
  264. package/src/query/compiler/select.ts +9 -0
  265. package/src/query/effect.ts +1119 -0
  266. package/src/query/index.ts +7 -0
  267. package/src/query/ir.ts +23 -2
  268. package/src/query/live/collection-config-builder.ts +778 -104
  269. package/src/query/live/collection-subscriber.ts +40 -156
  270. package/src/query/live/types.ts +10 -4
  271. package/src/query/live/utils.ts +417 -0
  272. package/src/query/live-query-collection.ts +43 -18
  273. package/src/query/query-once.ts +31 -12
  274. package/src/query/subset-dedupe.ts +11 -7
  275. package/src/types.ts +49 -9
  276. package/src/utils/array-utils.ts +49 -0
  277. package/src/utils/comparison.ts +14 -0
  278. package/src/utils/index-optimization.ts +4 -0
  279. package/src/utils.ts +12 -9
  280. package/src/virtual-props.ts +282 -0
  281. package/dist/cjs/indexes/lazy-index.cjs +0 -190
  282. package/dist/cjs/indexes/lazy-index.cjs.map +0 -1
  283. package/dist/cjs/indexes/lazy-index.d.cts +0 -96
  284. package/dist/esm/indexes/lazy-index.d.ts +0 -96
  285. package/dist/esm/indexes/lazy-index.js +0 -190
  286. package/dist/esm/indexes/lazy-index.js.map +0 -1
  287. package/src/indexes/lazy-index.ts +0 -251
@@ -1,6 +1,7 @@
1
1
  import { EventEmitter } from '../event-emitter.js'
2
2
  import type { Collection } from './index.js'
3
3
  import type { CollectionStatus } from '../types.js'
4
+ import type { BasicExpression } from '../query/ir.js'
4
5
 
5
6
  /**
6
7
  * Event emitted when the collection status changes
@@ -51,11 +52,57 @@ export interface CollectionTruncateEvent {
51
52
  collection: Collection<any, any, any, any, any>
52
53
  }
53
54
 
55
+ export type CollectionIndexSerializableValue =
56
+ | string
57
+ | number
58
+ | boolean
59
+ | null
60
+ | Array<CollectionIndexSerializableValue>
61
+ | {
62
+ [key: string]: CollectionIndexSerializableValue
63
+ }
64
+
65
+ export interface CollectionIndexResolverMetadata {
66
+ kind: `constructor` | `async`
67
+ name?: string
68
+ }
69
+
70
+ export interface CollectionIndexMetadata {
71
+ /**
72
+ * Version for the signature serialization contract.
73
+ */
74
+ signatureVersion: 1
75
+ /**
76
+ * Stable signature derived from expression + serializable options.
77
+ * Non-serializable option fields are intentionally omitted.
78
+ */
79
+ signature: string
80
+ indexId: number
81
+ name?: string
82
+ expression: BasicExpression
83
+ resolver: CollectionIndexResolverMetadata
84
+ options?: CollectionIndexSerializableValue
85
+ }
86
+
87
+ export interface CollectionIndexAddedEvent {
88
+ type: `index:added`
89
+ collection: Collection<any, any, any, any, any>
90
+ index: CollectionIndexMetadata
91
+ }
92
+
93
+ export interface CollectionIndexRemovedEvent {
94
+ type: `index:removed`
95
+ collection: Collection<any, any, any, any, any>
96
+ index: CollectionIndexMetadata
97
+ }
98
+
54
99
  export type AllCollectionEvents = {
55
100
  'status:change': CollectionStatusChangeEvent
56
101
  'subscribers:change': CollectionSubscribersChangeEvent
57
102
  'loadingSubset:change': CollectionLoadingSubsetChangeEvent
58
103
  truncate: CollectionTruncateEvent
104
+ 'index:added': CollectionIndexAddedEvent
105
+ 'index:removed': CollectionIndexRemovedEvent
59
106
  } & {
60
107
  [K in CollectionStatus as `status:${K}`]: CollectionStatusEvent<K>
61
108
  }
@@ -66,6 +113,8 @@ export type CollectionEvent =
66
113
  | CollectionSubscribersChangeEvent
67
114
  | CollectionLoadingSubsetChangeEvent
68
115
  | CollectionTruncateEvent
116
+ | CollectionIndexAddedEvent
117
+ | CollectionIndexRemovedEvent
69
118
 
70
119
  export type CollectionEventHandler<T extends keyof AllCollectionEvents> = (
71
120
  event: AllCollectionEvents[T],
@@ -126,6 +175,22 @@ export class CollectionEventsManager extends EventEmitter<AllCollectionEvents> {
126
175
  })
127
176
  }
128
177
 
178
+ emitIndexAdded(index: CollectionIndexMetadata) {
179
+ this.emit(`index:added`, {
180
+ type: `index:added`,
181
+ collection: this.collection,
182
+ index,
183
+ })
184
+ }
185
+
186
+ emitIndexRemoved(index: CollectionIndexMetadata) {
187
+ this.emit(`index:removed`, {
188
+ type: `index:removed`,
189
+ collection: this.collection,
190
+ index,
191
+ })
192
+ }
193
+
129
194
  cleanup() {
130
195
  this.clearListeners()
131
196
  }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ CollectionConfigurationError,
2
3
  CollectionRequiresConfigError,
3
4
  CollectionRequiresSyncConfigError,
4
5
  } from '../errors'
@@ -12,8 +13,12 @@ import { CollectionIndexesManager } from './indexes'
12
13
  import { CollectionMutationsManager } from './mutations'
13
14
  import { CollectionEventsManager } from './events.js'
14
15
  import type { CollectionSubscription } from './subscription'
15
- import type { AllCollectionEvents, CollectionEventHandler } from './events.js'
16
- import type { BaseIndex, IndexResolver } from '../indexes/base-index.js'
16
+ import type {
17
+ AllCollectionEvents,
18
+ CollectionEventHandler,
19
+ CollectionIndexMetadata,
20
+ } from './events.js'
21
+ import type { BaseIndex, IndexConstructor } from '../indexes/base-index.js'
17
22
  import type { IndexOptions } from '../indexes/index-options.js'
18
23
  import type {
19
24
  ChangeMessage,
@@ -35,8 +40,9 @@ import type {
35
40
  } from '../types'
36
41
  import type { SingleRowRefProxy } from '../query/builder/ref-proxy'
37
42
  import type { StandardSchemaV1 } from '@standard-schema/spec'
38
- import type { BTreeIndex } from '../indexes/btree-index.js'
39
- import type { IndexProxy } from '../indexes/lazy-index.js'
43
+ import type { WithVirtualProps } from '../virtual-props.js'
44
+
45
+ export type { CollectionIndexMetadata } from './events.js'
40
46
 
41
47
  /**
42
48
  * Enhanced Collection interface that includes both data type T and utilities TUtils
@@ -294,6 +300,13 @@ export class CollectionImpl<
294
300
  // and for debugging
295
301
  public _state: CollectionStateManager<TOutput, TKey, TSchema, TInput>
296
302
 
303
+ /**
304
+ * When set, collection consumers should defer processing incoming data
305
+ * refreshes until this promise resolves. This prevents stale data from
306
+ * overwriting optimistic state while pending writes are being applied.
307
+ */
308
+ public deferDataRefresh: Promise<void> | null = null
309
+
297
310
  private comparisonOpts: StringCollationConfig
298
311
 
299
312
  /**
@@ -322,7 +335,16 @@ export class CollectionImpl<
322
335
  // Set default values for optional config properties
323
336
  this.config = {
324
337
  ...config,
325
- autoIndex: config.autoIndex ?? `eager`,
338
+ autoIndex: config.autoIndex ?? `off`,
339
+ }
340
+
341
+ if (this.config.autoIndex === `eager` && !config.defaultIndexType) {
342
+ throw new CollectionConfigurationError(
343
+ `autoIndex: 'eager' requires defaultIndexType to be set. ` +
344
+ `Import an index type and set it:\n` +
345
+ ` import { BasicIndex } from '@tanstack/db'\n` +
346
+ ` createCollection({ defaultIndexType: BasicIndex, autoIndex: 'eager', ... })`,
347
+ )
326
348
  }
327
349
 
328
350
  this._changes = new CollectionChangesManager()
@@ -340,6 +362,7 @@ export class CollectionImpl<
340
362
  lifecycle: this._lifecycle,
341
363
  sync: this._sync,
342
364
  events: this._events,
365
+ state: this._state, // Required for enriching changes with virtual properties
343
366
  })
344
367
  this._events.setDeps({
345
368
  collection: this, // Required for adding to emitted events
@@ -347,6 +370,8 @@ export class CollectionImpl<
347
370
  this._indexes.setDeps({
348
371
  state: this._state,
349
372
  lifecycle: this._lifecycle,
373
+ defaultIndexType: config.defaultIndexType,
374
+ events: this._events,
350
375
  })
351
376
  this._lifecycle.setDeps({
352
377
  changes: this._changes,
@@ -451,8 +476,8 @@ export class CollectionImpl<
451
476
  /**
452
477
  * Get the current value for a key (virtual derived state)
453
478
  */
454
- public get(key: TKey): TOutput | undefined {
455
- return this._state.get(key)
479
+ public get(key: TKey): WithVirtualProps<TOutput, TKey> | undefined {
480
+ return this._state.getWithVirtualProps(key)
456
481
  }
457
482
 
458
483
  /**
@@ -479,40 +504,68 @@ export class CollectionImpl<
479
504
  /**
480
505
  * Get all values (virtual derived state)
481
506
  */
482
- public *values(): IterableIterator<TOutput> {
483
- yield* this._state.values()
507
+ public *values(): IterableIterator<WithVirtualProps<TOutput, TKey>> {
508
+ for (const key of this._state.keys()) {
509
+ const value = this.get(key)
510
+ if (value !== undefined) {
511
+ yield value
512
+ }
513
+ }
484
514
  }
485
515
 
486
516
  /**
487
517
  * Get all entries (virtual derived state)
488
518
  */
489
- public *entries(): IterableIterator<[TKey, TOutput]> {
490
- yield* this._state.entries()
519
+ public *entries(): IterableIterator<[TKey, WithVirtualProps<TOutput, TKey>]> {
520
+ for (const key of this._state.keys()) {
521
+ const value = this.get(key)
522
+ if (value !== undefined) {
523
+ yield [key, value]
524
+ }
525
+ }
491
526
  }
492
527
 
493
528
  /**
494
529
  * Get all entries (virtual derived state)
495
530
  */
496
- public *[Symbol.iterator](): IterableIterator<[TKey, TOutput]> {
497
- yield* this._state[Symbol.iterator]()
531
+ public *[Symbol.iterator](): IterableIterator<
532
+ [TKey, WithVirtualProps<TOutput, TKey>]
533
+ > {
534
+ yield* this.entries()
498
535
  }
499
536
 
500
537
  /**
501
538
  * Execute a callback for each entry in the collection
502
539
  */
503
540
  public forEach(
504
- callbackfn: (value: TOutput, key: TKey, index: number) => void,
541
+ callbackfn: (
542
+ value: WithVirtualProps<TOutput, TKey>,
543
+ key: TKey,
544
+ index: number,
545
+ ) => void,
505
546
  ): void {
506
- return this._state.forEach(callbackfn)
547
+ let index = 0
548
+ for (const [key, value] of this.entries()) {
549
+ callbackfn(value, key, index++)
550
+ }
507
551
  }
508
552
 
509
553
  /**
510
554
  * Create a new array with the results of calling a function for each entry in the collection
511
555
  */
512
556
  public map<U>(
513
- callbackfn: (value: TOutput, key: TKey, index: number) => U,
557
+ callbackfn: (
558
+ value: WithVirtualProps<TOutput, TKey>,
559
+ key: TKey,
560
+ index: number,
561
+ ) => U,
514
562
  ): Array<U> {
515
- return this._state.map(callbackfn)
563
+ const result: Array<U> = []
564
+ let index = 0
565
+ for (const [key, value] of this.entries()) {
566
+ result.push(callbackfn(value, key, index++))
567
+ }
568
+ return result
516
569
  }
517
570
 
518
571
  public getKeyFromItem(item: TOutput): TKey {
@@ -524,41 +577,51 @@ export class CollectionImpl<
524
577
  * Indexes significantly improve query performance by allowing constant time lookups
525
578
  * and logarithmic time range queries instead of full scans.
526
579
  *
527
- * @template TResolver - The type of the index resolver (constructor or async loader)
528
580
  * @param indexCallback - Function that extracts the indexed value from each item
529
581
  * @param config - Configuration including index type and type-specific options
530
- * @returns An index proxy that provides access to the index when ready
582
+ * @returns The created index
531
583
  *
532
584
  * @example
533
- * // Create a default B+ tree index
534
- * const ageIndex = collection.createIndex((row) => row.age)
585
+ * ```ts
586
+ * import { BasicIndex } from '@tanstack/db'
535
587
  *
536
- * // Create a ordered index with custom options
588
+ * // Create an index with explicit type
537
589
  * const ageIndex = collection.createIndex((row) => row.age, {
538
- * indexType: BTreeIndex,
539
- * options: {
540
- * compareFn: customComparator,
541
- * compareOptions: { direction: 'asc', nulls: 'first', stringSort: 'lexical' }
542
- * },
543
- * name: 'age_btree'
590
+ * indexType: BasicIndex
544
591
  * })
545
592
  *
546
- * // Create an async-loaded index
547
- * const textIndex = collection.createIndex((row) => row.content, {
548
- * indexType: async () => {
549
- * const { FullTextIndex } = await import('./indexes/fulltext.js')
550
- * return FullTextIndex
551
- * },
552
- * options: { language: 'en' }
553
- * })
593
+ * // Create an index with collection's default type
594
+ * const nameIndex = collection.createIndex((row) => row.name)
595
+ * ```
554
596
  */
555
- public createIndex<TResolver extends IndexResolver<TKey> = typeof BTreeIndex>(
597
+ public createIndex<TIndexType extends IndexConstructor<TKey>>(
556
598
  indexCallback: (row: SingleRowRefProxy<TOutput>) => any,
557
- config: IndexOptions<TResolver> = {},
558
- ): IndexProxy<TKey> {
599
+ config: IndexOptions<TIndexType> = {},
600
+ ): BaseIndex<TKey> {
559
601
  return this._indexes.createIndex(indexCallback, config)
560
602
  }
561
603
 
604
+ /**
605
+ * Removes an index created with createIndex.
606
+ * Returns true when an index existed and was removed.
607
+ *
608
+ * Best-effort semantics: removing an index guarantees it is detached from
609
+ * collection query planning. Existing index proxy references should be treated
610
+ * as invalid after removal.
611
+ */
612
+ public removeIndex(indexOrId: BaseIndex<TKey> | number): boolean {
613
+ return this._indexes.removeIndex(indexOrId)
614
+ }
615
+
616
+ /**
617
+ * Returns a snapshot of current index metadata sorted by indexId.
618
+ * Persistence wrappers can use this to bootstrap index state if indexes were
619
+ * created before event listeners were attached.
620
+ */
621
+ public getIndexMetadata(): Array<CollectionIndexMetadata> {
622
+ return this._indexes.getIndexMetadataSnapshot()
623
+ }
624
+
562
625
  /**
563
626
  * Get resolved indexes for query optimization
564
627
  */
@@ -755,7 +818,7 @@ export class CollectionImpl<
755
818
  * }
756
819
  */
757
820
  get state() {
758
- const result = new Map<TKey, TOutput>()
821
+ const result = new Map<TKey, WithVirtualProps<TOutput, TKey>>()
759
822
  for (const [key, value] of this.entries()) {
760
823
  result.set(key, value)
761
824
  }
@@ -768,7 +831,7 @@ export class CollectionImpl<
768
831
  *
769
832
  * @returns Promise that resolves to a Map containing all items in the collection
770
833
  */
771
- stateWhenReady(): Promise<Map<TKey, TOutput>> {
834
+ stateWhenReady(): Promise<Map<TKey, WithVirtualProps<TOutput, TKey>>> {
772
835
  // If we already have data or collection is ready, resolve immediately
773
836
  if (this.size > 0 || this.isReady()) {
774
837
  return Promise.resolve(this.state)
@@ -793,7 +856,7 @@ export class CollectionImpl<
793
856
  *
794
857
  * @returns Promise that resolves to an Array containing all items in the collection
795
858
  */
796
- toArrayWhenReady(): Promise<Array<TOutput>> {
859
+ toArrayWhenReady(): Promise<Array<WithVirtualProps<TOutput, TKey>>> {
797
860
  // If we already have data or collection is ready, resolve immediately
798
861
  if (this.size > 0 || this.isReady()) {
799
862
  return Promise.resolve(this.toArray)
@@ -823,7 +886,7 @@ export class CollectionImpl<
823
886
  */
824
887
  public currentStateAsChanges(
825
888
  options: CurrentStateAsChangesOptions = {},
826
- ): Array<ChangeMessage<TOutput>> | void {
889
+ ): Array<ChangeMessage<WithVirtualProps<TOutput, TKey>>> | void {
827
890
  return currentStateAsChanges(this, options)
828
891
  }
829
892
 
@@ -870,8 +933,10 @@ export class CollectionImpl<
870
933
  * })
871
934
  */
872
935
  public subscribeChanges(
873
- callback: (changes: Array<ChangeMessage<TOutput>>) => void,
874
- options: SubscribeChangesOptions<TOutput> = {},
936
+ callback: (
937
+ changes: Array<ChangeMessage<WithVirtualProps<TOutput, TKey>>>,
938
+ ) => void,
939
+ options: SubscribeChangesOptions<TOutput, TKey> = {},
875
940
  ): CollectionSubscription {
876
941
  return this._changes.subscribeChanges(callback, options)
877
942
  }