@abloatai/humans 0.37.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 (404) hide show
  1. package/README.md +52 -0
  2. package/dist/Ablo.d.ts +208 -0
  3. package/dist/Ablo.js +120 -0
  4. package/dist/client.d.ts +317 -0
  5. package/dist/client.js +13 -0
  6. package/dist/core.d.ts +35 -0
  7. package/dist/core.js +48 -0
  8. package/dist/humans.d.ts +28 -0
  9. package/dist/humans.js +34 -0
  10. package/dist/index.d.ts +10 -0
  11. package/dist/index.js +6 -0
  12. package/dist/local/BaseSyncedStore.d.ts +807 -0
  13. package/dist/local/BaseSyncedStore.js +1516 -0
  14. package/dist/local/Database.d.ts +322 -0
  15. package/dist/local/Database.js +1589 -0
  16. package/dist/local/InstanceCache.d.ts +255 -0
  17. package/dist/local/InstanceCache.js +1263 -0
  18. package/dist/local/LazyReferenceCollection.d.ts +177 -0
  19. package/dist/local/LazyReferenceCollection.js +461 -0
  20. package/dist/local/Model.d.ts +475 -0
  21. package/dist/local/Model.js +950 -0
  22. package/dist/local/ModelRegistry.d.ts +225 -0
  23. package/dist/local/ModelRegistry.js +539 -0
  24. package/dist/local/NetworkMonitor.d.ts +28 -0
  25. package/dist/local/NetworkMonitor.js +79 -0
  26. package/dist/local/RuntimeContext.d.ts +52 -0
  27. package/dist/local/RuntimeContext.js +80 -0
  28. package/dist/local/SyncClient.d.ts +516 -0
  29. package/dist/local/SyncClient.js +1754 -0
  30. package/dist/local/adapters/alwaysOnline.d.ts +14 -0
  31. package/dist/local/adapters/alwaysOnline.js +17 -0
  32. package/dist/local/adapters/inMemoryStorage.d.ts +37 -0
  33. package/dist/local/adapters/inMemoryStorage.js +122 -0
  34. package/dist/local/client/clientPrelude.d.ts +52 -0
  35. package/dist/local/client/clientPrelude.js +60 -0
  36. package/dist/local/client/consoleLogger.d.ts +35 -0
  37. package/dist/local/client/consoleLogger.js +44 -0
  38. package/dist/local/client/createInternalComponents.d.ts +50 -0
  39. package/dist/local/client/createInternalComponents.js +98 -0
  40. package/dist/local/client/createModelProxy.d.ts +248 -0
  41. package/dist/local/client/createModelProxy.js +880 -0
  42. package/dist/local/client/modelRegistration.d.ts +10 -0
  43. package/dist/local/client/modelRegistration.js +316 -0
  44. package/dist/local/client/options.d.ts +440 -0
  45. package/dist/local/client/options.js +7 -0
  46. package/dist/local/client/reactiveEngine.d.ts +53 -0
  47. package/dist/local/client/reactiveEngine.js +705 -0
  48. package/dist/local/client/resourceTypes.d.ts +12 -0
  49. package/dist/local/client/resourceTypes.js +10 -0
  50. package/dist/local/client/schemaConfig.d.ts +44 -0
  51. package/dist/local/client/schemaConfig.js +185 -0
  52. package/dist/local/client/storeCluster.d.ts +46 -0
  53. package/dist/local/client/storeCluster.js +133 -0
  54. package/dist/local/client/storeLifecycle.d.ts +61 -0
  55. package/dist/local/client/storeLifecycle.js +236 -0
  56. package/dist/local/client/validateAbloOptions.d.ts +42 -0
  57. package/dist/local/client/validateAbloOptions.js +43 -0
  58. package/dist/local/client/wsMutationExecutor.d.ts +27 -0
  59. package/dist/local/client/wsMutationExecutor.js +72 -0
  60. package/dist/local/context.d.ts +42 -0
  61. package/dist/local/context.js +81 -0
  62. package/dist/local/coordination/ClaimLog.d.ts +26 -0
  63. package/dist/local/coordination/ClaimLog.js +32 -0
  64. package/dist/local/interfaces/index.d.ts +311 -0
  65. package/dist/local/interfaces/index.js +9 -0
  66. package/dist/local/localModelContract.d.ts +14 -0
  67. package/dist/local/localModelContract.js +1 -0
  68. package/dist/local/logPosition.d.ts +31 -0
  69. package/dist/local/logPosition.js +53 -0
  70. package/dist/local/mutationPersistence.d.ts +6 -0
  71. package/dist/local/mutationPersistence.js +1 -0
  72. package/dist/local/mutators/RecordingMutation.d.ts +36 -0
  73. package/dist/local/mutators/RecordingMutation.js +182 -0
  74. package/dist/local/mutators/Transaction.d.ts +40 -0
  75. package/dist/local/mutators/Transaction.js +58 -0
  76. package/dist/local/mutators/UndoManager.d.ts +258 -0
  77. package/dist/local/mutators/UndoManager.js +665 -0
  78. package/dist/local/mutators/defineMutators.d.ts +60 -0
  79. package/dist/local/mutators/defineMutators.js +18 -0
  80. package/dist/local/mutators/inverseOp.d.ts +126 -0
  81. package/dist/local/mutators/inverseOp.js +71 -0
  82. package/dist/local/mutators/mutateActions.d.ts +45 -0
  83. package/dist/local/mutators/mutateActions.js +105 -0
  84. package/dist/local/mutators/readerActions.d.ts +33 -0
  85. package/dist/local/mutators/readerActions.js +57 -0
  86. package/dist/local/mutators/undoApply.d.ts +51 -0
  87. package/dist/local/mutators/undoApply.js +117 -0
  88. package/dist/local/persistence.d.ts +7 -0
  89. package/dist/local/persistence.js +9 -0
  90. package/dist/local/query/QueryProcessor.d.ts +75 -0
  91. package/dist/local/query/QueryProcessor.js +255 -0
  92. package/dist/local/query/client.d.ts +64 -0
  93. package/dist/local/query/client.js +138 -0
  94. package/dist/local/query/types.d.ts +85 -0
  95. package/dist/local/query/types.js +16 -0
  96. package/dist/local/schema/serialize.d.ts +1 -0
  97. package/dist/local/schema/serialize.js +1 -0
  98. package/dist/local/store/queryApi.d.ts +13 -0
  99. package/dist/local/store/queryApi.js +35 -0
  100. package/dist/local/storeContract.d.ts +145 -0
  101. package/dist/local/storeContract.js +12 -0
  102. package/dist/local/stores/DatabaseManager.d.ts +112 -0
  103. package/dist/local/stores/DatabaseManager.js +400 -0
  104. package/dist/local/stores/ObjectStore.d.ts +115 -0
  105. package/dist/local/stores/ObjectStore.js +393 -0
  106. package/dist/local/stores/ObjectStoreContract.d.ts +38 -0
  107. package/dist/local/stores/ObjectStoreContract.js +1 -0
  108. package/dist/local/stores/StoreManager.d.ts +114 -0
  109. package/dist/local/stores/StoreManager.js +304 -0
  110. package/dist/local/stores/SyncActionStore.d.ts +99 -0
  111. package/dist/local/stores/SyncActionStore.js +506 -0
  112. package/dist/local/stores/openIDBWithTimeout.d.ts +65 -0
  113. package/dist/local/stores/openIDBWithTimeout.js +153 -0
  114. package/dist/local/stores/persistenceCleanup.d.ts +7 -0
  115. package/dist/local/stores/persistenceCleanup.js +26 -0
  116. package/dist/local/stores/persistenceIdentity.d.ts +27 -0
  117. package/dist/local/stores/persistenceIdentity.js +38 -0
  118. package/dist/local/stores/syncAction.d.ts +26 -0
  119. package/dist/local/stores/syncAction.js +16 -0
  120. package/dist/local/stores/v1PersistenceDeletion.d.ts +8 -0
  121. package/dist/local/stores/v1PersistenceDeletion.js +16 -0
  122. package/dist/local/sync/BootstrapFetcher.d.ts +284 -0
  123. package/dist/local/sync/BootstrapFetcher.js +964 -0
  124. package/dist/local/sync/ConnectionManager.d.ts +8 -0
  125. package/dist/local/sync/ConnectionManager.js +8 -0
  126. package/dist/local/sync/OnDemandLoader.d.ts +231 -0
  127. package/dist/local/sync/OnDemandLoader.js +743 -0
  128. package/dist/local/sync/SubscriptionManager.d.ts +159 -0
  129. package/dist/local/sync/SubscriptionManager.js +243 -0
  130. package/dist/local/sync/SyncWebSocket.d.ts +173 -0
  131. package/dist/local/sync/SyncWebSocket.js +438 -0
  132. package/dist/local/sync/bootstrapApply.d.ts +73 -0
  133. package/dist/local/sync/bootstrapApply.js +73 -0
  134. package/dist/local/sync/commitFrames.d.ts +8 -0
  135. package/dist/local/sync/commitFrames.js +8 -0
  136. package/dist/local/sync/connectionManagerLifecycle.d.ts +23 -0
  137. package/dist/local/sync/connectionManagerLifecycle.js +126 -0
  138. package/dist/local/sync/contextPorts.d.ts +18 -0
  139. package/dist/local/sync/contextPorts.js +31 -0
  140. package/dist/local/sync/createClaimStream.d.ts +64 -0
  141. package/dist/local/sync/createClaimStream.js +475 -0
  142. package/dist/local/sync/createSnapshot.d.ts +29 -0
  143. package/dist/local/sync/createSnapshot.js +116 -0
  144. package/dist/local/sync/credentialLifecycle.d.ts +7 -0
  145. package/dist/local/sync/credentialLifecycle.js +7 -0
  146. package/dist/local/sync/deltaPipeline.d.ts +116 -0
  147. package/dist/local/sync/deltaPipeline.js +357 -0
  148. package/dist/local/sync/groupChange.d.ts +116 -0
  149. package/dist/local/sync/groupChange.js +244 -0
  150. package/dist/local/sync/initialize.d.ts +27 -0
  151. package/dist/local/sync/initialize.js +137 -0
  152. package/dist/local/sync/participants.d.ts +132 -0
  153. package/dist/local/sync/participants.js +342 -0
  154. package/dist/local/sync/persistedPrefix.d.ts +12 -0
  155. package/dist/local/sync/persistedPrefix.js +22 -0
  156. package/dist/local/sync/reconnect.d.ts +23 -0
  157. package/dist/local/sync/reconnect.js +55 -0
  158. package/dist/local/sync/schemaDrift.d.ts +55 -0
  159. package/dist/local/sync/schemaDrift.js +53 -0
  160. package/dist/local/sync/schemas.d.ts +71 -0
  161. package/dist/local/sync/schemas.js +94 -0
  162. package/dist/local/sync/socketEventWiring.d.ts +31 -0
  163. package/dist/local/sync/socketEventWiring.js +130 -0
  164. package/dist/local/sync/syncCursor.d.ts +40 -0
  165. package/dist/local/sync/syncCursor.js +55 -0
  166. package/dist/local/sync/syncPlan.d.ts +54 -0
  167. package/dist/local/sync/syncPlan.js +50 -0
  168. package/dist/local/sync/terminalSessionLifecycle.d.ts +20 -0
  169. package/dist/local/sync/terminalSessionLifecycle.js +50 -0
  170. package/dist/local/sync/wsFrameHandlers.d.ts +8 -0
  171. package/dist/local/sync/wsFrameHandlers.js +8 -0
  172. package/dist/local/transactions/databaseCommitOutbox.d.ts +15 -0
  173. package/dist/local/transactions/databaseCommitOutbox.js +16 -0
  174. package/dist/local/transactions/localMutation.d.ts +10 -0
  175. package/dist/local/transactions/localMutation.js +37 -0
  176. package/dist/local/transactions/mutations/MutationQueue.d.ts +511 -0
  177. package/dist/local/transactions/mutations/MutationQueue.js +1498 -0
  178. package/dist/local/transactions/mutations/MutationStore.d.ts +20 -0
  179. package/dist/local/transactions/mutations/MutationStore.js +53 -0
  180. package/dist/local/transactions/mutations/UnconfirmedWrites.d.ts +82 -0
  181. package/dist/local/transactions/mutations/UnconfirmedWrites.js +104 -0
  182. package/dist/local/transactions/mutations/batchProcessing.d.ts +64 -0
  183. package/dist/local/transactions/mutations/batchProcessing.js +349 -0
  184. package/dist/local/transactions/mutations/coalesceRules.d.ts +58 -0
  185. package/dist/local/transactions/mutations/coalesceRules.js +140 -0
  186. package/dist/local/transactions/mutations/commitApi.d.ts +19 -0
  187. package/dist/local/transactions/mutations/commitApi.js +74 -0
  188. package/dist/local/transactions/mutations/commitLane.d.ts +70 -0
  189. package/dist/local/transactions/mutations/commitLane.js +140 -0
  190. package/dist/local/transactions/mutations/commitLatency.d.ts +52 -0
  191. package/dist/local/transactions/mutations/commitLatency.js +130 -0
  192. package/dist/local/transactions/mutations/commitPayload.d.ts +165 -0
  193. package/dist/local/transactions/mutations/commitPayload.js +152 -0
  194. package/dist/local/transactions/mutations/commitTransport.d.ts +36 -0
  195. package/dist/local/transactions/mutations/commitTransport.js +104 -0
  196. package/dist/local/transactions/mutations/deltaConfirmation.d.ts +63 -0
  197. package/dist/local/transactions/mutations/deltaConfirmation.js +235 -0
  198. package/dist/local/transactions/mutations/durableCommitRestore.d.ts +17 -0
  199. package/dist/local/transactions/mutations/durableCommitRestore.js +95 -0
  200. package/dist/local/transactions/mutations/durableWriteStore.d.ts +14 -0
  201. package/dist/local/transactions/mutations/durableWriteStore.js +12 -0
  202. package/dist/local/transactions/mutations/executionSelection.d.ts +6 -0
  203. package/dist/local/transactions/mutations/executionSelection.js +42 -0
  204. package/dist/local/transactions/mutations/failureHandling.d.ts +16 -0
  205. package/dist/local/transactions/mutations/failureHandling.js +130 -0
  206. package/dist/local/transactions/mutations/failurePolicy.d.ts +13 -0
  207. package/dist/local/transactions/mutations/failurePolicy.js +48 -0
  208. package/dist/local/transactions/mutations/localMutation.d.ts +58 -0
  209. package/dist/local/transactions/mutations/localMutation.js +75 -0
  210. package/dist/local/transactions/mutations/modelOperations.d.ts +44 -0
  211. package/dist/local/transactions/mutations/modelOperations.js +144 -0
  212. package/dist/local/transactions/mutations/mutationPersistence.d.ts +25 -0
  213. package/dist/local/transactions/mutations/mutationPersistence.js +188 -0
  214. package/dist/local/transactions/mutations/pendingDrain.d.ts +33 -0
  215. package/dist/local/transactions/mutations/pendingDrain.js +112 -0
  216. package/dist/local/transactions/mutations/processingScheduler.d.ts +14 -0
  217. package/dist/local/transactions/mutations/processingScheduler.js +24 -0
  218. package/dist/local/transactions/mutations/queueCoalescing.d.ts +13 -0
  219. package/dist/local/transactions/mutations/queueCoalescing.js +35 -0
  220. package/dist/local/transactions/mutations/replayValidation.d.ts +187 -0
  221. package/dist/local/transactions/mutations/replayValidation.js +164 -0
  222. package/dist/local/transactions/reconnectDrain.d.ts +11 -0
  223. package/dist/local/transactions/reconnectDrain.js +13 -0
  224. package/dist/local/utils/mobxSetup.d.ts +53 -0
  225. package/dist/local/utils/mobxSetup.js +330 -0
  226. package/dist/local/views/QueryView.d.ts +79 -0
  227. package/dist/local/views/QueryView.js +218 -0
  228. package/dist/local/views/ViewRegistry.d.ts +20 -0
  229. package/dist/local/views/ViewRegistry.js +57 -0
  230. package/dist/local/views/incrementalView.d.ts +45 -0
  231. package/dist/local/views/incrementalView.js +69 -0
  232. package/dist/plugin.d.ts +285 -0
  233. package/dist/plugin.js +106 -0
  234. package/dist/presenceStream.d.ts +69 -0
  235. package/dist/presenceStream.js +200 -0
  236. package/dist/react/AbloProvider.d.ts +242 -0
  237. package/dist/react/AbloProvider.js +456 -0
  238. package/dist/react/ClientSideSuspense.d.ts +36 -0
  239. package/dist/react/ClientSideSuspense.js +17 -0
  240. package/dist/react/DefaultFallback.d.ts +24 -0
  241. package/dist/react/DefaultFallback.js +43 -0
  242. package/dist/react/context.d.ts +55 -0
  243. package/dist/react/context.js +29 -0
  244. package/dist/react/createAbloReact.d.ts +50 -0
  245. package/dist/react/createAbloReact.js +48 -0
  246. package/dist/react/internalContext.d.ts +33 -0
  247. package/dist/react/internalContext.js +3 -0
  248. package/dist/react/useAblo.d.ts +96 -0
  249. package/dist/react/useAblo.js +120 -0
  250. package/dist/react/useCurrentUserId.d.ts +2 -0
  251. package/dist/react/useCurrentUserId.js +12 -0
  252. package/dist/react/useErrorListener.d.ts +2 -0
  253. package/dist/react/useErrorListener.js +14 -0
  254. package/dist/react/useMutationFailureListener.d.ts +8 -0
  255. package/dist/react/useMutationFailureListener.js +19 -0
  256. package/dist/react/useMutators.d.ts +56 -0
  257. package/dist/react/useMutators.js +84 -0
  258. package/dist/react/useSyncStatus.d.ts +19 -0
  259. package/dist/react/useSyncStatus.js +37 -0
  260. package/dist/react/useUndoScope.d.ts +34 -0
  261. package/dist/react/useUndoScope.js +73 -0
  262. package/dist/react.d.ts +18 -0
  263. package/dist/react.js +14 -0
  264. package/dist/reactRuntime.d.ts +4 -0
  265. package/dist/reactRuntime.js +2 -0
  266. package/dist/surface.d.ts +36 -0
  267. package/dist/surface.js +77 -0
  268. package/dist/useReactive.d.ts +6 -0
  269. package/dist/useReactive.js +43 -0
  270. package/package.json +119 -0
  271. package/src/Ablo.ts +456 -0
  272. package/src/client.ts +374 -0
  273. package/src/core.ts +104 -0
  274. package/src/humans.ts +61 -0
  275. package/src/index.ts +40 -0
  276. package/src/local/BaseSyncedStore.ts +1991 -0
  277. package/src/local/Database.ts +2052 -0
  278. package/src/local/InstanceCache.ts +1503 -0
  279. package/src/local/LazyReferenceCollection.ts +563 -0
  280. package/src/local/Model.ts +1124 -0
  281. package/src/local/ModelRegistry.ts +762 -0
  282. package/src/local/NetworkMonitor.ts +88 -0
  283. package/src/local/RuntimeContext.ts +141 -0
  284. package/src/local/SyncClient.ts +2131 -0
  285. package/src/local/adapters/alwaysOnline.ts +20 -0
  286. package/src/local/adapters/inMemoryStorage.ts +141 -0
  287. package/src/local/client/clientPrelude.ts +112 -0
  288. package/src/local/client/consoleLogger.ts +60 -0
  289. package/src/local/client/createInternalComponents.ts +163 -0
  290. package/src/local/client/createModelProxy.ts +1390 -0
  291. package/src/local/client/modelRegistration.ts +350 -0
  292. package/src/local/client/options.ts +526 -0
  293. package/src/local/client/reactiveEngine.ts +935 -0
  294. package/src/local/client/resourceTypes.ts +37 -0
  295. package/src/local/client/schemaConfig.ts +194 -0
  296. package/src/local/client/storeCluster.ts +172 -0
  297. package/src/local/client/storeLifecycle.ts +343 -0
  298. package/src/local/client/validateAbloOptions.ts +95 -0
  299. package/src/local/client/wsMutationExecutor.ts +110 -0
  300. package/src/local/context.ts +96 -0
  301. package/src/local/coordination/ClaimLog.ts +39 -0
  302. package/src/local/interfaces/index.ts +468 -0
  303. package/src/local/localModelContract.ts +15 -0
  304. package/src/local/logPosition.ts +84 -0
  305. package/src/local/mutationPersistence.ts +7 -0
  306. package/src/local/mutators/RecordingMutation.ts +222 -0
  307. package/src/local/mutators/Transaction.ts +97 -0
  308. package/src/local/mutators/UndoManager.ts +741 -0
  309. package/src/local/mutators/defineMutators.ts +76 -0
  310. package/src/local/mutators/inverseOp.ts +83 -0
  311. package/src/local/mutators/mutateActions.ts +167 -0
  312. package/src/local/mutators/readerActions.ts +99 -0
  313. package/src/local/mutators/undoApply.ts +141 -0
  314. package/src/local/persistence.ts +16 -0
  315. package/src/local/query/QueryProcessor.ts +347 -0
  316. package/src/local/query/client.ts +197 -0
  317. package/src/local/query/types.ts +102 -0
  318. package/src/local/schema/serialize.ts +1 -0
  319. package/src/local/store/queryApi.ts +56 -0
  320. package/src/local/storeContract.ts +146 -0
  321. package/src/local/stores/DatabaseManager.ts +507 -0
  322. package/src/local/stores/ObjectStore.ts +449 -0
  323. package/src/local/stores/ObjectStoreContract.ts +48 -0
  324. package/src/local/stores/StoreManager.ts +388 -0
  325. package/src/local/stores/SyncActionStore.ts +579 -0
  326. package/src/local/stores/openIDBWithTimeout.ts +195 -0
  327. package/src/local/stores/persistenceCleanup.ts +43 -0
  328. package/src/local/stores/persistenceIdentity.ts +83 -0
  329. package/src/local/stores/syncAction.ts +21 -0
  330. package/src/local/stores/v1PersistenceDeletion.ts +21 -0
  331. package/src/local/sync/BootstrapFetcher.ts +1224 -0
  332. package/src/local/sync/ConnectionManager.ts +15 -0
  333. package/src/local/sync/OnDemandLoader.ts +927 -0
  334. package/src/local/sync/SubscriptionManager.ts +300 -0
  335. package/src/local/sync/SyncWebSocket.ts +584 -0
  336. package/src/local/sync/bootstrapApply.ts +130 -0
  337. package/src/local/sync/commitFrames.ts +16 -0
  338. package/src/local/sync/connectionManagerLifecycle.ts +158 -0
  339. package/src/local/sync/contextPorts.ts +37 -0
  340. package/src/local/sync/createClaimStream.ts +668 -0
  341. package/src/local/sync/createSnapshot.ts +160 -0
  342. package/src/local/sync/credentialLifecycle.ts +18 -0
  343. package/src/local/sync/deltaPipeline.ts +473 -0
  344. package/src/local/sync/groupChange.ts +343 -0
  345. package/src/local/sync/initialize.ts +205 -0
  346. package/src/local/sync/participants.ts +564 -0
  347. package/src/local/sync/persistedPrefix.ts +27 -0
  348. package/src/local/sync/reconnect.ts +88 -0
  349. package/src/local/sync/schemaDrift.ts +86 -0
  350. package/src/local/sync/schemas.ts +118 -0
  351. package/src/local/sync/socketEventWiring.ts +196 -0
  352. package/src/local/sync/syncCursor.ts +62 -0
  353. package/src/local/sync/syncPlan.ts +89 -0
  354. package/src/local/sync/terminalSessionLifecycle.ts +66 -0
  355. package/src/local/sync/wsFrameHandlers.ts +20 -0
  356. package/src/local/transactions/databaseCommitOutbox.ts +33 -0
  357. package/src/local/transactions/localMutation.ts +58 -0
  358. package/src/local/transactions/mutations/MutationQueue.ts +1998 -0
  359. package/src/local/transactions/mutations/MutationStore.ts +65 -0
  360. package/src/local/transactions/mutations/UnconfirmedWrites.ts +133 -0
  361. package/src/local/transactions/mutations/batchProcessing.ts +469 -0
  362. package/src/local/transactions/mutations/coalesceRules.ts +192 -0
  363. package/src/local/transactions/mutations/commitApi.ts +97 -0
  364. package/src/local/transactions/mutations/commitLane.ts +191 -0
  365. package/src/local/transactions/mutations/commitLatency.ts +164 -0
  366. package/src/local/transactions/mutations/commitPayload.ts +281 -0
  367. package/src/local/transactions/mutations/commitTransport.ts +174 -0
  368. package/src/local/transactions/mutations/deltaConfirmation.ts +298 -0
  369. package/src/local/transactions/mutations/durableCommitRestore.ts +128 -0
  370. package/src/local/transactions/mutations/durableWriteStore.ts +21 -0
  371. package/src/local/transactions/mutations/executionSelection.ts +42 -0
  372. package/src/local/transactions/mutations/failureHandling.ts +154 -0
  373. package/src/local/transactions/mutations/failurePolicy.ts +61 -0
  374. package/src/local/transactions/mutations/localMutation.ts +135 -0
  375. package/src/local/transactions/mutations/modelOperations.ts +210 -0
  376. package/src/local/transactions/mutations/mutationPersistence.ts +231 -0
  377. package/src/local/transactions/mutations/pendingDrain.ts +160 -0
  378. package/src/local/transactions/mutations/processingScheduler.ts +35 -0
  379. package/src/local/transactions/mutations/queueCoalescing.ts +45 -0
  380. package/src/local/transactions/mutations/replayValidation.ts +192 -0
  381. package/src/local/transactions/reconnectDrain.ts +24 -0
  382. package/src/local/utils/mobxSetup.ts +388 -0
  383. package/src/local/views/QueryView.ts +311 -0
  384. package/src/local/views/ViewRegistry.ts +61 -0
  385. package/src/local/views/incrementalView.ts +92 -0
  386. package/src/plugin.ts +396 -0
  387. package/src/presenceStream.ts +279 -0
  388. package/src/react/AbloProvider.tsx +744 -0
  389. package/src/react/ClientSideSuspense.tsx +57 -0
  390. package/src/react/DefaultFallback.tsx +60 -0
  391. package/src/react/context.ts +89 -0
  392. package/src/react/createAbloReact.ts +116 -0
  393. package/src/react/internalContext.ts +38 -0
  394. package/src/react/useAblo.ts +280 -0
  395. package/src/react/useCurrentUserId.ts +17 -0
  396. package/src/react/useErrorListener.ts +22 -0
  397. package/src/react/useMutationFailureListener.ts +34 -0
  398. package/src/react/useMutators.ts +184 -0
  399. package/src/react/useSyncStatus.ts +42 -0
  400. package/src/react/useUndoScope.ts +143 -0
  401. package/src/react.ts +69 -0
  402. package/src/reactRuntime.ts +10 -0
  403. package/src/surface.ts +106 -0
  404. package/src/useReactive.ts +51 -0
@@ -0,0 +1,584 @@
1
+ /**
2
+ * The reactive engine's connection to the sync server: the settlement core's
3
+ * duplex transport ({@link WsTransport}, ADR 0016) plus everything that turns
4
+ * the stream into a local, watchable copy — wire-delta validation, the resume
5
+ * cursor and its persistence-gated ack discipline, incremental sync and
6
+ * bootstrap requests, the catch-up poll, and presence. The socket lifecycle,
7
+ * reconnect backoff, heartbeat, and the commit/claim/release/subscription
8
+ * frames all live in the transport; this subclass overrides its frame hooks
9
+ * and open/close hooks with the materialisation the transport deliberately
10
+ * does not do.
11
+ */
12
+
13
+ import { getContext } from '../context.js';
14
+ import { clientSyncDeltaSchema, type ClientSyncDelta } from '@abloatai/transaction/wire/delta';
15
+ import {
16
+ WsTransport,
17
+ type WsTransportOptions,
18
+ type EventMap,
19
+ type DefaultCollaborationEvents,
20
+ } from '@abloatai/transaction/transport/wsTransport';
21
+ import { isRecord } from './wsFrameHandlers.js';
22
+ // Sync-position state (lastSyncId watermark, version vector, server cursor).
23
+ import { SyncCursor } from './syncCursor.js';
24
+ import { PROTOCOL_VERSION } from '@abloatai/transaction/wire/protocolVersion';
25
+ // Context-backed ports in the shape the core transport takes.
26
+ import {
27
+ contextLogger,
28
+ contextSocketObservability,
29
+ contextOnlineStatus,
30
+ } from './contextPorts.js';
31
+
32
+ // Moved leaves — re-exported so every importer's path stays unchanged.
33
+ export type { CommitAck } from './commitFrames.js';
34
+ export type {
35
+ SyncCapabilities,
36
+ BootstrapHint,
37
+ BootstrapDataEvent,
38
+ PresenceUpdate,
39
+ CoreSyncEventMap,
40
+ DefaultCollaborationEvents,
41
+ EventMap,
42
+ SyncWebSocketEventMap,
43
+ } from '@abloatai/transaction/transport/wsTransport';
44
+
45
+ /**
46
+ * How often, while connected, the client polls for any deltas whose best-effort
47
+ * broadcast was lost in transit. This is a client-side eventual-consistency
48
+ * setting, not part of the wire contract, so the server derives nothing from
49
+ * it. That it currently equals the 30-second ping is a coincidence, not a
50
+ * guarantee.
51
+ */
52
+ const CATCHUP_POLL_INTERVAL_MS = 30_000;
53
+
54
+ /**
55
+ * The wire delta the client receives. It is inferred from the canonical
56
+ * `clientSyncDeltaSchema` so the client and server share one contract rather
57
+ * than two hand-maintained definitions. The action vocabulary
58
+ * (`I`/`U`/`D`/`A`/`V`/`C`/`G`/`S`) and the client-only extras (`metadata`,
59
+ * `clientMutationId`, and the deprecated flat `createdBy`) live in that schema;
60
+ * see its own documentation for the full field reference.
61
+ */
62
+ export type SyncDelta = ClientSyncDelta;
63
+
64
+ /**
65
+ * Payload for an older actionType `'G'` delta. It carries both the added and
66
+ * removed sync groups in one delta and forces a full re-bootstrap.
67
+ */
68
+ export interface SyncGroupChangePayload {
69
+ removedGroups: string[];
70
+ addedGroups: string[];
71
+ }
72
+
73
+ /**
74
+ * Payload for an incremental actionType `'G'` delta. It signals that the
75
+ * recipient has joined a single sync group; the following `'C'` (covering)
76
+ * deltas deliver the newly visible entities. No re-bootstrap is required.
77
+ */
78
+ export interface GroupAddedPayload {
79
+ group: string;
80
+ userId: string;
81
+ }
82
+
83
+ /**
84
+ * Payload for an actionType `'S'` delta. It signals that the recipient has lost
85
+ * access to a sync group; the client purges the affected local entities and
86
+ * updates its subscription metadata.
87
+ */
88
+ export interface GroupRemovedPayload {
89
+ group: string;
90
+ userId: string;
91
+ }
92
+
93
+ /**
94
+ * The reactive engine's connection options — the transport's options under
95
+ * the name consumers have always imported.
96
+ */
97
+ export type SyncWebSocketOptions = WsTransportOptions;
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // Consumers pass their own event types as the TCollaboration generic parameter.
101
+
102
+ export class SyncWebSocket<
103
+ TCollaboration extends EventMap<TCollaboration> = DefaultCollaborationEvents
104
+ > extends WsTransport<TCollaboration> {
105
+ /** Periodic catchup interval — polls for missed deltas every 30s while connected */
106
+ private catchupInterval: ReturnType<typeof setInterval> | null = null;
107
+ /**
108
+ * Sync-position state: the lastSyncId watermark, version vector, and server
109
+ * cursor. The advance discipline is documented at `sendAck` and `handleDelta`;
110
+ * the state itself lives in {@link SyncCursor}.
111
+ */
112
+ private readonly cursor: SyncCursor;
113
+
114
+ constructor(options: SyncWebSocketOptions) {
115
+ super({
116
+ ...options,
117
+ logger: contextLogger,
118
+ observability: contextSocketObservability,
119
+ onlineStatus: contextOnlineStatus,
120
+ });
121
+ this.cursor = new SyncCursor(options.lastSyncId ?? 0);
122
+ }
123
+
124
+ /** The persisted resume position, sent on the upgrade URL. */
125
+ protected override resumeCursor(): string {
126
+ return this.cursor.syncCursor || '';
127
+ }
128
+
129
+ /**
130
+ * The open ritual, run by the transport between its `connected` emit and the
131
+ * heartbeat start: announce presence, tell the server where we left off,
132
+ * request the deltas we missed, and start the catch-up poll.
133
+ */
134
+ protected override onOpened(): void {
135
+ // Send presence update with timezone (server sets presence to "online" on connect,
136
+ // this improves localTime accuracy by providing the user's actual timezone)
137
+ this.sendPresenceUpdate('online');
138
+
139
+ // Immediately request incremental sync based on our stored cursor.
140
+ // `requestIncrementalSync` is async — a bare call inside try/catch is a
141
+ // rejection hole (the catch never sees it); route failures through
142
+ // `.catch` so they land in the same breadcrumb instead of an
143
+ // unhandled rejection.
144
+ const reportSyncRequestFailure = (e: unknown): void => {
145
+ getContext().observability.breadcrumb(
146
+ 'Failed to request incremental sync on open',
147
+ 'sync.websocket',
148
+ 'warning',
149
+ {
150
+ error: e instanceof Error ? e.message : String(e),
151
+ }
152
+ );
153
+ };
154
+ try {
155
+ if (this.cursor.lastSyncId && this.cursor.lastSyncId > 0) {
156
+ // Let server know where we left off before requesting deltas
157
+ this.sendAck(this.cursor.lastSyncId);
158
+ }
159
+ } catch (e) {
160
+ reportSyncRequestFailure(e);
161
+ }
162
+ this.requestIncrementalSync().catch(reportSyncRequestFailure);
163
+
164
+ // Start periodic catchup — polls for missed deltas every
165
+ // CATCHUP_POLL_INTERVAL_MS while connected. Real-time WebSocket delivery
166
+ // is best-effort, so this interval guarantees eventual consistency by
167
+ // fetching any deltas that were committed but whose broadcast was lost in
168
+ // transit.
169
+ this.stopCatchupInterval();
170
+ this.catchupInterval = setInterval(() => {
171
+ if (this.isConnected()) {
172
+ // A rejected sync request must never surface as an unhandled
173
+ // rejection from a background interval — log and let the next
174
+ // poll retry.
175
+ this.requestIncrementalSync().catch((e: unknown) => {
176
+ getContext().observability.breadcrumb(
177
+ 'Periodic catchup sync request failed',
178
+ 'sync.websocket',
179
+ 'warning',
180
+ {
181
+ error: e instanceof Error ? e.message : String(e),
182
+ }
183
+ );
184
+ });
185
+ }
186
+ }, CATCHUP_POLL_INTERVAL_MS);
187
+ }
188
+
189
+ /** The transport clears its socket reference before this runs. */
190
+ protected override onClosed(): void {
191
+ this.stopCatchupInterval();
192
+ }
193
+
194
+ /**
195
+ * Validates and normalizes a wire delta at the receive boundary — the single
196
+ * seam every inbound delta (a `delta` frame, a batch element, a `sync_response`
197
+ * replay, or the older bare frame) passes through before it is emitted,
198
+ * persisted, or allowed to advance any watermark.
199
+ *
200
+ * Normalization keeps already-deployed servers compatible:
201
+ * - `id`: the contract says `number`, but some servers have sent the raw
202
+ * Postgres BIGINT serialization — a string — and every downstream watermark
203
+ * gate treats a string as invalid, so acks are withheld, the resume cursor
204
+ * never advances, and every reconnect replays from zero. Coerce it once here.
205
+ * - `transactionId` / `createdBy`: the server projection sends these as
206
+ * nullable (and `createdBy` as a nested reference); the client contract
207
+ * types them as optional strings and never reads them, so normalize them to
208
+ * absent rather than reject every real server delta.
209
+ *
210
+ * Validation runs `clientSyncDeltaSchema.safeParse`, the canonical wire
211
+ * contract. A frame that fails is dropped (returns `null`) with a debug log
212
+ * and an observability breadcrumb; it is never applied. There is one parse per
213
+ * delta — callers must not re-parse.
214
+ */
215
+ private normalizeWireDelta(raw: unknown): SyncDelta | null {
216
+ let candidate: unknown = raw;
217
+ if (isRecord(raw)) {
218
+ const normalized: Record<string, unknown> = { ...raw };
219
+ if (typeof normalized.id !== 'number') {
220
+ const coerced = Number(normalized.id);
221
+ normalized.id = Number.isFinite(coerced) ? coerced : 0;
222
+ }
223
+ if (normalized.transactionId === null) delete normalized.transactionId;
224
+ if (normalized.createdBy !== undefined && typeof normalized.createdBy !== 'string') {
225
+ delete normalized.createdBy;
226
+ }
227
+ candidate = normalized;
228
+ }
229
+ const parsed = clientSyncDeltaSchema.safeParse(candidate);
230
+ if (!parsed.success) {
231
+ const issue = parsed.error.issues[0];
232
+ const detail = {
233
+ issue: issue ? `${issue.path.join('.')}: ${issue.message}` : 'not an object',
234
+ modelName:
235
+ isRecord(raw) && typeof raw.modelName === 'string' ? raw.modelName : undefined,
236
+ actionType:
237
+ isRecord(raw) && typeof raw.actionType === 'string' ? raw.actionType : undefined,
238
+ };
239
+ getContext().logger.debug('[SyncWebSocket] dropped malformed wire delta', detail);
240
+ getContext().observability.breadcrumb(
241
+ 'Dropped malformed wire delta',
242
+ 'sync.websocket',
243
+ 'warning',
244
+ detail,
245
+ );
246
+ return null;
247
+ }
248
+ return parsed.data;
249
+ }
250
+
251
+ /**
252
+ * Handle incoming sync delta (untrusted wire input — validated and
253
+ * normalized by {@link normalizeWireDelta}; malformed deltas are dropped).
254
+ */
255
+ protected override handleDelta(rawDelta: unknown): void {
256
+ const delta = this.normalizeWireDelta(rawDelta);
257
+ if (!delta) return;
258
+ getContext().logger.debug('Received delta', {
259
+ action: delta.actionType,
260
+ model: delta.modelName,
261
+ id: delta.modelId,
262
+ syncId: delta.id,
263
+ });
264
+
265
+ // Do not advance `this.cursor.lastSyncId` on receipt. The runtime cursor
266
+ // must stay consistent with what has been persisted locally; otherwise the
267
+ // next `requestIncrementalSync()` (and the connect-time handshake) would
268
+ // send an optimistic cursor and the server would skip deltas that never
269
+ // landed in local storage. `this.cursor.lastSyncId` advances only in
270
+ // `sendAck()`, which the store gates on its persisted-syncId watermark, so
271
+ // the cursor is never read ahead of the persisted client view.
272
+ //
273
+ // The version vector is intentionally not updated here for the same reason;
274
+ // it is left to the persistence-gated path.
275
+
276
+ // Emit delta for processing. Ack will be sent by SyncedStore after persistence.
277
+ this.emit('delta', delta);
278
+ }
279
+
280
+ /**
281
+ * Acknowledges received deltas up to the given syncId. This is the only place
282
+ * `this.cursor.lastSyncId` moves forward for live deltas. The store calls it
283
+ * with its persisted-syncId watermark — that is, only after the deltas have
284
+ * committed to local storage. Advancing the cursor here, rather than at
285
+ * receipt in `handleDelta` or `handleSyncResponse`, keeps the cursor from
286
+ * getting ahead of the persisted view, so reconnect and catch-up requests
287
+ * cannot skip un-persisted deltas.
288
+ */
289
+ private sendAck(syncId: number): void {
290
+ // Advance the local cursor *and* the version vector for this ack —
291
+ // these are what `requestIncrementalSync` and the connect handshake
292
+ // will send next, and what `getLastSyncId()` reports for clean-
293
+ // shutdown persistence.
294
+ this.cursor.ackAdvance(syncId);
295
+
296
+ if (!this.isConnected()) return;
297
+
298
+ this.send({
299
+ type: 'ack',
300
+ payload: {
301
+ lastSyncId: syncId, },
302
+ });
303
+ }
304
+
305
+ /**
306
+ * Public wrapper for sending ack from outside the class
307
+ */
308
+ acknowledge(syncId: number): void {
309
+ this.sendAck(syncId);
310
+ }
311
+
312
+ /**
313
+ * Send presence update to server.
314
+ * Use this for:
315
+ * - Updating timezone (improves localTime accuracy shown to other users)
316
+ * - Manual status changes (away, custom status)
317
+ *
318
+ * Note: "online" status is automatically set by server on WebSocket connect,
319
+ * and "offline" is set on disconnect. You don't need to call this for basic online/offline.
320
+ *
321
+ * @param status - "online", "away", or custom status string
322
+ * @param customStatus - Optional custom status message
323
+ */
324
+ sendPresenceUpdate(
325
+ status: 'online' | 'away' | 'offline' = 'online',
326
+ customStatus?: string
327
+ ): void {
328
+ if (!this.isConnected()) return;
329
+
330
+ const timezone = (() => {
331
+ try {
332
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
333
+ } catch {
334
+ return 'UTC';
335
+ }
336
+ })();
337
+
338
+ this.send({
339
+ type: 'presence_update',
340
+ payload: {
341
+ status,
342
+ timezone,
343
+ ...(customStatus ? { customStatus } : {}),
344
+ },
345
+ });
346
+ }
347
+
348
+ /**
349
+ * Stop the periodic catchup interval
350
+ */
351
+ private stopCatchupInterval(): void {
352
+ if (this.catchupInterval) {
353
+ clearInterval(this.catchupInterval);
354
+ this.catchupInterval = null;
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Disconnect from WebSocket
360
+ */
361
+ override disconnect(): void {
362
+ this.stopCatchupInterval();
363
+ super.disconnect();
364
+ }
365
+
366
+ // Cursor accessors — thin delegates; the state and semantics live in
367
+ // SyncCursor.
368
+
369
+ /**
370
+ * Update last sync ID (for persistence)
371
+ */
372
+ setLastSyncId(syncId: number): void {
373
+ this.cursor.setLastSyncId(syncId);
374
+ }
375
+
376
+ /**
377
+ * Update sync cursor (for incremental sync)
378
+ */
379
+ setSyncCursor(cursor: string | null): void {
380
+ this.cursor.setSyncCursor(cursor);
381
+ }
382
+
383
+ /**
384
+ * Get current sync cursor
385
+ */
386
+ getSyncCursor(): string | null {
387
+ return this.cursor.getSyncCursor();
388
+ }
389
+
390
+ /**
391
+ * Get the highest syncId seen this session (for persistence on clean shutdown)
392
+ */
393
+ getLastSyncId(): number {
394
+ return this.cursor.getLastSyncId();
395
+ }
396
+
397
+ /**
398
+ * Requests an incremental sync from the server, starting at the current cursor.
399
+ */
400
+ async requestIncrementalSync(): Promise<void> {
401
+ if (!this.isConnected()) {
402
+ // Silent when offline - not an error condition
403
+ if (getContext().onlineStatus.isOnline()) {
404
+ getContext().observability.breadcrumb(
405
+ 'WebSocket not connected, cannot request sync',
406
+ 'sync.websocket',
407
+ 'warning'
408
+ );
409
+ }
410
+ return;
411
+ }
412
+
413
+ // Normalize capabilities to an array of strings for server compatibility
414
+ const capsObj = this.options.capabilities || {};
415
+ const capsArr = Object.entries(capsObj)
416
+ .filter(([, v]) => !!v)
417
+ .map(([k]) => k);
418
+
419
+ this.send({
420
+ type: 'sync_request',
421
+ payload: {
422
+ cursor: this.cursor.syncCursor, // Always send lastSyncId to ensure server uses client's current position
423
+ lastSyncId: this.cursor.lastSyncId,
424
+ capabilities: capsArr,
425
+ // Protocol handshake: the server rejects an out-of-range version with
426
+ // WebSocket close code 4010 before serving any deltas.
427
+ protocolVersion: PROTOCOL_VERSION,
428
+ },
429
+ });
430
+ }
431
+
432
+ /**
433
+ * Request bootstrap for specific entities
434
+ */
435
+ async requestBootstrap(entities?: string[]): Promise<void> {
436
+ if (!this.isConnected()) {
437
+ // Silent when offline - not an error condition
438
+ if (getContext().onlineStatus.isOnline()) {
439
+ getContext().observability.breadcrumb(
440
+ 'WebSocket not connected, cannot request bootstrap',
441
+ 'sync.websocket',
442
+ 'warning'
443
+ );
444
+ }
445
+ return;
446
+ }
447
+
448
+ this.send({
449
+ type: 'bootstrap_request',
450
+ payload: {
451
+ entities: entities || [], capabilities: this.options.capabilities,
452
+ },
453
+ });
454
+ }
455
+
456
+ /**
457
+ * Handle sync response from server. Untrusted wire input — the envelope
458
+ * fields are narrowed defensively and every delta is validated through
459
+ * {@link normalizeWireDelta} (exactly once each; malformed ones drop out
460
+ * of the batch).
461
+ */
462
+ protected override handleSyncResponse(rawPayload: unknown): void {
463
+ const payload: Record<string, unknown> = isRecord(rawPayload) ? rawPayload : {};
464
+ const rawDeltas: unknown[] | null = Array.isArray(payload.deltas)
465
+ ? payload.deltas
466
+ : null;
467
+ // Cursor reconciliation. The server stamps its authoritative `currentSyncId`
468
+ // on every sync_response. If our local cursor is ahead of the server, our
469
+ // local view has somehow diverged (corrupted metadata, a regression that
470
+ // reintroduced an eager advance, or local storage lying about a successful
471
+ // commit). Trust the server, reset the cursor, and request another sync so
472
+ // any deltas we should have applied get re-delivered. When the field is
473
+ // absent (an older server build) we simply skip this step.
474
+ //
475
+ // We only reconcile when the response carries no deltas. If deltas are
476
+ // present they advance our cursor through the normal persistence-gated path
477
+ // anyway — and the in-flight round-trip means the snapshot's `currentSyncId`
478
+ // is naturally a few syncIds behind our locally-advanced cursor at receive
479
+ // time (live deltas may have landed in the meantime). Restricting to
480
+ // empty-delta responses eliminates that benign false positive while still
481
+ // catching the real corruption case (server head < local, and the server
482
+ // has nothing new to send).
483
+ const hasDeltas = rawDeltas !== null && rawDeltas.length > 0;
484
+ if (!hasDeltas && typeof payload.currentSyncId === 'number') {
485
+ const serverHead: number = payload.currentSyncId;
486
+ if (serverHead < this.cursor.lastSyncId) {
487
+ getContext().logger.debug(
488
+ '[SyncWebSocket] local cursor ahead of server head — resetting and resyncing',
489
+ {
490
+ local: this.cursor.lastSyncId,
491
+ server: serverHead,
492
+ drift: this.cursor.lastSyncId - serverHead,
493
+ },
494
+ );
495
+ getContext().observability.breadcrumb(
496
+ 'Local sync cursor diverged from server — reset',
497
+ 'sync.websocket',
498
+ 'warning',
499
+ { local: this.cursor.lastSyncId, server: serverHead },
500
+ );
501
+ this.cursor.lastSyncId = serverHead;
502
+ // Fire a follow-up incremental sync to re-deliver anything we
503
+ // were missing. Fire-and-forget — the next response will go
504
+ // through this same path. The infinite-loop concern is bounded
505
+ // by the `serverHead < this.cursor.lastSyncId` strict-less check: once
506
+ // we've reset to `serverHead`, the next response with the same
507
+ // (or higher) `currentSyncId` won't re-enter this branch. A `.catch`
508
+ // (not `void`) so a failed send logs instead of surfacing as an
509
+ // unhandled rejection.
510
+ this.requestIncrementalSync().catch((e: unknown) => {
511
+ getContext().observability.breadcrumb(
512
+ 'Post-cursor-reset sync request failed',
513
+ 'sync.websocket',
514
+ 'warning',
515
+ {
516
+ error: e instanceof Error ? e.message : String(e),
517
+ }
518
+ );
519
+ });
520
+ }
521
+ }
522
+
523
+ if (payload.requiresBootstrap) {
524
+ this.emit('bootstrap_required', payload.bootstrapHint);
525
+ return;
526
+ }
527
+
528
+ // Process incremental deltas
529
+ if (rawDeltas) {
530
+ // Process all deltas from sync response - store handles idempotency.
531
+ // Same receive-boundary validation + normalization as handleDelta —
532
+ // catch-up replays from older servers carry string ids too, and
533
+ // malformed deltas drop out of the batch instead of being applied.
534
+ const newDeltas: SyncDelta[] = [];
535
+ for (const d of rawDeltas) {
536
+ const delta = this.normalizeWireDelta(d);
537
+ if (delta) newDeltas.push(delta);
538
+ }
539
+
540
+ if (newDeltas.length > 0) {
541
+ // DO NOT pre-advance `this.cursor.lastSyncId` here. Same reasoning as
542
+ // `handleDelta`: the runtime cursor must stay consistent with
543
+ // IDB. The delta_batch event routes through
544
+ // `BaseSyncedStore.processDeltaWithBatching` →
545
+ // `flushPendingDeltas`, which calls `acknowledge()` with the
546
+ // honest `persistedSyncId` once IDB commits. That ack is what
547
+ // moves `this.cursor.lastSyncId` forward.
548
+
549
+ // Emit ALL deltas as a single batch event
550
+ this.emit('delta_batch', newDeltas);
551
+ }
552
+ }
553
+
554
+ // Update cursor. (`newVersions` from pre-cutover servers is ignored —
555
+ // the version vector was removed in W4a; `sync_id` is the causality token.)
556
+ if (typeof payload.newCursor === 'string' && payload.newCursor) {
557
+ this.cursor.syncCursor = payload.newCursor;
558
+ } else if (typeof payload.cursor === 'string' && payload.cursor) {
559
+ this.cursor.syncCursor = payload.cursor;
560
+ }
561
+ }
562
+
563
+ /**
564
+ * Handle bootstrap response from server
565
+ */
566
+ protected override handleBootstrapResponse(payload: unknown): void {
567
+ // Emit the bootstrap data for processing. (A `version` field from older
568
+ // servers is ignored; the version vector is no longer used.) The typeof
569
+ // guards mirror the cursor handling above: the frame is server-produced, so
570
+ // coercion only bites on a malformed frame.
571
+ const p = (payload && typeof payload === 'object' ? payload : {}) as {
572
+ entityType?: unknown;
573
+ data?: unknown;
574
+ isComplete?: unknown;
575
+ cursor?: unknown;
576
+ };
577
+ this.emit('bootstrap_data', {
578
+ entityType: typeof p.entityType === 'string' ? p.entityType : '',
579
+ data: p.data,
580
+ isComplete: p.isComplete === true,
581
+ cursor: typeof p.cursor === 'string' ? p.cursor : undefined,
582
+ });
583
+ }
584
+ }