@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,343 @@
1
+ /**
2
+ * Handles the delta types that change which sync groups a session can see. A
3
+ * sync group is a fan-out scope the server uses to decide which entities a
4
+ * client receives. When a session's membership changes, these handlers update
5
+ * the client's subscription list; when access is revoked, they clear cached
6
+ * data and trigger a full re-bootstrap so revoked rows cannot linger on the
7
+ * device.
8
+ *
9
+ * Every handler takes a {@link GroupChangeContext}, the narrow facade through
10
+ * which it reaches the client's local storage and connection lifecycle hooks.
11
+ */
12
+
13
+ import { globalRuntime } from '../context.js';
14
+ import type { RuntimeContext } from '../RuntimeContext.js';
15
+ import type {
16
+ SyncDelta,
17
+ SyncGroupChangePayload,
18
+ GroupAddedPayload,
19
+ } from './SyncWebSocket.js';
20
+
21
+ /**
22
+ * The collaborators the group-change handlers depend on. It gathers the
23
+ * client's local storage, in-memory pool, and connection lifecycle hooks
24
+ * behind one narrow interface, so the handlers stay decoupled from the larger
25
+ * store that supplies them.
26
+ */
27
+ export interface GroupChangeContext {
28
+ /**
29
+ * Local persistence. Performs the security clear, reads and writes the
30
+ * subscription metadata, and sets the flag that forces a full bootstrap.
31
+ */
32
+ readonly database: {
33
+ clear(): Promise<void>;
34
+ getWorkspaceMetadata(): Promise<{ subscribedSyncGroups?: string[] } | null>;
35
+ updateWorkspaceMetadata(metadata: { subscribedSyncGroups: string[] }): Promise<void>;
36
+ markRequiresFullBootstrap(): void;
37
+ };
38
+ /** The in-memory object cache, cleared alongside local storage when access is revoked. */
39
+ readonly objectPool: { clear(): void };
40
+ /** Returns the sync groups the live connection is currently subscribed to. */
41
+ getSubscribedSyncGroups(): readonly string[];
42
+ /**
43
+ * Returns the session's authoritative sync groups, resolved from the current
44
+ * user context via {@link resolveSyncGroups}; null when no user context has
45
+ * been set yet.
46
+ */
47
+ getCurrentSyncGroups(): readonly string[] | null;
48
+ /**
49
+ * Returns the session's bootstrap mode. A value of 'none' means the
50
+ * participant never pulls a baseline, so it never re-bootstraps.
51
+ */
52
+ getBootstrapMode(): 'full' | 'none' | undefined;
53
+ /** Disconnects the live connection, one step of the forced re-bootstrap cycle. */
54
+ disconnectWebSocket(): void;
55
+ /** Emits a connection lifecycle event to any registered listener; a no-op when none is set. */
56
+ emitConnectionEvent(event: string): void;
57
+ // Entry points the handlers call into each other through. Routing them via
58
+ // the context keeps any override the surrounding store provides in effect.
59
+ handleGroupAdded(payload: GroupAddedPayload, syncId: number): Promise<void>;
60
+ computeUpdatedSyncGroups(payload: SyncGroupChangePayload): string[];
61
+ forceFullRebootstrap(): void;
62
+ /** The owning client's runtime. Defaults to the module-global bridge. */
63
+ readonly runtime?: RuntimeContext;
64
+ }
65
+
66
+ /** The context's runtime, falling back to the module-global bridge. */
67
+ const runtimeOf = (ctx: GroupChangeContext): RuntimeContext =>
68
+ ctx.runtime ?? globalRuntime;
69
+
70
+ /**
71
+ * Marker returned when a group-change payload cannot be parsed, kept distinct
72
+ * from a valid null or absent payload, which the handlers accept normally.
73
+ */
74
+ const MALFORMED_PAYLOAD: unique symbol = Symbol('malformed-group-change-payload');
75
+
76
+ /**
77
+ * Parses a group-change delta payload without ever throwing. The server sends
78
+ * these as JSON strings. If a frame is corrupt, this returns
79
+ * {@link MALFORMED_PAYLOAD} rather than raising, because an error escaping here
80
+ * would leave the delta pipeline after the watermark has already advanced. The
81
+ * delta is never re-delivered, so the security clear it carried would be lost.
82
+ */
83
+ function parseGroupChangePayload(delta: SyncDelta, runtime: RuntimeContext): unknown {
84
+ if (typeof delta.data !== 'string') return delta.data;
85
+ try {
86
+ return JSON.parse(delta.data);
87
+ } catch (error) {
88
+ runtime.logger.debug('[BaseSyncedStore] Malformed group-change payload', {
89
+ syncId: delta.id,
90
+ actionType: delta.actionType,
91
+ error: error instanceof Error ? error.message : String(error),
92
+ });
93
+ return MALFORMED_PAYLOAD;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Fallback for a group-change delta that could not be read. Because we know
99
+ * access changed but not how, this treats it as a revocation: it clears cached
100
+ * data from both local storage and the in-memory pool, then forces a full
101
+ * re-bootstrap from the server.
102
+ */
103
+ async function clearForUnknownGroupChange(
104
+ ctx: GroupChangeContext,
105
+ delta: SyncDelta,
106
+ kind: string,
107
+ ): Promise<void> {
108
+ runtimeOf(ctx).logger.debug(
109
+ `[BaseSyncedStore] Unreadable ${kind} payload — clearing cached data and re-bootstrapping`,
110
+ { syncId: delta.id },
111
+ );
112
+ // Revoked data must not persist if the device goes offline before the
113
+ // re-bootstrap, the same reasoning as the explicit removed-groups path.
114
+ await ctx.database.clear();
115
+ ctx.objectPool.clear();
116
+ ctx.forceFullRebootstrap();
117
+ }
118
+
119
+ /**
120
+ * Handles a 'G' (group-change) delta. The server sends two shapes of this
121
+ * delta, told apart by the payload:
122
+ *
123
+ * Incremental — `{ group, userId }`: the recipient was added to a single
124
+ * sync group. No re-bootstrap follows; the newly visible entities arrive as
125
+ * ordinary 'C' (covering) deltas through the normal insert path.
126
+ *
127
+ * Full diff — `{ addedGroups, removedGroups }`: one delta carrying the whole
128
+ * membership change. This forces a full re-bootstrap (disconnect, reconnect,
129
+ * and refetch), clearing cached data first if any group was removed.
130
+ */
131
+ export async function handleSyncGroupChange(
132
+ ctx: GroupChangeContext,
133
+ delta: SyncDelta,
134
+ ): Promise<void> {
135
+ const raw = parseGroupChangePayload(delta, runtimeOf(ctx));
136
+ if (raw === MALFORMED_PAYLOAD) {
137
+ // The payload is unreadable, so we cannot tell which groups changed, and
138
+ // this delta will never be re-delivered because the watermark has already
139
+ // advanced. Fall back to the safe direction: assume a revocation, clear
140
+ // cached data, and rebuild from the server rather than throwing.
141
+ await clearForUnknownGroupChange(ctx, delta, 'sync-group change');
142
+ return;
143
+ }
144
+ const rawObj = (raw ?? {}) as Record<string, unknown>;
145
+
146
+ // Detect incremental payload shape: { group, userId }
147
+ if (typeof rawObj.group === 'string' && typeof rawObj.userId === 'string') {
148
+ const incremental: GroupAddedPayload = {
149
+ group: rawObj.group,
150
+ userId: rawObj.userId,
151
+ };
152
+ await ctx.handleGroupAdded(incremental, delta.id);
153
+ return;
154
+ }
155
+
156
+ // Full-diff payload: { addedGroups, removedGroups }
157
+ const payload: SyncGroupChangePayload = {
158
+ removedGroups: (rawObj.removedGroups as string[]) ?? [],
159
+ addedGroups: (rawObj.addedGroups as string[]) ?? [],
160
+ };
161
+
162
+ runtimeOf(ctx).logger.info('[BaseSyncedStore] Sync group change received (legacy)', {
163
+ removedGroups: payload.removedGroups,
164
+ addedGroups: payload.addedGroups,
165
+ syncId: delta.id,
166
+ });
167
+
168
+ // If any groups were removed, clear cached data immediately so revoked data
169
+ // cannot persist should the device go offline before the re-bootstrap
170
+ // completes.
171
+ if (payload.removedGroups.length > 0) {
172
+ await ctx.database.clear();
173
+ ctx.objectPool.clear();
174
+ runtimeOf(ctx).logger.info('[BaseSyncedStore] Cleared cached data due to revoked sync groups', {
175
+ removedGroups: payload.removedGroups,
176
+ });
177
+ }
178
+
179
+ const updatedGroups = ctx.computeUpdatedSyncGroups(payload);
180
+ await ctx.database.updateWorkspaceMetadata({ subscribedSyncGroups: updatedGroups });
181
+ ctx.forceFullRebootstrap();
182
+ }
183
+
184
+ /**
185
+ * Handles an incremental group-added delta. It records the new sync group in
186
+ * the subscription metadata without forcing a re-bootstrap; the server then
187
+ * sends a 'C' (covering) delta for each newly visible entity, which flows
188
+ * through the normal insert path.
189
+ */
190
+ export async function handleGroupAdded(
191
+ ctx: GroupChangeContext,
192
+ payload: GroupAddedPayload,
193
+ syncId: number,
194
+ ): Promise<void> {
195
+ runtimeOf(ctx).logger.info('[BaseSyncedStore] Group added (incremental)', {
196
+ group: payload.group,
197
+ syncId,
198
+ });
199
+
200
+ const current = new Set(ctx.getSubscribedSyncGroups());
201
+ current.add(payload.group);
202
+ await ctx.database.updateWorkspaceMetadata({ subscribedSyncGroups: Array.from(current) });
203
+ // No forceFullRebootstrap() here; the covering deltas will bring the entities.
204
+ }
205
+
206
+ /**
207
+ * Handles an 'S' (group-removed) delta, which signals the recipient has lost
208
+ * access to a sync group. The client does not track which entities belong to
209
+ * which group, so it cannot purge only the affected rows; instead it clears
210
+ * local state and forces a re-bootstrap with the updated group list.
211
+ */
212
+ export async function handleGroupRemoved(
213
+ ctx: GroupChangeContext,
214
+ delta: SyncDelta,
215
+ ): Promise<void> {
216
+ const raw = parseGroupChangePayload(delta, runtimeOf(ctx));
217
+ if (raw === MALFORMED_PAYLOAD) {
218
+ // The payload is unreadable: access was revoked but we cannot tell which
219
+ // group. Fall back to a full clear, the safe direction for an
220
+ // access-revocation delta, rather than throwing.
221
+ await clearForUnknownGroupChange(ctx, delta, 'group-removed');
222
+ return;
223
+ }
224
+ const rawObj = (raw ?? {}) as Record<string, unknown>;
225
+ const groupKey = typeof rawObj.group === 'string' ? rawObj.group : undefined;
226
+
227
+ if (!groupKey) {
228
+ runtimeOf(ctx).logger.debug('[BaseSyncedStore] Group removed delta missing group key', {
229
+ syncId: delta.id,
230
+ });
231
+ return;
232
+ }
233
+
234
+ runtimeOf(ctx).logger.info('[BaseSyncedStore] Group removed', {
235
+ group: groupKey,
236
+ syncId: delta.id,
237
+ });
238
+
239
+ // Clear cached data before the re-bootstrap so revoked-group data cannot
240
+ // persist if the device goes offline between receiving this delta and
241
+ // completing the re-bootstrap.
242
+ await ctx.database.clear();
243
+ ctx.objectPool.clear();
244
+
245
+ // Update subscription metadata so the re-bootstrap fetches the
246
+ // correct set of groups.
247
+ const current = new Set(ctx.getSubscribedSyncGroups());
248
+ current.delete(groupKey);
249
+ await ctx.database.updateWorkspaceMetadata({ subscribedSyncGroups: Array.from(current) });
250
+
251
+ ctx.forceFullRebootstrap();
252
+ }
253
+
254
+ /** Computes the new sync-group set after applying the additions and removals in a diff. */
255
+ export function computeUpdatedSyncGroups(
256
+ ctx: GroupChangeContext,
257
+ payload: SyncGroupChangePayload,
258
+ ): string[] {
259
+ const current = new Set(ctx.getSubscribedSyncGroups());
260
+ for (const g of payload.removedGroups) current.delete(g);
261
+ for (const g of payload.addedGroups) current.add(g);
262
+ return Array.from(current);
263
+ }
264
+
265
+ /**
266
+ * Forces a full re-bootstrap by marking local storage as needing one,
267
+ * disconnecting, and emitting a connection lifecycle event that the reconnect
268
+ * path acts on. Does nothing for participants whose bootstrap mode is 'none':
269
+ * they never pull a baseline, so after a trigger such as a sync-group shrink or
270
+ * an access revocation they rely on covering deltas to repopulate the data they
271
+ * subscribe to.
272
+ */
273
+ export function forceFullRebootstrap(ctx: GroupChangeContext): void {
274
+ if (ctx.getBootstrapMode() === 'none') {
275
+ runtimeOf(ctx).logger.info(
276
+ '[BaseSyncedStore] forceFullRebootstrap skipped (bootstrapMode=none)',
277
+ );
278
+ return;
279
+ }
280
+ ctx.database.markRequiresFullBootstrap();
281
+ ctx.disconnectWebSocket();
282
+ ctx.emitConnectionEvent('WS_DISCONNECTED');
283
+ }
284
+
285
+ /**
286
+ * Resolves the sync-group list this session subscribes to, and is the single
287
+ * place that decision is made. The server-issued `context.syncGroups` is
288
+ * authoritative; when it is absent, the session subscribes to no explicit
289
+ * groups. {@link checkSyncGroupShrinkage} and connection setup both read
290
+ * through here, so the live subscription and the access-revocation check can
291
+ * never disagree.
292
+ */
293
+ export function resolveSyncGroups(context: {
294
+ syncGroups?: readonly string[];
295
+ }): readonly string[] {
296
+ if (context.syncGroups && context.syncGroups.length > 0) {
297
+ return context.syncGroups;
298
+ }
299
+ return [];
300
+ }
301
+
302
+ /**
303
+ * Compares the session's current sync groups against the set stored from the
304
+ * last session. If any group is now missing, access has narrowed, so this
305
+ * clears cached data and forces a full bootstrap before recording the new set.
306
+ */
307
+ export async function checkSyncGroupShrinkage(ctx: GroupChangeContext): Promise<void> {
308
+ const currentSyncGroups = ctx.getCurrentSyncGroups();
309
+ if (!currentSyncGroups) return;
310
+
311
+ try {
312
+ const metadata = await ctx.database.getWorkspaceMetadata();
313
+ const stored = metadata?.subscribedSyncGroups ?? [];
314
+ if (stored.length === 0) return;
315
+
316
+ const currentGroups = new Set(currentSyncGroups);
317
+
318
+ const removedGroups = stored.filter((g: string) => !currentGroups.has(g));
319
+
320
+ if (removedGroups.length > 0) {
321
+ runtimeOf(ctx).logger.info('[BaseSyncedStore] Sync groups shrank — forcing full bootstrap', {
322
+ removedGroups,
323
+ storedCount: stored.length,
324
+ currentCount: currentGroups.size,
325
+ });
326
+
327
+ // Clear cached data before the re-bootstrap so revoked-group data cannot
328
+ // persist if the device goes offline first.
329
+ await ctx.database.clear();
330
+ ctx.objectPool.clear();
331
+
332
+ ctx.database.markRequiresFullBootstrap();
333
+ }
334
+
335
+ await ctx.database.updateWorkspaceMetadata({
336
+ subscribedSyncGroups: Array.from(currentGroups),
337
+ });
338
+ } catch (error) {
339
+ runtimeOf(ctx).logger.debug('[BaseSyncedStore] Failed to check sync group shrinkage', {
340
+ error: error instanceof Error ? error.message : String(error),
341
+ });
342
+ }
343
+ }
@@ -0,0 +1,205 @@
1
+ import { AbloSessionError } from '@abloatai/transaction/errors';
2
+ import type { RuntimeContext } from '../RuntimeContext.js';
3
+ import type { BootstrapRequirements, Database } from '../Database.js';
4
+ import type { SyncClient } from '../SyncClient.js';
5
+ import type { UserContext } from '../BaseSyncedStore.js';
6
+ import type { InstanceCache } from '../InstanceCache.js';
7
+ import type { DefaultCollaborationEvents, EventMap, SyncWebSocket } from './SyncWebSocket.js';
8
+ import type { SyncStatus } from '../storeContract.js';
9
+
10
+ export interface InitializeHost<
11
+ TCollaboration extends EventMap<TCollaboration> = DefaultCollaborationEvents,
12
+ > {
13
+ initialized: boolean;
14
+ userContext: UserContext;
15
+ dataReady: boolean;
16
+ runtime: RuntimeContext;
17
+ database: Database;
18
+ syncClient: SyncClient;
19
+ objectPool: InstanceCache;
20
+ syncWebSocket: SyncWebSocket<TCollaboration>;
21
+ updateSyncStatus(updates: Partial<SyncStatus>): void;
22
+ setupWebSocketSync(context: UserContext, lastSyncId: number): void;
23
+ waitForWebSocketConnected(timeoutMs: number): Promise<boolean>;
24
+ performBackgroundBootstrap(
25
+ requirements: Awaited<ReturnType<Database['requiredBootstrap']>>,
26
+ context: UserContext,
27
+ signal?: AbortSignal,
28
+ ): Promise<void>;
29
+ executeBootstrapWithTimeout(
30
+ fn: () => Promise<void>,
31
+ context: UserContext,
32
+ signal?: AbortSignal,
33
+ ): Promise<void>;
34
+ resolveSyncGroups(context: UserContext): readonly string[];
35
+ }
36
+
37
+ export function* initialize<TCollaboration extends EventMap<TCollaboration>>(
38
+ host: InitializeHost<TCollaboration>,
39
+ context: UserContext,
40
+ signal?: AbortSignal,
41
+ ): Generator<Promise<void | number | boolean | BootstrapRequirements>, { success: boolean; error?: Error }, void | number | boolean | BootstrapRequirements> {
42
+ if (host.initialized) return { success: true };
43
+
44
+ host.userContext = context;
45
+
46
+ try {
47
+ host.updateSyncStatus({ state: 'syncing', progress: 0 });
48
+
49
+ // The commit outbox and offline mutation journal live in IndexedDB.
50
+ // Open it before SyncClient restores either one; reading first used to
51
+ // make persistence silently look empty on every cold start.
52
+ yield host.database.open({
53
+ participantId: context.userId,
54
+ organizationId: context.organizationId,
55
+ participantKind: context.kind ?? 'user',
56
+ projectId: context.projectId ?? context.organizationId,
57
+ environment: context.environment ?? null,
58
+ sandboxId: context.sandboxId ?? null,
59
+ });
60
+
61
+ // Propagate identity only after storage is ready, then restore sealed
62
+ // requests before accepting fresh mutations.
63
+ yield host.syncClient.initialize(
64
+ context.userId,
65
+ context.organizationId,
66
+ );
67
+
68
+ // Hydrate from IndexedDB (fast, cached data)
69
+ let hasLocalData = false;
70
+ try {
71
+ yield host.syncClient.hydrateFromDatabase();
72
+ hasLocalData = host.objectPool.size > 0;
73
+ } catch (hydrateError) {
74
+ host.runtime.logger.debug('[sync-engine] IDB hydration failed', { error: hydrateError });
75
+ host.runtime.observability.captureBootstrapFailure(hydrateError, { type: 'hydration-from-idb' });
76
+ }
77
+
78
+ // Get sync baseline for WebSocket
79
+ const lastSyncId = (yield host.database.getLastSyncId()) as number;
80
+ host.syncClient.position.advancePersisted(lastSyncId || 0);
81
+
82
+ // If local data available, show UI immediately
83
+ if (hasLocalData) {
84
+ host.dataReady = true;
85
+ host.initialized = true;
86
+ host.updateSyncStatus({ state: 'syncing', progress: 50 });
87
+ }
88
+
89
+ // Setup WebSocket
90
+ host.setupWebSocketSync(context, lastSyncId);
91
+
92
+ // Bootstrap from server if needed.
93
+ //
94
+ // `bootstrapMode: 'none'` participants (agent-worker, headless
95
+ // task runners) skip baseline replication — they read via
96
+ // `model.get()` round-trips and rely on covering deltas
97
+ // from filtered subscriptions to populate the pool lazily. The
98
+ // WS is already open by `setupWebSocketSync` above, so live
99
+ // delta flow works regardless of this branch.
100
+ const requirements = (yield host.database.requiredBootstrap()) as Awaited<
101
+ ReturnType<typeof host.database.requiredBootstrap>
102
+ >;
103
+
104
+ if (context.bootstrapMode === 'none') {
105
+ host.runtime.logger.info(
106
+ '[BaseSyncedStore] Bootstrap skipped (bootstrapMode=none)',
107
+ { kind: context.kind ?? 'user' },
108
+ );
109
+ // `setupWebSocketSync` above creates the SyncWebSocket and
110
+ // initiates the upgrade, but it does NOT await the 'connected'
111
+ // event — it returns synchronously after wiring listeners.
112
+ // For bootstrapMode='none' consumers (agent-worker, headless
113
+ // task runners), this branch is the entire body of initialize()
114
+ // after the WS is set up, so `ready()` would otherwise resolve
115
+ // while the WS is still in 'connecting' state. The very next
116
+ // `commits.create` then throws "SyncWebSocket not connected".
117
+ //
118
+ // For bootstrapMode='full' consumers we don't need this await:
119
+ // `executeBootstrapWithTimeout` below sends the bootstrap RPC
120
+ // which inherently requires the WS to be open, so it surfaces
121
+ // a connection error if the upgrade hasn't completed.
122
+ //
123
+ // 5s bound is generous (typical connect is <100ms); past that
124
+ // we return anyway and let the next commit attempt fail loudly
125
+ // rather than block initialize() forever.
126
+ yield host.waitForWebSocketConnected(5000);
127
+ } else if (requirements.type !== 'local') {
128
+ if (hasLocalData) {
129
+ // Background bootstrap — don't block UI. The method captures its own
130
+ // operational failures; this backstop covers escapes from the
131
+ // delta-queue replay in withDeltaQueuing's finally (and the error
132
+ // handler itself), which would otherwise vanish unhandled.
133
+ void host.performBackgroundBootstrap(requirements, context, signal).catch(
134
+ (error) => {
135
+ host.runtime.observability.captureBootstrapFailure(error, {
136
+ type: 'background-orchestration',
137
+ });
138
+ }
139
+ );
140
+ } else {
141
+ // First load — must wait for server data
142
+ yield host.executeBootstrapWithTimeout(
143
+ async () => {
144
+ await host.database.bootstrapFromServer(
145
+ requirements,
146
+ host.resolveSyncGroups(context),
147
+ );
148
+ },
149
+ context,
150
+ signal
151
+ );
152
+ yield host.syncClient.hydrateFromDatabase();
153
+ host.dataReady = true;
154
+ host.initialized = true;
155
+ }
156
+ }
157
+
158
+ if (!host.initialized) host.initialized = true;
159
+ if (!host.dataReady) {
160
+ host.dataReady = true;
161
+ }
162
+
163
+ host.updateSyncStatus({ state: 'idle', progress: 100 });
164
+ return { success: true };
165
+ } catch (error) {
166
+ const isAbort = error instanceof DOMException && error.name === 'AbortError';
167
+ if (isAbort) {
168
+ host.dataReady = false;
169
+ host.initialized = false;
170
+ host.updateSyncStatus({ state: 'idle', progress: 0 });
171
+ return { success: false, error: error };
172
+ }
173
+
174
+ const isSession = AbloSessionError.isSessionError(error);
175
+ host.runtime.observability.captureBootstrapFailure(error, { type: 'initialize' });
176
+
177
+ if (isSession) {
178
+ host.syncWebSocket.setSessionErrorDetected();
179
+ host.syncWebSocket.disconnect();
180
+ host.updateSyncStatus({ state: 'error', error: error });
181
+ return { success: false, error: error };
182
+ }
183
+
184
+ // Fallback: show local data if available
185
+ if (host.objectPool.size === 0) {
186
+ try {
187
+ yield host.syncClient.hydrateFromDatabase();
188
+ } catch {}
189
+ }
190
+
191
+ if (host.objectPool.size > 0) {
192
+ host.dataReady = true;
193
+ host.initialized = true;
194
+ host.updateSyncStatus(
195
+ host.syncWebSocket.isConnected()
196
+ ? { state: 'idle', progress: 100 }
197
+ : { state: 'offline', offlineSince: new Date() }
198
+ );
199
+ return { success: true };
200
+ }
201
+
202
+ host.updateSyncStatus({ state: 'error', error: error as Error });
203
+ return { success: false, error: error as Error };
204
+ }
205
+ }