@livestore/common 0.3.0-dev.3 → 0.3.0-dev.30

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 (426) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/__tests__/fixture.d.ts +83 -221
  3. package/dist/__tests__/fixture.d.ts.map +1 -1
  4. package/dist/__tests__/fixture.js +33 -11
  5. package/dist/__tests__/fixture.js.map +1 -1
  6. package/dist/adapter-types.d.ts +128 -68
  7. package/dist/adapter-types.d.ts.map +1 -1
  8. package/dist/adapter-types.js +36 -7
  9. package/dist/adapter-types.js.map +1 -1
  10. package/dist/bounded-collections.d.ts.map +1 -1
  11. package/dist/debug-info.d.ts +1 -1
  12. package/dist/debug-info.d.ts.map +1 -1
  13. package/dist/debug-info.js +1 -0
  14. package/dist/debug-info.js.map +1 -1
  15. package/dist/devtools/devtools-messages-client-session.d.ts +389 -0
  16. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -0
  17. package/dist/devtools/devtools-messages-client-session.js +96 -0
  18. package/dist/devtools/devtools-messages-client-session.js.map +1 -0
  19. package/dist/devtools/devtools-messages-common.d.ts +68 -0
  20. package/dist/devtools/devtools-messages-common.d.ts.map +1 -0
  21. package/dist/devtools/devtools-messages-common.js +60 -0
  22. package/dist/devtools/devtools-messages-common.js.map +1 -0
  23. package/dist/devtools/devtools-messages-leader.d.ts +394 -0
  24. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -0
  25. package/dist/devtools/devtools-messages-leader.js +147 -0
  26. package/dist/devtools/devtools-messages-leader.js.map +1 -0
  27. package/dist/devtools/devtools-messages.d.ts +3 -592
  28. package/dist/devtools/devtools-messages.d.ts.map +1 -1
  29. package/dist/devtools/devtools-messages.js +3 -171
  30. package/dist/devtools/devtools-messages.js.map +1 -1
  31. package/dist/devtools/devtools-sessioninfo.d.ts +28 -0
  32. package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -0
  33. package/dist/devtools/devtools-sessioninfo.js +34 -0
  34. package/dist/devtools/devtools-sessioninfo.js.map +1 -0
  35. package/dist/devtools/mod.d.ts +39 -0
  36. package/dist/devtools/mod.d.ts.map +1 -0
  37. package/dist/devtools/mod.js +27 -0
  38. package/dist/devtools/mod.js.map +1 -0
  39. package/dist/index.d.ts +4 -11
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +4 -7
  42. package/dist/index.js.map +1 -1
  43. package/dist/leader-thread/LeaderSyncProcessor.d.ts +62 -0
  44. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -0
  45. package/dist/leader-thread/LeaderSyncProcessor.js +589 -0
  46. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -0
  47. package/dist/leader-thread/apply-event.d.ts +16 -0
  48. package/dist/leader-thread/apply-event.d.ts.map +1 -0
  49. package/dist/leader-thread/apply-event.js +103 -0
  50. package/dist/leader-thread/apply-event.js.map +1 -0
  51. package/dist/leader-thread/connection.d.ts +34 -6
  52. package/dist/leader-thread/connection.d.ts.map +1 -1
  53. package/dist/leader-thread/connection.js +22 -7
  54. package/dist/leader-thread/connection.js.map +1 -1
  55. package/dist/leader-thread/eventlog.d.ts +27 -0
  56. package/dist/leader-thread/eventlog.d.ts.map +1 -0
  57. package/dist/leader-thread/eventlog.js +123 -0
  58. package/dist/leader-thread/eventlog.js.map +1 -0
  59. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
  60. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  61. package/dist/leader-thread/leader-worker-devtools.js +154 -132
  62. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  63. package/dist/leader-thread/make-leader-thread-layer.d.ts +26 -12
  64. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  65. package/dist/leader-thread/make-leader-thread-layer.js +82 -47
  66. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  67. package/dist/leader-thread/mod.d.ts +1 -1
  68. package/dist/leader-thread/mod.d.ts.map +1 -1
  69. package/dist/leader-thread/mod.js +1 -1
  70. package/dist/leader-thread/mod.js.map +1 -1
  71. package/dist/leader-thread/recreate-db.d.ts +4 -2
  72. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  73. package/dist/leader-thread/recreate-db.js +35 -25
  74. package/dist/leader-thread/recreate-db.js.map +1 -1
  75. package/dist/leader-thread/shutdown-channel.d.ts +2 -5
  76. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  77. package/dist/leader-thread/shutdown-channel.js +2 -4
  78. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  79. package/dist/leader-thread/types.d.ts +86 -39
  80. package/dist/leader-thread/types.d.ts.map +1 -1
  81. package/dist/leader-thread/types.js +1 -3
  82. package/dist/leader-thread/types.js.map +1 -1
  83. package/dist/materializer-helper.d.ts +23 -0
  84. package/dist/materializer-helper.d.ts.map +1 -0
  85. package/dist/materializer-helper.js +70 -0
  86. package/dist/materializer-helper.js.map +1 -0
  87. package/dist/otel.d.ts +2 -0
  88. package/dist/otel.d.ts.map +1 -1
  89. package/dist/otel.js +5 -0
  90. package/dist/otel.js.map +1 -1
  91. package/dist/query-builder/api.d.ts +158 -55
  92. package/dist/query-builder/api.d.ts.map +1 -1
  93. package/dist/query-builder/api.js +3 -5
  94. package/dist/query-builder/api.js.map +1 -1
  95. package/dist/query-builder/astToSql.d.ts +7 -0
  96. package/dist/query-builder/astToSql.d.ts.map +1 -0
  97. package/dist/query-builder/astToSql.js +190 -0
  98. package/dist/query-builder/astToSql.js.map +1 -0
  99. package/dist/query-builder/impl.d.ts +3 -8
  100. package/dist/query-builder/impl.d.ts.map +1 -1
  101. package/dist/query-builder/impl.js +166 -124
  102. package/dist/query-builder/impl.js.map +1 -1
  103. package/dist/query-builder/impl.test.d.ts +86 -1
  104. package/dist/query-builder/impl.test.d.ts.map +1 -1
  105. package/dist/query-builder/impl.test.js +411 -69
  106. package/dist/query-builder/impl.test.js.map +1 -1
  107. package/dist/query-builder/mod.d.ts +7 -0
  108. package/dist/query-builder/mod.d.ts.map +1 -1
  109. package/dist/query-builder/mod.js +7 -0
  110. package/dist/query-builder/mod.js.map +1 -1
  111. package/dist/rehydrate-from-eventlog.d.ts +14 -0
  112. package/dist/rehydrate-from-eventlog.d.ts.map +1 -0
  113. package/dist/rehydrate-from-eventlog.js +65 -0
  114. package/dist/rehydrate-from-eventlog.js.map +1 -0
  115. package/dist/schema/EventDef.d.ts +136 -0
  116. package/dist/schema/EventDef.d.ts.map +1 -0
  117. package/dist/schema/EventDef.js +58 -0
  118. package/dist/schema/EventDef.js.map +1 -0
  119. package/dist/schema/EventId.d.ts +35 -15
  120. package/dist/schema/EventId.d.ts.map +1 -1
  121. package/dist/schema/EventId.js +57 -11
  122. package/dist/schema/EventId.js.map +1 -1
  123. package/dist/schema/EventId.test.d.ts +2 -0
  124. package/dist/schema/EventId.test.d.ts.map +1 -0
  125. package/dist/schema/EventId.test.js +11 -0
  126. package/dist/schema/EventId.test.js.map +1 -0
  127. package/dist/schema/LiveStoreEvent.d.ts +255 -0
  128. package/dist/schema/LiveStoreEvent.d.ts.map +1 -0
  129. package/dist/schema/LiveStoreEvent.js +118 -0
  130. package/dist/schema/LiveStoreEvent.js.map +1 -0
  131. package/dist/schema/client-document-def.d.ts +223 -0
  132. package/dist/schema/client-document-def.d.ts.map +1 -0
  133. package/dist/schema/client-document-def.js +170 -0
  134. package/dist/schema/client-document-def.js.map +1 -0
  135. package/dist/schema/client-document-def.test.d.ts +2 -0
  136. package/dist/schema/client-document-def.test.d.ts.map +1 -0
  137. package/dist/schema/client-document-def.test.js +201 -0
  138. package/dist/schema/client-document-def.test.js.map +1 -0
  139. package/dist/schema/db-schema/ast/sqlite.d.ts +69 -0
  140. package/dist/schema/db-schema/ast/sqlite.d.ts.map +1 -0
  141. package/dist/schema/db-schema/ast/sqlite.js +71 -0
  142. package/dist/schema/db-schema/ast/sqlite.js.map +1 -0
  143. package/dist/schema/db-schema/ast/validate.d.ts +3 -0
  144. package/dist/schema/db-schema/ast/validate.d.ts.map +1 -0
  145. package/dist/schema/db-schema/ast/validate.js +12 -0
  146. package/dist/schema/db-schema/ast/validate.js.map +1 -0
  147. package/dist/schema/db-schema/dsl/field-defs.d.ts +90 -0
  148. package/dist/schema/db-schema/dsl/field-defs.d.ts.map +1 -0
  149. package/dist/schema/db-schema/dsl/field-defs.js +87 -0
  150. package/dist/schema/db-schema/dsl/field-defs.js.map +1 -0
  151. package/dist/schema/db-schema/dsl/field-defs.test.d.ts +2 -0
  152. package/dist/schema/db-schema/dsl/field-defs.test.d.ts.map +1 -0
  153. package/dist/schema/db-schema/dsl/field-defs.test.js +29 -0
  154. package/dist/schema/db-schema/dsl/field-defs.test.js.map +1 -0
  155. package/dist/schema/db-schema/dsl/mod.d.ts +90 -0
  156. package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -0
  157. package/dist/schema/db-schema/dsl/mod.js +41 -0
  158. package/dist/schema/db-schema/dsl/mod.js.map +1 -0
  159. package/dist/schema/db-schema/hash.d.ts +2 -0
  160. package/dist/schema/db-schema/hash.d.ts.map +1 -0
  161. package/dist/schema/db-schema/hash.js +14 -0
  162. package/dist/schema/db-schema/hash.js.map +1 -0
  163. package/dist/schema/db-schema/mod.d.ts +3 -0
  164. package/dist/schema/db-schema/mod.d.ts.map +1 -0
  165. package/dist/schema/db-schema/mod.js +3 -0
  166. package/dist/schema/db-schema/mod.js.map +1 -0
  167. package/dist/schema/events.d.ts +2 -0
  168. package/dist/schema/events.d.ts.map +1 -0
  169. package/dist/schema/events.js +2 -0
  170. package/dist/schema/events.js.map +1 -0
  171. package/dist/schema/mod.d.ts +5 -3
  172. package/dist/schema/mod.d.ts.map +1 -1
  173. package/dist/schema/mod.js +5 -3
  174. package/dist/schema/mod.js.map +1 -1
  175. package/dist/schema/schema-helpers.d.ts.map +1 -1
  176. package/dist/schema/schema-helpers.js +1 -1
  177. package/dist/schema/schema-helpers.js.map +1 -1
  178. package/dist/schema/schema.d.ts +30 -23
  179. package/dist/schema/schema.d.ts.map +1 -1
  180. package/dist/schema/schema.js +48 -35
  181. package/dist/schema/schema.js.map +1 -1
  182. package/dist/schema/sqlite-state.d.ts +12 -0
  183. package/dist/schema/sqlite-state.d.ts.map +1 -0
  184. package/dist/schema/sqlite-state.js +36 -0
  185. package/dist/schema/sqlite-state.js.map +1 -0
  186. package/dist/schema/system-tables.d.ts +179 -125
  187. package/dist/schema/system-tables.d.ts.map +1 -1
  188. package/dist/schema/system-tables.js +76 -41
  189. package/dist/schema/system-tables.js.map +1 -1
  190. package/dist/schema/table-def.d.ts +37 -109
  191. package/dist/schema/table-def.d.ts.map +1 -1
  192. package/dist/schema/table-def.js +23 -66
  193. package/dist/schema/table-def.js.map +1 -1
  194. package/dist/schema/view.d.ts +3 -0
  195. package/dist/schema/view.d.ts.map +1 -0
  196. package/dist/schema/view.js +3 -0
  197. package/dist/schema/view.js.map +1 -0
  198. package/dist/schema-management/common.d.ts +7 -7
  199. package/dist/schema-management/common.d.ts.map +1 -1
  200. package/dist/schema-management/common.js.map +1 -1
  201. package/dist/schema-management/migrations.d.ts +6 -6
  202. package/dist/schema-management/migrations.d.ts.map +1 -1
  203. package/dist/schema-management/migrations.js +19 -14
  204. package/dist/schema-management/migrations.js.map +1 -1
  205. package/dist/schema-management/validate-mutation-defs.d.ts +3 -3
  206. package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -1
  207. package/dist/schema-management/validate-mutation-defs.js +17 -17
  208. package/dist/schema-management/validate-mutation-defs.js.map +1 -1
  209. package/dist/sql-queries/misc.d.ts.map +1 -1
  210. package/dist/sql-queries/sql-queries.d.ts +1 -1
  211. package/dist/sql-queries/sql-queries.d.ts.map +1 -1
  212. package/dist/sql-queries/sql-queries.js.map +1 -1
  213. package/dist/sql-queries/sql-query-builder.d.ts +1 -1
  214. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  215. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  216. package/dist/sql-queries/types.d.ts +2 -1
  217. package/dist/sql-queries/types.d.ts.map +1 -1
  218. package/dist/sql-queries/types.js.map +1 -1
  219. package/dist/sync/ClientSessionSyncProcessor.d.ts +66 -0
  220. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -0
  221. package/dist/sync/ClientSessionSyncProcessor.js +209 -0
  222. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -0
  223. package/dist/sync/index.d.ts +1 -1
  224. package/dist/sync/index.d.ts.map +1 -1
  225. package/dist/sync/index.js +1 -1
  226. package/dist/sync/index.js.map +1 -1
  227. package/dist/sync/next/compact-events.d.ts.map +1 -1
  228. package/dist/sync/next/facts.d.ts +19 -19
  229. package/dist/sync/next/facts.d.ts.map +1 -1
  230. package/dist/sync/next/facts.js +3 -3
  231. package/dist/sync/next/facts.js.map +1 -1
  232. package/dist/sync/next/history-dag-common.d.ts +6 -7
  233. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  234. package/dist/sync/next/history-dag-common.js +4 -2
  235. package/dist/sync/next/history-dag-common.js.map +1 -1
  236. package/dist/sync/next/history-dag.d.ts.map +1 -1
  237. package/dist/sync/next/history-dag.js +2 -2
  238. package/dist/sync/next/history-dag.js.map +1 -1
  239. package/dist/sync/next/rebase-events.d.ts +10 -8
  240. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  241. package/dist/sync/next/rebase-events.js +11 -8
  242. package/dist/sync/next/rebase-events.js.map +1 -1
  243. package/dist/sync/next/test/compact-events.calculator.test.js +38 -33
  244. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  245. package/dist/sync/next/test/compact-events.test.js +76 -76
  246. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  247. package/dist/sync/next/test/{mutation-fixtures.d.ts → event-fixtures.d.ts} +29 -29
  248. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -0
  249. package/dist/sync/next/test/{mutation-fixtures.js → event-fixtures.js} +67 -36
  250. package/dist/sync/next/test/event-fixtures.js.map +1 -0
  251. package/dist/sync/next/test/mod.d.ts +1 -1
  252. package/dist/sync/next/test/mod.d.ts.map +1 -1
  253. package/dist/sync/next/test/mod.js +1 -1
  254. package/dist/sync/next/test/mod.js.map +1 -1
  255. package/dist/sync/sync.d.ts +55 -20
  256. package/dist/sync/sync.d.ts.map +1 -1
  257. package/dist/sync/sync.js +7 -3
  258. package/dist/sync/sync.js.map +1 -1
  259. package/dist/sync/syncstate.d.ts +213 -82
  260. package/dist/sync/syncstate.d.ts.map +1 -1
  261. package/dist/sync/syncstate.js +319 -120
  262. package/dist/sync/syncstate.js.map +1 -1
  263. package/dist/sync/syncstate.test.js +295 -275
  264. package/dist/sync/syncstate.test.js.map +1 -1
  265. package/dist/sync/validate-push-payload.d.ts +2 -2
  266. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  267. package/dist/sync/validate-push-payload.js +2 -2
  268. package/dist/sync/validate-push-payload.js.map +1 -1
  269. package/dist/util.d.ts +2 -2
  270. package/dist/util.d.ts.map +1 -1
  271. package/dist/version.d.ts +1 -1
  272. package/dist/version.d.ts.map +1 -1
  273. package/dist/version.js +1 -1
  274. package/dist/version.js.map +1 -1
  275. package/package.json +6 -6
  276. package/src/__tests__/fixture.ts +36 -15
  277. package/src/adapter-types.ts +111 -74
  278. package/src/debug-info.ts +1 -0
  279. package/src/devtools/devtools-messages-client-session.ts +141 -0
  280. package/src/devtools/devtools-messages-common.ts +115 -0
  281. package/src/devtools/devtools-messages-leader.ts +191 -0
  282. package/src/devtools/devtools-messages.ts +3 -243
  283. package/src/devtools/devtools-sessioninfo.ts +99 -0
  284. package/src/devtools/mod.ts +36 -0
  285. package/src/index.ts +4 -13
  286. package/src/leader-thread/LeaderSyncProcessor.ts +935 -0
  287. package/src/leader-thread/apply-event.ts +173 -0
  288. package/src/leader-thread/connection.ts +54 -9
  289. package/src/leader-thread/eventlog.ts +199 -0
  290. package/src/leader-thread/leader-worker-devtools.ts +212 -189
  291. package/src/leader-thread/make-leader-thread-layer.ts +143 -77
  292. package/src/leader-thread/mod.ts +1 -1
  293. package/src/leader-thread/recreate-db.ts +41 -30
  294. package/src/leader-thread/shutdown-channel.ts +2 -4
  295. package/src/leader-thread/types.ts +95 -51
  296. package/src/materializer-helper.ts +110 -0
  297. package/src/otel.ts +8 -0
  298. package/src/query-builder/api.ts +236 -85
  299. package/src/query-builder/astToSql.ts +232 -0
  300. package/src/query-builder/impl.test.ts +447 -78
  301. package/src/query-builder/impl.ts +209 -144
  302. package/src/query-builder/mod.ts +7 -0
  303. package/src/rehydrate-from-eventlog.ts +114 -0
  304. package/src/schema/EventDef.ts +216 -0
  305. package/src/schema/EventId.test.ts +12 -0
  306. package/src/schema/EventId.ts +75 -15
  307. package/src/schema/LiveStoreEvent.ts +239 -0
  308. package/src/schema/client-document-def.test.ts +239 -0
  309. package/src/schema/client-document-def.ts +444 -0
  310. package/src/schema/db-schema/ast/sqlite.ts +142 -0
  311. package/src/schema/db-schema/ast/validate.ts +13 -0
  312. package/src/schema/db-schema/dsl/__snapshots__/field-defs.test.ts.snap +206 -0
  313. package/src/schema/db-schema/dsl/field-defs.test.ts +35 -0
  314. package/src/schema/db-schema/dsl/field-defs.ts +242 -0
  315. package/src/schema/db-schema/dsl/mod.ts +222 -0
  316. package/src/schema/db-schema/hash.ts +14 -0
  317. package/src/schema/db-schema/mod.ts +2 -0
  318. package/src/schema/events.ts +1 -0
  319. package/src/schema/mod.ts +5 -3
  320. package/src/schema/schema-helpers.ts +1 -1
  321. package/src/schema/schema.ts +84 -62
  322. package/src/schema/sqlite-state.ts +62 -0
  323. package/src/schema/system-tables.ts +68 -50
  324. package/src/schema/table-def.ts +68 -214
  325. package/src/schema/view.ts +2 -0
  326. package/src/schema-management/common.ts +7 -7
  327. package/src/schema-management/migrations.ts +27 -24
  328. package/src/schema-management/validate-mutation-defs.ts +22 -24
  329. package/src/sql-queries/sql-queries.ts +1 -1
  330. package/src/sql-queries/sql-query-builder.ts +1 -2
  331. package/src/sql-queries/types.ts +3 -1
  332. package/src/sync/ClientSessionSyncProcessor.ts +332 -0
  333. package/src/sync/index.ts +1 -1
  334. package/src/sync/next/facts.ts +32 -33
  335. package/src/sync/next/history-dag-common.ts +9 -5
  336. package/src/sync/next/history-dag.ts +2 -2
  337. package/src/sync/next/rebase-events.ts +22 -16
  338. package/src/sync/next/test/compact-events.calculator.test.ts +45 -45
  339. package/src/sync/next/test/compact-events.test.ts +78 -78
  340. package/src/sync/next/test/event-fixtures.ts +219 -0
  341. package/src/sync/next/test/mod.ts +1 -1
  342. package/src/sync/sync.ts +51 -19
  343. package/src/sync/syncstate.test.ts +335 -308
  344. package/src/sync/syncstate.ts +394 -212
  345. package/src/sync/validate-push-payload.ts +7 -4
  346. package/src/version.ts +1 -1
  347. package/tmp/pack.tgz +0 -0
  348. package/tsconfig.json +2 -1
  349. package/dist/derived-mutations.d.ts +0 -109
  350. package/dist/derived-mutations.d.ts.map +0 -1
  351. package/dist/derived-mutations.js +0 -54
  352. package/dist/derived-mutations.js.map +0 -1
  353. package/dist/derived-mutations.test.d.ts +0 -2
  354. package/dist/derived-mutations.test.d.ts.map +0 -1
  355. package/dist/derived-mutations.test.js +0 -93
  356. package/dist/derived-mutations.test.js.map +0 -1
  357. package/dist/devtools/devtools-bridge.d.ts +0 -12
  358. package/dist/devtools/devtools-bridge.d.ts.map +0 -1
  359. package/dist/devtools/devtools-bridge.js +0 -2
  360. package/dist/devtools/devtools-bridge.js.map +0 -1
  361. package/dist/devtools/index.d.ts +0 -42
  362. package/dist/devtools/index.d.ts.map +0 -1
  363. package/dist/devtools/index.js +0 -48
  364. package/dist/devtools/index.js.map +0 -1
  365. package/dist/init-singleton-tables.d.ts +0 -4
  366. package/dist/init-singleton-tables.d.ts.map +0 -1
  367. package/dist/init-singleton-tables.js +0 -16
  368. package/dist/init-singleton-tables.js.map +0 -1
  369. package/dist/leader-thread/apply-mutation.d.ts +0 -8
  370. package/dist/leader-thread/apply-mutation.d.ts.map +0 -1
  371. package/dist/leader-thread/apply-mutation.js +0 -95
  372. package/dist/leader-thread/apply-mutation.js.map +0 -1
  373. package/dist/leader-thread/leader-sync-processor.d.ts +0 -47
  374. package/dist/leader-thread/leader-sync-processor.d.ts.map +0 -1
  375. package/dist/leader-thread/leader-sync-processor.js +0 -422
  376. package/dist/leader-thread/leader-sync-processor.js.map +0 -1
  377. package/dist/leader-thread/mutationlog.d.ts +0 -23
  378. package/dist/leader-thread/mutationlog.d.ts.map +0 -1
  379. package/dist/leader-thread/mutationlog.js +0 -27
  380. package/dist/leader-thread/mutationlog.js.map +0 -1
  381. package/dist/leader-thread/pull-queue-set.d.ts +0 -7
  382. package/dist/leader-thread/pull-queue-set.d.ts.map +0 -1
  383. package/dist/leader-thread/pull-queue-set.js +0 -39
  384. package/dist/leader-thread/pull-queue-set.js.map +0 -1
  385. package/dist/mutation.d.ts +0 -13
  386. package/dist/mutation.d.ts.map +0 -1
  387. package/dist/mutation.js +0 -57
  388. package/dist/mutation.js.map +0 -1
  389. package/dist/query-info.d.ts +0 -38
  390. package/dist/query-info.d.ts.map +0 -1
  391. package/dist/query-info.js +0 -7
  392. package/dist/query-info.js.map +0 -1
  393. package/dist/rehydrate-from-mutationlog.d.ts +0 -14
  394. package/dist/rehydrate-from-mutationlog.d.ts.map +0 -1
  395. package/dist/rehydrate-from-mutationlog.js +0 -72
  396. package/dist/rehydrate-from-mutationlog.js.map +0 -1
  397. package/dist/schema/MutationEvent.d.ts +0 -191
  398. package/dist/schema/MutationEvent.d.ts.map +0 -1
  399. package/dist/schema/MutationEvent.js +0 -56
  400. package/dist/schema/MutationEvent.js.map +0 -1
  401. package/dist/schema/mutations.d.ts +0 -107
  402. package/dist/schema/mutations.d.ts.map +0 -1
  403. package/dist/schema/mutations.js +0 -42
  404. package/dist/schema/mutations.js.map +0 -1
  405. package/dist/sync/client-session-sync-processor.d.ts +0 -45
  406. package/dist/sync/client-session-sync-processor.d.ts.map +0 -1
  407. package/dist/sync/client-session-sync-processor.js +0 -131
  408. package/dist/sync/client-session-sync-processor.js.map +0 -1
  409. package/dist/sync/next/test/mutation-fixtures.d.ts.map +0 -1
  410. package/dist/sync/next/test/mutation-fixtures.js.map +0 -1
  411. package/src/derived-mutations.test.ts +0 -101
  412. package/src/derived-mutations.ts +0 -166
  413. package/src/devtools/devtools-bridge.ts +0 -13
  414. package/src/devtools/index.ts +0 -48
  415. package/src/init-singleton-tables.ts +0 -24
  416. package/src/leader-thread/apply-mutation.ts +0 -143
  417. package/src/leader-thread/leader-sync-processor.ts +0 -666
  418. package/src/leader-thread/mutationlog.ts +0 -42
  419. package/src/leader-thread/pull-queue-set.ts +0 -58
  420. package/src/mutation.ts +0 -81
  421. package/src/query-info.ts +0 -78
  422. package/src/rehydrate-from-mutationlog.ts +0 -127
  423. package/src/schema/MutationEvent.ts +0 -161
  424. package/src/schema/mutations.ts +0 -192
  425. package/src/sync/client-session-sync-processor.ts +0 -207
  426. package/src/sync/next/test/mutation-fixtures.ts +0 -231
@@ -1,15 +1,15 @@
1
- import { SqliteAst, SqliteDsl } from '@livestore/db-schema'
2
1
  import { memoizeByStringifyArgs } from '@livestore/utils'
3
2
  import { Effect, Schema as EffectSchema } from '@livestore/utils/effect'
4
3
 
5
- import type { SynchronousDatabase } from '../adapter-types.js'
4
+ import type { MigrationsReport, MigrationsReportEntry, SqliteDb, UnexpectedError } from '../adapter-types.js'
5
+ import { SqliteAst, SqliteDsl } from '../schema/db-schema/mod.js'
6
6
  import type { LiveStoreSchema } from '../schema/mod.js'
7
- import type { SchemaMetaRow, SchemaMutationsMetaRow } from '../schema/system-tables.js'
7
+ import type { SchemaEventDefsMetaRow, SchemaMetaRow } from '../schema/system-tables.js'
8
8
  import {
9
+ SCHEMA_EVENT_DEFS_META_TABLE,
9
10
  SCHEMA_META_TABLE,
10
- SCHEMA_MUTATIONS_META_TABLE,
11
+ schemaEventDefsMetaTable,
11
12
  schemaMetaTable,
12
- schemaMutationsMetaTable,
13
13
  systemTables,
14
14
  } from '../schema/system-tables.js'
15
15
  import { sql } from '../util.js'
@@ -19,24 +19,23 @@ import { validateSchema } from './validate-mutation-defs.js'
19
19
 
20
20
  const getMemoizedTimestamp = memoizeByStringifyArgs(() => new Date().toISOString())
21
21
 
22
- export const makeSchemaManager = (db: SynchronousDatabase): Effect.Effect<SchemaManager> =>
22
+ export const makeSchemaManager = (db: SqliteDb): Effect.Effect<SchemaManager> =>
23
23
  Effect.gen(function* () {
24
24
  yield* migrateTable({
25
25
  db,
26
- tableAst: schemaMutationsMetaTable.sqliteDef.ast,
26
+ tableAst: schemaEventDefsMetaTable.sqliteDef.ast,
27
27
  behaviour: 'create-if-not-exists',
28
28
  })
29
29
 
30
30
  return {
31
- getMutationDefInfos: () =>
32
- dbSelect<SchemaMutationsMetaRow>(db, sql`SELECT * FROM ${SCHEMA_MUTATIONS_META_TABLE}`),
31
+ getEventDefInfos: () => dbSelect<SchemaEventDefsMetaRow>(db, sql`SELECT * FROM ${SCHEMA_EVENT_DEFS_META_TABLE}`),
33
32
 
34
- setMutationDefInfo: (info) => {
33
+ setEventDefInfo: (info) => {
35
34
  dbExecute(
36
35
  db,
37
- sql`INSERT OR REPLACE INTO ${SCHEMA_MUTATIONS_META_TABLE} (mutationName, schemaHash, updatedAt) VALUES ($mutationName, $schemaHash, $updatedAt)`,
36
+ sql`INSERT OR REPLACE INTO ${SCHEMA_EVENT_DEFS_META_TABLE} (eventName, schemaHash, updatedAt) VALUES ($eventName, $schemaHash, $updatedAt)`,
38
37
  {
39
- mutationName: info.mutationName,
38
+ eventName: info.eventName,
40
39
  schemaHash: info.schemaHash,
41
40
  updatedAt: new Date().toISOString(),
42
41
  },
@@ -51,10 +50,10 @@ export const migrateDb = ({
51
50
  schema,
52
51
  onProgress,
53
52
  }: {
54
- db: SynchronousDatabase
53
+ db: SqliteDb
55
54
  schema: LiveStoreSchema
56
55
  onProgress?: (opts: { done: number; total: number }) => Effect.Effect<void>
57
- }) =>
56
+ }): Effect.Effect<MigrationsReport, UnexpectedError> =>
58
57
  Effect.gen(function* () {
59
58
  yield* migrateTable({
60
59
  db,
@@ -81,6 +80,7 @@ export const migrateDb = ({
81
80
 
82
81
  const tablesToMigrate = new Set<{ tableAst: SqliteAst.Table; schemaHash: number }>()
83
82
 
83
+ const migrationsReportEntries: MigrationsReportEntry[] = []
84
84
  for (const tableDef of tableDefs) {
85
85
  const tableAst = tableDef.sqliteDef.ast
86
86
  const tableName = tableAst.name
@@ -90,9 +90,10 @@ export const migrateDb = ({
90
90
  if (schemaHash !== dbSchemaHash) {
91
91
  tablesToMigrate.add({ tableAst, schemaHash })
92
92
 
93
- console.log(
94
- `Schema hash mismatch for table '${tableName}' (DB: ${dbSchemaHash}, expected: ${schemaHash}), migrating table...`,
95
- )
93
+ migrationsReportEntries.push({
94
+ tableName,
95
+ hashes: { expected: schemaHash, actual: dbSchemaHash },
96
+ })
96
97
  }
97
98
  }
98
99
 
@@ -107,6 +108,8 @@ export const migrateDb = ({
107
108
  yield* onProgress({ done: processedTables, total: tablesCount })
108
109
  }
109
110
  }
111
+
112
+ return { migrations: migrationsReportEntries }
110
113
  })
111
114
 
112
115
  export const migrateTable = ({
@@ -116,7 +119,7 @@ export const migrateTable = ({
116
119
  behaviour,
117
120
  skipMetaTable = false,
118
121
  }: {
119
- db: SynchronousDatabase
122
+ db: SqliteDb
120
123
  tableAst: SqliteAst.Table
121
124
  schemaHash?: number
122
125
  behaviour: 'drop-and-recreate' | 'create-if-not-exists'
@@ -129,10 +132,10 @@ export const migrateTable = ({
129
132
 
130
133
  if (behaviour === 'drop-and-recreate') {
131
134
  // TODO need to possibly handle cascading deletes due to foreign keys
132
- dbExecute(db, sql`drop table if exists ${tableName}`)
133
- dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
135
+ dbExecute(db, sql`drop table if exists '${tableName}'`)
136
+ dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
134
137
  } else if (behaviour === 'create-if-not-exists') {
135
- dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
138
+ dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
136
139
  }
137
140
 
138
141
  for (const index of tableAst.indexes) {
@@ -162,11 +165,11 @@ export const migrateTable = ({
162
165
 
163
166
  const createIndexFromDefinition = (tableName: string, index: SqliteAst.Index) => {
164
167
  const uniqueStr = index.unique ? 'UNIQUE' : ''
165
- return sql`create ${uniqueStr} index if not exists ${index.name} on ${tableName} (${index.columns.join(', ')})`
168
+ return sql`create ${uniqueStr} index if not exists '${index.name}' on '${tableName}' (${index.columns.join(', ')})`
166
169
  }
167
170
 
168
171
  export const makeColumnSpec = (tableAst: SqliteAst.Table) => {
169
- const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => _.name)
172
+ const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => `'${_.name}'`)
170
173
  const columnDefStrs = tableAst.columns.map(toSqliteColumnSpec)
171
174
  if (primaryKeys.length > 0) {
172
175
  columnDefStrs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`)
@@ -191,5 +194,5 @@ const toSqliteColumnSpec = (column: SqliteAst.Column) => {
191
194
  return `default ${encodedDefaultValue}`
192
195
  })()
193
196
 
194
- return `${column.name} ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
197
+ return `'${column.name}' ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
195
198
  }
@@ -1,63 +1,61 @@
1
1
  import { Effect, Schema } from '@livestore/utils/effect'
2
2
 
3
3
  import { UnexpectedError } from '../adapter-types.js'
4
+ import type { EventDef } from '../schema/EventDef.js'
4
5
  import type { LiveStoreSchema } from '../schema/mod.js'
5
- import type { MutationDef } from '../schema/mutations.js'
6
- import type { MutationDefInfo, SchemaManager } from './common.js'
6
+ import type { EventDefInfo, SchemaManager } from './common.js'
7
7
 
8
8
  export const validateSchema = (schema: LiveStoreSchema, schemaManager: SchemaManager) =>
9
9
  Effect.gen(function* () {
10
10
  // Validate mutation definitions
11
- const registeredMutationDefInfos = schemaManager.getMutationDefInfos()
11
+ const registeredEventDefInfos = schemaManager.getEventDefInfos()
12
12
 
13
- const missingMutationDefs = registeredMutationDefInfos.filter(
14
- (registeredMutationDefInfo) => !schema.mutations.has(registeredMutationDefInfo.mutationName),
13
+ const missingEventDefs = registeredEventDefInfos.filter(
14
+ (registeredEventDefInfo) => !schema.eventsDefsMap.has(registeredEventDefInfo.eventName),
15
15
  )
16
16
 
17
- if (missingMutationDefs.length > 0) {
17
+ if (missingEventDefs.length > 0) {
18
18
  yield* new UnexpectedError({
19
- cause: `Missing mutation definitions: ${missingMutationDefs.map((info) => info.mutationName).join(', ')}`,
19
+ cause: `Missing mutation definitions: ${missingEventDefs.map((info) => info.eventName).join(', ')}`,
20
20
  })
21
21
  }
22
22
 
23
- for (const [, mutationDef] of schema.mutations) {
24
- const registeredMutationDefInfo = registeredMutationDefInfos.find(
25
- (info) => info.mutationName === mutationDef.name,
26
- )
23
+ for (const [, eventDef] of schema.eventsDefsMap) {
24
+ const registeredEventDefInfo = registeredEventDefInfos.find((info) => info.eventName === eventDef.name)
27
25
 
28
- validateMutationDef(mutationDef, schemaManager, registeredMutationDefInfo)
26
+ validateEventDef(eventDef, schemaManager, registeredEventDefInfo)
29
27
  }
30
28
 
31
29
  // Validate table schemas
32
30
  })
33
31
 
34
- export const validateMutationDef = (
35
- mutationDef: MutationDef.Any,
32
+ export const validateEventDef = (
33
+ eventDef: EventDef.AnyWithoutFn,
36
34
  schemaManager: SchemaManager,
37
- registeredMutationDefInfo: MutationDefInfo | undefined,
35
+ registeredEventDefInfo: EventDefInfo | undefined,
38
36
  ) => {
39
- const schemaHash = Schema.hash(mutationDef.schema)
37
+ const schemaHash = Schema.hash(eventDef.schema)
40
38
 
41
- if (registeredMutationDefInfo === undefined) {
42
- schemaManager.setMutationDefInfo({
39
+ if (registeredEventDefInfo === undefined) {
40
+ schemaManager.setEventDefInfo({
43
41
  schemaHash,
44
- mutationName: mutationDef.name,
42
+ eventName: eventDef.name,
45
43
  })
46
44
 
47
45
  return
48
46
  }
49
47
 
50
- if (schemaHash === registeredMutationDefInfo.schemaHash) return
48
+ if (schemaHash === registeredEventDefInfo.schemaHash) return
51
49
 
52
50
  // TODO bring back some form of schema compatibility check (see https://github.com/livestorejs/livestore/issues/69)
53
- // const newSchemaIsCompatibleWithOldSchema = Schema.isSubType(jsonSchemaDefFromMgmtStore, mutationDef.schema)
51
+ // const newSchemaIsCompatibleWithOldSchema = Schema.isSubType(jsonSchemaDefFromMgmtStore, eventDef.schema)
54
52
 
55
53
  // if (!newSchemaIsCompatibleWithOldSchema) {
56
- // shouldNeverHappen(`Schema for mutation ${mutationDef.name} has changed in an incompatible way`)
54
+ // shouldNeverHappen(`Schema for mutation ${eventDef.name} has changed in an incompatible way`)
57
55
  // }
58
56
 
59
- schemaManager.setMutationDefInfo({
57
+ schemaManager.setEventDefInfo({
60
58
  schemaHash,
61
- mutationName: mutationDef.name,
59
+ eventName: eventDef.name,
62
60
  })
63
61
  }
@@ -1,7 +1,7 @@
1
- import type { SqliteDsl } from '@livestore/db-schema'
2
1
  import { shouldNeverHappen } from '@livestore/utils'
3
2
  import { pipe, ReadonlyArray, Schema, TreeFormatter } from '@livestore/utils/effect'
4
3
 
4
+ import type { SqliteDsl } from '../schema/db-schema/mod.js'
5
5
  import { sql } from '../util.js'
6
6
  import { objectEntries } from './misc.js'
7
7
  import * as ClientTypes from './types.js'
@@ -1,5 +1,4 @@
1
- import type { SqliteDsl } from '@livestore/db-schema'
2
-
1
+ import type { SqliteDsl } from '../schema/db-schema/mod.js'
3
2
  import type { BindValues } from './sql-queries.js'
4
3
  import * as SqlQueries from './sql-queries.js'
5
4
  import type * as ClientTypes from './types.js'
@@ -1,6 +1,8 @@
1
- import type { Prettify, SqliteDsl } from '@livestore/db-schema'
1
+ import type { Prettify } from '@livestore/utils'
2
2
  import type { Schema } from '@livestore/utils/effect'
3
3
 
4
+ import type { SqliteDsl } from '../schema/db-schema/mod.js'
5
+
4
6
  export type DecodedValuesForTableAll<TSchema extends SqliteDsl.DbSchema, TTableName extends keyof TSchema> = {
5
7
  [K in keyof GetColumns<TSchema, TTableName>]: Schema.Schema.Type<GetColumn<TSchema, TTableName, K>['schema']>
6
8
  }
@@ -0,0 +1,332 @@
1
+ /// <reference lib="dom" />
2
+ import { LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils'
3
+ import type { Runtime, Scope } from '@livestore/utils/effect'
4
+ import { BucketQueue, Effect, FiberHandle, Queue, Schema, Stream, Subscribable } from '@livestore/utils/effect'
5
+ import * as otel from '@opentelemetry/api'
6
+
7
+ import type { ClientSession, UnexpectedError } from '../adapter-types.js'
8
+ import * as EventId from '../schema/EventId.js'
9
+ import * as LiveStoreEvent from '../schema/LiveStoreEvent.js'
10
+ import { getEventDef, LEADER_MERGE_COUNTER_TABLE, type LiveStoreSchema } from '../schema/mod.js'
11
+ import { sql } from '../util.js'
12
+ import * as SyncState from './syncstate.js'
13
+
14
+ /**
15
+ * Rebase behaviour:
16
+ * - We continously pull events from the leader and apply them to the local store.
17
+ * - If there was a race condition (i.e. the leader and client session have both advacned),
18
+ * we'll need to rebase the local pending events on top of the leader's head.
19
+ * - The goal is to never block the UI, so we'll interrupt rebasing if a new events is pushed by the client session.
20
+ * - We also want to avoid "backwards-jumping" in the UI, so we'll transactionally apply a read model changes during a rebase.
21
+ * - We might need to make the rebase behaviour configurable e.g. to let users manually trigger a rebase
22
+ *
23
+ * Longer term we should evalutate whether we can unify the ClientSessionSyncProcessor with the LeaderSyncProcessor.
24
+ */
25
+ export const makeClientSessionSyncProcessor = ({
26
+ schema,
27
+ clientSession,
28
+ runtime,
29
+ applyEvent,
30
+ rollback,
31
+ refreshTables,
32
+ span,
33
+ params,
34
+ confirmUnsavedChanges,
35
+ }: {
36
+ schema: LiveStoreSchema
37
+ clientSession: ClientSession
38
+ runtime: Runtime.Runtime<Scope.Scope>
39
+ applyEvent: (
40
+ eventDecoded: LiveStoreEvent.PartialAnyDecoded,
41
+ options: { otelContext: otel.Context; withChangeset: boolean },
42
+ ) => {
43
+ writeTables: Set<string>
44
+ sessionChangeset: { _tag: 'sessionChangeset'; data: Uint8Array; debug: any } | { _tag: 'no-op' } | { _tag: 'unset' }
45
+ }
46
+ rollback: (changeset: Uint8Array) => void
47
+ refreshTables: (tables: Set<string>) => void
48
+ span: otel.Span
49
+ params: {
50
+ leaderPushBatchSize: number
51
+ }
52
+ /**
53
+ * Currently only used in the web adapter:
54
+ * If true, registers a beforeunload event listener to confirm unsaved changes.
55
+ */
56
+ confirmUnsavedChanges: boolean
57
+ }): ClientSessionSyncProcessor => {
58
+ const eventSchema = LiveStoreEvent.makeEventDefSchemaMemo(schema)
59
+
60
+ const syncStateRef = {
61
+ // The initial state is identical to the leader's initial state
62
+ current: new SyncState.SyncState({
63
+ localHead: clientSession.leaderThread.initialState.leaderHead,
64
+ upstreamHead: clientSession.leaderThread.initialState.leaderHead,
65
+ // Given we're starting with the leader's snapshot, we don't have any pending events intially
66
+ pending: [],
67
+ }),
68
+ }
69
+
70
+ const syncStateUpdateQueue = Queue.unbounded<SyncState.SyncState>().pipe(Effect.runSync)
71
+ const isClientEvent = (eventEncoded: LiveStoreEvent.EncodedWithMeta) =>
72
+ getEventDef(schema, eventEncoded.name).eventDef.options.clientOnly
73
+
74
+ /** We're queuing push requests to reduce the number of messages sent to the leader by batching them */
75
+ const leaderPushQueue = BucketQueue.make<LiveStoreEvent.EncodedWithMeta>().pipe(Effect.runSync)
76
+
77
+ const push: ClientSessionSyncProcessor['push'] = (batch, { otelContext }) => {
78
+ // TODO validate batch
79
+
80
+ let baseEventId = syncStateRef.current.localHead
81
+ const encodedEventDefs = batch.map(({ name, args }) => {
82
+ const eventDef = getEventDef(schema, name)
83
+ const nextIdPair = EventId.nextPair(baseEventId, eventDef.eventDef.options.clientOnly)
84
+ baseEventId = nextIdPair.id
85
+ return new LiveStoreEvent.EncodedWithMeta(
86
+ Schema.encodeUnknownSync(eventSchema)({
87
+ name,
88
+ args,
89
+ ...nextIdPair,
90
+ clientId: clientSession.clientId,
91
+ sessionId: clientSession.sessionId,
92
+ }),
93
+ )
94
+ })
95
+
96
+ const mergeResult = SyncState.merge({
97
+ syncState: syncStateRef.current,
98
+ payload: { _tag: 'local-push', newEvents: encodedEventDefs },
99
+ isClientEvent,
100
+ isEqualEvent: LiveStoreEvent.isEqualEncoded,
101
+ })
102
+
103
+ if (mergeResult._tag === 'unexpected-error') {
104
+ return shouldNeverHappen('Unexpected error in client-session-sync-processor', mergeResult.cause)
105
+ }
106
+
107
+ span.addEvent('local-push', {
108
+ batchSize: encodedEventDefs.length,
109
+ mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
110
+ })
111
+
112
+ if (mergeResult._tag !== 'advance') {
113
+ return shouldNeverHappen(`Expected advance, got ${mergeResult._tag}`)
114
+ }
115
+
116
+ syncStateRef.current = mergeResult.newSyncState
117
+ syncStateUpdateQueue.offer(mergeResult.newSyncState).pipe(Effect.runSync)
118
+
119
+ const writeTables = new Set<string>()
120
+ for (const event of mergeResult.newEvents) {
121
+ // TODO avoid encoding and decoding here again
122
+ const decodedEventDef = Schema.decodeSync(eventSchema)(event)
123
+ const res = applyEvent(decodedEventDef, { otelContext, withChangeset: true })
124
+ for (const table of res.writeTables) {
125
+ writeTables.add(table)
126
+ }
127
+ event.meta.sessionChangeset = res.sessionChangeset
128
+ }
129
+
130
+ // console.debug('pushToLeader', encodedEventDefs.length, ...encodedEventDefs.map((_) => _.toJSON()))
131
+ BucketQueue.offerAll(leaderPushQueue, encodedEventDefs).pipe(Effect.runSync)
132
+
133
+ return { writeTables }
134
+ }
135
+
136
+ const debugInfo = {
137
+ rebaseCount: 0,
138
+ advanceCount: 0,
139
+ rejectCount: 0,
140
+ }
141
+
142
+ const otelContext = otel.trace.setSpan(otel.context.active(), span)
143
+
144
+ const boot: ClientSessionSyncProcessor['boot'] = Effect.gen(function* () {
145
+ // eslint-disable-next-line unicorn/prefer-global-this
146
+ if (confirmUnsavedChanges && typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
147
+ const onBeforeUnload = (event: BeforeUnloadEvent) => {
148
+ if (syncStateRef.current.pending.length > 0) {
149
+ // Trigger the default browser dialog
150
+ event.preventDefault()
151
+ }
152
+ }
153
+
154
+ yield* Effect.acquireRelease(
155
+ Effect.sync(() => window.addEventListener('beforeunload', onBeforeUnload)),
156
+ () => Effect.sync(() => window.removeEventListener('beforeunload', onBeforeUnload)),
157
+ )
158
+ }
159
+
160
+ const leaderPushingFiberHandle = yield* FiberHandle.make()
161
+
162
+ const backgroundLeaderPushing = Effect.gen(function* () {
163
+ const batch = yield* BucketQueue.takeBetween(leaderPushQueue, 1, params.leaderPushBatchSize)
164
+ yield* clientSession.leaderThread.events.push(batch).pipe(
165
+ Effect.catchTag('LeaderAheadError', () => {
166
+ debugInfo.rejectCount++
167
+ return BucketQueue.clear(leaderPushQueue)
168
+ }),
169
+ )
170
+ }).pipe(Effect.forever, Effect.interruptible, Effect.tapCauseLogPretty)
171
+
172
+ yield* FiberHandle.run(leaderPushingFiberHandle, backgroundLeaderPushing)
173
+
174
+ const getMergeCounter = () =>
175
+ clientSession.sqliteDb.select<{ mergeCounter: number }>(
176
+ sql`SELECT mergeCounter FROM ${LEADER_MERGE_COUNTER_TABLE} WHERE id = 0`,
177
+ )[0]?.mergeCounter ?? 0
178
+
179
+ // NOTE We need to lazily call `.pull` as we want the cursor to be updated
180
+ yield* Stream.suspend(() =>
181
+ clientSession.leaderThread.events.pull({
182
+ cursor: { mergeCounter: getMergeCounter(), eventId: syncStateRef.current.localHead },
183
+ }),
184
+ ).pipe(
185
+ Stream.tap(({ payload, mergeCounter: leaderMergeCounter }) =>
186
+ Effect.gen(function* () {
187
+ // yield* Effect.logDebug('ClientSessionSyncProcessor:pull', payload)
188
+
189
+ if (clientSession.devtools.enabled) {
190
+ yield* clientSession.devtools.pullLatch.await
191
+ }
192
+
193
+ const mergeResult = SyncState.merge({
194
+ syncState: syncStateRef.current,
195
+ payload,
196
+ isClientEvent,
197
+ isEqualEvent: LiveStoreEvent.isEqualEncoded,
198
+ })
199
+
200
+ if (mergeResult._tag === 'unexpected-error') {
201
+ return yield* Effect.fail(mergeResult.cause)
202
+ } else if (mergeResult._tag === 'reject') {
203
+ return shouldNeverHappen('Unexpected reject in client-session-sync-processor', mergeResult)
204
+ }
205
+
206
+ syncStateRef.current = mergeResult.newSyncState
207
+ syncStateUpdateQueue.offer(mergeResult.newSyncState).pipe(Effect.runSync)
208
+
209
+ if (mergeResult._tag === 'rebase') {
210
+ span.addEvent('merge:pull:rebase', {
211
+ payloadTag: payload._tag,
212
+ payload: TRACE_VERBOSE ? JSON.stringify(payload) : undefined,
213
+ newEventsCount: mergeResult.newEvents.length,
214
+ rollbackCount: mergeResult.rollbackEvents.length,
215
+ res: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
216
+ leaderMergeCounter,
217
+ })
218
+
219
+ debugInfo.rebaseCount++
220
+
221
+ yield* FiberHandle.clear(leaderPushingFiberHandle)
222
+
223
+ // Reset the leader push queue since we're rebasing and will push again
224
+ yield* BucketQueue.clear(leaderPushQueue)
225
+
226
+ yield* FiberHandle.run(leaderPushingFiberHandle, backgroundLeaderPushing)
227
+
228
+ if (LS_DEV) {
229
+ Effect.logDebug(
230
+ 'merge:pull:rebase: rollback',
231
+ mergeResult.rollbackEvents.length,
232
+ ...mergeResult.rollbackEvents.slice(0, 10).map((_) => _.toJSON()),
233
+ { leaderMergeCounter },
234
+ ).pipe(Effect.provide(runtime), Effect.runSync)
235
+ }
236
+
237
+ for (let i = mergeResult.rollbackEvents.length - 1; i >= 0; i--) {
238
+ const event = mergeResult.rollbackEvents[i]!
239
+ if (event.meta.sessionChangeset._tag !== 'no-op' && event.meta.sessionChangeset._tag !== 'unset') {
240
+ rollback(event.meta.sessionChangeset.data)
241
+ event.meta.sessionChangeset = { _tag: 'unset' }
242
+ }
243
+ }
244
+
245
+ yield* BucketQueue.offerAll(leaderPushQueue, mergeResult.newSyncState.pending)
246
+ } else {
247
+ span.addEvent('merge:pull:advance', {
248
+ payloadTag: payload._tag,
249
+ payload: TRACE_VERBOSE ? JSON.stringify(payload) : undefined,
250
+ newEventsCount: mergeResult.newEvents.length,
251
+ res: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
252
+ leaderMergeCounter,
253
+ })
254
+
255
+ debugInfo.advanceCount++
256
+ }
257
+
258
+ if (mergeResult.newEvents.length === 0) return
259
+
260
+ const writeTables = new Set<string>()
261
+ for (const event of mergeResult.newEvents) {
262
+ // TODO apply changeset if available (will require tracking of write tables as well)
263
+ const decodedEventDef = Schema.decodeSync(eventSchema)(event)
264
+ const res = applyEvent(decodedEventDef, { otelContext, withChangeset: true })
265
+ for (const table of res.writeTables) {
266
+ writeTables.add(table)
267
+ }
268
+
269
+ event.meta.sessionChangeset = res.sessionChangeset
270
+ }
271
+
272
+ refreshTables(writeTables)
273
+ }).pipe(
274
+ Effect.tapCauseLogPretty,
275
+ Effect.catchAllCause((cause) => Effect.sync(() => clientSession.shutdown(cause))),
276
+ ),
277
+ ),
278
+ Stream.runDrain,
279
+ Effect.forever, // NOTE Whenever the leader changes, we need to re-start the stream
280
+ Effect.interruptible,
281
+ Effect.withSpan('client-session-sync-processor:pull'),
282
+ Effect.tapCauseLogPretty,
283
+ Effect.forkScoped,
284
+ )
285
+ })
286
+
287
+ return {
288
+ push,
289
+ boot,
290
+ syncState: Subscribable.make({
291
+ get: Effect.gen(function* () {
292
+ const syncState = syncStateRef.current
293
+ if (syncStateRef === undefined) return shouldNeverHappen('Not initialized')
294
+ return syncState
295
+ }),
296
+ changes: Stream.fromQueue(syncStateUpdateQueue),
297
+ }),
298
+ debug: {
299
+ print: () =>
300
+ Effect.gen(function* () {
301
+ console.log('debugInfo', debugInfo)
302
+ console.log('syncState', syncStateRef.current)
303
+ const pushQueueSize = yield* BucketQueue.size(leaderPushQueue)
304
+ console.log('pushQueueSize', pushQueueSize)
305
+ const pushQueueItems = yield* BucketQueue.peekAll(leaderPushQueue)
306
+ console.log(
307
+ 'pushQueueItems',
308
+ pushQueueItems.map((_) => _.toJSON()),
309
+ )
310
+ }).pipe(Effect.provide(runtime), Effect.runSync),
311
+ debugInfo: () => debugInfo,
312
+ },
313
+ } satisfies ClientSessionSyncProcessor
314
+ }
315
+
316
+ export interface ClientSessionSyncProcessor {
317
+ push: (
318
+ batch: ReadonlyArray<LiveStoreEvent.PartialAnyDecoded>,
319
+ options: { otelContext: otel.Context },
320
+ ) => {
321
+ writeTables: Set<string>
322
+ }
323
+ boot: Effect.Effect<void, UnexpectedError, Scope.Scope>
324
+ syncState: Subscribable.Subscribable<SyncState.SyncState>
325
+ debug: {
326
+ print: () => void
327
+ debugInfo: () => {
328
+ rebaseCount: number
329
+ advanceCount: number
330
+ }
331
+ }
332
+ }
package/src/sync/index.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from './sync.js'
2
2
  export * from './validate-push-payload.js'
3
- export * from './client-session-sync-processor.js'
3
+ export * from './ClientSessionSyncProcessor.js'