@abloatai/ablo 0.26.0 → 0.28.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 (418) hide show
  1. package/CHANGELOG.md +42 -2
  2. package/README.md +102 -86
  3. package/dist/BaseSyncedStore.d.ts +85 -88
  4. package/dist/BaseSyncedStore.js +134 -151
  5. package/dist/Database.d.ts +68 -69
  6. package/dist/Database.js +316 -135
  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 +54 -52
  12. package/dist/Model.js +78 -62
  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 +122 -118
  18. package/dist/SyncClient.js +541 -245
  19. package/dist/adapters/alwaysOnline.d.ts +6 -8
  20. package/dist/adapters/alwaysOnline.js +6 -8
  21. package/dist/adapters/inMemoryStorage.d.ts +10 -9
  22. package/dist/adapters/inMemoryStorage.js +21 -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 +173 -121
  50. package/dist/client/Ablo.d.ts +97 -74
  51. package/dist/client/Ablo.js +129 -163
  52. package/dist/client/ApiClient.d.ts +30 -19
  53. package/dist/client/ApiClient.js +442 -81
  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 +16 -17
  61. package/dist/client/createInternalComponents.js +26 -31
  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 +59 -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 +78 -87
  76. package/dist/client/options.d.ts +157 -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 +16 -20
  91. package/dist/client/wsMutationExecutor.js +18 -23
  92. package/dist/commit/contract.d.ts +493 -0
  93. package/dist/commit/contract.js +187 -0
  94. package/dist/commit/index.d.ts +6 -0
  95. package/dist/commit/index.js +5 -0
  96. package/dist/context.d.ts +6 -4
  97. package/dist/context.js +6 -4
  98. package/dist/coordination/index.d.ts +10 -8
  99. package/dist/coordination/index.js +14 -12
  100. package/dist/coordination/schema.d.ts +176 -128
  101. package/dist/coordination/schema.js +197 -133
  102. package/dist/coordination/trace.d.ts +9 -10
  103. package/dist/coordination/trace.js +13 -14
  104. package/dist/core/DatabaseManager.d.ts +5 -7
  105. package/dist/core/DatabaseManager.js +15 -19
  106. package/dist/core/QueryProcessor.d.ts +7 -9
  107. package/dist/core/QueryProcessor.js +22 -28
  108. package/dist/core/QueryView.d.ts +8 -8
  109. package/dist/core/QueryView.js +2 -2
  110. package/dist/core/StoreManager.d.ts +14 -14
  111. package/dist/core/StoreManager.js +33 -24
  112. package/dist/core/ViewRegistry.d.ts +5 -5
  113. package/dist/core/ViewRegistry.js +4 -4
  114. package/dist/core/index.d.ts +17 -12
  115. package/dist/core/index.js +32 -26
  116. package/dist/core/openIDBWithTimeout.d.ts +38 -36
  117. package/dist/core/openIDBWithTimeout.js +42 -43
  118. package/dist/core/queryUtils.d.ts +45 -0
  119. package/dist/core/queryUtils.js +69 -0
  120. package/dist/core/storeContract.d.ts +63 -61
  121. package/dist/core/storeContract.js +8 -12
  122. package/dist/environment.d.ts +28 -0
  123. package/dist/environment.js +21 -0
  124. package/dist/errorCodes.d.ts +107 -99
  125. package/dist/errorCodes.js +137 -134
  126. package/dist/errors.d.ts +160 -166
  127. package/dist/errors.js +155 -158
  128. package/dist/index.d.ts +36 -27
  129. package/dist/index.js +91 -86
  130. package/dist/interfaces/index.d.ts +102 -113
  131. package/dist/interfaces/index.js +5 -4
  132. package/dist/keys/index.d.ts +27 -29
  133. package/dist/keys/index.js +41 -40
  134. package/dist/mutators/RecordingTransaction.d.ts +16 -16
  135. package/dist/mutators/RecordingTransaction.js +31 -37
  136. package/dist/mutators/Transaction.d.ts +18 -26
  137. package/dist/mutators/Transaction.js +14 -20
  138. package/dist/mutators/UndoManager.d.ts +124 -131
  139. package/dist/mutators/UndoManager.js +177 -156
  140. package/dist/mutators/defineMutators.d.ts +23 -34
  141. package/dist/mutators/defineMutators.js +14 -20
  142. package/dist/mutators/inverseOp.d.ts +12 -15
  143. package/dist/mutators/inverseOp.js +12 -15
  144. package/dist/mutators/mutateActions.d.ts +10 -9
  145. package/dist/mutators/mutateActions.js +1 -1
  146. package/dist/mutators/readerActions.d.ts +9 -8
  147. package/dist/mutators/readerActions.js +2 -2
  148. package/dist/mutators/undoApply.d.ts +31 -27
  149. package/dist/mutators/undoApply.js +26 -24
  150. package/dist/policy/index.d.ts +5 -3
  151. package/dist/policy/index.js +5 -3
  152. package/dist/policy/types.d.ts +104 -100
  153. package/dist/policy/types.js +67 -66
  154. package/dist/query/client.d.ts +28 -23
  155. package/dist/query/client.js +45 -43
  156. package/dist/query/types.d.ts +37 -60
  157. package/dist/query/types.js +13 -33
  158. package/dist/react/AbloProvider.d.ts +1 -1
  159. package/dist/react/AbloProvider.js +2 -2
  160. package/dist/react/context.d.ts +25 -28
  161. package/dist/react/context.js +9 -10
  162. package/dist/react/index.d.ts +41 -42
  163. package/dist/react/index.js +37 -38
  164. package/dist/react/internalContext.d.ts +17 -19
  165. package/dist/react/useAblo.d.ts +28 -25
  166. package/dist/react/useAblo.js +41 -17
  167. package/dist/react/useCurrentUserId.d.ts +8 -7
  168. package/dist/react/useCurrentUserId.js +8 -7
  169. package/dist/react/useErrorListener.d.ts +7 -7
  170. package/dist/react/useErrorListener.js +10 -11
  171. package/dist/react/useMutationFailureListener.d.ts +8 -8
  172. package/dist/react/useMutationFailureListener.js +8 -8
  173. package/dist/react/useMutators.d.ts +11 -11
  174. package/dist/react/useMutators.js +3 -3
  175. package/dist/react/useReactive.js +2 -2
  176. package/dist/react/useSyncStatus.d.ts +4 -6
  177. package/dist/react/useUndoScope.d.ts +7 -9
  178. package/dist/react/useUndoScope.js +1 -1
  179. package/dist/schema/coordination.d.ts +21 -25
  180. package/dist/schema/coordination.js +21 -25
  181. package/dist/schema/ddl.d.ts +43 -39
  182. package/dist/schema/ddl.js +75 -68
  183. package/dist/schema/ddlLock.d.ts +20 -24
  184. package/dist/schema/ddlLock.js +18 -23
  185. package/dist/schema/diff.d.ts +99 -61
  186. package/dist/schema/diff.js +43 -34
  187. package/dist/schema/field.d.ts +37 -42
  188. package/dist/schema/field.js +35 -48
  189. package/dist/schema/generate.d.ts +12 -12
  190. package/dist/schema/generate.js +12 -12
  191. package/dist/schema/index.d.ts +3 -3
  192. package/dist/schema/index.js +21 -23
  193. package/dist/schema/model.d.ts +118 -143
  194. package/dist/schema/model.js +22 -33
  195. package/dist/schema/openapi.d.ts +10 -9
  196. package/dist/schema/openapi.js +5 -3
  197. package/dist/schema/queries.d.ts +29 -31
  198. package/dist/schema/queries.js +23 -25
  199. package/dist/schema/relation.d.ts +89 -99
  200. package/dist/schema/relation.js +13 -13
  201. package/dist/schema/residency.d.ts +16 -13
  202. package/dist/schema/residency.js +16 -13
  203. package/dist/schema/roles.d.ts +36 -43
  204. package/dist/schema/roles.js +31 -37
  205. package/dist/schema/schema.d.ts +64 -43
  206. package/dist/schema/schema.js +31 -32
  207. package/dist/schema/select.d.ts +13 -13
  208. package/dist/schema/select.js +13 -13
  209. package/dist/schema/serialize.d.ts +28 -31
  210. package/dist/schema/serialize.js +27 -31
  211. package/dist/schema/sugar.d.ts +17 -32
  212. package/dist/schema/sugar.js +14 -29
  213. package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +26 -49
  214. package/dist/schema/syncDeltaRow.js +89 -0
  215. package/dist/schema/tenancy.d.ts +44 -46
  216. package/dist/schema/tenancy.js +46 -48
  217. package/dist/server/adapter.d.ts +58 -58
  218. package/dist/server/adapter.js +13 -14
  219. package/dist/server/commit.d.ts +60 -64
  220. package/dist/server/index.d.ts +9 -10
  221. package/dist/server/index.js +1 -1
  222. package/dist/server/readConfig.d.ts +70 -0
  223. package/dist/server/readConfig.js +8 -0
  224. package/dist/server/storageMode.d.ts +23 -0
  225. package/dist/server/storageMode.js +17 -0
  226. package/dist/source/adapter.d.ts +30 -25
  227. package/dist/source/adapter.js +10 -10
  228. package/dist/source/adapters/drizzle.d.ts +28 -23
  229. package/dist/source/adapters/drizzle.js +30 -25
  230. package/dist/source/adapters/kysely.d.ts +27 -25
  231. package/dist/source/adapters/kysely.js +24 -23
  232. package/dist/source/adapters/memory.d.ts +8 -7
  233. package/dist/source/adapters/memory.js +9 -8
  234. package/dist/source/adapters/prisma.d.ts +13 -12
  235. package/dist/source/adapters/prisma.js +22 -25
  236. package/dist/source/conformance.d.ts +18 -11
  237. package/dist/source/conformance.js +17 -11
  238. package/dist/source/connector.d.ts +31 -32
  239. package/dist/source/connector.js +28 -28
  240. package/dist/source/connectorProtocol.d.ts +160 -0
  241. package/dist/source/connectorProtocol.js +162 -0
  242. package/dist/source/contract.d.ts +26 -27
  243. package/dist/source/contract.js +28 -29
  244. package/dist/source/factory.d.ts +46 -58
  245. package/dist/source/factory.js +22 -27
  246. package/dist/source/index.d.ts +7 -9
  247. package/dist/source/index.js +12 -14
  248. package/dist/source/migrations.d.ts +9 -9
  249. package/dist/source/migrations.js +9 -9
  250. package/dist/source/next.d.ts +9 -10
  251. package/dist/source/next.js +6 -7
  252. package/dist/source/pushQueue.d.ts +69 -47
  253. package/dist/source/pushQueue.js +32 -28
  254. package/dist/source/signing.d.ts +46 -17
  255. package/dist/source/signing.js +28 -11
  256. package/dist/source/types.d.ts +121 -104
  257. package/dist/source/types.js +13 -14
  258. package/dist/stores/ObjectStore.d.ts +24 -12
  259. package/dist/stores/ObjectStore.js +38 -16
  260. package/dist/stores/ObjectStoreContract.d.ts +14 -15
  261. package/dist/stores/SyncActionStore.d.ts +7 -11
  262. package/dist/stores/SyncActionStore.js +13 -17
  263. package/dist/surface.d.ts +28 -21
  264. package/dist/surface.js +29 -20
  265. package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +36 -42
  266. package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +76 -76
  267. package/dist/sync/ConnectionManager.d.ts +39 -50
  268. package/dist/sync/ConnectionManager.js +55 -66
  269. package/dist/sync/NetworkProbe.d.ts +24 -29
  270. package/dist/sync/NetworkProbe.js +63 -69
  271. package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +42 -41
  272. package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +59 -54
  273. package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +43 -57
  274. package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +43 -51
  275. package/dist/sync/SyncWebSocket.d.ts +141 -166
  276. package/dist/sync/SyncWebSocket.js +191 -223
  277. package/dist/sync/awaitClaimGrant.d.ts +18 -18
  278. package/dist/sync/awaitClaimGrant.js +11 -11
  279. package/dist/sync/bootstrapApply.d.ts +34 -24
  280. package/dist/sync/bootstrapApply.js +27 -19
  281. package/dist/sync/commitFrames.d.ts +21 -20
  282. package/dist/sync/commitFrames.js +18 -18
  283. package/dist/sync/createClaimStream.d.ts +23 -22
  284. package/dist/sync/createClaimStream.js +105 -23
  285. package/dist/sync/createPresenceStream.d.ts +19 -18
  286. package/dist/sync/createPresenceStream.js +25 -26
  287. package/dist/sync/createSnapshot.d.ts +12 -14
  288. package/dist/sync/createSnapshot.js +20 -26
  289. package/dist/sync/credentialLifecycle.d.ts +104 -104
  290. package/dist/sync/credentialLifecycle.js +140 -147
  291. package/dist/sync/deltaPipeline.d.ts +36 -34
  292. package/dist/sync/deltaPipeline.js +64 -65
  293. package/dist/sync/groupChange.d.ts +63 -61
  294. package/dist/sync/groupChange.js +74 -78
  295. package/dist/sync/heartbeat.d.ts +34 -33
  296. package/dist/sync/heartbeat.js +31 -31
  297. package/dist/sync/participants.d.ts +19 -19
  298. package/dist/sync/persistedPrefix.d.ts +12 -0
  299. package/dist/sync/persistedPrefix.js +22 -0
  300. package/dist/sync/schemas.d.ts +3 -2
  301. package/dist/sync/schemas.js +14 -10
  302. package/dist/sync/syncCursor.d.ts +17 -21
  303. package/dist/sync/syncCursor.js +17 -21
  304. package/dist/sync/syncPlan.d.ts +28 -36
  305. package/dist/sync/syncPlan.js +18 -19
  306. package/dist/sync/syncPosition.d.ts +54 -49
  307. package/dist/sync/syncPosition.js +57 -52
  308. package/dist/sync/wsFrameHandlers.d.ts +35 -36
  309. package/dist/sync/wsFrameHandlers.js +63 -67
  310. package/dist/testing/fixtures/bootstrap.d.ts +12 -6
  311. package/dist/testing/fixtures/bootstrap.js +12 -6
  312. package/dist/testing/fixtures/deltas.d.ts +30 -33
  313. package/dist/testing/fixtures/deltas.js +30 -33
  314. package/dist/testing/fixtures/models.d.ts +11 -10
  315. package/dist/testing/fixtures/models.js +11 -10
  316. package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
  317. package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
  318. package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -15
  319. package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +12 -10
  320. package/dist/testing/helpers/wait.d.ts +13 -8
  321. package/dist/testing/helpers/wait.js +13 -8
  322. package/dist/testing/index.d.ts +5 -3
  323. package/dist/testing/index.js +3 -2
  324. package/dist/testing/mocks/FakeDatabase.d.ts +18 -0
  325. package/dist/testing/mocks/FakeDatabase.js +10 -0
  326. package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
  327. package/dist/testing/mocks/MockMutationExecutor.js +15 -14
  328. package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
  329. package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
  330. package/dist/testing/mocks/MockSyncContext.d.ts +20 -17
  331. package/dist/testing/mocks/MockSyncContext.js +15 -13
  332. package/dist/testing/mocks/MockSyncStore.d.ts +10 -10
  333. package/dist/testing/mocks/MockSyncStore.js +11 -11
  334. package/dist/testing/mocks/MockWebSocket.d.ts +28 -23
  335. package/dist/testing/mocks/MockWebSocket.js +22 -21
  336. package/dist/transactions/TransactionQueue.d.ts +244 -181
  337. package/dist/transactions/TransactionQueue.js +929 -423
  338. package/dist/transactions/TransactionStore.d.ts +6 -4
  339. package/dist/transactions/TransactionStore.js +6 -4
  340. package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
  341. package/dist/transactions/UnconfirmedWrites.js +104 -0
  342. package/dist/transactions/coalesceRules.d.ts +41 -17
  343. package/dist/transactions/coalesceRules.js +40 -17
  344. package/dist/transactions/commitEnvelope.d.ts +132 -0
  345. package/dist/transactions/commitEnvelope.js +139 -0
  346. package/dist/transactions/commitOutboxStore.d.ts +32 -0
  347. package/dist/transactions/commitOutboxStore.js +26 -0
  348. package/dist/transactions/commitPayload.d.ts +63 -52
  349. package/dist/transactions/commitPayload.js +54 -57
  350. package/dist/transactions/deltaConfirmation.d.ts +20 -22
  351. package/dist/transactions/deltaConfirmation.js +37 -45
  352. package/dist/transactions/httpCommitEnvelope.d.ts +43 -0
  353. package/dist/transactions/httpCommitEnvelope.js +179 -0
  354. package/dist/transactions/optimisticApply.d.ts +49 -0
  355. package/dist/transactions/optimisticApply.js +65 -0
  356. package/dist/transactions/replayValidation.d.ts +182 -0
  357. package/dist/transactions/replayValidation.js +156 -0
  358. package/dist/types/global.d.ts +46 -41
  359. package/dist/types/global.js +20 -19
  360. package/dist/types/index.d.ts +71 -77
  361. package/dist/types/index.js +22 -22
  362. package/dist/types/modelData.d.ts +6 -8
  363. package/dist/types/modelData.js +5 -7
  364. package/dist/types/participant.d.ts +10 -11
  365. package/dist/types/participant.js +6 -8
  366. package/dist/types/streams.d.ts +208 -195
  367. package/dist/types/streams.js +7 -7
  368. package/dist/utils/asyncIterator.d.ts +25 -32
  369. package/dist/utils/asyncIterator.js +25 -32
  370. package/dist/utils/duration.d.ts +12 -15
  371. package/dist/utils/duration.js +12 -15
  372. package/dist/utils/mobxSetup.d.ts +53 -0
  373. package/dist/utils/{mobx-setup.js → mobxSetup.js} +42 -98
  374. package/dist/webhooks/events.d.ts +21 -16
  375. package/dist/webhooks/events.js +10 -8
  376. package/dist/webhooks/index.d.ts +5 -7
  377. package/dist/webhooks/index.js +5 -7
  378. package/dist/wire/bootstrapReason.d.ts +9 -0
  379. package/dist/wire/bootstrapReason.js +8 -0
  380. package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
  381. package/dist/wire/delta.js +114 -0
  382. package/dist/wire/errorEnvelope.d.ts +30 -31
  383. package/dist/wire/errorEnvelope.js +34 -40
  384. package/dist/wire/frames.d.ts +315 -86
  385. package/dist/wire/frames.js +47 -33
  386. package/dist/wire/index.d.ts +18 -14
  387. package/dist/wire/index.js +32 -27
  388. package/dist/wire/listEnvelope.d.ts +16 -23
  389. package/dist/wire/listEnvelope.js +7 -6
  390. package/dist/wire/protocol.d.ts +25 -32
  391. package/dist/wire/protocol.js +25 -32
  392. package/dist/wire/protocolVersion.d.ts +44 -40
  393. package/dist/wire/protocolVersion.js +44 -40
  394. package/docs/api.md +10 -10
  395. package/docs/coordination.md +59 -0
  396. package/docs/mcp.md +1 -1
  397. package/package.json +17 -11
  398. package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
  399. package/dist/ai-sdk/coordination-context.d.ts +0 -52
  400. package/dist/core/query-utils.d.ts +0 -34
  401. package/dist/core/query-utils.js +0 -59
  402. package/dist/schema/sync-delta-row.js +0 -103
  403. package/dist/schema/sync-delta-wire.js +0 -102
  404. package/dist/server/read-config.d.ts +0 -67
  405. package/dist/server/read-config.js +0 -8
  406. package/dist/server/storage-mode.d.ts +0 -8
  407. package/dist/server/storage-mode.js +0 -28
  408. package/dist/source/connector-protocol.d.ts +0 -159
  409. package/dist/source/connector-protocol.js +0 -161
  410. package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
  411. package/dist/transactions/OptimisticEchoTracker.js +0 -104
  412. package/dist/transactions/mutation-error-handler.d.ts +0 -5
  413. package/dist/transactions/mutation-error-handler.js +0 -39
  414. package/dist/transactions/optimistic.d.ts +0 -24
  415. package/dist/transactions/optimistic.js +0 -45
  416. package/dist/transactions/persistedReplay.d.ts +0 -93
  417. package/dist/transactions/persistedReplay.js +0 -105
  418. package/dist/utils/mobx-setup.d.ts +0 -42
@@ -1,28 +1,29 @@
1
1
  /**
2
- * HydrationCoordinator — the lazy-load lane of the sync engine.
2
+ * Loads model rows on demand — the lazy-load path of the sync engine. When
3
+ * something needs an entity that the initial bootstrap did not fetch,
4
+ * {@link OnDemandLoader.fetch | fetch} finds it and populates the
5
+ * in-memory {@link InstanceCache} so the rest of the engine can read it normally.
3
6
  *
4
- * Bridges "I need this entity but bootstrap didn't fetch it" pool
5
- * hydration. Replaces the per-app loader files (documentLoaders,
6
- * slideLayerLoaders, layoutLoaders, ensureVaultFiles, ensureDataroomFiles)
7
- * with one engine-level path.
7
+ * A fetch resolves against three tiers in order, stopping at the first that can
8
+ * answer:
9
+ * 1. The object pool — if rows already in memory match the query, return them.
10
+ * 2. Local storage if matching rows exist there, hydrate the pool and return.
11
+ * 3. The network — post the query to `/sync/query`, then hydrate both the pool
12
+ * and local storage.
8
13
  *
9
- * Lookup order on `fetch(modelName, where)`:
10
- * 1. ObjectPool if rows already match the where, return them (cheap).
11
- * 2. IndexedDB if matching rows exist locally, hydrate pool, return.
12
- * 3. Network — `postQuery` against `/sync/query`, hydrate pool + IDB.
14
+ * Concurrent calls with the same query key share one in-flight promise, so a
15
+ * burst of components mounting and asking for the same data on first paint
16
+ * triggers a single fetch rather than one each.
13
17
  *
14
- * Single-flight dedup: concurrent calls with the same query key share
15
- * one in-flight promise. Prevents the loader anti-pattern where N
16
- * components mount and fire N identical hydrations on first paint.
17
- *
18
- * The coordinator does NOT replace bootstrap (full sync of `instant`
19
- * models) or live deltas (WS push). It only fills the gap for `lazy`
20
- * models accessed by id/where after the engine is ready.
18
+ * The coordinator does not replace the bootstrap (which fully syncs instantly
19
+ * loaded models) or the live delta stream (pushed over the WebSocket). It only
20
+ * fills the gap for lazily loaded models read by id or filter after the engine
21
+ * is ready.
21
22
  */
22
- import { ModelScope } from '../ObjectPool.js';
23
+ import { ModelScope } from '../InstanceCache.js';
23
24
  import { AbloValidationError } from '../errors.js';
24
25
  import { postQuery } from '../query/client.js';
25
- export class HydrationCoordinator {
26
+ export class OnDemandLoader {
26
27
  opts;
27
28
  inFlight = new Map();
28
29
  /**
@@ -36,9 +37,9 @@ export class HydrationCoordinator {
36
37
  /**
37
38
  * Query keys that have been satisfied from the server at least once this
38
39
  * session. Once a key is here, repeat reads serve purely from the pool with
39
- * NO network: the WebSocket delta stream keeps those pool rows fresh, so
40
- * re-running the HTTP query would be redundant polling. This is the ledger
41
- * that stops an already-open deck from re-querying on every navigation.
40
+ * no network round-trip: the WebSocket delta stream keeps those pool rows
41
+ * fresh, so re-running the HTTP query would be redundant polling. This ledger
42
+ * is what stops an already-open view from re-querying on every navigation.
42
43
  *
43
44
  * Cleared on reconnect (see {@link invalidate}) so that, after a connection
44
45
  * drop where deltas may have been missed, the next read re-confirms once.
@@ -46,16 +47,20 @@ export class HydrationCoordinator {
46
47
  hydratedKeys = new Set();
47
48
  authTokenProvider = null;
48
49
  /**
49
- * The auth-recovery backbone (the store's `recoverFromAuthRejection`),
50
- * late-bound like {@link setAuthTokenProvider} because the store doesn't
50
+ * The credential-recovery hook (the store's `recoverFromAuthRejection`),
51
+ * late-bound like {@link setAuthTokenProvider} because the store does not
51
52
  * exist yet when the coordinator is constructed. Handed to `postQuery` so a
52
- * 401 on the lazy lane re-mints through the SAME single-flight path the WS
53
- * probe and proactive pre-roll use, then replays once — instead of silently
54
- * returning empty rows against an expired key forever.
53
+ * 401 on the lazy lane re-mints through the same single-flight path the
54
+ * WebSocket probe uses, then replays the query once — instead of silently
55
+ * returning empty rows against an expired key.
55
56
  */
56
57
  credentialRecovery = null;
57
58
  constructor(opts) {
58
59
  this.opts = opts;
60
+ // Reading the deprecated `getCapabilityToken` is deliberate: it's the
61
+ // back-compat shim that keeps older callers who still pass it working
62
+ // until they migrate to `getAuthToken`.
63
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
59
64
  this.authTokenProvider = opts.getAuthToken ?? opts.getCapabilityToken ?? null;
60
65
  }
61
66
  /**
@@ -84,7 +89,7 @@ export class HydrationCoordinator {
84
89
  const ModelClass = this.opts.registry.getModelByName(typename)
85
90
  ?? this.opts.registry.getModelByName(modelName);
86
91
  if (!ModelClass) {
87
- throw new AbloValidationError(`HydrationCoordinator.fetch: unknown model "${modelName}" — ` +
92
+ throw new AbloValidationError(`OnDemandLoader.fetch: unknown model "${modelName}" — ` +
88
93
  `not registered in the schema.`, { code: 'model_not_registered' });
89
94
  }
90
95
  const clauses = normalizeWhere(options?.where);
@@ -114,24 +119,24 @@ export class HydrationCoordinator {
114
119
  const hasExpand = !!(expand && expand.length > 0);
115
120
  // Fast path — this exact query was already satisfied from the server this
116
121
  // session. The WebSocket delta stream has kept the pool fresh since, so a
117
- // repeat read needs ZERO network: serve straight from local. This is what
118
- // stops an already-open deck from re-querying on every navigation when no
122
+ // repeat read needs no network: serve straight from local. This is what
123
+ // stops an already-open view from re-querying on every navigation when no
119
124
  // new deltas have arrived.
120
125
  if (!explicitComplete && this.hydratedKeys.has(queryKey)) {
121
126
  return applyLimit(await this.readLocal(modelName, typename, ModelClass, clauses, hasExpand, expand), options?.limit);
122
127
  }
123
128
  // Not yet hydrated (or an explicit complete read). For a non-complete read
124
- // WITHOUT expand, if there's anything local to show (warm pool, or IDB
125
- // after a reload), hand it back immediately and confirm with the server
126
- // ONCE in the background — then mark the key hydrated so subsequent reads
127
- // are pure-local. First paint never blocks on the network.
129
+ // without expand, if there is anything local to show (a warm pool, or local
130
+ // storage after a reload), hand it back immediately and confirm with the
131
+ // server once in the background — then mark the key hydrated so subsequent
132
+ // reads are purely local. First paint never blocks on the network.
128
133
  //
129
- // Expand queries are deliberately excluded here: a present primary says
130
- // nothing about whether its relations are loaded. Returning the parent now
131
- // would surface it with empty children and let `layersReady` flip before
132
- // the layers exist (the "pop-in" the deck gate guards against). So an
133
- // un-hydrated expand query falls through to the blocking fetch that brings
134
- // parent + children together; the SECOND open is served by the fast path.
134
+ // Expand queries are deliberately excluded here: the presence of a primary
135
+ // row says nothing about whether its relations are loaded. Returning the
136
+ // parent now would surface it with empty children, letting a readiness flag
137
+ // flip before the children exist. So an un-hydrated expand query falls
138
+ // through to the blocking fetch that brings parent and children together;
139
+ // the second open is served by the fast path.
135
140
  if (!explicitComplete && !hasExpand) {
136
141
  const local = await this.readLocal(modelName, typename, ModelClass, clauses, hasExpand, expand);
137
142
  if (local.length > 0) {
@@ -190,10 +195,10 @@ export class HydrationCoordinator {
190
195
  async fetchFromNetwork(modelName, typename, clauses, options) {
191
196
  const networkRows = await this.queryNetwork(modelName, clauses, options);
192
197
  const networkModels = networkRows
193
- // Strict: a row the SERVER returned whose typename this client never
194
- // registered is a genuine schema collision (the org's pushed schema
195
- // differs from local) throw it here, naming the cause, rather than
196
- // silently dropping the row and failing downstream as `entity_not_found`.
198
+ // Strict: a row the server returned whose type name this client never
199
+ // registered is a genuine schema collision (the pushed schema differs
200
+ // from the local one). Throw here, naming the cause, rather than silently
201
+ // dropping the row and failing downstream as `entity_not_found`.
197
202
  .map((raw) => this.hydrateOne(raw, typename, { strict: true }))
198
203
  .filter((m) => m !== null);
199
204
  if (networkModels.length > 0) {
@@ -205,13 +210,13 @@ export class HydrationCoordinator {
205
210
  return networkModels;
206
211
  }
207
212
  /**
208
- * Fire-and-forget the ONE server confirm for a query that was just served
209
- * from local cache but isn't hydrated yet. On success the key is marked
210
- * hydrated, so every later read serves pure-local with no network until a
213
+ * Fires the single background confirm for a query that was just served from
214
+ * local cache but is not hydrated yet. On success the key is marked hydrated,
215
+ * so every later read serves purely from local with no network until a
211
216
  * reconnect invalidates the ledger. Deduped per query key so a render burst
212
- * doesn't stampede. Errors are swallowed — the caller already has a usable
213
- * local snapshot, and a failed confirm leaves the key un-hydrated so the
214
- * next read simply tries again.
217
+ * does not stampede. Errors are swallowed — the caller already has a usable
218
+ * local snapshot, and a failed confirm leaves the key un-hydrated so the next
219
+ * read simply tries again.
215
220
  */
216
221
  scheduleHydratingFetch(queryKey, modelName, typename, clauses, options) {
217
222
  if (this.revalidating.has(queryKey))
@@ -325,7 +330,7 @@ export class HydrationCoordinator {
325
330
  // after a missed delta (WS dropped, tab slept, redeploy) silently
326
331
  // discards the fresh state and the consumer keeps seeing the
327
332
  // birth-time snapshot forever. `updateFromData` is the same
328
- // primitive `ObjectPool.upsert()` uses for delta application,
333
+ // primitive `InstanceCache.upsert()` uses for delta application,
329
334
  // so the behaviour matches "delta-applied" semantics exactly.
330
335
  const existing = this.opts.objectPool.get(obj.id);
331
336
  if (existing) {
@@ -337,9 +342,9 @@ export class HydrationCoordinator {
337
342
  }
338
343
  // Stamp the known relation typename onto the row when the source
339
344
  // (IndexedDB rows, sometimes network rows) didn't carry one. Without
340
- // this, ObjectPool.createFromData falls through to the 'Unknown'
345
+ // this, InstanceCache.createFromData falls through to the 'Unknown'
341
346
  // model-name branch and emits the
342
- // "ObjectPool.createFromData: No model identifier found" warning,
347
+ // "InstanceCache.createFromData: No model identifier found" warning,
343
348
  // failing to hydrate the entity from cache (network path then has to
344
349
  // re-populate it). The typename comes from the schema relation
345
350
  // (`'SlideLayer'`, `'SlideLayoutLayer'`, etc.) so no guessing involved.
@@ -352,7 +357,7 @@ export class HydrationCoordinator {
352
357
  * `postgres.camel` driver leaves behind when the server's SQL
353
358
  * bakes `__typename` into a JSONB literal — the driver's
354
359
  * snake↔camel transform misreads `__typename` as `_typename` with
355
- * a leading underscore and produces `_Typename`. ObjectPool only
360
+ * a leading underscore and produces `_Typename`. InstanceCache only
356
361
  * recognises `__typename`, so without this step nested rows fall
357
362
  * through to the 'Unknown' branch and never instantiate.
358
363
  */
@@ -471,7 +476,7 @@ export class HydrationCoordinator {
471
476
  resolveTypename(modelName) {
472
477
  // Schema is the source of truth for wire typenames. The model proxy
473
478
  // is keyed by camelCase plural (`slideLayers`) but the wire query +
474
- // ObjectPool typeIndex use the typename (`SlideLayer`).
479
+ // InstanceCache typeIndex use the typename (`SlideLayer`).
475
480
  const def = this.opts.schema
476
481
  .models?.[modelName];
477
482
  return def?.typename ?? modelName;
@@ -1,51 +1,42 @@
1
1
  /**
2
- * AreaOfInterestManager client-side hysteresis + prominence policy over
3
- * the `update_subscription` read primitive.
2
+ * Decides which sync groups a connection subscribes to as the user navigates,
3
+ * and pushes each change through the {@link SubscriptionTransport}'s
4
+ * `update_subscription` call. It smooths two kinds of churn so that opening and
5
+ * closing entities does not turn into a storm of subscription changes.
4
6
  *
5
- * Game netcode never thrashes its area-of-interest on a boundary: a cell
6
- * you walk out of stays subscribed for a margin before it's dropped
7
- * (hysteresis), and "important" entities stay relevant from farther away
8
- * (prominence). This manager applies both to Ablo sync groups:
7
+ * The first is hysteresis. Calling {@link SubscriptionManager.leave | leave}
8
+ * on a group does not unsubscribe it right away; the group stays subscribed for
9
+ * a grace period — its warm window — and drops only once that window lapses.
10
+ * Re-entering within the window costs nothing, since the group was never
11
+ * dropped, so rapid back-and-forth navigation becomes a cache hit rather than a
12
+ * repeated bootstrap.
9
13
  *
10
- * - `enter(group)` / `leave(group)` move read interest as the user opens
11
- * and closes entities (decks, sheets, docs). A `leave` does NOT
12
- * immediately unsubscribe the group goes WARM with a TTL and stays
13
- * in the effective set. Re-entering within the window is a no-op
14
- * (already subscribed → no bootstrap), and only when the warm TTL
15
- * lapses does the group actually drop. This is the boundary hysteresis
16
- * that turns deck-tab flipping from a re-bootstrap storm into a
17
- * cache hit.
14
+ * The second is prominence. A group that holds an active write claim is pinned
15
+ * (see {@link SubscriptionManager.pin | pin}) and stays subscribed regardless
16
+ * of navigation, so a row someone is actively editing never loses its live
17
+ * updates. The `baseGroups` are permanent scopes that are always subscribed.
18
18
  *
19
- * - `pin(group)` / `unpin(group)` express prominence: a group that holds
20
- * an active claim (write-claim) is pinned and never goes warm or
21
- * expires while pinned. The claim machinery is the prominence oracle
22
- * the row two agents are fighting over stays subscribed regardless of
23
- * navigation.
24
- *
25
- * - `baseGroups` are permanent infrastructure scopes (e.g. `org:<id>`,
26
- * `user:<id>`) that are always in the effective set.
27
- *
28
- * The effective set is recomputed and diffed against what was last sent;
29
- * the transport's `update_subscription` is only called when it actually
30
- * changes, so hysteresis genuinely suppresses network churn rather than
31
- * just deferring it.
32
- *
33
- * Transport-agnostic: it depends only on {@link SubscriptionTransport},
34
- * which `SyncWebSocket` satisfies structurally. `now` and the sweep timer
35
- * are injectable so the policy is deterministic under test.
19
+ * The manager recomputes the full desired set on every change, diffs it against
20
+ * the set the transport last confirmed, and calls `update_subscription` only
21
+ * when the set actually changes so the smoothing suppresses network traffic
22
+ * rather than merely deferring it. It depends only on
23
+ * {@link SubscriptionTransport}, which {@link SyncWebSocket} satisfies. The
24
+ * clock and the sweep timer are injectable so the policy is deterministic under
25
+ * test.
36
26
  */
37
27
  /** The single capability this manager needs from the connection. */
38
28
  export interface SubscriptionTransport {
39
29
  /**
40
- * Replace the connection's read interest with the COMPLETE group set.
41
- * Resolves with the server's effective set (which the manager treats as
42
- * authoritative for its next diff).
30
+ * Replaces the connection's read interest with the complete group set. This
31
+ * is a full replace, not an incremental add or remove. Resolves with the
32
+ * effective set the server applied, which the manager treats as authoritative
33
+ * for its next diff.
43
34
  */
44
35
  updateSubscription(syncGroups: readonly string[]): Promise<{
45
36
  syncGroups: string[];
46
37
  }>;
47
38
  }
48
- export interface AreaOfInterestOptions {
39
+ export interface SubscriptionManagerOptions {
49
40
  /** Connection to drive. `SyncWebSocket` satisfies this structurally. */
50
41
  transport: SubscriptionTransport;
51
42
  /**
@@ -59,17 +50,16 @@ export interface AreaOfInterestOptions {
59
50
  */
60
51
  warmTtlMs?: number;
61
52
  /**
62
- * Maximum number of warm (left-but-still-subscribed) groups. Under heavy
63
- * navigation opening and closing many entities quickly warm groups
64
- * would otherwise pile up until each TTL lapses, inflating the connection's
65
- * subscription set. When the cap is exceeded, the LEAST-recently-warmed
66
- * group is evicted immediately (dropped) instead of waiting for its TTL.
67
- * This is the bounded relevant-set discipline from game netcode. Default 16.
53
+ * The maximum number of warm (left but still subscribed) groups. Under heavy
54
+ * navigation, warm groups would otherwise pile up until each one's window
55
+ * lapses, inflating the connection's subscription set. When the cap is
56
+ * exceeded, the least-recently-warmed group is dropped immediately instead of
57
+ * waiting for its window. Default 16.
68
58
  */
69
59
  maxWarm?: number;
70
60
  /**
71
61
  * Auto-run the warm-expiry sweep on this cadence. Set `0` to disable and
72
- * drive {@link AreaOfInterestManager.sweep} yourself (tests do this).
62
+ * drive {@link SubscriptionManager.sweep} yourself (tests do this).
73
63
  * Default = `warmTtlMs` (checks about once per margin).
74
64
  */
75
65
  sweepIntervalMs?: number;
@@ -81,7 +71,7 @@ export interface AreaOfInterestOptions {
81
71
  */
82
72
  scheduler?: (fn: () => void, intervalMs: number) => () => void;
83
73
  }
84
- export declare class AreaOfInterestManager {
74
+ export declare class SubscriptionManager {
85
75
  private readonly transport;
86
76
  private readonly baseGroups;
87
77
  private readonly warmTtlMs;
@@ -99,7 +89,7 @@ export declare class AreaOfInterestManager {
99
89
  private inFlight;
100
90
  private dirty;
101
91
  private readonly cancelSweep;
102
- constructor(options: AreaOfInterestOptions);
92
+ constructor(options: SubscriptionManagerOptions);
103
93
  /**
104
94
  * Move a group into the warm set with a fresh TTL, maintaining LRU order
105
95
  * and the `maxWarm` cap. JS `Map` preserves insertion order, so deleting
@@ -134,19 +124,15 @@ export declare class AreaOfInterestManager {
134
124
  /** The set the manager believes is subscribed (post-confirmation). */
135
125
  effectiveGroups(): string[];
136
126
  /**
137
- * Re-assert the full desired set against the transport, forgetting what
138
- * was previously confirmed. Call after a reconnect: a fresh
139
- * `SyncWebSocket` instance starts from the connect-time URL groups, so
140
- * the manager's `lastSent` diff baseline is stale. Clearing it forces
141
- * one `update_subscription` that re-establishes the live interest on the
142
- * new socket.
143
- *
144
- * Resetting `lastSent` makes the next reconcile unconditionally re-push
145
- * the current desired set (one `update_subscription` frame) so the fresh
146
- * socket's server-side index matches local interest, even if warm/pinned
147
- * groups drifted across the disconnect window. The connect-time URL
148
- * already carries the last-acked set, so this is a correction frame, not
149
- * the primary mechanism.
127
+ * Re-asserts the full desired set against the transport, forgetting what was
128
+ * previously confirmed. Call this after a reconnect: a fresh
129
+ * {@link SyncWebSocket} starts from the sync groups named in the connect-time
130
+ * URL, so the manager's diff baseline no longer reflects the new socket.
131
+ * Clearing that baseline makes the next reconcile push one
132
+ * `update_subscription` frame that re-establishes the current interest —
133
+ * including any warm or pinned groups that drifted while the connection was
134
+ * down. The connect-time URL already carries the last-acknowledged set, so
135
+ * this is a correction, not the primary mechanism.
150
136
  */
151
137
  resync(): Promise<void>;
152
138
  /** Stop the sweep timer. The connection is unaffected. */
@@ -1,38 +1,28 @@
1
1
  /**
2
- * AreaOfInterestManager client-side hysteresis + prominence policy over
3
- * the `update_subscription` read primitive.
2
+ * Decides which sync groups a connection subscribes to as the user navigates,
3
+ * and pushes each change through the {@link SubscriptionTransport}'s
4
+ * `update_subscription` call. It smooths two kinds of churn so that opening and
5
+ * closing entities does not turn into a storm of subscription changes.
4
6
  *
5
- * Game netcode never thrashes its area-of-interest on a boundary: a cell
6
- * you walk out of stays subscribed for a margin before it's dropped
7
- * (hysteresis), and "important" entities stay relevant from farther away
8
- * (prominence). This manager applies both to Ablo sync groups:
7
+ * The first is hysteresis. Calling {@link SubscriptionManager.leave | leave}
8
+ * on a group does not unsubscribe it right away; the group stays subscribed for
9
+ * a grace period — its warm window — and drops only once that window lapses.
10
+ * Re-entering within the window costs nothing, since the group was never
11
+ * dropped, so rapid back-and-forth navigation becomes a cache hit rather than a
12
+ * repeated bootstrap.
9
13
  *
10
- * - `enter(group)` / `leave(group)` move read interest as the user opens
11
- * and closes entities (decks, sheets, docs). A `leave` does NOT
12
- * immediately unsubscribe the group goes WARM with a TTL and stays
13
- * in the effective set. Re-entering within the window is a no-op
14
- * (already subscribed → no bootstrap), and only when the warm TTL
15
- * lapses does the group actually drop. This is the boundary hysteresis
16
- * that turns deck-tab flipping from a re-bootstrap storm into a
17
- * cache hit.
14
+ * The second is prominence. A group that holds an active write claim is pinned
15
+ * (see {@link SubscriptionManager.pin | pin}) and stays subscribed regardless
16
+ * of navigation, so a row someone is actively editing never loses its live
17
+ * updates. The `baseGroups` are permanent scopes that are always subscribed.
18
18
  *
19
- * - `pin(group)` / `unpin(group)` express prominence: a group that holds
20
- * an active claim (write-claim) is pinned and never goes warm or
21
- * expires while pinned. The claim machinery is the prominence oracle
22
- * the row two agents are fighting over stays subscribed regardless of
23
- * navigation.
24
- *
25
- * - `baseGroups` are permanent infrastructure scopes (e.g. `org:<id>`,
26
- * `user:<id>`) that are always in the effective set.
27
- *
28
- * The effective set is recomputed and diffed against what was last sent;
29
- * the transport's `update_subscription` is only called when it actually
30
- * changes, so hysteresis genuinely suppresses network churn rather than
31
- * just deferring it.
32
- *
33
- * Transport-agnostic: it depends only on {@link SubscriptionTransport},
34
- * which `SyncWebSocket` satisfies structurally. `now` and the sweep timer
35
- * are injectable so the policy is deterministic under test.
19
+ * The manager recomputes the full desired set on every change, diffs it against
20
+ * the set the transport last confirmed, and calls `update_subscription` only
21
+ * when the set actually changes so the smoothing suppresses network traffic
22
+ * rather than merely deferring it. It depends only on
23
+ * {@link SubscriptionTransport}, which {@link SyncWebSocket} satisfies. The
24
+ * clock and the sweep timer are injectable so the policy is deterministic under
25
+ * test.
36
26
  */
37
27
  function setsEqual(a, b) {
38
28
  if (a.size !== b.size)
@@ -42,7 +32,7 @@ function setsEqual(a, b) {
42
32
  return false;
43
33
  return true;
44
34
  }
45
- export class AreaOfInterestManager {
35
+ export class SubscriptionManager {
46
36
  transport;
47
37
  baseGroups;
48
38
  warmTtlMs;
@@ -165,19 +155,15 @@ export class AreaOfInterestManager {
165
155
  return [...this.lastSent];
166
156
  }
167
157
  /**
168
- * Re-assert the full desired set against the transport, forgetting what
169
- * was previously confirmed. Call after a reconnect: a fresh
170
- * `SyncWebSocket` instance starts from the connect-time URL groups, so
171
- * the manager's `lastSent` diff baseline is stale. Clearing it forces
172
- * one `update_subscription` that re-establishes the live interest on the
173
- * new socket.
174
- *
175
- * Resetting `lastSent` makes the next reconcile unconditionally re-push
176
- * the current desired set (one `update_subscription` frame) so the fresh
177
- * socket's server-side index matches local interest, even if warm/pinned
178
- * groups drifted across the disconnect window. The connect-time URL
179
- * already carries the last-acked set, so this is a correction frame, not
180
- * the primary mechanism.
158
+ * Re-asserts the full desired set against the transport, forgetting what was
159
+ * previously confirmed. Call this after a reconnect: a fresh
160
+ * {@link SyncWebSocket} starts from the sync groups named in the connect-time
161
+ * URL, so the manager's diff baseline no longer reflects the new socket.
162
+ * Clearing that baseline makes the next reconcile push one
163
+ * `update_subscription` frame that re-establishes the current interest —
164
+ * including any warm or pinned groups that drifted while the connection was
165
+ * down. The connect-time URL already carries the last-acknowledged set, so
166
+ * this is a correction, not the primary mechanism.
181
167
  */
182
168
  resync() {
183
169
  this.lastSent = new Set();
@@ -214,14 +200,20 @@ export class AreaOfInterestManager {
214
200
  this.lastSent = new Set(result.syncGroups);
215
201
  }
216
202
  catch {
217
- // Transport unavailable (offline / socket not open) or the
218
- // server rejected the set. Interest is SOFT state never throw
219
- // out of enter/leave/sweep for an expected transient. Leave
220
- // `lastSent` unchanged so the diff persists; `resync()` on the
221
- // next `connected` re-pushes the then-current desired set,
222
- // which is what recovers "interest changed while offline."
203
+ // Transport unavailable (offline, or socket not open) or the
204
+ // server rejected the set. Read interest is soft state, so enter,
205
+ // leave, and sweep never throw for an expected transient failure.
206
+ // Leaving `lastSent` unchanged keeps the pending diff; `resync()`
207
+ // on the next successful connect re-pushes the then-current desired
208
+ // set, which recovers any interest that changed while offline.
223
209
  break;
224
210
  }
211
+ // A concurrent reconcile() arriving during the await above sets
212
+ // `this.dirty` back to true (the coalescing path near line 245).
213
+ // TypeScript's intra-closure flow analysis can't see that cross-
214
+ // invocation mutation and reads this as always-false, but the loop
215
+ // is genuinely reentrant.
216
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
225
217
  } while (this.dirty);
226
218
  }
227
219
  finally {