@livestore/livestore 0.4.0-dev.21 → 0.4.0-dev.23

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 (216) hide show
  1. package/README.md +0 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/QueryCache.js +1 -1
  4. package/dist/QueryCache.js.map +1 -1
  5. package/dist/SqliteDbWrapper.d.ts +5 -5
  6. package/dist/SqliteDbWrapper.d.ts.map +1 -1
  7. package/dist/SqliteDbWrapper.js +8 -8
  8. package/dist/SqliteDbWrapper.js.map +1 -1
  9. package/dist/SqliteDbWrapper.test.js +2 -2
  10. package/dist/SqliteDbWrapper.test.js.map +1 -1
  11. package/dist/effect/LiveStore.d.ts +130 -2
  12. package/dist/effect/LiveStore.d.ts.map +1 -1
  13. package/dist/effect/LiveStore.js +185 -6
  14. package/dist/effect/LiveStore.js.map +1 -1
  15. package/dist/effect/LiveStore.test.d.ts +2 -0
  16. package/dist/effect/LiveStore.test.d.ts.map +1 -0
  17. package/dist/effect/LiveStore.test.js +42 -0
  18. package/dist/effect/LiveStore.test.js.map +1 -0
  19. package/dist/effect/mod.d.ts +1 -1
  20. package/dist/effect/mod.d.ts.map +1 -1
  21. package/dist/effect/mod.js +3 -1
  22. package/dist/effect/mod.js.map +1 -1
  23. package/dist/live-queries/base-class.d.ts +3 -3
  24. package/dist/live-queries/base-class.d.ts.map +1 -1
  25. package/dist/live-queries/base-class.js +2 -2
  26. package/dist/live-queries/base-class.js.map +1 -1
  27. package/dist/live-queries/client-document-get-query.d.ts +1 -1
  28. package/dist/live-queries/client-document-get-query.d.ts.map +1 -1
  29. package/dist/live-queries/client-document-get-query.js +1 -1
  30. package/dist/live-queries/client-document-get-query.js.map +1 -1
  31. package/dist/live-queries/computed.d.ts.map +1 -1
  32. package/dist/live-queries/computed.js +2 -2
  33. package/dist/live-queries/computed.js.map +1 -1
  34. package/dist/live-queries/db-query.js +14 -14
  35. package/dist/live-queries/db-query.js.map +1 -1
  36. package/dist/live-queries/db-query.test.js +2 -2
  37. package/dist/live-queries/db-query.test.js.map +1 -1
  38. package/dist/live-queries/signal.test.js +2 -2
  39. package/dist/live-queries/signal.test.js.map +1 -1
  40. package/dist/mod.d.ts +2 -1
  41. package/dist/mod.d.ts.map +1 -1
  42. package/dist/mod.js +1 -0
  43. package/dist/mod.js.map +1 -1
  44. package/dist/reactive.d.ts +9 -9
  45. package/dist/reactive.d.ts.map +1 -1
  46. package/dist/reactive.js +9 -26
  47. package/dist/reactive.js.map +1 -1
  48. package/dist/reactive.test.js +2 -2
  49. package/dist/reactive.test.js.map +1 -1
  50. package/dist/store/StoreRegistry.d.ts +215 -0
  51. package/dist/store/StoreRegistry.d.ts.map +1 -0
  52. package/dist/store/StoreRegistry.js +267 -0
  53. package/dist/store/StoreRegistry.js.map +1 -0
  54. package/dist/store/StoreRegistry.test.d.ts +2 -0
  55. package/dist/store/StoreRegistry.test.d.ts.map +1 -0
  56. package/dist/store/StoreRegistry.test.js +381 -0
  57. package/dist/store/StoreRegistry.test.js.map +1 -0
  58. package/dist/store/create-store.d.ts +56 -6
  59. package/dist/store/create-store.d.ts.map +1 -1
  60. package/dist/store/create-store.js +32 -7
  61. package/dist/store/create-store.js.map +1 -1
  62. package/dist/store/devtools.d.ts +1 -1
  63. package/dist/store/devtools.d.ts.map +1 -1
  64. package/dist/store/devtools.js +16 -3
  65. package/dist/store/devtools.js.map +1 -1
  66. package/dist/store/store-eventstream.test.js +2 -2
  67. package/dist/store/store-eventstream.test.js.map +1 -1
  68. package/dist/store/store-types.d.ts +59 -9
  69. package/dist/store/store-types.d.ts.map +1 -1
  70. package/dist/store/store-types.js.map +1 -1
  71. package/dist/store/store-types.test.js +1 -1
  72. package/dist/store/store-types.test.js.map +1 -1
  73. package/dist/store/store.d.ts +102 -6
  74. package/dist/store/store.d.ts.map +1 -1
  75. package/dist/store/store.js +148 -47
  76. package/dist/store/store.js.map +1 -1
  77. package/dist/utils/dev.js.map +1 -1
  78. package/dist/utils/stack-info.js +2 -2
  79. package/dist/utils/stack-info.js.map +1 -1
  80. package/dist/utils/tests/fixture.d.ts +1 -1
  81. package/dist/utils/tests/fixture.d.ts.map +1 -1
  82. package/dist/utils/tests/fixture.js.map +1 -1
  83. package/dist/utils/tests/otel.d.ts.map +1 -1
  84. package/dist/utils/tests/otel.js +5 -5
  85. package/dist/utils/tests/otel.js.map +1 -1
  86. package/package.json +59 -18
  87. package/src/QueryCache.ts +1 -1
  88. package/src/SqliteDbWrapper.test.ts +4 -2
  89. package/src/SqliteDbWrapper.ts +12 -11
  90. package/src/ambient.d.ts +0 -7
  91. package/src/effect/LiveStore.test.ts +61 -0
  92. package/src/effect/LiveStore.ts +381 -8
  93. package/src/effect/mod.ts +13 -1
  94. package/src/live-queries/__snapshots__/db-query.test.ts.snap +336 -231
  95. package/src/live-queries/base-class.ts +7 -6
  96. package/src/live-queries/client-document-get-query.ts +4 -2
  97. package/src/live-queries/computed.ts +3 -2
  98. package/src/live-queries/db-query.test.ts +3 -2
  99. package/src/live-queries/db-query.ts +15 -15
  100. package/src/live-queries/signal.test.ts +3 -2
  101. package/src/mod.ts +2 -0
  102. package/src/reactive.test.ts +3 -2
  103. package/src/reactive.ts +22 -23
  104. package/src/store/StoreRegistry.test.ts +540 -0
  105. package/src/store/StoreRegistry.ts +418 -0
  106. package/src/store/create-store.ts +76 -15
  107. package/src/store/devtools.ts +20 -6
  108. package/src/store/store-eventstream.test.ts +4 -2
  109. package/src/store/store-types.test.ts +3 -1
  110. package/src/store/store-types.ts +64 -13
  111. package/src/store/store.ts +197 -60
  112. package/src/utils/dev.ts +2 -2
  113. package/src/utils/stack-info.ts +2 -2
  114. package/src/utils/tests/fixture.ts +2 -1
  115. package/src/utils/tests/otel.ts +8 -7
  116. package/docs/api/index.md +0 -3
  117. package/docs/building-with-livestore/complex-ui-state/index.md +0 -5
  118. package/docs/building-with-livestore/crud/index.md +0 -5
  119. package/docs/building-with-livestore/data-modeling/index.md +0 -1
  120. package/docs/building-with-livestore/debugging/index.md +0 -17
  121. package/docs/building-with-livestore/devtools/index.md +0 -79
  122. package/docs/building-with-livestore/events/index.md +0 -355
  123. package/docs/building-with-livestore/examples/ai-agent/index.md +0 -5
  124. package/docs/building-with-livestore/examples/index.md +0 -30
  125. package/docs/building-with-livestore/examples/todo-workspaces/index.md +0 -891
  126. package/docs/building-with-livestore/examples/turnbased-game/index.md +0 -7
  127. package/docs/building-with-livestore/opentelemetry/index.md +0 -208
  128. package/docs/building-with-livestore/production-checklist/index.md +0 -5
  129. package/docs/building-with-livestore/reactivity-system/index.md +0 -202
  130. package/docs/building-with-livestore/rules-for-ai-agents/index.md +0 -9
  131. package/docs/building-with-livestore/state/materializers/index.md +0 -300
  132. package/docs/building-with-livestore/state/sql-queries/index.md +0 -72
  133. package/docs/building-with-livestore/state/sqlite/index.md +0 -45
  134. package/docs/building-with-livestore/state/sqlite-schema/index.md +0 -306
  135. package/docs/building-with-livestore/state/sqlite-schema-effect/index.md +0 -300
  136. package/docs/building-with-livestore/store/index.md +0 -281
  137. package/docs/building-with-livestore/syncing/index.md +0 -136
  138. package/docs/building-with-livestore/tools/cli/index.md +0 -177
  139. package/docs/building-with-livestore/tools/mcp/index.md +0 -187
  140. package/docs/examples/cloudflare-adapter/index.md +0 -44
  141. package/docs/examples/expo-adapter/index.md +0 -44
  142. package/docs/examples/index.md +0 -55
  143. package/docs/examples/node-adapter/index.md +0 -44
  144. package/docs/examples/web-adapter/index.md +0 -52
  145. package/docs/framework-integrations/custom-elements/index.md +0 -142
  146. package/docs/framework-integrations/react-integration/index.md +0 -918
  147. package/docs/framework-integrations/solid-integration/index.md +0 -293
  148. package/docs/framework-integrations/svelte-integration/index.md +0 -42
  149. package/docs/framework-integrations/vue-integration/index.md +0 -294
  150. package/docs/getting-started/expo/index.md +0 -736
  151. package/docs/getting-started/node/index.md +0 -115
  152. package/docs/getting-started/react-web/index.md +0 -573
  153. package/docs/getting-started/solid/index.md +0 -3
  154. package/docs/getting-started/vue/index.md +0 -471
  155. package/docs/index.md +0 -209
  156. package/docs/llms.txt +0 -147
  157. package/docs/misc/CODE_OF_CONDUCT/index.md +0 -133
  158. package/docs/misc/FAQ/index.md +0 -37
  159. package/docs/misc/community/index.md +0 -88
  160. package/docs/misc/credits/index.md +0 -14
  161. package/docs/misc/design-partners/index.md +0 -13
  162. package/docs/misc/package-management/index.md +0 -21
  163. package/docs/misc/performance/index.md +0 -25
  164. package/docs/misc/resources/index.md +0 -46
  165. package/docs/misc/state-of-the-project/index.md +0 -37
  166. package/docs/misc/troubleshooting/index.md +0 -82
  167. package/docs/overview/concepts/index.md +0 -78
  168. package/docs/overview/how-livestore-works/index.md +0 -56
  169. package/docs/overview/introduction/index.md +0 -5
  170. package/docs/overview/technology-comparison/index.md +0 -40
  171. package/docs/overview/when-livestore/index.md +0 -81
  172. package/docs/overview/why-livestore/index.md +0 -5
  173. package/docs/patterns/ai/index.md +0 -15
  174. package/docs/patterns/anonymous-user-transition/index.md +0 -10
  175. package/docs/patterns/app-evolution/index.md +0 -72
  176. package/docs/patterns/auth/index.md +0 -226
  177. package/docs/patterns/effect/index.md +0 -1495
  178. package/docs/patterns/encryption/index.md +0 -6
  179. package/docs/patterns/external-data/index.md +0 -5
  180. package/docs/patterns/file-management/index.md +0 -11
  181. package/docs/patterns/file-structure/index.md +0 -14
  182. package/docs/patterns/list-ordering/index.md +0 -369
  183. package/docs/patterns/offline/index.md +0 -32
  184. package/docs/patterns/orm/index.md +0 -18
  185. package/docs/patterns/presence/index.md +0 -11
  186. package/docs/patterns/rich-text-editing/index.md +0 -11
  187. package/docs/patterns/server-side-clients/index.md +0 -97
  188. package/docs/patterns/side-effects/index.md +0 -11
  189. package/docs/patterns/state-machines/index.md +0 -11
  190. package/docs/patterns/storybook/index.md +0 -192
  191. package/docs/patterns/undo-redo/index.md +0 -9
  192. package/docs/patterns/version-control/index.md +0 -8
  193. package/docs/platform-adapters/cloudflare-durable-object-adapter/index.md +0 -453
  194. package/docs/platform-adapters/electron-adapter/index.md +0 -15
  195. package/docs/platform-adapters/expo-adapter/index.md +0 -245
  196. package/docs/platform-adapters/node-adapter/index.md +0 -160
  197. package/docs/platform-adapters/tauri-adapter/index.md +0 -15
  198. package/docs/platform-adapters/web-adapter/index.md +0 -218
  199. package/docs/sustainable-open-source/contributing/docs/index.md +0 -94
  200. package/docs/sustainable-open-source/contributing/info/index.md +0 -63
  201. package/docs/sustainable-open-source/contributing/monorepo/index.md +0 -195
  202. package/docs/sustainable-open-source/sponsoring/index.md +0 -104
  203. package/docs/sync-providers/cloudflare/index.md +0 -773
  204. package/docs/sync-providers/custom/index.md +0 -65
  205. package/docs/sync-providers/electricsql/index.md +0 -159
  206. package/docs/sync-providers/s2/index.md +0 -230
  207. package/docs/tutorial/0-welcome/index.md +0 -48
  208. package/docs/tutorial/1-setup-starter-project/index.md +0 -105
  209. package/docs/tutorial/2-deploy-to-cloudflare/index.md +0 -195
  210. package/docs/tutorial/3-read-and-write-todos-via-livestore/index.md +0 -511
  211. package/docs/tutorial/4-sync-data-via-cloudflare/index.md +0 -210
  212. package/docs/tutorial/5-expand-business-logic/index.md +0 -174
  213. package/docs/tutorial/6-persist-ui-state/index.md +0 -453
  214. package/docs/tutorial/7-next-steps/index.md +0 -22
  215. package/docs/understanding-livestore/design-decisions/index.md +0 -33
  216. package/docs/understanding-livestore/event-sourcing/index.md +0 -40
@@ -1,6 +1,6 @@
1
+ import { describe, expect, it } from 'vitest';
1
2
  import { QueryBuilderTypeId } from '@livestore/common';
2
3
  import { Schema } from '@livestore/utils/effect';
3
- import { describe, expect, it } from 'vitest';
4
4
  import { TypeId } from "../live-queries/base-class.js";
5
5
  import { queryDb, signal } from "../live-queries/mod.js";
6
6
  import { isQueryable } from "./store-types.js";
@@ -1 +1 @@
1
- {"version":3,"file":"store-types.test.js","sourceRoot":"","sources":["../../src/store/store-types.test.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAA;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,MAAM,gBAAgB,GAAG,GAAgC,EAAE,CACzD,CAAC;IACC,CAAC,kBAAkB,CAAC,EAAE,kBAAkB;IACxC,UAAU,EAAE,IAAI;IAChB,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,GAAG,EAAU,EAAE,CAAC;IACnF,QAAQ,EAAE,GAAG,EAAE,CAAC,UAAU;CAC3B,CAA2C,CAAA;AAE9C,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,GAAG,GAAG,OAAO,CAAC;YAClB,KAAK,EAAE,mBAAmB;YAC1B,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;SAC9D,CAAC,CAAA;QAEF,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;QAEzC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,aAAa,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAW,CAAA;QAEnD,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAA;QAE7B,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACrC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC1C,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"store-types.test.js","sourceRoot":"","sources":["../../src/store/store-types.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAG7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEhD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAA;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,MAAM,gBAAgB,GAAG,GAAgC,EAAE,CACzD,CAAC;IACC,CAAC,kBAAkB,CAAC,EAAE,kBAAkB;IACxC,UAAU,EAAE,IAAI;IAChB,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,GAAG,EAAU,EAAE,CAAC;IACnF,QAAQ,EAAE,GAAG,EAAE,CAAC,UAAU;CAC3B,CAA2C,CAAA;AAE9C,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,GAAG,GAAG,OAAO,CAAC;YAClB,KAAK,EAAE,mBAAmB;YAC1B,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;SAC9D,CAAC,CAAA;QAEF,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;QAEzC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,aAAa,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAW,CAAA;QAEnD,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAA;QAE7B,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACrC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC1C,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1,10 +1,10 @@
1
- import { type Bindable, type ClientSession, MaterializeError, UnknownError } from '@livestore/common';
1
+ import { type Bindable, type ClientSession, MaterializeError, type StorageMode, type SyncState, UnknownError } from '@livestore/common';
2
2
  import type { LiveStoreSchema } from '@livestore/common/schema';
3
3
  import { LiveStoreEvent } from '@livestore/common/schema';
4
4
  import { Cause, Effect, Inspectable, Schema, Stream } from '@livestore/utils/effect';
5
5
  import * as otel from '@opentelemetry/api';
6
6
  import type { SignalDef } from '../live-queries/base-class.ts';
7
- import { type Queryable, type RefreshReason, type StoreCommitOptions, type StoreEventsOptions, type StoreInternals, StoreInternalsSymbol, type StoreOptions, type SubscribeOptions, type Unsubscribe } from './store-types.ts';
7
+ import { type Queryable, type RefreshReason, type StoreCommitOptions, type StoreConstructorParams, type StoreEventsOptions, type StoreInternals, StoreInternalsSymbol, type SubscribeOptions, type SyncStatus, type Unsubscribe } from './store-types.ts';
8
8
  export type SubscribeFn = {
9
9
  <TResult>(query: Queryable<TResult>, onUpdate: (value: TResult) => void, options?: SubscribeOptions<TResult>): Unsubscribe;
10
10
  <TResult>(query: Queryable<TResult>, options?: SubscribeOptions<TResult>): AsyncIterable<TResult>;
@@ -26,8 +26,8 @@ export declare const STORE_DEFAULT_PARAMS: {
26
26
  * ## Creating a Store
27
27
  *
28
28
  * Use `createStore` (Effect-based) or `createStorePromise` to obtain a Store instance.
29
- * In React applications, use the `<LiveStoreProvider>` component which manages the Store lifecycle
30
- * and exposes it via React context.
29
+ * In React applications, use `StoreRegistry` with `<StoreRegistryProvider>` and the `useStore()` hook
30
+ * which manages the Store lifecycle.
31
31
  *
32
32
  * ## Querying Data
33
33
  *
@@ -69,7 +69,7 @@ export declare class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any
69
69
  /** User-defined context attached to this Store (e.g. for dependency injection). */
70
70
  readonly context: TContext;
71
71
  /** Options provided to the Store constructor. */
72
- readonly params: StoreOptions<TSchema, TContext>['params'];
72
+ readonly params: StoreConstructorParams<TSchema, TContext>['params'];
73
73
  /**
74
74
  * Reactive connectivity updates emitted by the backing sync backend.
75
75
  *
@@ -88,11 +88,28 @@ export declare class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any
88
88
  * ```
89
89
  */
90
90
  readonly networkStatus: ClientSession['leaderThread']['networkStatus'];
91
+ /**
92
+ * Indicates how data is being stored.
93
+ *
94
+ * - `persisted`: Data is persisted to disk (e.g., via OPFS on web, SQLite file on native)
95
+ * - `in-memory`: Data is only stored in memory and will be lost on page refresh
96
+ *
97
+ * The store operates in `in-memory` mode when persistent storage is unavailable,
98
+ * such as in Safari/Firefox private browsing mode where OPFS is restricted.
99
+ *
100
+ * @example
101
+ * ```tsx
102
+ * if (store.storageMode === 'in-memory') {
103
+ * showWarning('Data will not be persisted in private browsing mode')
104
+ * }
105
+ * ```
106
+ */
107
+ readonly storageMode: StorageMode;
91
108
  /**
92
109
  * Store internals. Not part of the public API — shapes and semantics may change without notice.
93
110
  */
94
111
  readonly [StoreInternalsSymbol]: StoreInternals;
95
- constructor({ clientSession, schema, otelOptions, context, batchUpdates, storeId, effectContext, params, confirmUnsavedChanges, __runningInDevtools, }: StoreOptions<TSchema, TContext>);
112
+ constructor({ clientSession, schema, otelOptions, context, batchUpdates, storeId, effectContext, params, confirmUnsavedChanges, __runningInDevtools, }: StoreConstructorParams<TSchema, TContext>);
96
113
  /**
97
114
  * Current session identifier for this Store instance.
98
115
  *
@@ -272,6 +289,65 @@ export declare class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any
272
289
  * See `store.events` for details on options and behaviour.
273
290
  */
274
291
  eventsStream: (options?: StoreEventsOptions<TSchema>) => Stream.Stream<LiveStoreEvent.Client.ForSchema<TSchema>, UnknownError>;
292
+ /**
293
+ * Returns the current synchronization status of the store.
294
+ *
295
+ * This is a synchronous operation that returns the sync state between the
296
+ * client session and the leader thread. Use this to display sync indicators
297
+ * or check if local changes have been pushed to the leader.
298
+ *
299
+ * @example
300
+ * ```ts
301
+ * const status = store.syncStatus()
302
+ * console.log(status.isSynced ? 'Synced' : `${status.pendingCount} pending`)
303
+ * ```
304
+ *
305
+ * @example
306
+ * ```ts
307
+ * // Health check for backend connectivity
308
+ * const status = store.syncStatus()
309
+ * if (!status.isSynced && status.pendingCount > 100) {
310
+ * console.warn('Large backlog of unsynced events')
311
+ * }
312
+ * ```
313
+ */
314
+ syncStatus: () => SyncStatus;
315
+ /**
316
+ * Returns an Effect Stream of sync status updates.
317
+ *
318
+ * Emits the current status immediately and then whenever the sync state changes.
319
+ * Use this for Effect-based workflows or when you need more control over the stream.
320
+ *
321
+ * @example
322
+ * ```ts
323
+ * store.syncStatusStream().pipe(
324
+ * Stream.tap((status) => Effect.log(`Sync status: ${status.isSynced}`)),
325
+ * Stream.runDrain,
326
+ * )
327
+ * ```
328
+ */
329
+ syncStatusStream: () => Stream.Stream<SyncStatus>;
330
+ /**
331
+ * Subscribes to sync status changes.
332
+ *
333
+ * The callback is invoked immediately with the current status and then
334
+ * whenever the sync state changes (e.g., when events are pushed or confirmed).
335
+ *
336
+ * @param onUpdate - Callback invoked with the current sync status
337
+ * @returns Unsubscribe function to stop receiving updates
338
+ *
339
+ * @example
340
+ * ```ts
341
+ * const unsubscribe = store.subscribeSyncStatus((status) => {
342
+ * updateUI(status.isSynced ? 'Synced' : 'Syncing...')
343
+ * })
344
+ *
345
+ * // Later, stop listening
346
+ * unsubscribe()
347
+ * ```
348
+ */
349
+ subscribeSyncStatus: (onUpdate: (status: SyncStatus) => void) => Unsubscribe;
350
+ private makeSyncStatus;
275
351
  /**
276
352
  * This can be used in combination with `skipRefresh` when committing events.
277
353
  * We might need a better solution for this. Let's see.
@@ -291,6 +367,26 @@ export declare class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any
291
367
  * This is called automatically when the store was created using the React or Effect API.
292
368
  */
293
369
  shutdown: (cause?: Cause.Cause<UnknownError | MaterializeError>) => Effect.Effect<void>;
370
+ /**
371
+ * Helper methods useful during development
372
+ *
373
+ * @internal
374
+ */
375
+ _dev: {
376
+ downloadDb: (source?: "local" | "leader") => void;
377
+ downloadEventlogDb: () => void;
378
+ hardReset: (mode?: "all-data" | "only-app-db") => void;
379
+ overrideNetworkStatus: (status: "online" | "offline") => void;
380
+ syncStates: () => Promise<{
381
+ session: SyncState.SyncState;
382
+ leader: SyncState.SyncState;
383
+ }>;
384
+ printSyncStates: () => void;
385
+ version: string;
386
+ otel: {
387
+ rootSpanContext: () => otel.SpanContext | undefined;
388
+ };
389
+ };
294
390
  toJSON: () => {
295
391
  _tag: string;
296
392
  reactivityGraph: import("../reactive.ts").ReactiveGraphSnapshot;
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store/store.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { Devtools, getExecStatementsFromMaterializer, getResultSchema, hashMaterializerResults, IntentionalShutdownCause, isQueryBuilder, liveStoreVersion, MaterializeError, MaterializerHashMismatchError, makeClientSessionSyncProcessor, prepareBindValues, QueryBuilderAstSymbol, replaceSessionIdSymbol, UnknownError, } from '@livestore/common';
2
- import { LiveStoreEvent, resolveEventDef, SystemTables } from '@livestore/common/schema';
3
- import { assertNever, isDevEnv, omitUndefineds, shouldNeverHappen } from '@livestore/utils';
2
+ import { EventSequenceNumber, LiveStoreEvent, resolveEventDef, SystemTables } from '@livestore/common/schema';
3
+ import { assertNever, isDevEnv, objectToString, omitUndefineds, shouldNeverHappen } from '@livestore/utils';
4
4
  import { Cause, Effect, Exit, Fiber, Inspectable, Option, OtelTracer, Runtime, Schema, Stream, } from '@livestore/utils/effect';
5
5
  import { nanoid } from '@livestore/utils/nanoid';
6
6
  import * as otel from '@opentelemetry/api';
@@ -11,7 +11,7 @@ import { SqliteDbWrapper } from "../SqliteDbWrapper.js";
11
11
  import { ReferenceCountedSet } from "../utils/data-structures.js";
12
12
  import { downloadBlob, exposeDebugUtils } from "../utils/dev.js";
13
13
  import { StoreInternalsSymbol, } from "./store-types.js";
14
- if (isDevEnv()) {
14
+ if (isDevEnv() === true) {
15
15
  exposeDebugUtils();
16
16
  }
17
17
  /**
@@ -32,8 +32,8 @@ export const STORE_DEFAULT_PARAMS = {
32
32
  * ## Creating a Store
33
33
  *
34
34
  * Use `createStore` (Effect-based) or `createStorePromise` to obtain a Store instance.
35
- * In React applications, use the `<LiveStoreProvider>` component which manages the Store lifecycle
36
- * and exposes it via React context.
35
+ * In React applications, use `StoreRegistry` with `<StoreRegistryProvider>` and the `useStore()` hook
36
+ * which manages the Store lifecycle.
37
37
  *
38
38
  * ## Querying Data
39
39
  *
@@ -94,11 +94,28 @@ export class Store extends Inspectable.Class {
94
94
  * ```
95
95
  */
96
96
  networkStatus;
97
+ /**
98
+ * Indicates how data is being stored.
99
+ *
100
+ * - `persisted`: Data is persisted to disk (e.g., via OPFS on web, SQLite file on native)
101
+ * - `in-memory`: Data is only stored in memory and will be lost on page refresh
102
+ *
103
+ * The store operates in `in-memory` mode when persistent storage is unavailable,
104
+ * such as in Safari/Firefox private browsing mode where OPFS is restricted.
105
+ *
106
+ * @example
107
+ * ```tsx
108
+ * if (store.storageMode === 'in-memory') {
109
+ * showWarning('Data will not be persisted in private browsing mode')
110
+ * }
111
+ * ```
112
+ */
113
+ storageMode;
97
114
  /**
98
115
  * Store internals. Not part of the public API — shapes and semantics may change without notice.
99
116
  */
100
117
  [StoreInternalsSymbol];
101
- // #region constructor
118
+ //#region constructor
102
119
  constructor({ clientSession, schema, otelOptions, context, batchUpdates, storeId, effectContext, params, confirmUnsavedChanges, __runningInDevtools, }) {
103
120
  super();
104
121
  this.storeId = storeId;
@@ -106,12 +123,11 @@ export class Store extends Inspectable.Class {
106
123
  this.context = context;
107
124
  this.params = params;
108
125
  this.networkStatus = clientSession.leaderThread.networkStatus;
126
+ this.storageMode = clientSession.leaderThread.initialState.storageMode;
109
127
  const reactivityGraph = makeReactivityGraph();
110
- const syncSpan = otelOptions.tracer.startSpan('LiveStore:sync', {}, otelOptions.rootSpanContext);
111
128
  const syncProcessor = makeClientSessionSyncProcessor({
112
129
  schema,
113
130
  clientSession,
114
- runtime: effectContext.runtime,
115
131
  materializeEvent: Effect.fn('client-session-sync-processor:materialize-event')((eventEncoded, { withChangeset, materializerHashLeader }) =>
116
132
  // We need to use `Effect.gen` (even though we're using `Effect.fn`) so that we can pass `this` to the function
117
133
  Effect.gen(this, function* () {
@@ -135,7 +151,7 @@ export class Store extends Inspectable.Class {
135
151
  dbState: this[StoreInternalsSymbol].sqliteDbWrapper,
136
152
  event: { decoded: undefined, encoded: eventEncoded },
137
153
  });
138
- const materializerHash = isDevEnv() ? Option.some(hashMaterializerResults(execArgsArr)) : Option.none();
154
+ const materializerHash = isDevEnv() === true ? Option.some(hashMaterializerResults(execArgsArr)) : Option.none();
139
155
  // Hash mismatch detection only occurs during the pull path (when receiving events from the leader).
140
156
  // During push path (local commits), materializerHashLeader is always Option.none(), so this condition
141
157
  // will never be met. The check happens when the same event comes back from the leader during sync,
@@ -191,7 +207,6 @@ export class Store extends Inspectable.Class {
191
207
  }
192
208
  reactivityGraph.setRefs(tablesToUpdate);
193
209
  },
194
- span: syncSpan,
195
210
  params: {
196
211
  ...omitUndefineds({
197
212
  leaderPushBatchSize: params.leaderPushBatchSize,
@@ -201,7 +216,7 @@ export class Store extends Inspectable.Class {
201
216
  : {}),
202
217
  },
203
218
  confirmUnsavedChanges,
204
- });
219
+ }).pipe(Runtime.runSync(effectContext.runtime));
205
220
  // TODO generalize the `tableRefs` concept to allow finer-grained refs
206
221
  const tableRefs = {};
207
222
  const activeQueries = new ReferenceCountedSet();
@@ -227,7 +242,7 @@ export class Store extends Inspectable.Class {
227
242
  const allTableNames = new Set(
228
243
  // NOTE we're excluding the LiveStore schema and events tables as they are not user-facing
229
244
  // unless LiveStore is running in the devtools
230
- __runningInDevtools
245
+ __runningInDevtools === true
231
246
  ? this.schema.state.sqlite.tables.keys()
232
247
  : Array.from(this.schema.state.sqlite.tables.keys()).filter((_) => !SystemTables.isStateSystemTable(_)));
233
248
  const existingTableRefs = new Map(Array.from(reactivityGraph.atoms.values())
@@ -238,7 +253,7 @@ export class Store extends Inspectable.Class {
238
253
  existingTableRefs.get(tableName) ??
239
254
  reactivityGraph.makeRef(null, {
240
255
  equal: () => false,
241
- label: `tableRef:${tableName}`,
256
+ label: `tableRef:${String(tableName)}`,
242
257
  meta: { liveStoreRefType: 'table' },
243
258
  });
244
259
  }
@@ -251,7 +266,6 @@ export class Store extends Inspectable.Class {
251
266
  }
252
267
  }
253
268
  // End the otel spans
254
- syncSpan.end();
255
269
  commitsSpan.end();
256
270
  queriesSpan.end();
257
271
  }));
@@ -276,7 +290,7 @@ export class Store extends Inspectable.Class {
276
290
  // Initialize stable network status property from client session
277
291
  this.networkStatus = clientSession.leaderThread.networkStatus;
278
292
  }
279
- // #endregion constructor
293
+ //#endregion constructor
280
294
  /**
281
295
  * Current session identifier for this Store instance.
282
296
  *
@@ -296,7 +310,7 @@ export class Store extends Inspectable.Class {
296
310
  return this[StoreInternalsSymbol].clientSession.clientId;
297
311
  }
298
312
  checkShutdown = (operation) => {
299
- if (this[StoreInternalsSymbol].isShutdown) {
313
+ if (this[StoreInternalsSymbol].isShutdown === true) {
300
314
  throw new UnknownError({
301
315
  cause: `Store has been shut down (while performing "${operation}").`,
302
316
  note: `You cannot perform this operation after the store has been shut down.`,
@@ -329,9 +343,14 @@ export class Store extends Inspectable.Class {
329
343
  });
330
344
  subscribeWithCallback = (query, onUpdate, options) => {
331
345
  this.checkShutdown('subscribe');
332
- return this[StoreInternalsSymbol].otel.tracer.startActiveSpan(`LiveStore.subscribe`, { attributes: { label: options?.label, queryLabel: isQueryBuilder(query) ? query.toString() : query.label } }, options?.otelContext ?? this[StoreInternalsSymbol].otel.queriesSpanContext, (span) => {
346
+ return this[StoreInternalsSymbol].otel.tracer.startActiveSpan(`LiveStore.subscribe`, {
347
+ attributes: {
348
+ label: options?.label,
349
+ queryLabel: isQueryBuilder(query) === true ? query.toString() : query.label,
350
+ },
351
+ }, options?.otelContext ?? this[StoreInternalsSymbol].otel.queriesSpanContext, (span) => {
333
352
  const otelContext = otel.trace.setSpan(otel.context.active(), span);
334
- const queryRcRef = isQueryBuilder(query)
353
+ const queryRcRef = isQueryBuilder(query) === true
335
354
  ? queryDb(query).make(this[StoreInternalsSymbol].reactivityGraph.context)
336
355
  : query._tag === 'def' || query._tag === 'signal-def'
337
356
  ? query.make(this[StoreInternalsSymbol].reactivityGraph.context)
@@ -344,7 +363,7 @@ export class Store extends Inspectable.Class {
344
363
  let suppressCallback = options?.skipInitialRun === true;
345
364
  const effect = this[StoreInternalsSymbol].reactivityGraph.makeEffect((get, _otelContext, debugRefreshReason) => {
346
365
  const result = get(query$.results$, otelContext, debugRefreshReason);
347
- if (suppressCallback) {
366
+ if (suppressCallback === true) {
348
367
  return;
349
368
  }
350
369
  onUpdate(result);
@@ -355,13 +374,13 @@ export class Store extends Inspectable.Class {
355
374
  label: `subscribe-initial-run:${options?.label}`,
356
375
  });
357
376
  };
358
- if (options?.stackInfo) {
377
+ if (options?.stackInfo !== undefined) {
359
378
  query$.activeSubscriptions.add(options.stackInfo);
360
379
  }
361
380
  options?.onSubscribe?.(query$);
362
381
  this[StoreInternalsSymbol].activeQueries.add(query$);
363
- if (!query$.isDestroyed) {
364
- if (suppressCallback) {
382
+ if (query$.isDestroyed === false) {
383
+ if (suppressCallback === true) {
365
384
  // We still run once to register dependencies in the reactive graph, but suppress the initial callback so the
366
385
  // caller truly skips the first emission; subsequent runs (after commits) will call the callback.
367
386
  runInitialEffect();
@@ -375,7 +394,7 @@ export class Store extends Inspectable.Class {
375
394
  try {
376
395
  this[StoreInternalsSymbol].reactivityGraph.destroyNode(effect);
377
396
  this[StoreInternalsSymbol].activeQueries.remove(query$);
378
- if (options?.stackInfo) {
397
+ if (options?.stackInfo !== undefined) {
379
398
  query$.activeSubscriptions.delete(options.stackInfo);
380
399
  }
381
400
  queryRcRef.deref();
@@ -394,9 +413,9 @@ export class Store extends Inspectable.Class {
394
413
  };
395
414
  subscribeStream = (query, options) => Stream.asyncPush((emit) => Effect.gen(this, function* () {
396
415
  const otelSpan = yield* OtelTracer.currentOtelSpan.pipe(Effect.catchTag('NoSuchElementException', () => Effect.succeed(undefined)));
397
- const otelContext = otelSpan ? otel.trace.setSpan(otel.context.active(), otelSpan) : otel.context.active();
416
+ const otelContext = otelSpan !== undefined ? otel.trace.setSpan(otel.context.active(), otelSpan) : otel.context.active();
398
417
  yield* Effect.acquireRelease(Effect.sync(() => this.subscribe(query, (result) => emit.single(result), {
399
- ...(options ?? {}),
418
+ ...options,
400
419
  otelContext,
401
420
  })), (unsub) => Effect.sync(() => unsub()));
402
421
  }));
@@ -420,12 +439,12 @@ export class Store extends Inspectable.Class {
420
439
  const res = this[StoreInternalsSymbol].sqliteDbWrapper.cachedSelect(query.query, prepareBindValues(query.bindValues, query.query), {
421
440
  ...omitUndefineds({ otelContext: options?.otelContext }),
422
441
  });
423
- if (query.schema) {
442
+ if (query.schema !== undefined) {
424
443
  return Schema.decodeSync(query.schema)(res);
425
444
  }
426
445
  return res;
427
446
  }
428
- else if (isQueryBuilder(query)) {
447
+ else if (isQueryBuilder(query) === true) {
429
448
  const ast = query[QueryBuilderAstSymbol];
430
449
  if (ast._tag === 'RowQuery') {
431
450
  makeExecBeforeFirstRun({
@@ -438,7 +457,7 @@ export class Store extends Inspectable.Class {
438
457
  const sqlRes = query.asSql();
439
458
  const schema = getResultSchema(query);
440
459
  // Replace SessionIdSymbol in bind values before executing the query
441
- if (sqlRes.bindValues) {
460
+ if (sqlRes.bindValues !== undefined) {
442
461
  replaceSessionIdSymbol(sqlRes.bindValues, this[StoreInternalsSymbol].clientSession.sessionId);
443
462
  }
444
463
  const rawRes = this[StoreInternalsSymbol].sqliteDbWrapper.cachedSelect(sqlRes.query, sqlRes.bindValues, {
@@ -450,7 +469,7 @@ export class Store extends Inspectable.Class {
450
469
  return decodeResult.right;
451
470
  }
452
471
  else {
453
- return shouldNeverHappen(`Failed to decode query result with for schema:`, schema.toString(), 'raw result:', rawRes, 'decode error:', decodeResult.left);
472
+ return shouldNeverHappen('Failed to decode query result with for schema:', objectToString(schema), 'raw result:', rawRes, 'decode error:', decodeResult.left);
454
473
  }
455
474
  }
456
475
  else if (query._tag === 'def') {
@@ -498,7 +517,7 @@ export class Store extends Inspectable.Class {
498
517
  signalRef.deref();
499
518
  }
500
519
  };
501
- // #region commit
520
+ //#region commit
502
521
  /**
503
522
  * Commit a list of events to the store which will immediately update the local database
504
523
  * and sync the events across other clients (similar to a `git commit`).
@@ -564,22 +583,17 @@ export class Store extends Inspectable.Class {
564
583
  if (events.length === 0)
565
584
  return;
566
585
  const localRuntime = yield* Effect.runtime();
567
- const materializeEventsTx = Effect.try({
586
+ const encodedEvents = yield* this[StoreInternalsSymbol].syncProcessor.encodeEvents(events);
587
+ const { writeTables } = yield* Effect.try({
568
588
  try: () => {
569
- const runMaterializeEvents = () => {
570
- return this[StoreInternalsSymbol].syncProcessor.push(events).pipe(Runtime.runSync(localRuntime));
571
- };
572
- if (events.length > 1) {
573
- return this[StoreInternalsSymbol].sqliteDbWrapper.txn(runMaterializeEvents);
574
- }
575
- else {
576
- return runMaterializeEvents();
577
- }
589
+ const materialize = () => this[StoreInternalsSymbol].syncProcessor.materializeEvents(encodedEvents).pipe(Runtime.runSync(localRuntime));
590
+ return events.length > 1
591
+ ? this[StoreInternalsSymbol].sqliteDbWrapper.txn(materialize)
592
+ : materialize();
578
593
  },
579
594
  catch: (cause) => UnknownError.make({ cause }),
580
595
  });
581
- // Materialize events to state
582
- const { writeTables } = yield* materializeEventsTx;
596
+ yield* this[StoreInternalsSymbol].syncProcessor.push(encodedEvents);
583
597
  const tablesToUpdate = [];
584
598
  for (const tableName of writeTables) {
585
599
  const tableRef = this[StoreInternalsSymbol].tableRefs[tableName];
@@ -615,7 +629,7 @@ export class Store extends Inspectable.Class {
615
629
  ],
616
630
  }), Effect.tapErrorCause(Effect.logError), Effect.catchAllCause((cause) => Effect.fork(this.shutdown(cause))), Runtime.runSync(this[StoreInternalsSymbol].effectContext.runtime));
617
631
  };
618
- // #endregion commit
632
+ //#endregion commit
619
633
  /**
620
634
  * Returns an async iterable of events from the eventlog.
621
635
  * Currently only events confirmed by the sync backend is supported.
@@ -683,6 +697,92 @@ export class Store extends Inspectable.Class {
683
697
  };
684
698
  return clientSession.leaderThread.events.stream(baseOptions).pipe(Stream.mapChunksEffect(Schema.decode(Schema.ChunkFromSelf(eventSchema))), Stream.catchTag('ParseError', (cause) => Stream.fail(UnknownError.make({ cause }))), Stream.tapError((error) => Effect.logError('Error in eventsStream', error)));
685
699
  };
700
+ /**
701
+ * Returns the current synchronization status of the store.
702
+ *
703
+ * This is a synchronous operation that returns the sync state between the
704
+ * client session and the leader thread. Use this to display sync indicators
705
+ * or check if local changes have been pushed to the leader.
706
+ *
707
+ * @example
708
+ * ```ts
709
+ * const status = store.syncStatus()
710
+ * console.log(status.isSynced ? 'Synced' : `${status.pendingCount} pending`)
711
+ * ```
712
+ *
713
+ * @example
714
+ * ```ts
715
+ * // Health check for backend connectivity
716
+ * const status = store.syncStatus()
717
+ * if (!status.isSynced && status.pendingCount > 100) {
718
+ * console.warn('Large backlog of unsynced events')
719
+ * }
720
+ * ```
721
+ */
722
+ syncStatus = () => {
723
+ this.checkShutdown('syncStatus');
724
+ const syncState = this[StoreInternalsSymbol].syncProcessor.syncState.pipe(Effect.runSync);
725
+ const pendingCount = syncState.pending.length;
726
+ return {
727
+ localHead: EventSequenceNumber.Client.toString(syncState.localHead),
728
+ upstreamHead: EventSequenceNumber.Client.toString(syncState.upstreamHead),
729
+ pendingCount,
730
+ isSynced: pendingCount === 0,
731
+ };
732
+ };
733
+ /**
734
+ * Returns an Effect Stream of sync status updates.
735
+ *
736
+ * Emits the current status immediately and then whenever the sync state changes.
737
+ * Use this for Effect-based workflows or when you need more control over the stream.
738
+ *
739
+ * @example
740
+ * ```ts
741
+ * store.syncStatusStream().pipe(
742
+ * Stream.tap((status) => Effect.log(`Sync status: ${status.isSynced}`)),
743
+ * Stream.runDrain,
744
+ * )
745
+ * ```
746
+ */
747
+ syncStatusStream = () => {
748
+ const syncStateSubscribable = this[StoreInternalsSymbol].syncProcessor.syncState;
749
+ return Stream.concat(Stream.fromEffect(syncStateSubscribable.pipe(Effect.map(this.makeSyncStatus))), syncStateSubscribable.changes.pipe(Stream.map(this.makeSyncStatus)));
750
+ };
751
+ /**
752
+ * Subscribes to sync status changes.
753
+ *
754
+ * The callback is invoked immediately with the current status and then
755
+ * whenever the sync state changes (e.g., when events are pushed or confirmed).
756
+ *
757
+ * @param onUpdate - Callback invoked with the current sync status
758
+ * @returns Unsubscribe function to stop receiving updates
759
+ *
760
+ * @example
761
+ * ```ts
762
+ * const unsubscribe = store.subscribeSyncStatus((status) => {
763
+ * updateUI(status.isSynced ? 'Synced' : 'Syncing...')
764
+ * })
765
+ *
766
+ * // Later, stop listening
767
+ * unsubscribe()
768
+ * ```
769
+ */
770
+ subscribeSyncStatus = (onUpdate) => {
771
+ this.checkShutdown('subscribeSyncStatus');
772
+ const fiber = this.syncStatusStream().pipe(Stream.tap((status) => Effect.sync(() => onUpdate(status))), Stream.runDrain, this.runEffectFork);
773
+ return () => {
774
+ Fiber.interrupt(fiber).pipe(Runtime.runFork(this[StoreInternalsSymbol].effectContext.runtime));
775
+ };
776
+ };
777
+ makeSyncStatus = (syncState) => {
778
+ const pendingCount = syncState.pending.length;
779
+ return {
780
+ localHead: EventSequenceNumber.Client.toString(syncState.localHead),
781
+ upstreamHead: EventSequenceNumber.Client.toString(syncState.upstreamHead),
782
+ pendingCount,
783
+ isSynced: pendingCount === 0,
784
+ };
785
+ };
686
786
  /**
687
787
  * This can be used in combination with `skipRefresh` when committing events.
688
788
  * We might need a better solution for this. Let's see.
@@ -704,7 +804,7 @@ export class Store extends Inspectable.Class {
704
804
  shutdownPromise = async (cause) => {
705
805
  this.checkShutdown('shutdownPromise');
706
806
  this[StoreInternalsSymbol].isShutdown = true;
707
- await this.shutdown(cause ? Cause.fail(cause) : undefined).pipe(this.runEffectFork, Fiber.join, Effect.runPromise);
807
+ await this.shutdown(cause !== undefined ? Cause.fail(cause) : undefined).pipe(this.runEffectFork, Fiber.join, Effect.runPromise);
708
808
  };
709
809
  /**
710
810
  * Shuts down the store and closes the client session.
@@ -713,7 +813,7 @@ export class Store extends Inspectable.Class {
713
813
  */
714
814
  shutdown = (cause) => {
715
815
  this[StoreInternalsSymbol].isShutdown = true;
716
- return this[StoreInternalsSymbol].clientSession.shutdown(cause ? Exit.failCause(cause) : Exit.succeed(IntentionalShutdownCause.make({ reason: 'manual' })));
816
+ return this[StoreInternalsSymbol].clientSession.shutdown(cause !== undefined ? Exit.failCause(cause) : Exit.succeed(IntentionalShutdownCause.make({ reason: 'manual' })));
717
817
  };
718
818
  /**
719
819
  * Helper methods useful during development
@@ -752,6 +852,7 @@ export class Store extends Inspectable.Class {
752
852
  }))
753
853
  .pipe(this.runEffectFork);
754
854
  },
855
+ // NOTE: Explicit return type needed to avoid TS2742 (inferred type references internal path)
755
856
  syncStates: () => Effect.gen(this, function* () {
756
857
  const session = yield* this[StoreInternalsSymbol].syncProcessor.syncState;
757
858
  const leader = yield* this[StoreInternalsSymbol].clientSession.leaderThread.syncState;
@@ -760,9 +861,9 @@ export class Store extends Inspectable.Class {
760
861
  printSyncStates: () => {
761
862
  Effect.gen(this, function* () {
762
863
  const session = yield* this[StoreInternalsSymbol].syncProcessor.syncState;
763
- yield* Effect.log(`Session sync state: ${session.localHead} (upstream: ${session.upstreamHead})`, session.toJSON());
864
+ yield* Effect.log(`Session sync state: ${objectToString(session.localHead)} (upstream: ${objectToString(session.upstreamHead)})`, session.toJSON());
764
865
  const leader = yield* this[StoreInternalsSymbol].clientSession.leaderThread.syncState;
765
- yield* Effect.log(`Leader sync state: ${leader.localHead} (upstream: ${leader.upstreamHead})`, leader.toJSON());
866
+ yield* Effect.log(`Leader sync state: ${objectToString(leader.localHead)} (upstream: ${objectToString(leader.upstreamHead)})`, leader.toJSON());
766
867
  }).pipe(this.runEffectFork);
767
868
  },
768
869
  version: liveStoreVersion,