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