@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,539 @@
1
+ /**
2
+ * ModelRegistry is the source of truth for model metadata: which model classes
3
+ * exist, the properties and references declared on each, the back-references
4
+ * used for cascade handling, and a stable hash of the whole schema.
5
+ * {@link Model} instances resolve their metadata through the active registry,
6
+ * and {@link InstanceCache} uses it to map between model names and constructor
7
+ * classes. References resolve lazily, so a model may declare a reference to
8
+ * another model that is registered later.
9
+ */
10
+ // Removed Node.js crypto import for browser compatibility
11
+ import { PropertyType, LoadStrategy, } from '@abloatai/transaction/types';
12
+ import { globalRuntime } from './context.js';
13
+ import { AbloValidationError } from '@abloatai/transaction/errors';
14
+ /**
15
+ * Module-level active registry. Set by createSyncEngine so that Model instances
16
+ * (which don't receive DI) can look up metadata without static maps.
17
+ */
18
+ let _activeRegistry = null;
19
+ /** Set the active ModelRegistry instance (called by createSyncEngine) */
20
+ export function setActiveRegistry(registry) {
21
+ _activeRegistry = registry;
22
+ }
23
+ /** Get the active ModelRegistry. Throws if none set. */
24
+ export function getActiveRegistry() {
25
+ if (!_activeRegistry) {
26
+ throw new AbloValidationError('No active ModelRegistry — call createSyncEngine() first', { code: 'registry_not_initialized' });
27
+ }
28
+ return _activeRegistry;
29
+ }
30
+ /** Whether an active ModelRegistry has been set. */
31
+ export function hasActiveRegistry() {
32
+ return _activeRegistry !== null;
33
+ }
34
+ /** Clear the active ModelRegistry (tests only). */
35
+ export function clearActiveRegistry() {
36
+ _activeRegistry = null;
37
+ }
38
+ export class ModelRegistry {
39
+ models = new Map();
40
+ modelMetadata = new Map();
41
+ properties = new Map();
42
+ references = new Map();
43
+ pendingReferences = new Map();
44
+ // Maps a constructor back to its model name. Keyed as `unknown` on purpose:
45
+ // lookups arrive both as `this.constructor` (a Function) and as typed model
46
+ // classes, and both are accepted without a cast.
47
+ constructorToModelName = new Map();
48
+ // Back-references for cascade-aware transaction handling. Maps a child model
49
+ // name to the parent models it references. The inverse direction (parent to
50
+ // children) is derived on demand by `getChildModels`; it is populated here.
51
+ backReferences = new Map();
52
+ schemaHash;
53
+ config;
54
+ runtime;
55
+ registeredModels = new Set();
56
+ pendingHashUpdate = false;
57
+ constructor(config = {}) {
58
+ this.config = {
59
+ validateOnRegister: config.validateOnRegister ?? true,
60
+ allowLateReferences: config.allowLateReferences ?? true,
61
+ };
62
+ this.runtime = config.runtime ?? globalRuntime;
63
+ }
64
+ validateModelConstructor(name, constructor) {
65
+ if (typeof constructor !== 'function') {
66
+ throw new AbloValidationError(`Model ${name} constructor must be a function`, { code: 'registry_invalid_constructor' });
67
+ }
68
+ const prototype = constructor.prototype;
69
+ if (!prototype || typeof prototype !== 'object') {
70
+ throw new AbloValidationError(`Model ${name} constructor must have a prototype`, { code: 'registry_invalid_constructor' });
71
+ }
72
+ // Check for required methods
73
+ const required = ['updateFromData', 'toJSON', 'getModelName'];
74
+ for (const method of required) {
75
+ if (typeof prototype[method] !== 'function') {
76
+ this.runtime.logger.debug('Model missing required method', name, { method });
77
+ }
78
+ }
79
+ }
80
+ arePropertiesCompatible(existing, incoming) {
81
+ // For reference-generated ID properties, be more lenient
82
+ // Only check core compatibility, not all metadata fields
83
+ return (existing.type === incoming.type &&
84
+ // For indexed, treat undefined as false for comparison
85
+ (existing.indexed ?? false) === (incoming.indexed ?? false) &&
86
+ // For optional, treat undefined as false for comparison
87
+ (existing.optional ?? false) === (incoming.optional ?? false));
88
+ }
89
+ addPendingReference(modelName, propertyName, metadata) {
90
+ // Get target model name
91
+ let targetName;
92
+ try {
93
+ targetName = metadata.referencedModel()?.name || 'Unknown';
94
+ }
95
+ catch {
96
+ targetName = 'Unknown';
97
+ }
98
+ let pending = this.pendingReferences.get(targetName);
99
+ if (!pending) {
100
+ pending = [];
101
+ this.pendingReferences.set(targetName, pending);
102
+ }
103
+ pending.push({ modelName, propertyName, metadata });
104
+ this.runtime.logger.debug('Reference deferred', `${modelName}.${propertyName}`, { targetModel: targetName });
105
+ }
106
+ resolvePendingReferences(targetModelName) {
107
+ const pending = this.pendingReferences.get(targetModelName);
108
+ if (!pending)
109
+ return;
110
+ for (const ref of pending) {
111
+ try {
112
+ this.completeReferenceRegistration(ref.modelName, ref.propertyName, ref.metadata);
113
+ this.runtime.logger.debug('Reference resolved', `${ref.modelName}.${ref.propertyName}`, {
114
+ targetModel: targetModelName,
115
+ });
116
+ }
117
+ catch (error) {
118
+ this.runtime.observability.breadcrumb(`Failed to resolve reference ${ref.modelName}.${ref.propertyName}`, 'sync.database', 'error', {
119
+ error: error instanceof Error ? error.message : String(error),
120
+ });
121
+ }
122
+ }
123
+ this.pendingReferences.delete(targetModelName);
124
+ }
125
+ completeReferenceRegistration(modelName, propertyName, metadata) {
126
+ // Store reference
127
+ let refs = this.references.get(modelName);
128
+ if (!refs) {
129
+ refs = new Map();
130
+ this.references.set(modelName, refs);
131
+ }
132
+ refs.set(propertyName, metadata);
133
+ // Register ID property (skip organizationId as it's handled by models themselves)
134
+ const idPropName = propertyName.endsWith('Id') ? propertyName : `${propertyName}Id`;
135
+ if (idPropName !== 'organizationId') {
136
+ this.registerProperty(modelName, idPropName, {
137
+ type: PropertyType.reference,
138
+ indexed: metadata.indexed || false,
139
+ optional: metadata.nullable || false,
140
+ });
141
+ }
142
+ // Register model property
143
+ this.registerProperty(modelName, propertyName, {
144
+ type: PropertyType.referenceModel,
145
+ optional: metadata.nullable || false,
146
+ });
147
+ this.schemaHash = undefined;
148
+ }
149
+ /**
150
+ * Register a model with validation
151
+ */
152
+ registerModel(name, constructor, metadata = { loadStrategy: LoadStrategy.instant }) {
153
+ // Validate
154
+ if (this.config.validateOnRegister) {
155
+ this.validateModelConstructor(name, constructor);
156
+ }
157
+ // Check for duplicate
158
+ if (this.models.has(name)) {
159
+ this.runtime.logger.debug('Model already registered, skipping', name);
160
+ return;
161
+ }
162
+ this.runtime.logger.debug('Registering model', name);
163
+ // Register. The one cast in this file: input is any Model-subclass
164
+ // constructor (validated above); registered classes are concrete
165
+ // subclasses constructible with `data?` and carrying Model's statics —
166
+ // the shape `RegisteredModelClass` names for every read site.
167
+ const modelClass = constructor;
168
+ this.models.set(name, modelClass);
169
+ this.modelMetadata.set(name, metadata);
170
+ // Record the reverse mapping from constructor to model name
171
+ this.constructorToModelName.set(constructor, name);
172
+ // Initialize property maps
173
+ if (!this.properties.has(name)) {
174
+ this.properties.set(name, new Map());
175
+ }
176
+ if (!this.references.has(name)) {
177
+ this.references.set(name, new Map());
178
+ }
179
+ // Mark as registered
180
+ this.registeredModels.add(name);
181
+ // Resolve pending references to this model
182
+ this.resolvePendingReferences(name);
183
+ // Invalidate schema hash
184
+ this.schemaHash = undefined;
185
+ this.runtime.logger.debug('Model registered', name, metadata);
186
+ }
187
+ /**
188
+ * Register property with validation
189
+ */
190
+ registerProperty(modelName, propertyName, metadata) {
191
+ // Validate model exists
192
+ if (!this.models.has(modelName) && this.config.validateOnRegister) {
193
+ throw new AbloValidationError(`Cannot register property for unknown model: ${modelName}`, { code: 'registry_unknown_model' });
194
+ }
195
+ // Get or create property map
196
+ let props = this.properties.get(modelName);
197
+ if (!props) {
198
+ props = new Map();
199
+ this.properties.set(modelName, props);
200
+ }
201
+ // Check for conflicts
202
+ const existing = props.get(propertyName);
203
+ if (existing) {
204
+ if (this.arePropertiesCompatible(existing, metadata)) {
205
+ // Properties are compatible, skip re-registration
206
+ this.runtime.logger.debug('Property already registered (compatible)', `${modelName}.${propertyName}`);
207
+ return;
208
+ }
209
+ else {
210
+ throw new AbloValidationError(`Property ${modelName}.${propertyName} already registered with incompatible metadata`, { code: 'registry_property_conflict' });
211
+ }
212
+ }
213
+ props.set(propertyName, metadata);
214
+ this.schemaHash = undefined;
215
+ this.runtime.logger.debug('Property registered', `${modelName}.${propertyName}`, metadata);
216
+ }
217
+ /**
218
+ * Register reference with lazy resolution
219
+ */
220
+ registerReference(modelName, propertyName, metadata) {
221
+ // Try to resolve target model
222
+ let targetModelName;
223
+ try {
224
+ const targetModel = metadata.referencedModel();
225
+ targetModelName = targetModel?.name;
226
+ }
227
+ catch {
228
+ // Defer resolution
229
+ if (this.config.allowLateReferences) {
230
+ this.addPendingReference(modelName, propertyName, metadata);
231
+ return;
232
+ }
233
+ throw new AbloValidationError(`Cannot resolve reference ${modelName}.${propertyName}`, { code: 'registry_reference_unresolved' });
234
+ }
235
+ // Validate target exists or defer
236
+ if (!this.models.has(targetModelName)) {
237
+ if (this.config.allowLateReferences) {
238
+ this.addPendingReference(modelName, propertyName, metadata);
239
+ return;
240
+ }
241
+ throw new AbloValidationError(`Reference ${modelName}.${propertyName} points to unknown model ${targetModelName}`, { code: 'registry_reference_unknown_target' });
242
+ }
243
+ // Complete registration
244
+ this.completeReferenceRegistration(modelName, propertyName, metadata);
245
+ }
246
+ /**
247
+ * Register a back-reference for cascade-aware transaction handling.
248
+ *
249
+ * When a parent model is deleted, the transaction queue cancels pending
250
+ * transactions for every child model that declares a back-reference to that
251
+ * parent.
252
+ *
253
+ * @param childModelName - The model that holds a foreign key to the parent (e.g., 'Section')
254
+ * @param metadata - The back-reference configuration
255
+ */
256
+ registerBackReference(childModelName, metadata) {
257
+ // Add to instance map
258
+ let refs = this.backReferences.get(childModelName);
259
+ if (!refs) {
260
+ refs = [];
261
+ this.backReferences.set(childModelName, refs);
262
+ }
263
+ // Avoid duplicates
264
+ const exists = refs.some((r) => r.parentModel === metadata.parentModel && r.foreignKey === metadata.foreignKey);
265
+ if (!exists) {
266
+ refs.push(metadata);
267
+ }
268
+ // Reverse lookup (parent → children) is derived on demand by
269
+ // `getChildModels`, which scans this map.
270
+ this.runtime.logger.debug('BackReference registered', `${childModelName} -> ${metadata.parentModel}`, {
271
+ foreignKey: metadata.foreignKey,
272
+ cascadeDelete: metadata.cascadeDelete,
273
+ });
274
+ }
275
+ /** Get all models with specific load strategy. */
276
+ getModelsByLoadStrategy(strategy) {
277
+ const models = [];
278
+ for (const [modelName, metadata] of this.modelMetadata) {
279
+ if (metadata.loadStrategy === strategy) {
280
+ models.push(modelName);
281
+ }
282
+ }
283
+ return models;
284
+ }
285
+ /** Get model name from constructor (production-safe). */
286
+ getModelNameFromConstructor(constructor) {
287
+ return this.constructorToModelName.get(constructor);
288
+ }
289
+ /** Get properties for a model. */
290
+ getPropertiesForModel(modelName) {
291
+ return this.properties.get(modelName) || new Map();
292
+ }
293
+ /**
294
+ * Get all registered model names for this instance
295
+ */
296
+ getRegisteredModelNames() {
297
+ return Array.from(this.models.keys());
298
+ }
299
+ /** Get model constructor by name */
300
+ getModelByName(name) {
301
+ return this.models.get(name);
302
+ }
303
+ /** Check if model is registered */
304
+ hasModel(name) {
305
+ return this.models.has(name);
306
+ }
307
+ /** Get model metadata by name */
308
+ getMetadata(name) {
309
+ return this.modelMetadata.get(name);
310
+ }
311
+ /** Get properties for a model */
312
+ getProperties(name) {
313
+ return this.properties.get(name) || new Map();
314
+ }
315
+ /** Get references for a model */
316
+ getReferences(name) {
317
+ return this.references.get(name) || new Map();
318
+ }
319
+ /** Get indexed properties for a model */
320
+ getIndexedProperties(modelName) {
321
+ const properties = this.getProperties(modelName);
322
+ const indexed = [];
323
+ for (const [propName, metadata] of properties) {
324
+ if (metadata.indexed)
325
+ indexed.push(propName);
326
+ }
327
+ return indexed;
328
+ }
329
+ /** Get back-references for a child model */
330
+ getBackReferences(childModelName) {
331
+ return this.backReferences.get(childModelName) || [];
332
+ }
333
+ /** Get child models for a parent */
334
+ getChildModels(parentModelName) {
335
+ // Derive from backReferences
336
+ const children = [];
337
+ for (const [childModel, refs] of this.backReferences) {
338
+ for (const ref of refs) {
339
+ if (ref.parentModel === parentModelName) {
340
+ children.push({ childModel, foreignKey: ref.foreignKey });
341
+ }
342
+ }
343
+ }
344
+ return children;
345
+ }
346
+ /**
347
+ * Compute a stable hash of the registered schema — model names, property
348
+ * types, and their indexed and optional flags. Memoized until the schema
349
+ * changes.
350
+ */
351
+ getSchemaHash() {
352
+ if (this.schemaHash)
353
+ return this.schemaHash;
354
+ const schema = {};
355
+ // Build schema object
356
+ for (const [modelName, props] of this.properties) {
357
+ schema[modelName] = {};
358
+ for (const [propName, meta] of props) {
359
+ schema[modelName][propName] = {
360
+ type: meta.type,
361
+ indexed: meta.indexed || false,
362
+ optional: meta.optional || false,
363
+ };
364
+ }
365
+ }
366
+ // Sort and stringify
367
+ const sorted = JSON.stringify(schema, Object.keys(schema).sort());
368
+ // Create hash - browser-compatible simple hash
369
+ this.schemaHash = this.simpleHash(sorted);
370
+ this.runtime.logger.debug('Schema hash updated', this.schemaHash);
371
+ return this.schemaHash;
372
+ }
373
+ /**
374
+ * Browser-compatible hash function
375
+ */
376
+ simpleHash(str) {
377
+ let hash = 0;
378
+ for (let i = 0; i < str.length; i++) {
379
+ const char = str.charCodeAt(i);
380
+ hash = (hash << 5) - hash + char;
381
+ hash = hash & hash; // Convert to 32bit integer
382
+ }
383
+ return Math.abs(hash).toString(16).padStart(8, '0');
384
+ }
385
+ /**
386
+ * Static wrapper for backward compatibility
387
+ */
388
+ /**
389
+ * Validate all references
390
+ */
391
+ validateReferences() {
392
+ const errors = [];
393
+ // Check pending references
394
+ for (const [target, pending] of this.pendingReferences) {
395
+ for (const ref of pending) {
396
+ errors.push(`Unresolved reference: ${ref.modelName}.${ref.propertyName} -> ${target}`);
397
+ }
398
+ }
399
+ // Check resolved references
400
+ for (const [modelName, refs] of this.references) {
401
+ for (const [propName, meta] of refs) {
402
+ try {
403
+ const target = meta.referencedModel();
404
+ if (!this.models.has(target.name)) {
405
+ errors.push(`Invalid reference: ${modelName}.${propName} -> ${target.name}`);
406
+ }
407
+ }
408
+ catch (error) {
409
+ errors.push(`Cannot resolve reference: ${modelName}.${propName}`);
410
+ }
411
+ }
412
+ }
413
+ const isValid = errors.length === 0;
414
+ if (isValid) {
415
+ this.runtime.logger.info('All model references are valid');
416
+ }
417
+ else {
418
+ this.runtime.observability.breadcrumb('Reference validation failed', 'sync.database', 'error');
419
+ }
420
+ return {
421
+ valid: isValid,
422
+ errors,
423
+ };
424
+ }
425
+ /**
426
+ * Static wrapper for backward compatibility
427
+ */
428
+ /**
429
+ * Start batch registration mode to optimize performance
430
+ */
431
+ startBatch() {
432
+ this.pendingHashUpdate = false;
433
+ }
434
+ /**
435
+ * Static wrapper for backward compatibility
436
+ */
437
+ /**
438
+ * End batch registration mode and update schema hash if needed
439
+ */
440
+ endBatch() {
441
+ if (this.pendingHashUpdate) {
442
+ this.getSchemaHash(); // This will recalculate if needed
443
+ this.pendingHashUpdate = false;
444
+ }
445
+ }
446
+ /**
447
+ * Static wrapper for backward compatibility
448
+ */
449
+ /**
450
+ * Clear registry
451
+ */
452
+ clear() {
453
+ this.models.clear();
454
+ this.modelMetadata.clear();
455
+ this.properties.clear();
456
+ this.references.clear();
457
+ this.pendingReferences.clear();
458
+ this.registeredModels.clear();
459
+ this.backReferences.clear();
460
+ this.constructorToModelName.clear();
461
+ this.schemaHash = undefined;
462
+ this.pendingHashUpdate = false;
463
+ this.runtime.logger.info('ModelRegistry cleared');
464
+ }
465
+ /**
466
+ * Static wrapper for backward compatibility
467
+ */
468
+ /**
469
+ * Export for debugging
470
+ */
471
+ export() {
472
+ return {
473
+ models: Array.from(this.models.keys()),
474
+ metadata: Object.fromEntries(this.modelMetadata),
475
+ properties: Object.fromEntries(Array.from(this.properties.entries()).map(([name, props]) => [
476
+ name,
477
+ Object.fromEntries(props),
478
+ ])),
479
+ references: Object.fromEntries(Array.from(this.references.entries()).map(([name, refs]) => [
480
+ name,
481
+ Object.fromEntries(refs),
482
+ ])),
483
+ pending: Object.fromEntries(Array.from(this.pendingReferences.entries()).map(([name, refs]) => [
484
+ name,
485
+ refs.map((r) => `${r.modelName}.${r.propertyName}`),
486
+ ])),
487
+ schemaHash: this.getSchemaHash(),
488
+ };
489
+ }
490
+ /**
491
+ * Export registry data for debugging (backward compatibility)
492
+ */
493
+ exportRegistryData() {
494
+ const models = {};
495
+ const properties = {};
496
+ const references = {};
497
+ const metadata = {};
498
+ // Export models
499
+ for (const [name, constructor] of this.models) {
500
+ models[name] = constructor.name;
501
+ }
502
+ // Export properties
503
+ for (const [modelName, propertyMap] of this.properties) {
504
+ properties[modelName] = {};
505
+ for (const [propName, propMetadata] of propertyMap) {
506
+ properties[modelName][propName] = propMetadata;
507
+ }
508
+ }
509
+ // Export references
510
+ for (const [modelName, referenceMap] of this.references) {
511
+ references[modelName] = {};
512
+ for (const [refName, refMetadata] of referenceMap) {
513
+ try {
514
+ references[modelName][refName] = {
515
+ ...refMetadata,
516
+ referencedModel: refMetadata.referencedModel().name,
517
+ };
518
+ }
519
+ catch {
520
+ references[modelName][refName] = {
521
+ ...refMetadata,
522
+ referencedModel: 'Unresolved',
523
+ };
524
+ }
525
+ }
526
+ }
527
+ // Export metadata
528
+ for (const [modelName, modelMetadata] of this.modelMetadata) {
529
+ metadata[modelName] = modelMetadata;
530
+ }
531
+ return {
532
+ models,
533
+ properties,
534
+ references,
535
+ metadata,
536
+ schemaHash: this.getSchemaHash(),
537
+ };
538
+ }
539
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * NetworkMonitor tracks network connectivity and reports it through events.
3
+ * It listens to the browser's online and offline events, and it also watches
4
+ * for a tab becoming visible again: after a laptop sleep/wake or a long spell
5
+ * in the background, the WebSocket can die silently without an offline event
6
+ * firing, so returning to the tab emits a recovery signal the store can act on.
7
+ */
8
+ import { EventEmitter } from 'events';
9
+ import type { RuntimeContext } from './RuntimeContext.js';
10
+ export declare class NetworkMonitor extends EventEmitter {
11
+ private readonly runtime;
12
+ private isOnline;
13
+ private lastOnlineCheck;
14
+ constructor(runtime?: RuntimeContext);
15
+ private handleOnline;
16
+ private handleOffline;
17
+ /**
18
+ * When the tab becomes visible, the WebSocket may have silently died
19
+ * (e.g., laptop sleep/wake, long background). Browser online/offline events
20
+ * don't fire in this case because the network itself didn't change.
21
+ * Emit 'visibility_online' so SyncedStore can check and recover.
22
+ */
23
+ private handleVisibilityChange;
24
+ private setupListeners;
25
+ getStatus(): boolean;
26
+ getLastOnlineTime(): Date;
27
+ dispose(): void;
28
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * NetworkMonitor tracks network connectivity and reports it through events.
3
+ * It listens to the browser's online and offline events, and it also watches
4
+ * for a tab becoming visible again: after a laptop sleep/wake or a long spell
5
+ * in the background, the WebSocket can die silently without an offline event
6
+ * firing, so returning to the tab emits a recovery signal the store can act on.
7
+ */
8
+ import { EventEmitter } from 'events';
9
+ import { globalRuntime } from './context.js';
10
+ export class NetworkMonitor extends EventEmitter {
11
+ runtime;
12
+ // Only `navigator.onLine === false` means offline. Node 18+ exposes a global
13
+ // `navigator` with `onLine === undefined`, so the naive `navigator.onLine`
14
+ // would seed `false` (offline) on every server client — start optimistic.
15
+ isOnline = !(typeof navigator !== 'undefined' && navigator.onLine === false);
16
+ lastOnlineCheck = new Date();
17
+ constructor(runtime = globalRuntime) {
18
+ super();
19
+ this.runtime = runtime;
20
+ this.setupListeners();
21
+ }
22
+ handleOnline = () => {
23
+ const wasOffline = !this.isOnline;
24
+ this.isOnline = true;
25
+ this.lastOnlineCheck = new Date();
26
+ if (wasOffline) {
27
+ this.runtime.logger.info('Network connection restored');
28
+ this.emit('online');
29
+ }
30
+ };
31
+ handleOffline = () => {
32
+ const wasOnline = this.isOnline;
33
+ this.isOnline = false;
34
+ if (wasOnline) {
35
+ // Symmetric with 'Network connection restored' (info) — expected,
36
+ // transient connectivity state, not an actionable warning.
37
+ this.runtime.logger.info('Network connection lost');
38
+ this.emit('offline');
39
+ }
40
+ };
41
+ /**
42
+ * When the tab becomes visible, the WebSocket may have silently died
43
+ * (e.g., laptop sleep/wake, long background). Browser online/offline events
44
+ * don't fire in this case because the network itself didn't change.
45
+ * Emit 'visibility_online' so SyncedStore can check and recover.
46
+ */
47
+ handleVisibilityChange = () => {
48
+ if (document.visibilityState !== 'visible')
49
+ return;
50
+ // Update navigator.onLine state — it may have changed while hidden
51
+ this.isOnline = navigator.onLine;
52
+ this.lastOnlineCheck = new Date();
53
+ if (this.isOnline) {
54
+ this.runtime.logger.info('Tab became visible with network available — emitting visibility_online');
55
+ this.emit('visibility_online');
56
+ }
57
+ };
58
+ setupListeners() {
59
+ if (typeof window === 'undefined')
60
+ return;
61
+ window.addEventListener('online', this.handleOnline);
62
+ window.addEventListener('offline', this.handleOffline);
63
+ document.addEventListener('visibilitychange', this.handleVisibilityChange);
64
+ }
65
+ getStatus() {
66
+ return this.isOnline;
67
+ }
68
+ getLastOnlineTime() {
69
+ return this.lastOnlineCheck;
70
+ }
71
+ dispose() {
72
+ if (typeof window !== 'undefined') {
73
+ window.removeEventListener('online', this.handleOnline);
74
+ window.removeEventListener('offline', this.handleOffline);
75
+ document.removeEventListener('visibilitychange', this.handleVisibilityChange);
76
+ }
77
+ this.removeAllListeners();
78
+ }
79
+ }