@abloatai/ablo 0.26.0 → 0.27.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 (398) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +101 -85
  3. package/dist/BaseSyncedStore.d.ts +85 -88
  4. package/dist/BaseSyncedStore.js +131 -147
  5. package/dist/Database.d.ts +54 -68
  6. package/dist/Database.js +97 -113
  7. package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
  8. package/dist/{ObjectPool.js → InstanceCache.js} +85 -83
  9. package/dist/LazyReferenceCollection.d.ts +11 -15
  10. package/dist/LazyReferenceCollection.js +12 -16
  11. package/dist/Model.d.ts +37 -52
  12. package/dist/Model.js +46 -61
  13. package/dist/ModelRegistry.d.ts +21 -19
  14. package/dist/ModelRegistry.js +23 -27
  15. package/dist/NetworkMonitor.d.ts +5 -6
  16. package/dist/NetworkMonitor.js +5 -6
  17. package/dist/SyncClient.d.ts +112 -112
  18. package/dist/SyncClient.js +165 -172
  19. package/dist/adapters/alwaysOnline.d.ts +6 -8
  20. package/dist/adapters/alwaysOnline.js +6 -8
  21. package/dist/adapters/inMemoryStorage.d.ts +9 -9
  22. package/dist/adapters/inMemoryStorage.js +9 -9
  23. package/dist/agent/Agent.d.ts +27 -32
  24. package/dist/agent/Agent.js +18 -19
  25. package/dist/agent/index.d.ts +4 -4
  26. package/dist/agent/index.js +5 -5
  27. package/dist/agent/session.d.ts +47 -44
  28. package/dist/agent/session.js +37 -48
  29. package/dist/agent/types.d.ts +26 -31
  30. package/dist/agent/types.js +6 -7
  31. package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
  32. package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
  33. package/dist/ai-sdk/coordinationContext.d.ts +46 -0
  34. package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +26 -33
  35. package/dist/ai-sdk/index.d.ts +25 -22
  36. package/dist/ai-sdk/index.js +25 -22
  37. package/dist/ai-sdk/wrap.d.ts +6 -7
  38. package/dist/ai-sdk/wrap.js +1 -1
  39. package/dist/auth/credentialPolicy.d.ts +69 -74
  40. package/dist/auth/credentialPolicy.js +51 -56
  41. package/dist/auth/credentialSource.d.ts +6 -5
  42. package/dist/auth/credentialSource.js +9 -10
  43. package/dist/auth/index.d.ts +59 -58
  44. package/dist/auth/index.js +31 -37
  45. package/dist/auth/schemas.d.ts +5 -4
  46. package/dist/auth/schemas.js +5 -4
  47. package/dist/batching/index.d.ts +19 -21
  48. package/dist/batching/index.js +14 -17
  49. package/dist/cli.cjs +167 -119
  50. package/dist/client/Ablo.d.ts +73 -73
  51. package/dist/client/Ablo.js +125 -160
  52. package/dist/client/ApiClient.d.ts +30 -19
  53. package/dist/client/ApiClient.js +133 -38
  54. package/dist/client/auth.d.ts +47 -47
  55. package/dist/client/auth.js +108 -117
  56. package/dist/client/claimHeartbeatLoop.d.ts +50 -0
  57. package/dist/client/claimHeartbeatLoop.js +88 -0
  58. package/dist/client/consoleLogger.d.ts +5 -6
  59. package/dist/client/consoleLogger.js +5 -6
  60. package/dist/client/createInternalComponents.d.ts +14 -17
  61. package/dist/client/createInternalComponents.js +25 -30
  62. package/dist/client/createModelProxy.d.ts +130 -120
  63. package/dist/client/createModelProxy.js +152 -122
  64. package/dist/client/credentialEndpoint.d.ts +40 -42
  65. package/dist/client/credentialEndpoint.js +35 -36
  66. package/dist/client/functionalUpdate.d.ts +29 -27
  67. package/dist/client/functionalUpdate.js +21 -21
  68. package/dist/client/hostedEndpoints.d.ts +9 -12
  69. package/dist/client/hostedEndpoints.js +9 -12
  70. package/dist/client/httpClient.d.ts +57 -53
  71. package/dist/client/httpClient.js +29 -31
  72. package/dist/client/identity.d.ts +15 -20
  73. package/dist/client/identity.js +47 -58
  74. package/dist/client/modelRegistration.d.ts +5 -9
  75. package/dist/client/modelRegistration.js +67 -87
  76. package/dist/client/options.d.ts +134 -157
  77. package/dist/client/options.js +3 -7
  78. package/dist/client/registerDataSource.d.ts +9 -9
  79. package/dist/client/registerDataSource.js +15 -16
  80. package/dist/client/resourceTypes.d.ts +64 -75
  81. package/dist/client/resourceTypes.js +4 -10
  82. package/dist/client/schemaConfig.d.ts +31 -43
  83. package/dist/client/schemaConfig.js +38 -50
  84. package/dist/client/sessionMint.d.ts +16 -12
  85. package/dist/client/sessionMint.js +26 -31
  86. package/dist/client/validateAbloOptions.d.ts +12 -14
  87. package/dist/client/validateAbloOptions.js +8 -9
  88. package/dist/client/writeOptionsSchema.d.ts +18 -16
  89. package/dist/client/writeOptionsSchema.js +23 -20
  90. package/dist/client/wsMutationExecutor.d.ts +15 -20
  91. package/dist/client/wsMutationExecutor.js +17 -23
  92. package/dist/context.d.ts +6 -4
  93. package/dist/context.js +6 -4
  94. package/dist/coordination/index.d.ts +10 -8
  95. package/dist/coordination/index.js +14 -12
  96. package/dist/coordination/schema.d.ts +176 -128
  97. package/dist/coordination/schema.js +197 -133
  98. package/dist/coordination/trace.d.ts +9 -10
  99. package/dist/coordination/trace.js +13 -14
  100. package/dist/core/DatabaseManager.d.ts +5 -7
  101. package/dist/core/DatabaseManager.js +15 -19
  102. package/dist/core/QueryProcessor.d.ts +7 -9
  103. package/dist/core/QueryProcessor.js +22 -28
  104. package/dist/core/QueryView.d.ts +8 -8
  105. package/dist/core/QueryView.js +2 -2
  106. package/dist/core/StoreManager.d.ts +12 -14
  107. package/dist/core/StoreManager.js +21 -24
  108. package/dist/core/ViewRegistry.d.ts +5 -5
  109. package/dist/core/ViewRegistry.js +4 -4
  110. package/dist/core/index.d.ts +17 -12
  111. package/dist/core/index.js +32 -26
  112. package/dist/core/openIDBWithTimeout.d.ts +38 -36
  113. package/dist/core/openIDBWithTimeout.js +42 -43
  114. package/dist/core/queryUtils.d.ts +45 -0
  115. package/dist/core/queryUtils.js +69 -0
  116. package/dist/core/storeContract.d.ts +63 -61
  117. package/dist/core/storeContract.js +8 -12
  118. package/dist/environment.d.ts +28 -0
  119. package/dist/environment.js +21 -0
  120. package/dist/errorCodes.d.ts +107 -99
  121. package/dist/errorCodes.js +131 -132
  122. package/dist/errors.d.ts +160 -166
  123. package/dist/errors.js +155 -158
  124. package/dist/index.d.ts +30 -27
  125. package/dist/index.js +89 -86
  126. package/dist/interfaces/index.d.ts +102 -113
  127. package/dist/interfaces/index.js +5 -4
  128. package/dist/keys/index.d.ts +27 -29
  129. package/dist/keys/index.js +41 -40
  130. package/dist/mutators/RecordingTransaction.d.ts +16 -16
  131. package/dist/mutators/RecordingTransaction.js +31 -37
  132. package/dist/mutators/Transaction.d.ts +18 -26
  133. package/dist/mutators/Transaction.js +14 -20
  134. package/dist/mutators/UndoManager.d.ts +122 -131
  135. package/dist/mutators/UndoManager.js +145 -156
  136. package/dist/mutators/defineMutators.d.ts +23 -34
  137. package/dist/mutators/defineMutators.js +14 -20
  138. package/dist/mutators/inverseOp.d.ts +12 -15
  139. package/dist/mutators/inverseOp.js +12 -15
  140. package/dist/mutators/mutateActions.d.ts +10 -9
  141. package/dist/mutators/mutateActions.js +1 -1
  142. package/dist/mutators/readerActions.d.ts +9 -8
  143. package/dist/mutators/readerActions.js +2 -2
  144. package/dist/mutators/undoApply.d.ts +31 -27
  145. package/dist/mutators/undoApply.js +26 -24
  146. package/dist/policy/index.d.ts +5 -3
  147. package/dist/policy/index.js +5 -3
  148. package/dist/policy/types.d.ts +104 -100
  149. package/dist/policy/types.js +67 -66
  150. package/dist/query/client.d.ts +28 -23
  151. package/dist/query/client.js +45 -43
  152. package/dist/query/types.d.ts +37 -60
  153. package/dist/query/types.js +13 -33
  154. package/dist/react/AbloProvider.d.ts +1 -1
  155. package/dist/react/AbloProvider.js +2 -2
  156. package/dist/react/context.d.ts +25 -28
  157. package/dist/react/context.js +9 -10
  158. package/dist/react/index.d.ts +41 -42
  159. package/dist/react/index.js +37 -38
  160. package/dist/react/internalContext.d.ts +17 -19
  161. package/dist/react/useAblo.d.ts +23 -22
  162. package/dist/react/useAblo.js +16 -14
  163. package/dist/react/useCurrentUserId.d.ts +8 -7
  164. package/dist/react/useCurrentUserId.js +8 -7
  165. package/dist/react/useErrorListener.d.ts +7 -7
  166. package/dist/react/useErrorListener.js +10 -11
  167. package/dist/react/useMutationFailureListener.d.ts +8 -8
  168. package/dist/react/useMutationFailureListener.js +8 -8
  169. package/dist/react/useMutators.d.ts +11 -11
  170. package/dist/react/useMutators.js +3 -3
  171. package/dist/react/useReactive.js +2 -2
  172. package/dist/react/useSyncStatus.d.ts +4 -6
  173. package/dist/react/useUndoScope.d.ts +7 -9
  174. package/dist/react/useUndoScope.js +1 -1
  175. package/dist/schema/coordination.d.ts +21 -25
  176. package/dist/schema/coordination.js +21 -25
  177. package/dist/schema/ddl.d.ts +43 -39
  178. package/dist/schema/ddl.js +75 -68
  179. package/dist/schema/ddlLock.d.ts +20 -24
  180. package/dist/schema/ddlLock.js +18 -23
  181. package/dist/schema/diff.d.ts +99 -61
  182. package/dist/schema/diff.js +43 -34
  183. package/dist/schema/field.d.ts +37 -42
  184. package/dist/schema/field.js +35 -48
  185. package/dist/schema/generate.d.ts +12 -12
  186. package/dist/schema/generate.js +12 -12
  187. package/dist/schema/index.d.ts +2 -2
  188. package/dist/schema/index.js +21 -23
  189. package/dist/schema/model.d.ts +118 -143
  190. package/dist/schema/model.js +22 -33
  191. package/dist/schema/openapi.d.ts +10 -9
  192. package/dist/schema/openapi.js +5 -3
  193. package/dist/schema/queries.d.ts +29 -31
  194. package/dist/schema/queries.js +23 -25
  195. package/dist/schema/relation.d.ts +89 -99
  196. package/dist/schema/relation.js +13 -13
  197. package/dist/schema/residency.d.ts +16 -13
  198. package/dist/schema/residency.js +16 -13
  199. package/dist/schema/roles.d.ts +36 -43
  200. package/dist/schema/roles.js +31 -37
  201. package/dist/schema/schema.d.ts +33 -42
  202. package/dist/schema/schema.js +31 -32
  203. package/dist/schema/select.d.ts +13 -13
  204. package/dist/schema/select.js +13 -13
  205. package/dist/schema/serialize.d.ts +28 -31
  206. package/dist/schema/serialize.js +27 -31
  207. package/dist/schema/sugar.d.ts +17 -32
  208. package/dist/schema/sugar.js +14 -29
  209. package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +26 -49
  210. package/dist/schema/syncDeltaRow.js +89 -0
  211. package/dist/schema/tenancy.d.ts +44 -46
  212. package/dist/schema/tenancy.js +46 -48
  213. package/dist/server/adapter.d.ts +58 -58
  214. package/dist/server/adapter.js +13 -14
  215. package/dist/server/commit.d.ts +60 -64
  216. package/dist/server/index.d.ts +9 -10
  217. package/dist/server/index.js +1 -1
  218. package/dist/server/readConfig.d.ts +70 -0
  219. package/dist/server/readConfig.js +8 -0
  220. package/dist/server/storageMode.d.ts +23 -0
  221. package/dist/server/storageMode.js +17 -0
  222. package/dist/source/adapter.d.ts +30 -25
  223. package/dist/source/adapter.js +10 -10
  224. package/dist/source/adapters/drizzle.d.ts +28 -23
  225. package/dist/source/adapters/drizzle.js +30 -25
  226. package/dist/source/adapters/kysely.d.ts +27 -25
  227. package/dist/source/adapters/kysely.js +24 -23
  228. package/dist/source/adapters/memory.d.ts +8 -7
  229. package/dist/source/adapters/memory.js +9 -8
  230. package/dist/source/adapters/prisma.d.ts +13 -12
  231. package/dist/source/adapters/prisma.js +22 -25
  232. package/dist/source/conformance.d.ts +18 -11
  233. package/dist/source/conformance.js +17 -11
  234. package/dist/source/connector.d.ts +31 -32
  235. package/dist/source/connector.js +28 -28
  236. package/dist/source/connectorProtocol.d.ts +160 -0
  237. package/dist/source/connectorProtocol.js +162 -0
  238. package/dist/source/contract.d.ts +26 -27
  239. package/dist/source/contract.js +28 -29
  240. package/dist/source/factory.d.ts +46 -58
  241. package/dist/source/factory.js +22 -27
  242. package/dist/source/index.d.ts +7 -9
  243. package/dist/source/index.js +12 -14
  244. package/dist/source/migrations.d.ts +9 -9
  245. package/dist/source/migrations.js +9 -9
  246. package/dist/source/next.d.ts +9 -10
  247. package/dist/source/next.js +6 -7
  248. package/dist/source/pushQueue.d.ts +69 -47
  249. package/dist/source/pushQueue.js +32 -28
  250. package/dist/source/signing.d.ts +46 -17
  251. package/dist/source/signing.js +28 -11
  252. package/dist/source/types.d.ts +121 -104
  253. package/dist/source/types.js +13 -14
  254. package/dist/stores/ObjectStore.d.ts +10 -11
  255. package/dist/stores/ObjectStore.js +11 -12
  256. package/dist/stores/ObjectStoreContract.d.ts +12 -15
  257. package/dist/stores/SyncActionStore.d.ts +7 -11
  258. package/dist/stores/SyncActionStore.js +13 -17
  259. package/dist/surface.d.ts +27 -20
  260. package/dist/surface.js +27 -20
  261. package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +36 -42
  262. package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +76 -76
  263. package/dist/sync/ConnectionManager.d.ts +39 -50
  264. package/dist/sync/ConnectionManager.js +55 -66
  265. package/dist/sync/NetworkProbe.d.ts +24 -29
  266. package/dist/sync/NetworkProbe.js +63 -69
  267. package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +42 -41
  268. package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +59 -54
  269. package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +43 -57
  270. package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +43 -51
  271. package/dist/sync/SyncWebSocket.d.ts +139 -165
  272. package/dist/sync/SyncWebSocket.js +191 -223
  273. package/dist/sync/awaitClaimGrant.d.ts +18 -18
  274. package/dist/sync/awaitClaimGrant.js +11 -11
  275. package/dist/sync/bootstrapApply.d.ts +34 -24
  276. package/dist/sync/bootstrapApply.js +27 -19
  277. package/dist/sync/commitFrames.d.ts +21 -20
  278. package/dist/sync/commitFrames.js +18 -18
  279. package/dist/sync/createClaimStream.d.ts +23 -22
  280. package/dist/sync/createClaimStream.js +105 -23
  281. package/dist/sync/createPresenceStream.d.ts +19 -18
  282. package/dist/sync/createPresenceStream.js +25 -26
  283. package/dist/sync/createSnapshot.d.ts +12 -14
  284. package/dist/sync/createSnapshot.js +20 -26
  285. package/dist/sync/credentialLifecycle.d.ts +104 -104
  286. package/dist/sync/credentialLifecycle.js +140 -147
  287. package/dist/sync/deltaPipeline.d.ts +36 -34
  288. package/dist/sync/deltaPipeline.js +64 -65
  289. package/dist/sync/groupChange.d.ts +63 -61
  290. package/dist/sync/groupChange.js +74 -78
  291. package/dist/sync/heartbeat.d.ts +34 -33
  292. package/dist/sync/heartbeat.js +31 -31
  293. package/dist/sync/participants.d.ts +19 -19
  294. package/dist/sync/schemas.d.ts +3 -2
  295. package/dist/sync/schemas.js +14 -10
  296. package/dist/sync/syncCursor.d.ts +17 -21
  297. package/dist/sync/syncCursor.js +17 -21
  298. package/dist/sync/syncPlan.d.ts +28 -36
  299. package/dist/sync/syncPlan.js +18 -19
  300. package/dist/sync/syncPosition.d.ts +54 -49
  301. package/dist/sync/syncPosition.js +57 -52
  302. package/dist/sync/wsFrameHandlers.d.ts +35 -36
  303. package/dist/sync/wsFrameHandlers.js +63 -67
  304. package/dist/testing/fixtures/bootstrap.d.ts +12 -6
  305. package/dist/testing/fixtures/bootstrap.js +12 -6
  306. package/dist/testing/fixtures/deltas.d.ts +30 -33
  307. package/dist/testing/fixtures/deltas.js +30 -33
  308. package/dist/testing/fixtures/models.d.ts +11 -10
  309. package/dist/testing/fixtures/models.js +11 -10
  310. package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
  311. package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
  312. package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -15
  313. package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +12 -10
  314. package/dist/testing/helpers/wait.d.ts +13 -8
  315. package/dist/testing/helpers/wait.js +13 -8
  316. package/dist/testing/index.d.ts +3 -3
  317. package/dist/testing/index.js +2 -2
  318. package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
  319. package/dist/testing/mocks/MockMutationExecutor.js +15 -14
  320. package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
  321. package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
  322. package/dist/testing/mocks/MockSyncContext.d.ts +20 -17
  323. package/dist/testing/mocks/MockSyncContext.js +15 -13
  324. package/dist/testing/mocks/MockSyncStore.d.ts +10 -10
  325. package/dist/testing/mocks/MockSyncStore.js +11 -11
  326. package/dist/testing/mocks/MockWebSocket.d.ts +26 -22
  327. package/dist/testing/mocks/MockWebSocket.js +22 -21
  328. package/dist/transactions/TransactionQueue.d.ts +181 -176
  329. package/dist/transactions/TransactionQueue.js +338 -350
  330. package/dist/transactions/TransactionStore.d.ts +6 -4
  331. package/dist/transactions/TransactionStore.js +6 -4
  332. package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
  333. package/dist/transactions/UnconfirmedWrites.js +104 -0
  334. package/dist/transactions/coalesceRules.d.ts +41 -17
  335. package/dist/transactions/coalesceRules.js +40 -17
  336. package/dist/transactions/commitPayload.d.ts +48 -52
  337. package/dist/transactions/commitPayload.js +48 -57
  338. package/dist/transactions/deltaConfirmation.d.ts +20 -22
  339. package/dist/transactions/deltaConfirmation.js +37 -45
  340. package/dist/transactions/optimisticApply.d.ts +49 -0
  341. package/dist/transactions/optimisticApply.js +65 -0
  342. package/dist/transactions/{persistedReplay.d.ts → replayValidation.d.ts} +28 -22
  343. package/dist/transactions/{persistedReplay.js → replayValidation.js} +33 -27
  344. package/dist/types/global.d.ts +46 -41
  345. package/dist/types/global.js +20 -19
  346. package/dist/types/index.d.ts +71 -77
  347. package/dist/types/index.js +22 -22
  348. package/dist/types/modelData.d.ts +6 -8
  349. package/dist/types/modelData.js +5 -7
  350. package/dist/types/participant.d.ts +10 -11
  351. package/dist/types/participant.js +6 -8
  352. package/dist/types/streams.d.ts +208 -195
  353. package/dist/types/streams.js +7 -7
  354. package/dist/utils/asyncIterator.d.ts +25 -32
  355. package/dist/utils/asyncIterator.js +25 -32
  356. package/dist/utils/duration.d.ts +12 -15
  357. package/dist/utils/duration.js +12 -15
  358. package/dist/utils/mobxSetup.d.ts +53 -0
  359. package/dist/utils/{mobx-setup.js → mobxSetup.js} +42 -98
  360. package/dist/webhooks/events.d.ts +21 -16
  361. package/dist/webhooks/events.js +10 -8
  362. package/dist/webhooks/index.d.ts +5 -7
  363. package/dist/webhooks/index.js +5 -7
  364. package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
  365. package/dist/wire/delta.js +114 -0
  366. package/dist/wire/errorEnvelope.d.ts +30 -31
  367. package/dist/wire/errorEnvelope.js +34 -40
  368. package/dist/wire/frames.d.ts +79 -86
  369. package/dist/wire/frames.js +26 -33
  370. package/dist/wire/index.d.ts +14 -12
  371. package/dist/wire/index.js +30 -26
  372. package/dist/wire/listEnvelope.d.ts +16 -23
  373. package/dist/wire/listEnvelope.js +7 -6
  374. package/dist/wire/protocol.d.ts +25 -32
  375. package/dist/wire/protocol.js +25 -32
  376. package/dist/wire/protocolVersion.d.ts +44 -40
  377. package/dist/wire/protocolVersion.js +44 -40
  378. package/docs/coordination.md +59 -0
  379. package/package.json +11 -10
  380. package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
  381. package/dist/ai-sdk/coordination-context.d.ts +0 -52
  382. package/dist/core/query-utils.d.ts +0 -34
  383. package/dist/core/query-utils.js +0 -59
  384. package/dist/schema/sync-delta-row.js +0 -103
  385. package/dist/schema/sync-delta-wire.js +0 -102
  386. package/dist/server/read-config.d.ts +0 -67
  387. package/dist/server/read-config.js +0 -8
  388. package/dist/server/storage-mode.d.ts +0 -8
  389. package/dist/server/storage-mode.js +0 -28
  390. package/dist/source/connector-protocol.d.ts +0 -159
  391. package/dist/source/connector-protocol.js +0 -161
  392. package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
  393. package/dist/transactions/OptimisticEchoTracker.js +0 -104
  394. package/dist/transactions/mutation-error-handler.d.ts +0 -5
  395. package/dist/transactions/mutation-error-handler.js +0 -39
  396. package/dist/transactions/optimistic.d.ts +0 -24
  397. package/dist/transactions/optimistic.js +0 -45
  398. package/dist/utils/mobx-setup.d.ts +0 -42
@@ -1,8 +1,10 @@
1
1
  /**
2
- * ObjectPool - In-memory model cache with deduplication
3
- *
4
- * Pure memory management without database or registry dependencies.
5
- * Uses static ModelRegistry for model class lookup only.
2
+ * InstanceCache is the in-memory cache of live model instances, keyed by id and
3
+ * deduplicated so each entity has a single instance. It maintains type and
4
+ * foreign-key indexes for fast lookups, evicts entries under a size cap, and
5
+ * notifies subscribers and query views as models are added, updated, or
6
+ * removed. It holds a {@link ModelRegistry} to map between model names and
7
+ * constructor classes, but performs no persistence of its own.
6
8
  */
7
9
  import { Model } from './Model.js';
8
10
  import { ModelRegistry } from './ModelRegistry.js';
@@ -23,9 +25,10 @@ interface DeltaInfo {
23
25
  syncId?: number;
24
26
  }
25
27
  /**
26
- * ObjectPool - Pure in-memory model cache with deduplication
28
+ * The in-memory cache of model instances, keyed by id and deduplicated so each
29
+ * entity resolves to a single instance.
27
30
  */
28
- export declare class ObjectPool {
31
+ export declare class InstanceCache {
29
32
  private entries;
30
33
  private typeIndex;
31
34
  private accessTimes;
@@ -45,12 +48,6 @@ export declare class ObjectPool {
45
48
  subscribe<T extends Model>(modelClass: ModelConstructor<T>, callback: (model: T) => void): () => void;
46
49
  private notifySubscribers;
47
50
  constructor(config?: PoolConfig, modelRegistry?: ModelRegistry);
48
- /**
49
- * 🔧 PRODUCTION FIX: Initialize type indexes for all registered models
50
- * This prevents the "No type index found" error in production where constructor
51
- * references are lost due to minification.
52
- */
53
- private initializeTypeIndexes;
54
51
  private resolveModel;
55
52
  get<T extends Model = Model>(id: string): T | undefined;
56
53
  /**
@@ -115,7 +112,7 @@ export declare class ObjectPool {
115
112
  /**
116
113
  * Throw (instead of warn + return null) when the wire names a model
117
114
  * this client never registered. Passed by the developer-await read
118
- * path (`HydrationCoordinator`'s network leg) so a schema collision
115
+ * path (`OnDemandLoader`'s network leg) so a schema collision
119
116
  * — the org's pushed schema names `Document` but this client only
120
117
  * registered `documents` — surfaces AT the row that failed, with the
121
118
  * known-model list and `ablo status` pointer, instead of bubbling up
@@ -1,10 +1,12 @@
1
1
  /**
2
- * ObjectPool - In-memory model cache with deduplication
3
- *
4
- * Pure memory management without database or registry dependencies.
5
- * Uses static ModelRegistry for model class lookup only.
2
+ * InstanceCache is the in-memory cache of live model instances, keyed by id and
3
+ * deduplicated so each entity has a single instance. It maintains type and
4
+ * foreign-key indexes for fast lookups, evicts entries under a size cap, and
5
+ * notifies subscribers and query views as models are added, updated, or
6
+ * removed. It holds a {@link ModelRegistry} to map between model names and
7
+ * constructor classes, but performs no persistence of its own.
6
8
  */
7
- import { makeObservable, observable, action, computed, runInAction, set } from 'mobx';
9
+ import { makeObservable, observable, action, computed, runInAction } from 'mobx';
8
10
  import { Model } from './Model.js';
9
11
  import { ModelRegistry } from './ModelRegistry.js';
10
12
  import { getContext } from './context.js';
@@ -12,12 +14,13 @@ import { AbloValidationError } from './errors.js';
12
14
  import { ModelScope } from './types/index.js';
13
15
  import { ViewRegistry } from './core/ViewRegistry.js';
14
16
  import { QueryView } from './core/QueryView.js';
15
- // Re-export so existing `import { ModelScope } from './ObjectPool.js'` still resolves
17
+ // Re-exported so `import { ModelScope } from './InstanceCache.js'` resolves
16
18
  export { ModelScope };
17
19
  /**
18
- * ObjectPool - Pure in-memory model cache with deduplication
20
+ * The in-memory cache of model instances, keyed by id and deduplicated so each
21
+ * entity resolves to a single instance.
19
22
  */
20
- export class ObjectPool {
23
+ export class InstanceCache {
21
24
  // Single source of truth for all models (observable for reactivity)
22
25
  entries = observable.map();
23
26
  typeIndex = observable.map();
@@ -28,9 +31,10 @@ export class ObjectPool {
28
31
  // Deduplication tracking
29
32
  recentAdditions = new Map(); // "modelType:modelId" -> timestamp
30
33
  deltaHistory = new Map();
31
- // No intermediate cache layer — getByType() reads typeIndex + entries directly.
32
- // This follows Linear's sync engine pattern: observable data structures ARE the
33
- // reactivity source. No computed getters with conditional cache invalidation.
34
+ // No intermediate cache layer — getByType() reads typeIndex and entries
35
+ // directly. Both are observable, so the data structures are themselves the
36
+ // reactivity source; there are no computed getters with conditional cache
37
+ // invalidation to get wrong.
34
38
  // Foreign key indexes: Map<"ModelType:fieldName", Map<fieldValue, ObservableSet<modelId>>>
35
39
  // Enables O(1) lookups like "all SlideLayer models where slideId = X"
36
40
  // instead of scanning all models of a type and filtering.
@@ -64,10 +68,11 @@ export class ObjectPool {
64
68
  code: 'pool_subscribe_unregistered',
65
69
  });
66
70
  }
67
- if (!this.subscriptions.has(modelName)) {
68
- this.subscriptions.set(modelName, new Set());
71
+ let subs = this.subscriptions.get(modelName);
72
+ if (!subs) {
73
+ subs = new Set();
74
+ this.subscriptions.set(modelName, subs);
69
75
  }
70
- const subs = this.subscriptions.get(modelName);
71
76
  const erased = callback;
72
77
  subs.add(erased);
73
78
  return () => subs.delete(erased);
@@ -101,15 +106,14 @@ export class ObjectPool {
101
106
  gcInterval: config.gcInterval ?? 60000, // 1 minute
102
107
  useWeakRefs: config.useWeakRefs ?? true,
103
108
  };
104
- // 🔧 PROPER FIX: Store model registry reference
109
+ // Store the model registry reference
105
110
  if (!modelRegistry) {
106
- throw new AbloValidationError('ObjectPool requires ModelRegistry for production-safe model name lookup', { code: 'pool_registry_missing' });
111
+ throw new AbloValidationError('InstanceCache requires ModelRegistry for production-safe model name lookup', { code: 'pool_registry_missing' });
107
112
  }
108
113
  this.registry = modelRegistry;
109
- // 🔧 PRODUCTION FIX: Defer type index initialization until first use
110
- // This allows models to be registered after ObjectPool creation
111
- // Type indexes will be initialized on first getByType call
112
- // Linear-style: no computed cache layer. entries + typeIndex are both observable.
114
+ // Type indexes are initialized on first use, so models can be registered
115
+ // after the InstanceCache is created; the first getByType call builds them.
116
+ // No computed cache layer: entries and typeIndex are both observable, and
113
117
  // getByType() reads them directly, so MobX always tracks the dependency.
114
118
  makeObservable(this, {
115
119
  add: action,
@@ -125,24 +129,11 @@ export class ObjectPool {
125
129
  });
126
130
  this.startGC();
127
131
  }
128
- /**
129
- * 🔧 PRODUCTION FIX: Initialize type indexes for all registered models
130
- * This prevents the "No type index found" error in production where constructor
131
- * references are lost due to minification.
132
- */
133
- initializeTypeIndexes() {
134
- const names = this.registry.getRegisteredModelNames();
135
- for (const modelName of names) {
136
- if (!this.typeIndex.has(modelName)) {
137
- this.typeIndex.set(modelName, observable.set());
138
- }
139
- }
140
- }
141
- // No computed getters — getByType() reads typeIndex + entries directly.
142
- // This eliminates the conditional dependency bug where MobX lost tracking
143
- // because _cacheInvalid (non-observable) gated whether entries was read.
144
- // _rebuildCaches and _invalidateCache removed — no cache layer to manage.
145
- // typeIndex + entries are observable and read directly by getByType().
132
+ // No computed getters — getByType() reads typeIndex and entries directly.
133
+ // Both are observable, so MobX always tracks the dependency; there is no
134
+ // conditional cache path that could silently drop a dependency.
135
+ // There is no cache layer to manage: typeIndex and entries are observable
136
+ // and read directly by getByType().
146
137
  resolveModel(entry, id) {
147
138
  if (entry.model)
148
139
  return entry.model;
@@ -157,6 +148,10 @@ export class ObjectPool {
157
148
  }
158
149
  return undefined;
159
150
  }
151
+ // The type parameter appears only in the return position on purpose: this is
152
+ // an ergonomic typed accessor (like Map<K, V>.get) that centralizes what would
153
+ // otherwise be an `as T` cast at every call site.
154
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
160
155
  get(id) {
161
156
  const entry = this.entries.get(id);
162
157
  if (!entry) {
@@ -236,12 +231,12 @@ export class ObjectPool {
236
231
  (history.lastAction === 'U' || history.lastAction === 'D')) {
237
232
  // Internal delta-ordering anomaly that reconciles on the next
238
233
  // catch-up — forensic, not consumer-actionable → debug.
239
- getContext().logger.debug(`ObjectPool.add() SUSPICIOUS: INSERT after ${history.lastAction}`, { modelType, id, syncId: deltaInfo.syncId });
234
+ getContext().logger.debug(`InstanceCache.add() SUSPICIOUS: INSERT after ${history.lastAction}`, { modelType, id, syncId: deltaInfo.syncId });
240
235
  }
241
236
  }
242
237
  // Update delta history
243
238
  this.deltaHistory.set(addKey, {
244
- lastAction: deltaInfo.action || 'U',
239
+ lastAction: deltaInfo.action ?? 'U',
245
240
  lastSyncId: deltaInfo.syncId,
246
241
  timestamp: Date.now(),
247
242
  });
@@ -350,7 +345,7 @@ export class ObjectPool {
350
345
  // loader (`ensureDeckLayers`, `prefetchSlideLayers`, bootstrap
351
346
  // hydration) was in the pool but invisible to `hasMany` lookups
352
347
  // — `slide.layers` returned `[]` until the user clicked a layer
353
- // and SOMETHING else ran a non-batch `add` that happened to
348
+ // and something else ran a non-batch `add` that happened to
354
349
  // populate the FK index as a side effect. The UX symptom was
355
350
  // "slides show empty until you click on one." Adding this one
356
351
  // line closes the gap.
@@ -423,8 +418,8 @@ export class ObjectPool {
423
418
  const entry = this.entries.get(id);
424
419
  if (!entry)
425
420
  continue;
426
- const modelName = entry.model?.getModelName() || entry.weakRef?.deref()?.getModelName();
427
- // FK/type cleanup must run BEFORE entries.delete — see `remove()`
421
+ const modelName = entry.model?.getModelName() ?? entry.weakRef?.deref()?.getModelName();
422
+ // FK/type cleanup must run before entries.delete — see `remove()`
428
423
  // for the full explanation. Same bug, same fix.
429
424
  this.removeFromTypeIndex(id, modelName);
430
425
  this.entries.delete(id);
@@ -432,8 +427,10 @@ export class ObjectPool {
432
427
  if (modelName) {
433
428
  this.viewRegistry.notifyRemoved(modelName, id);
434
429
  }
435
- const model = entry.model || entry.weakRef?.deref();
436
- model?.dispose?.();
430
+ const model = entry.model ?? entry.weakRef?.deref();
431
+ // A non-Model object can reach the pool (see `clear`); only dispose a real one.
432
+ if (typeof model?.dispose === 'function')
433
+ model.dispose();
437
434
  const addKey = modelName ? `${modelName}:${id}` : id;
438
435
  this.recentAdditions.delete(addKey);
439
436
  this.deltaHistory.delete(addKey);
@@ -457,7 +454,7 @@ export class ObjectPool {
457
454
  const entry = this.entries.get(id);
458
455
  if (!entry)
459
456
  return false;
460
- const modelName = entry.model?.getModelName() || entry.weakRef?.deref()?.getModelName();
457
+ const modelName = entry.model?.getModelName() ?? entry.weakRef?.deref()?.getModelName();
461
458
  // Order matters here: `removeFromTypeIndex` → `removeFromForeignKeyIndex`
462
459
  // reads the FK field values off the model via `this.entries.get(id)`.
463
460
  // If we `this.entries.delete(id)` first, the model is gone and the
@@ -465,7 +462,7 @@ export class ObjectPool {
465
462
  // That causes `getByForeignKey(..., parentId)` to report
466
463
  // `matched > returned` (dropped-no-entry) and, on the UI, keeps the
467
464
  // stale layer visible until the next reload rebuilds the index
468
- // from fresh data. Do the FK/type cleanup FIRST, then delete the
465
+ // from fresh data. Do the FK/type cleanup first, then delete the
469
466
  // entry.
470
467
  runInAction(() => {
471
468
  this.removeFromTypeIndex(id, modelName);
@@ -476,8 +473,10 @@ export class ObjectPool {
476
473
  if (modelName) {
477
474
  this.viewRegistry.notifyRemoved(modelName, id);
478
475
  }
479
- const model = entry.model || entry.weakRef?.deref();
480
- model?.dispose?.();
476
+ const model = entry.model ?? entry.weakRef?.deref();
477
+ // A non-Model object can reach the pool (see `clear`); only dispose a real one.
478
+ if (typeof model?.dispose === 'function')
479
+ model.dispose();
481
480
  // Clean tracking
482
481
  const addKey = modelName ? `${modelName}:${id}` : id;
483
482
  this.recentAdditions.delete(addKey);
@@ -487,14 +486,14 @@ export class ObjectPool {
487
486
  }
488
487
  removeFromArchive(id) {
489
488
  const entry = this.entries.get(id);
490
- if (!entry || entry.scope !== ModelScope.archived) {
489
+ if (entry?.scope !== ModelScope.archived) {
491
490
  return false;
492
491
  }
493
492
  return this.remove(id);
494
493
  }
495
494
  getByType(modelClass, scope = ModelScope.all) {
496
- // Linear-style: read typeIndex + entries directly. Both are observable maps,
497
- // so MobX always tracks the dependency — no conditional cache path.
495
+ // Read typeIndex and entries directly. Both are observable maps, so MobX
496
+ // always tracks the dependency — there is no conditional cache path.
498
497
  let actualModelName = this.registry.getModelNameFromConstructor(modelClass);
499
498
  if (!actualModelName) {
500
499
  actualModelName = this.registry.getModelNameFromConstructor(modelClass);
@@ -520,7 +519,7 @@ export class ObjectPool {
520
519
  return [];
521
520
  }
522
521
  // Resolve each ID from entries (observable) with scope filtering.
523
- // Note: we do NOT check `instanceof modelClass` because schema-generated
522
+ // Note: we do not check `instanceof modelClass`, because schema-generated
524
523
  // dynamic classes and hand-coded classes are different constructors that
525
524
  // both represent the same model type. The typeIndex lookup by name is
526
525
  // authoritative — if the name matched, the model belongs to this type.
@@ -610,12 +609,12 @@ export class ObjectPool {
610
609
  createFromData(data, ModelClass, opts) {
611
610
  // Support multiple model identifier fields for backwards compatibility
612
611
  const modelName = data.__typename ?? data.__class ?? data.modelName ?? 'Unknown';
613
- const Constructor = ModelClass || this.registry.getModelByName(modelName);
612
+ const Constructor = ModelClass ?? this.registry.getModelByName(modelName);
614
613
  if (!Constructor) {
615
- if (!ModelClass && modelName === 'Unknown') {
614
+ if (modelName === 'Unknown') {
616
615
  // Malformed row with no type marker — dropped, but nothing the consumer
617
616
  // can act on (the actionable schema-drift case is handled below) → debug.
618
- getContext().logger.debug('ObjectPool.createFromData: No model identifier found', { data });
617
+ getContext().logger.debug('InstanceCache.createFromData: No model identifier found', { data });
619
618
  getContext().modelDebugLogger?.logError('Unknown', 'CREATE', 'No model identifier found', data);
620
619
  return null;
621
620
  }
@@ -630,16 +629,16 @@ export class ObjectPool {
630
629
  // isn't in your schema, so these rows are silently skipped. Keep at warn,
631
630
  // consumer register (their model name + the `ablo status` fix); forensics ride debug.
632
631
  getContext().logger.warn(`Received data for "${modelName}", which isn't in your schema — these rows will be skipped. Run \`ablo status\` to compare your local schema with the server.`);
633
- getContext().logger.debug(`ObjectPool.createFromData: No constructor found for model "${modelName}"`, { data });
632
+ getContext().logger.debug(`InstanceCache.createFromData: No constructor found for model "${modelName}"`, { data });
634
633
  getContext().modelDebugLogger?.logError(modelName, 'CREATE', `No constructor found for model "${modelName}"`, data);
635
634
  return null;
636
635
  }
637
- // Check if model already exists and UPDATE it instead of creating duplicate
638
- // LINEAR PATTERN: Keep existing model instances alive, just update their data
639
- // This preserves React's references and MobX observation tracking
636
+ // If the model already exists, update it in place instead of creating a
637
+ // duplicate. Keeping the existing instance alive preserves React's
638
+ // references and MobX's observation tracking.
640
639
  if (data.id && this.entries.has(data.id)) {
641
640
  const existing = this.get(data.id);
642
- if (existing && existing.getModelName() === modelName) {
641
+ if (existing?.getModelName() === modelName) {
643
642
  // Same ID and same type - update existing model with new data and return it
644
643
  existing.updateFromData(data);
645
644
  return existing;
@@ -658,7 +657,7 @@ export class ObjectPool {
658
657
  const errorMessage = error instanceof Error ? error.message : String(error);
659
658
  // Internal construction failure — captured via observability below and
660
659
  // re-fetched on resync; the stack is forensic → debug.
661
- getContext().logger.debug(`[ObjectPool.createFromData] FAILED ${modelName}`, { errorMessage, stack: error instanceof Error ? error.stack : undefined });
660
+ getContext().logger.debug(`[InstanceCache.createFromData] FAILED ${modelName}`, { errorMessage, stack: error instanceof Error ? error.stack : undefined });
662
661
  getContext().observability.captureTransactionFailure({
663
662
  context: 'createFromData',
664
663
  modelName,
@@ -682,11 +681,8 @@ export class ObjectPool {
682
681
  const preserveObserved = options.preserveObserved ?? false;
683
682
  const preservedIds = [];
684
683
  const preservedEntries = [];
685
- let disposedCount = 0;
686
- let checkedCount = 0;
687
684
  for (const [id, entry] of this.entries) {
688
- const model = entry.model || entry.weakRef?.deref();
689
- checkedCount++;
685
+ const model = entry.model ?? entry.weakRef?.deref();
690
686
  // Check if this model should be preserved (has active React observers)
691
687
  if (preserveObserved &&
692
688
  model &&
@@ -697,8 +693,12 @@ export class ObjectPool {
697
693
  preservedEntries.push([id, entry]);
698
694
  continue;
699
695
  }
700
- model?.dispose?.();
701
- disposedCount++;
696
+ // `rowAsModel` only casts, so a non-Model object can reach the pool (see
697
+ // the SyncClient no-op UPDATE guard). Guard that `dispose` is actually
698
+ // callable — mirroring the `hasObservedCollections` typeof-check above —
699
+ // rather than assume every pooled entry is a real Model.
700
+ if (typeof model?.dispose === 'function')
701
+ model.dispose();
702
702
  }
703
703
  // Save access times for preserved entries before clearing
704
704
  const preservedAccessTimes = new Map();
@@ -726,7 +726,7 @@ export class ObjectPool {
726
726
  // Re-add preserved entries (also rebuilds foreign key indexes via addToTypeIndex)
727
727
  for (const [id, entry] of preservedEntries) {
728
728
  this.entries.set(id, entry);
729
- const model = entry.model || entry.weakRef?.deref();
729
+ const model = entry.model ?? entry.weakRef?.deref();
730
730
  if (model) {
731
731
  this.addToTypeIndex(id, model.getModelName());
732
732
  }
@@ -782,9 +782,9 @@ export class ObjectPool {
782
782
  scopeCounts.live++;
783
783
  else if (entry.scope === ModelScope.archived)
784
784
  scopeCounts.archived++;
785
- const modelName = entry.model?.getModelName() || entry.weakRef?.deref()?.getModelName();
785
+ const modelName = entry.model?.getModelName() ?? entry.weakRef?.deref()?.getModelName();
786
786
  if (modelName) {
787
- typeCounts.set(modelName, (typeCounts.get(modelName) || 0) + 1);
787
+ typeCounts.set(modelName, (typeCounts.get(modelName) ?? 0) + 1);
788
788
  }
789
789
  }
790
790
  return {
@@ -825,12 +825,12 @@ export class ObjectPool {
825
825
  let skippedObserved = 0;
826
826
  for (const [id, entry] of this.entries) {
827
827
  // Check if model has expired based on last access time
828
- const lastAccessed = this.accessTimes.get(id) || 0;
828
+ const lastAccessed = this.accessTimes.get(id) ?? 0;
829
829
  if (now - lastAccessed > this.config.maxAge) {
830
- // CRITICAL: Check if model has observed collections before GC
831
- // Following MobX best practice: don't dispose models being observed by React
830
+ // Do not GC a model that has observed collections disposing one
831
+ // React is still observing would break it (per MobX guidance).
832
832
  // See: https://mobx.js.org/lazy-observables.html
833
- const model = entry.model || entry.weakRef?.deref();
833
+ const model = entry.model ?? entry.weakRef?.deref();
834
834
  if (model &&
835
835
  typeof model.hasObservedCollections === 'function' &&
836
836
  model.hasObservedCollections()) {
@@ -871,7 +871,7 @@ export class ObjectPool {
871
871
  }
872
872
  }
873
873
  if (skippedObserved > 0) {
874
- getContext().logger.debug(`[ObjectPool GC] Skipped ${skippedObserved} models with active React observers`);
874
+ getContext().logger.debug(`[InstanceCache GC] Skipped ${skippedObserved} models with active React observers`);
875
875
  }
876
876
  // Also clean up old tracking data
877
877
  this.clearDeltaHistory();
@@ -885,7 +885,9 @@ export class ObjectPool {
885
885
  this.gcTimer = setInterval(() => this.gc(), this.config.gcInterval);
886
886
  // Don't hold a headless Node process open just for pool GC — without
887
887
  // this, an agent that never calls disconnect() can never exit. No-op in
888
- // browsers (where setInterval returns a number without `unref`).
888
+ // browsers (where setInterval returns a number without `unref`), which is
889
+ // why the call is optional even though the Node timer type always has it.
890
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
889
891
  this.gcTimer.unref?.();
890
892
  }
891
893
  stopGC() {
@@ -900,13 +902,13 @@ export class ObjectPool {
900
902
  let oldestTime = Date.now();
901
903
  for (const [id, entry] of this.entries) {
902
904
  // Skip models that are being observed by React - they must stay alive
903
- const model = entry.model || entry.weakRef?.deref();
905
+ const model = entry.model ?? entry.weakRef?.deref();
904
906
  if (model &&
905
907
  typeof model.hasObservedCollections === 'function' &&
906
908
  model.hasObservedCollections()) {
907
909
  continue;
908
910
  }
909
- const entryAccessTime = this.accessTimes.get(id) || 0;
911
+ const entryAccessTime = this.accessTimes.get(id) ?? 0;
910
912
  if (entryAccessTime < oldestTime) {
911
913
  oldest = [id, entry];
912
914
  oldestTime = entryAccessTime;
@@ -970,7 +972,7 @@ export class ObjectPool {
970
972
  getByForeignKey(modelName, fieldName, fieldValue) {
971
973
  const indexKey = `${modelName}:${fieldName}`;
972
974
  const index = this.foreignKeyIndexes.get(indexKey);
973
- // Both empty-path early-returns below are NORMAL states, not errors:
975
+ // Both empty-path early-returns below are normal states, not errors:
974
976
  // a model with no FK index yet (not populated), or an index with no
975
977
  // entry for this specific parent id (entity genuinely has no
976
978
  // children). These used to `console.warn` diagnostic dumps on every
@@ -1011,7 +1013,7 @@ export class ObjectPool {
1011
1013
  // has dangling refs (legacy orphan deltas, pending CREATE
1012
1014
  // transactions, etc.). Noisy at warn level, useful during
1013
1015
  // investigation.
1014
- getContext().logger.debug('[ObjectPool.getByForeignKey] ROWS DROPPED', {
1016
+ getContext().logger.debug('[InstanceCache.getByForeignKey] ROWS DROPPED', {
1015
1017
  modelName,
1016
1018
  fieldName,
1017
1019
  fieldValue,
@@ -1037,7 +1039,7 @@ export class ObjectPool {
1037
1039
  if (!fields)
1038
1040
  return;
1039
1041
  for (const fieldName of fields) {
1040
- const fieldValue = Reflect.get(model, fieldName);
1042
+ const fieldValue = model.getField(fieldName);
1041
1043
  if (typeof fieldValue !== 'string')
1042
1044
  continue;
1043
1045
  const indexKey = `${modelName}:${fieldName}`;
@@ -1067,7 +1069,7 @@ export class ObjectPool {
1067
1069
  if (!model)
1068
1070
  return;
1069
1071
  for (const fieldName of fields) {
1070
- const fieldValue = Reflect.get(model, fieldName);
1072
+ const fieldValue = model.getField(fieldName);
1071
1073
  if (typeof fieldValue !== 'string')
1072
1074
  continue;
1073
1075
  const indexKey = `${modelName}:${fieldName}`;
@@ -1,12 +1,11 @@
1
1
  /**
2
- * Linear Sync Engine - Lazy Reference Collection
3
- *
4
- * Efficient implementation of one-to-many relationships that loads
5
- * data on-demand with intelligent caching and batching.
2
+ * LazyReferenceCollection implements a lazy-loaded one-to-many relationship.
3
+ * It loads related rows on demand, caches them, and batches lookups so that
4
+ * reading a parent's children does not trigger a query per parent.
6
5
  */
7
6
  import type { Model } from './Model.js';
8
7
  import { Database } from './Database.js';
9
- import { ObjectPool } from './ObjectPool.js';
8
+ import { InstanceCache } from './InstanceCache.js';
10
9
  /**
11
10
  * Options for LazyReferenceCollection behavior
12
11
  */
@@ -23,14 +22,11 @@ export interface LazyCollectionOptions {
23
22
  autoRefresh?: boolean;
24
23
  }
25
24
  /**
26
- * LazyReferenceCollection - Lazy-loaded one-to-many relationships
27
- *
28
- * Key features:
29
- * - Loads from IndexedDB first, then network if needed
30
- * - Automatic batching to prevent N+1 queries
31
- * - Observable for React integration
32
- * - Memory efficient with intelligent caching
33
- * - Support for filtering and sorting
25
+ * A lazy-loaded one-to-many relationship between a parent {@link Model} and
26
+ * its children. It reads from the local store first and falls back to the
27
+ * network, batches lookups to avoid one query per parent, and is observable so
28
+ * a React component re-renders when the set of children changes. Loaded items
29
+ * can be filtered, sorted, and limited through {@link LazyCollectionOptions}.
34
30
  */
35
31
  export declare class LazyReferenceCollection<T extends Model> {
36
32
  private modelName;
@@ -45,7 +41,7 @@ export declare class LazyReferenceCollection<T extends Model> {
45
41
  * Set global dependencies for all LazyReferenceCollection instances
46
42
  * Called once during SyncedStore initialization
47
43
  */
48
- static setDependencies(database: Database, objectPool: ObjectPool): void;
44
+ static setDependencies(database: Database, objectPool: InstanceCache): void;
49
45
  /**
50
46
  * Clear dependencies (e.g., on logout/store disposal)
51
47
  */
@@ -82,7 +78,7 @@ export declare class LazyReferenceCollection<T extends Model> {
82
78
  /**
83
79
  * Get the collection value (triggers hydration if needed).
84
80
  *
85
- * Filters out items whose id is no longer in the ObjectPool. The
81
+ * Filters out items whose id is no longer in the InstanceCache. The
86
82
  * local `items` array isn't auto-synced with `pool.remove()` — a
87
83
  * deleted entity would linger here until hydrate() re-runs on
88
84
  * reload. Reading `pool.has(item.id)` inside this computed getter
@@ -1,23 +1,19 @@
1
1
  /**
2
- * Linear Sync Engine - Lazy Reference Collection
3
- *
4
- * Efficient implementation of one-to-many relationships that loads
5
- * data on-demand with intelligent caching and batching.
2
+ * LazyReferenceCollection implements a lazy-loaded one-to-many relationship.
3
+ * It loads related rows on demand, caches them, and batches lookups so that
4
+ * reading a parent's children does not trigger a query per parent.
6
5
  */
7
6
  import { makeObservable, observable, action, computed, onBecomeObserved, onBecomeUnobserved, } from 'mobx';
8
7
  import { Database } from './Database.js';
9
- import { ObjectPool } from './ObjectPool.js';
8
+ import { InstanceCache } from './InstanceCache.js';
10
9
  import { getActiveRegistry } from './ModelRegistry.js';
11
10
  import { AbloValidationError } from './errors.js';
12
11
  /**
13
- * LazyReferenceCollection - Lazy-loaded one-to-many relationships
14
- *
15
- * Key features:
16
- * - Loads from IndexedDB first, then network if needed
17
- * - Automatic batching to prevent N+1 queries
18
- * - Observable for React integration
19
- * - Memory efficient with intelligent caching
20
- * - Support for filtering and sorting
12
+ * A lazy-loaded one-to-many relationship between a parent {@link Model} and
13
+ * its children. It reads from the local store first and falls back to the
14
+ * network, batches lookups to avoid one query per parent, and is observable so
15
+ * a React component re-renders when the set of children changes. Loaded items
16
+ * can be filtered, sorted, and limited through {@link LazyCollectionOptions}.
21
17
  */
22
18
  export class LazyReferenceCollection {
23
19
  modelName;
@@ -132,7 +128,7 @@ export class LazyReferenceCollection {
132
128
  /**
133
129
  * Get the collection value (triggers hydration if needed).
134
130
  *
135
- * Filters out items whose id is no longer in the ObjectPool. The
131
+ * Filters out items whose id is no longer in the InstanceCache. The
136
132
  * local `items` array isn't auto-synced with `pool.remove()` — a
137
133
  * deleted entity would linger here until hydrate() re-runs on
138
134
  * reload. Reading `pool.has(item.id)` inside this computed getter
@@ -262,7 +258,7 @@ export class LazyReferenceCollection {
262
258
  throw new AbloValidationError(`Database dependency not provided to LazyReferenceCollection for ${this.modelName}`, { code: 'lazy_ref_db_missing' });
263
259
  }
264
260
  if (!this.objectPool) {
265
- throw new AbloValidationError(`ObjectPool dependency not provided to LazyReferenceCollection for ${this.modelName}`, { code: 'lazy_ref_pool_missing' });
261
+ throw new AbloValidationError(`InstanceCache dependency not provided to LazyReferenceCollection for ${this.modelName}`, { code: 'lazy_ref_pool_missing' });
266
262
  }
267
263
  const store = this.database.getStore(this.modelName);
268
264
  const rawData = store ? await store.getAllFromIndex(this.foreignKey, this.parent.id) : [];
@@ -282,7 +278,7 @@ export class LazyReferenceCollection {
282
278
  // narrow-checked here rather than assumed.
283
279
  if (typeof id !== 'string')
284
280
  continue;
285
- // Check if already in ObjectPool
281
+ // Check if already in InstanceCache
286
282
  let model = this.objectPool.get(id);
287
283
  if (!model) {
288
284
  // Create new model instance