@livestore/common 0.3.0-dev.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) 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 +120 -64
  7. package/dist/adapter-types.d.ts.map +1 -1
  8. package/dist/adapter-types.js +39 -8
  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 +390 -0
  16. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -0
  17. package/dist/devtools/devtools-messages-client-session.js +97 -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 -580
  28. package/dist/devtools/devtools-messages.d.ts.map +1 -1
  29. package/dist/devtools/devtools-messages.js +3 -174
  30. package/dist/devtools/devtools-messages.js.map +1 -1
  31. package/dist/devtools/devtools-sessioninfo.d.ts +32 -0
  32. package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -0
  33. package/dist/devtools/devtools-sessioninfo.js +36 -0
  34. package/dist/devtools/devtools-sessioninfo.js.map +1 -0
  35. package/dist/devtools/mod.d.ts +55 -0
  36. package/dist/devtools/mod.d.ts.map +1 -0
  37. package/dist/devtools/mod.js +33 -0
  38. package/dist/devtools/mod.js.map +1 -0
  39. package/dist/index.d.ts +7 -9
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +7 -9
  42. package/dist/index.js.map +1 -1
  43. package/dist/leader-thread/LeaderSyncProcessor.d.ts +45 -30
  44. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  45. package/dist/leader-thread/LeaderSyncProcessor.js +484 -321
  46. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  47. package/dist/leader-thread/connection.d.ts +34 -6
  48. package/dist/leader-thread/connection.d.ts.map +1 -1
  49. package/dist/leader-thread/connection.js +22 -7
  50. package/dist/leader-thread/connection.js.map +1 -1
  51. package/dist/leader-thread/eventlog.d.ts +27 -0
  52. package/dist/leader-thread/eventlog.d.ts.map +1 -0
  53. package/dist/leader-thread/eventlog.js +119 -0
  54. package/dist/leader-thread/eventlog.js.map +1 -0
  55. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  56. package/dist/leader-thread/leader-worker-devtools.js +155 -80
  57. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  58. package/dist/leader-thread/make-leader-thread-layer.d.ts +22 -9
  59. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  60. package/dist/leader-thread/make-leader-thread-layer.js +67 -45
  61. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  62. package/dist/leader-thread/materialize-event.d.ts +16 -0
  63. package/dist/leader-thread/materialize-event.d.ts.map +1 -0
  64. package/dist/leader-thread/materialize-event.js +109 -0
  65. package/dist/leader-thread/materialize-event.js.map +1 -0
  66. package/dist/leader-thread/mod.d.ts +1 -1
  67. package/dist/leader-thread/mod.d.ts.map +1 -1
  68. package/dist/leader-thread/mod.js +1 -1
  69. package/dist/leader-thread/mod.js.map +1 -1
  70. package/dist/leader-thread/recreate-db.d.ts +4 -2
  71. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  72. package/dist/leader-thread/recreate-db.js +28 -32
  73. package/dist/leader-thread/recreate-db.js.map +1 -1
  74. package/dist/leader-thread/shutdown-channel.d.ts +2 -5
  75. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  76. package/dist/leader-thread/shutdown-channel.js +2 -4
  77. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  78. package/dist/leader-thread/types.d.ts +85 -38
  79. package/dist/leader-thread/types.d.ts.map +1 -1
  80. package/dist/leader-thread/types.js +1 -3
  81. package/dist/leader-thread/types.js.map +1 -1
  82. package/dist/make-client-session.d.ts +23 -0
  83. package/dist/make-client-session.d.ts.map +1 -0
  84. package/dist/make-client-session.js +57 -0
  85. package/dist/make-client-session.js.map +1 -0
  86. package/dist/materializer-helper.d.ts +23 -0
  87. package/dist/materializer-helper.d.ts.map +1 -0
  88. package/dist/materializer-helper.js +86 -0
  89. package/dist/materializer-helper.js.map +1 -0
  90. package/dist/otel.d.ts +2 -0
  91. package/dist/otel.d.ts.map +1 -1
  92. package/dist/otel.js +5 -0
  93. package/dist/otel.js.map +1 -1
  94. package/dist/rematerialize-from-eventlog.d.ts +14 -0
  95. package/dist/rematerialize-from-eventlog.d.ts.map +1 -0
  96. package/dist/rematerialize-from-eventlog.js +64 -0
  97. package/dist/rematerialize-from-eventlog.js.map +1 -0
  98. package/dist/schema/EventDef.d.ts +146 -0
  99. package/dist/schema/EventDef.d.ts.map +1 -0
  100. package/dist/schema/EventDef.js +58 -0
  101. package/dist/schema/EventDef.js.map +1 -0
  102. package/dist/schema/EventSequenceNumber.d.ts +57 -0
  103. package/dist/schema/EventSequenceNumber.d.ts.map +1 -0
  104. package/dist/schema/EventSequenceNumber.js +82 -0
  105. package/dist/schema/EventSequenceNumber.js.map +1 -0
  106. package/dist/schema/EventSequenceNumber.test.d.ts +2 -0
  107. package/dist/schema/EventSequenceNumber.test.d.ts.map +1 -0
  108. package/dist/schema/EventSequenceNumber.test.js +11 -0
  109. package/dist/schema/EventSequenceNumber.test.js.map +1 -0
  110. package/dist/schema/LiveStoreEvent.d.ts +257 -0
  111. package/dist/schema/LiveStoreEvent.d.ts.map +1 -0
  112. package/dist/schema/LiveStoreEvent.js +117 -0
  113. package/dist/schema/LiveStoreEvent.js.map +1 -0
  114. package/dist/schema/events.d.ts +2 -0
  115. package/dist/schema/events.d.ts.map +1 -0
  116. package/dist/schema/events.js +2 -0
  117. package/dist/schema/events.js.map +1 -0
  118. package/dist/schema/mod.d.ts +8 -6
  119. package/dist/schema/mod.d.ts.map +1 -1
  120. package/dist/schema/mod.js +8 -6
  121. package/dist/schema/mod.js.map +1 -1
  122. package/dist/schema/schema.d.ts +50 -32
  123. package/dist/schema/schema.d.ts.map +1 -1
  124. package/dist/schema/schema.js +36 -43
  125. package/dist/schema/schema.js.map +1 -1
  126. package/dist/schema/state/mod.d.ts +3 -0
  127. package/dist/schema/state/mod.d.ts.map +1 -0
  128. package/dist/schema/state/mod.js +3 -0
  129. package/dist/schema/state/mod.js.map +1 -0
  130. package/dist/schema/state/sqlite/client-document-def.d.ts +223 -0
  131. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -0
  132. package/dist/schema/state/sqlite/client-document-def.js +170 -0
  133. package/dist/schema/state/sqlite/client-document-def.js.map +1 -0
  134. package/dist/schema/state/sqlite/client-document-def.test.d.ts +2 -0
  135. package/dist/schema/state/sqlite/client-document-def.test.d.ts.map +1 -0
  136. package/dist/schema/state/sqlite/client-document-def.test.js +201 -0
  137. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -0
  138. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +69 -0
  139. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -0
  140. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +71 -0
  141. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -0
  142. package/dist/schema/state/sqlite/db-schema/ast/validate.d.ts +3 -0
  143. package/dist/schema/state/sqlite/db-schema/ast/validate.d.ts.map +1 -0
  144. package/dist/schema/state/sqlite/db-schema/ast/validate.js +12 -0
  145. package/dist/schema/state/sqlite/db-schema/ast/validate.js.map +1 -0
  146. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +90 -0
  147. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -0
  148. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +87 -0
  149. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -0
  150. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.d.ts +2 -0
  151. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.d.ts.map +1 -0
  152. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js +29 -0
  153. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js.map +1 -0
  154. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts +90 -0
  155. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -0
  156. package/dist/schema/state/sqlite/db-schema/dsl/mod.js +41 -0
  157. package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -0
  158. package/dist/schema/state/sqlite/db-schema/hash.d.ts +2 -0
  159. package/dist/schema/state/sqlite/db-schema/hash.d.ts.map +1 -0
  160. package/dist/schema/state/sqlite/db-schema/hash.js +14 -0
  161. package/dist/schema/state/sqlite/db-schema/hash.js.map +1 -0
  162. package/dist/schema/state/sqlite/db-schema/mod.d.ts +3 -0
  163. package/dist/schema/state/sqlite/db-schema/mod.d.ts.map +1 -0
  164. package/dist/schema/state/sqlite/db-schema/mod.js +3 -0
  165. package/dist/schema/state/sqlite/db-schema/mod.js.map +1 -0
  166. package/dist/schema/state/sqlite/mod.d.ts +17 -0
  167. package/dist/schema/state/sqlite/mod.d.ts.map +1 -0
  168. package/dist/schema/state/sqlite/mod.js +41 -0
  169. package/dist/schema/state/sqlite/mod.js.map +1 -0
  170. package/dist/schema/state/sqlite/query-builder/api.d.ts +294 -0
  171. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -0
  172. package/dist/schema/state/sqlite/query-builder/api.js +6 -0
  173. package/dist/schema/state/sqlite/query-builder/api.js.map +1 -0
  174. package/dist/schema/state/sqlite/query-builder/astToSql.d.ts +7 -0
  175. package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -0
  176. package/dist/schema/state/sqlite/query-builder/astToSql.js +190 -0
  177. package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -0
  178. package/dist/schema/state/sqlite/query-builder/impl.d.ts +7 -0
  179. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -0
  180. package/dist/schema/state/sqlite/query-builder/impl.js +286 -0
  181. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -0
  182. package/dist/schema/state/sqlite/query-builder/impl.test.d.ts +87 -0
  183. package/dist/schema/state/sqlite/query-builder/impl.test.d.ts.map +1 -0
  184. package/dist/schema/state/sqlite/query-builder/impl.test.js +563 -0
  185. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -0
  186. package/dist/{query-builder → schema/state/sqlite/query-builder}/mod.d.ts +7 -0
  187. package/dist/schema/state/sqlite/query-builder/mod.d.ts.map +1 -0
  188. package/dist/{query-builder → schema/state/sqlite/query-builder}/mod.js +7 -0
  189. package/dist/schema/state/sqlite/query-builder/mod.js.map +1 -0
  190. package/dist/schema/state/sqlite/schema-helpers.d.ts.map +1 -0
  191. package/dist/schema/{schema-helpers.js → state/sqlite/schema-helpers.js} +1 -1
  192. package/dist/schema/state/sqlite/schema-helpers.js.map +1 -0
  193. package/dist/schema/state/sqlite/system-tables.d.ts +574 -0
  194. package/dist/schema/state/sqlite/system-tables.d.ts.map +1 -0
  195. package/dist/schema/state/sqlite/system-tables.js +88 -0
  196. package/dist/schema/state/sqlite/system-tables.js.map +1 -0
  197. package/dist/schema/state/sqlite/table-def.d.ts +84 -0
  198. package/dist/schema/state/sqlite/table-def.d.ts.map +1 -0
  199. package/dist/schema/state/sqlite/table-def.js +36 -0
  200. package/dist/schema/state/sqlite/table-def.js.map +1 -0
  201. package/dist/schema-management/common.d.ts +7 -7
  202. package/dist/schema-management/common.d.ts.map +1 -1
  203. package/dist/schema-management/common.js.map +1 -1
  204. package/dist/schema-management/migrations.d.ts +6 -6
  205. package/dist/schema-management/migrations.d.ts.map +1 -1
  206. package/dist/schema-management/migrations.js +27 -18
  207. package/dist/schema-management/migrations.js.map +1 -1
  208. package/dist/schema-management/validate-schema.d.ts +8 -0
  209. package/dist/schema-management/validate-schema.d.ts.map +1 -0
  210. package/dist/schema-management/validate-schema.js +39 -0
  211. package/dist/schema-management/validate-schema.js.map +1 -0
  212. package/dist/sql-queries/misc.d.ts.map +1 -1
  213. package/dist/sql-queries/sql-queries.d.ts +1 -1
  214. package/dist/sql-queries/sql-queries.d.ts.map +1 -1
  215. package/dist/sql-queries/sql-queries.js.map +1 -1
  216. package/dist/sql-queries/sql-query-builder.d.ts +1 -1
  217. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  218. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  219. package/dist/sql-queries/types.d.ts +2 -1
  220. package/dist/sql-queries/types.d.ts.map +1 -1
  221. package/dist/sql-queries/types.js.map +1 -1
  222. package/dist/sync/ClientSessionSyncProcessor.d.ts +40 -19
  223. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  224. package/dist/sync/ClientSessionSyncProcessor.js +150 -72
  225. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  226. package/dist/sync/next/compact-events.d.ts.map +1 -1
  227. package/dist/sync/next/compact-events.js +38 -35
  228. package/dist/sync/next/compact-events.js.map +1 -1
  229. package/dist/sync/next/facts.d.ts +21 -21
  230. package/dist/sync/next/facts.d.ts.map +1 -1
  231. package/dist/sync/next/facts.js +11 -11
  232. package/dist/sync/next/facts.js.map +1 -1
  233. package/dist/sync/next/history-dag-common.d.ts +9 -7
  234. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  235. package/dist/sync/next/history-dag-common.js +10 -5
  236. package/dist/sync/next/history-dag-common.js.map +1 -1
  237. package/dist/sync/next/history-dag.d.ts +0 -2
  238. package/dist/sync/next/history-dag.d.ts.map +1 -1
  239. package/dist/sync/next/history-dag.js +16 -14
  240. package/dist/sync/next/history-dag.js.map +1 -1
  241. package/dist/sync/next/rebase-events.d.ts +10 -8
  242. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  243. package/dist/sync/next/rebase-events.js +18 -10
  244. package/dist/sync/next/rebase-events.js.map +1 -1
  245. package/dist/sync/next/test/compact-events.calculator.test.js +39 -34
  246. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  247. package/dist/sync/next/test/compact-events.test.js +77 -77
  248. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  249. package/dist/sync/next/test/{mutation-fixtures.d.ts → event-fixtures.d.ts} +35 -25
  250. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -0
  251. package/dist/sync/next/test/{mutation-fixtures.js → event-fixtures.js} +81 -38
  252. package/dist/sync/next/test/event-fixtures.js.map +1 -0
  253. package/dist/sync/next/test/mod.d.ts +1 -1
  254. package/dist/sync/next/test/mod.d.ts.map +1 -1
  255. package/dist/sync/next/test/mod.js +1 -1
  256. package/dist/sync/next/test/mod.js.map +1 -1
  257. package/dist/sync/sync.d.ts +46 -21
  258. package/dist/sync/sync.d.ts.map +1 -1
  259. package/dist/sync/sync.js +10 -6
  260. package/dist/sync/sync.js.map +1 -1
  261. package/dist/sync/syncstate.d.ts +213 -82
  262. package/dist/sync/syncstate.d.ts.map +1 -1
  263. package/dist/sync/syncstate.js +337 -139
  264. package/dist/sync/syncstate.js.map +1 -1
  265. package/dist/sync/syncstate.test.js +309 -286
  266. package/dist/sync/syncstate.test.js.map +1 -1
  267. package/dist/sync/validate-push-payload.d.ts +2 -2
  268. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  269. package/dist/sync/validate-push-payload.js +4 -4
  270. package/dist/sync/validate-push-payload.js.map +1 -1
  271. package/dist/util.d.ts +2 -2
  272. package/dist/util.d.ts.map +1 -1
  273. package/dist/version.d.ts +2 -2
  274. package/dist/version.d.ts.map +1 -1
  275. package/dist/version.js +2 -2
  276. package/dist/version.js.map +1 -1
  277. package/package.json +10 -4
  278. package/src/__tests__/fixture.ts +36 -15
  279. package/src/adapter-types.ts +107 -68
  280. package/src/debug-info.ts +1 -0
  281. package/src/devtools/devtools-messages-client-session.ts +142 -0
  282. package/src/devtools/devtools-messages-common.ts +115 -0
  283. package/src/devtools/devtools-messages-leader.ts +191 -0
  284. package/src/devtools/devtools-messages.ts +3 -246
  285. package/src/devtools/devtools-sessioninfo.ts +101 -0
  286. package/src/devtools/mod.ts +59 -0
  287. package/src/index.ts +7 -9
  288. package/src/leader-thread/LeaderSyncProcessor.ts +738 -477
  289. package/src/leader-thread/connection.ts +54 -9
  290. package/src/leader-thread/eventlog.ts +199 -0
  291. package/src/leader-thread/leader-worker-devtools.ts +227 -104
  292. package/src/leader-thread/make-leader-thread-layer.ts +121 -72
  293. package/src/leader-thread/materialize-event.ts +173 -0
  294. package/src/leader-thread/mod.ts +1 -1
  295. package/src/leader-thread/recreate-db.ts +33 -38
  296. package/src/leader-thread/shutdown-channel.ts +2 -4
  297. package/src/leader-thread/types.ts +94 -48
  298. package/src/make-client-session.ts +136 -0
  299. package/src/materializer-helper.ts +138 -0
  300. package/src/otel.ts +8 -0
  301. package/src/rematerialize-from-eventlog.ts +117 -0
  302. package/src/schema/EventDef.ts +227 -0
  303. package/src/schema/EventSequenceNumber.test.ts +12 -0
  304. package/src/schema/EventSequenceNumber.ts +121 -0
  305. package/src/schema/LiveStoreEvent.ts +240 -0
  306. package/src/schema/events.ts +1 -0
  307. package/src/schema/mod.ts +8 -6
  308. package/src/schema/schema.ts +88 -84
  309. package/src/schema/state/mod.ts +2 -0
  310. package/src/schema/state/sqlite/client-document-def.test.ts +238 -0
  311. package/src/schema/state/sqlite/client-document-def.ts +444 -0
  312. package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +142 -0
  313. package/src/schema/state/sqlite/db-schema/ast/validate.ts +13 -0
  314. package/src/schema/state/sqlite/db-schema/dsl/__snapshots__/field-defs.test.ts.snap +206 -0
  315. package/src/schema/state/sqlite/db-schema/dsl/field-defs.test.ts +35 -0
  316. package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +242 -0
  317. package/src/schema/state/sqlite/db-schema/dsl/mod.ts +222 -0
  318. package/src/schema/state/sqlite/db-schema/hash.ts +14 -0
  319. package/src/schema/state/sqlite/db-schema/mod.ts +2 -0
  320. package/src/schema/state/sqlite/mod.ts +73 -0
  321. package/src/schema/state/sqlite/query-builder/api.ts +440 -0
  322. package/src/schema/state/sqlite/query-builder/astToSql.ts +232 -0
  323. package/src/schema/state/sqlite/query-builder/impl.test.ts +617 -0
  324. package/src/schema/state/sqlite/query-builder/impl.ts +351 -0
  325. package/src/{query-builder → schema/state/sqlite/query-builder}/mod.ts +7 -0
  326. package/src/schema/{schema-helpers.ts → state/sqlite/schema-helpers.ts} +1 -1
  327. package/src/schema/state/sqlite/system-tables.ts +117 -0
  328. package/src/schema/state/sqlite/table-def.ts +197 -0
  329. package/src/schema-management/common.ts +7 -7
  330. package/src/schema-management/migrations.ts +37 -31
  331. package/src/schema-management/validate-schema.ts +61 -0
  332. package/src/sql-queries/sql-queries.ts +1 -1
  333. package/src/sql-queries/sql-query-builder.ts +1 -2
  334. package/src/sql-queries/types.ts +3 -1
  335. package/src/sync/ClientSessionSyncProcessor.ts +220 -94
  336. package/src/sync/next/compact-events.ts +38 -35
  337. package/src/sync/next/facts.ts +43 -41
  338. package/src/sync/next/history-dag-common.ts +17 -10
  339. package/src/sync/next/history-dag.ts +16 -17
  340. package/src/sync/next/rebase-events.ts +29 -17
  341. package/src/sync/next/test/compact-events.calculator.test.ts +46 -46
  342. package/src/sync/next/test/compact-events.test.ts +79 -79
  343. package/src/sync/next/test/event-fixtures.ts +226 -0
  344. package/src/sync/next/test/mod.ts +1 -1
  345. package/src/sync/sync.ts +46 -21
  346. package/src/sync/syncstate.test.ts +346 -320
  347. package/src/sync/syncstate.ts +422 -230
  348. package/src/sync/validate-push-payload.ts +6 -6
  349. package/src/version.ts +2 -2
  350. package/dist/derived-mutations.d.ts +0 -109
  351. package/dist/derived-mutations.d.ts.map +0 -1
  352. package/dist/derived-mutations.js +0 -54
  353. package/dist/derived-mutations.js.map +0 -1
  354. package/dist/derived-mutations.test.d.ts +0 -2
  355. package/dist/derived-mutations.test.d.ts.map +0 -1
  356. package/dist/derived-mutations.test.js +0 -93
  357. package/dist/derived-mutations.test.js.map +0 -1
  358. package/dist/devtools/devtools-bridge.d.ts +0 -13
  359. package/dist/devtools/devtools-bridge.d.ts.map +0 -1
  360. package/dist/devtools/devtools-bridge.js +0 -2
  361. package/dist/devtools/devtools-bridge.js.map +0 -1
  362. package/dist/devtools/devtools-window-message.d.ts +0 -29
  363. package/dist/devtools/devtools-window-message.d.ts.map +0 -1
  364. package/dist/devtools/devtools-window-message.js +0 -33
  365. package/dist/devtools/devtools-window-message.js.map +0 -1
  366. package/dist/devtools/index.d.ts +0 -42
  367. package/dist/devtools/index.d.ts.map +0 -1
  368. package/dist/devtools/index.js +0 -48
  369. package/dist/devtools/index.js.map +0 -1
  370. package/dist/init-singleton-tables.d.ts +0 -4
  371. package/dist/init-singleton-tables.d.ts.map +0 -1
  372. package/dist/init-singleton-tables.js +0 -16
  373. package/dist/init-singleton-tables.js.map +0 -1
  374. package/dist/leader-thread/apply-mutation.d.ts +0 -11
  375. package/dist/leader-thread/apply-mutation.d.ts.map +0 -1
  376. package/dist/leader-thread/apply-mutation.js +0 -107
  377. package/dist/leader-thread/apply-mutation.js.map +0 -1
  378. package/dist/leader-thread/leader-sync-processor.d.ts +0 -47
  379. package/dist/leader-thread/leader-sync-processor.d.ts.map +0 -1
  380. package/dist/leader-thread/leader-sync-processor.js +0 -430
  381. package/dist/leader-thread/leader-sync-processor.js.map +0 -1
  382. package/dist/leader-thread/mutationlog.d.ts +0 -10
  383. package/dist/leader-thread/mutationlog.d.ts.map +0 -1
  384. package/dist/leader-thread/mutationlog.js +0 -28
  385. package/dist/leader-thread/mutationlog.js.map +0 -1
  386. package/dist/leader-thread/pull-queue-set.d.ts +0 -7
  387. package/dist/leader-thread/pull-queue-set.d.ts.map +0 -1
  388. package/dist/leader-thread/pull-queue-set.js +0 -39
  389. package/dist/leader-thread/pull-queue-set.js.map +0 -1
  390. package/dist/mutation.d.ts +0 -20
  391. package/dist/mutation.d.ts.map +0 -1
  392. package/dist/mutation.js +0 -57
  393. package/dist/mutation.js.map +0 -1
  394. package/dist/query-builder/api.d.ts +0 -190
  395. package/dist/query-builder/api.d.ts.map +0 -1
  396. package/dist/query-builder/api.js +0 -8
  397. package/dist/query-builder/api.js.map +0 -1
  398. package/dist/query-builder/impl.d.ts +0 -12
  399. package/dist/query-builder/impl.d.ts.map +0 -1
  400. package/dist/query-builder/impl.js +0 -244
  401. package/dist/query-builder/impl.js.map +0 -1
  402. package/dist/query-builder/impl.test.d.ts +0 -2
  403. package/dist/query-builder/impl.test.d.ts.map +0 -1
  404. package/dist/query-builder/impl.test.js +0 -212
  405. package/dist/query-builder/impl.test.js.map +0 -1
  406. package/dist/query-builder/mod.d.ts.map +0 -1
  407. package/dist/query-builder/mod.js.map +0 -1
  408. package/dist/query-info.d.ts +0 -38
  409. package/dist/query-info.d.ts.map +0 -1
  410. package/dist/query-info.js +0 -7
  411. package/dist/query-info.js.map +0 -1
  412. package/dist/rehydrate-from-mutationlog.d.ts +0 -14
  413. package/dist/rehydrate-from-mutationlog.d.ts.map +0 -1
  414. package/dist/rehydrate-from-mutationlog.js +0 -66
  415. package/dist/rehydrate-from-mutationlog.js.map +0 -1
  416. package/dist/schema/EventId.d.ts +0 -39
  417. package/dist/schema/EventId.d.ts.map +0 -1
  418. package/dist/schema/EventId.js +0 -38
  419. package/dist/schema/EventId.js.map +0 -1
  420. package/dist/schema/EventId.test.d.ts +0 -2
  421. package/dist/schema/EventId.test.d.ts.map +0 -1
  422. package/dist/schema/EventId.test.js +0 -11
  423. package/dist/schema/EventId.test.js.map +0 -1
  424. package/dist/schema/MutationEvent.d.ts +0 -166
  425. package/dist/schema/MutationEvent.d.ts.map +0 -1
  426. package/dist/schema/MutationEvent.js +0 -72
  427. package/dist/schema/MutationEvent.js.map +0 -1
  428. package/dist/schema/MutationEvent.test.d.ts +0 -2
  429. package/dist/schema/MutationEvent.test.d.ts.map +0 -1
  430. package/dist/schema/MutationEvent.test.js +0 -2
  431. package/dist/schema/MutationEvent.test.js.map +0 -1
  432. package/dist/schema/mutations.d.ts +0 -107
  433. package/dist/schema/mutations.d.ts.map +0 -1
  434. package/dist/schema/mutations.js +0 -42
  435. package/dist/schema/mutations.js.map +0 -1
  436. package/dist/schema/schema-helpers.d.ts.map +0 -1
  437. package/dist/schema/schema-helpers.js.map +0 -1
  438. package/dist/schema/system-tables.d.ts +0 -399
  439. package/dist/schema/system-tables.d.ts.map +0 -1
  440. package/dist/schema/system-tables.js +0 -59
  441. package/dist/schema/system-tables.js.map +0 -1
  442. package/dist/schema/table-def.d.ts +0 -156
  443. package/dist/schema/table-def.d.ts.map +0 -1
  444. package/dist/schema/table-def.js +0 -79
  445. package/dist/schema/table-def.js.map +0 -1
  446. package/dist/schema-management/validate-mutation-defs.d.ts +0 -8
  447. package/dist/schema-management/validate-mutation-defs.d.ts.map +0 -1
  448. package/dist/schema-management/validate-mutation-defs.js +0 -39
  449. package/dist/schema-management/validate-mutation-defs.js.map +0 -1
  450. package/dist/sync/client-session-sync-processor.d.ts +0 -45
  451. package/dist/sync/client-session-sync-processor.d.ts.map +0 -1
  452. package/dist/sync/client-session-sync-processor.js +0 -131
  453. package/dist/sync/client-session-sync-processor.js.map +0 -1
  454. package/dist/sync/next/test/mutation-fixtures.d.ts.map +0 -1
  455. package/dist/sync/next/test/mutation-fixtures.js.map +0 -1
  456. package/src/derived-mutations.test.ts +0 -101
  457. package/src/derived-mutations.ts +0 -170
  458. package/src/devtools/devtools-bridge.ts +0 -14
  459. package/src/devtools/devtools-window-message.ts +0 -27
  460. package/src/devtools/index.ts +0 -48
  461. package/src/init-singleton-tables.ts +0 -24
  462. package/src/leader-thread/apply-mutation.ts +0 -161
  463. package/src/leader-thread/mutationlog.ts +0 -46
  464. package/src/leader-thread/pull-queue-set.ts +0 -58
  465. package/src/mutation.ts +0 -91
  466. package/src/query-builder/api.ts +0 -289
  467. package/src/query-builder/impl.test.ts +0 -239
  468. package/src/query-builder/impl.ts +0 -285
  469. package/src/query-info.ts +0 -78
  470. package/src/rehydrate-from-mutationlog.ts +0 -119
  471. package/src/schema/EventId.test.ts +0 -12
  472. package/src/schema/EventId.ts +0 -60
  473. package/src/schema/MutationEvent.ts +0 -181
  474. package/src/schema/mutations.ts +0 -192
  475. package/src/schema/system-tables.ts +0 -105
  476. package/src/schema/table-def.ts +0 -343
  477. package/src/schema-management/validate-mutation-defs.ts +0 -63
  478. package/src/sync/next/test/mutation-fixtures.ts +0 -224
  479. package/tsconfig.json +0 -11
  480. /package/dist/schema/{schema-helpers.d.ts → state/sqlite/schema-helpers.d.ts} +0 -0
@@ -1,186 +1,284 @@
1
+ /// <reference lib="dom" />
1
2
  import { LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils'
2
- import type { Scope } from '@livestore/utils/effect'
3
- import { Effect, Schema, Stream } from '@livestore/utils/effect'
3
+ import type { Runtime, Scope } from '@livestore/utils/effect'
4
+ import { BucketQueue, Effect, FiberHandle, Queue, Schema, Stream, Subscribable } from '@livestore/utils/effect'
4
5
  import * as otel from '@opentelemetry/api'
5
6
 
6
- import type { ClientSessionLeaderThreadProxy, UnexpectedError } from '../adapter-types.js'
7
- import * as EventId from '../schema/EventId.js'
8
- import { type LiveStoreSchema } from '../schema/mod.js'
9
- import * as MutationEvent from '../schema/MutationEvent.js'
10
- import type { SyncState } from './syncstate.js'
11
- import { updateSyncState } from './syncstate.js'
7
+ import type { ClientSession, UnexpectedError } from '../adapter-types.js'
8
+ import * as EventSequenceNumber from '../schema/EventSequenceNumber.js'
9
+ import * as LiveStoreEvent from '../schema/LiveStoreEvent.js'
10
+ import { getEventDef, type LiveStoreSchema, SystemTables } from '../schema/mod.js'
11
+ import { sql } from '../util.js'
12
+ import * as SyncState from './syncstate.js'
12
13
 
13
14
  /**
14
15
  * Rebase behaviour:
15
- * - We continously pull mutations from the leader and apply them to the local store.
16
+ * - We continously pull events from the leader and apply them to the local store.
16
17
  * - If there was a race condition (i.e. the leader and client session have both advacned),
17
- * we'll need to rebase the local pending mutations on top of the leader's head.
18
- * - The goal is to never block the UI, so we'll interrupt rebasing if a new mutations is pushed by the client session.
19
- * - We also want to avoid "backwards-jumping" in the UI, so we'll transactionally apply a read model changes during a rebase.
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 state changes during a rebase.
20
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.
21
24
  */
22
25
  export const makeClientSessionSyncProcessor = ({
23
26
  schema,
24
- initialLeaderHead,
25
- pushToLeader,
26
- pullFromLeader,
27
- applyMutation,
27
+ clientSession,
28
+ runtime,
29
+ materializeEvent,
28
30
  rollback,
29
31
  refreshTables,
30
32
  span,
33
+ params,
34
+ confirmUnsavedChanges,
31
35
  }: {
32
36
  schema: LiveStoreSchema
33
- initialLeaderHead: EventId.EventId
34
- pushToLeader: (batch: ReadonlyArray<MutationEvent.AnyEncoded>) => void
35
- pullFromLeader: ClientSessionLeaderThreadProxy['mutations']['pull']
36
- applyMutation: (
37
- mutationEventDecoded: MutationEvent.PartialAnyDecoded,
37
+ clientSession: ClientSession
38
+ runtime: Runtime.Runtime<Scope.Scope>
39
+ materializeEvent: (
40
+ eventDecoded: LiveStoreEvent.PartialAnyDecoded,
38
41
  options: { otelContext: otel.Context; withChangeset: boolean },
39
42
  ) => {
40
43
  writeTables: Set<string>
41
- sessionChangeset: Uint8Array | undefined
44
+ sessionChangeset: { _tag: 'sessionChangeset'; data: Uint8Array; debug: any } | { _tag: 'no-op' } | { _tag: 'unset' }
42
45
  }
43
46
  rollback: (changeset: Uint8Array) => void
44
47
  refreshTables: (tables: Set<string>) => void
45
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
46
57
  }): ClientSessionSyncProcessor => {
47
- const mutationEventSchema = MutationEvent.makeMutationEventSchemaMemo(schema)
58
+ const eventSchema = LiveStoreEvent.makeEventDefSchemaMemo(schema)
48
59
 
49
60
  const syncStateRef = {
50
- current: {
51
- localHead: initialLeaderHead,
52
- upstreamHead: initialLeaderHead,
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
53
66
  pending: [],
54
- // TODO init rollbackTail from leader to be ready for backend rebasing
55
- rollbackTail: [],
56
- } as SyncState,
67
+ }),
57
68
  }
58
69
 
59
- const isLocalEvent = (mutationEventEncoded: MutationEvent.EncodedWithMeta) => {
60
- const mutationDef = schema.mutations.get(mutationEventEncoded.mutation)!
61
- return mutationDef.options.localOnly
62
- }
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)
63
76
 
64
77
  const push: ClientSessionSyncProcessor['push'] = (batch, { otelContext }) => {
65
78
  // TODO validate batch
66
79
 
67
- let baseEventId = syncStateRef.current.localHead
68
- const encodedMutationEvents = batch.map((mutationEvent) => {
69
- const mutationDef = schema.mutations.get(mutationEvent.mutation)!
70
- const nextIdPair = EventId.nextPair(baseEventId, mutationDef.options.localOnly)
71
- baseEventId = nextIdPair.id
72
- return new MutationEvent.EncodedWithMeta(
73
- Schema.encodeUnknownSync(mutationEventSchema)({ ...mutationEvent, ...nextIdPair }),
80
+ let baseEventSequenceNumber = syncStateRef.current.localHead
81
+ const encodedEventDefs = batch.map(({ name, args }) => {
82
+ const eventDef = getEventDef(schema, name)
83
+ const nextNumPair = EventSequenceNumber.nextPair(baseEventSequenceNumber, eventDef.eventDef.options.clientOnly)
84
+ baseEventSequenceNumber = nextNumPair.seqNum
85
+ return new LiveStoreEvent.EncodedWithMeta(
86
+ Schema.encodeUnknownSync(eventSchema)({
87
+ name,
88
+ args,
89
+ ...nextNumPair,
90
+ clientId: clientSession.clientId,
91
+ sessionId: clientSession.sessionId,
92
+ }),
74
93
  )
75
94
  })
76
95
 
77
- const updateResult = updateSyncState({
96
+ const mergeResult = SyncState.merge({
78
97
  syncState: syncStateRef.current,
79
- payload: { _tag: 'local-push', newEvents: encodedMutationEvents },
80
- isLocalEvent,
81
- isEqualEvent: MutationEvent.isEqualEncoded,
98
+ payload: { _tag: 'local-push', newEvents: encodedEventDefs },
99
+ isClientEvent,
100
+ isEqualEvent: LiveStoreEvent.isEqualEncoded,
82
101
  })
83
102
 
103
+ if (mergeResult._tag === 'unexpected-error') {
104
+ return shouldNeverHappen('Unexpected error in client-session-sync-processor', mergeResult.cause)
105
+ }
106
+
84
107
  span.addEvent('local-push', {
85
- batchSize: encodedMutationEvents.length,
86
- updateResult: TRACE_VERBOSE ? JSON.stringify(updateResult) : undefined,
108
+ batchSize: encodedEventDefs.length,
109
+ mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
87
110
  })
88
111
 
89
- if (updateResult._tag !== 'advance') {
90
- return shouldNeverHappen(`Expected advance, got ${updateResult._tag}`)
112
+ if (mergeResult._tag !== 'advance') {
113
+ return shouldNeverHappen(`Expected advance, got ${mergeResult._tag}`)
91
114
  }
92
115
 
93
- syncStateRef.current = updateResult.newSyncState
116
+ syncStateRef.current = mergeResult.newSyncState
117
+ syncStateUpdateQueue.offer(mergeResult.newSyncState).pipe(Effect.runSync)
94
118
 
95
119
  const writeTables = new Set<string>()
96
- for (const mutationEvent of updateResult.newEvents) {
120
+ for (const event of mergeResult.newEvents) {
97
121
  // TODO avoid encoding and decoding here again
98
- const decodedMutationEvent = Schema.decodeSync(mutationEventSchema)(mutationEvent)
99
- const res = applyMutation(decodedMutationEvent, { otelContext, withChangeset: true })
122
+ const decodedEventDef = Schema.decodeSync(eventSchema)(event)
123
+ const res = materializeEvent(decodedEventDef, { otelContext, withChangeset: true })
100
124
  for (const table of res.writeTables) {
101
125
  writeTables.add(table)
102
126
  }
103
- mutationEvent.meta.sessionChangeset = res.sessionChangeset
127
+ event.meta.sessionChangeset = res.sessionChangeset
104
128
  }
105
129
 
106
- pushToLeader(encodedMutationEvents)
130
+ // console.debug('pushToLeader', encodedEventDefs.length, ...encodedEventDefs.map((_) => _.toJSON()))
131
+ BucketQueue.offerAll(leaderPushQueue, encodedEventDefs).pipe(Effect.runSync)
107
132
 
108
133
  return { writeTables }
109
134
  }
110
135
 
136
+ const debugInfo = {
137
+ rebaseCount: 0,
138
+ advanceCount: 0,
139
+ rejectCount: 0,
140
+ }
141
+
111
142
  const otelContext = otel.trace.setSpan(otel.context.active(), span)
112
143
 
113
144
  const boot: ClientSessionSyncProcessor['boot'] = Effect.gen(function* () {
114
- yield* pullFromLeader.pipe(
115
- Stream.tap(({ payload, remaining }) =>
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 ${SystemTables.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(), eventNum: syncStateRef.current.localHead },
183
+ }),
184
+ ).pipe(
185
+ Stream.tap(({ payload, mergeCounter: leaderMergeCounter }) =>
116
186
  Effect.gen(function* () {
117
- // console.log('pulled payload from leader', { payload, remaining })
187
+ // yield* Effect.logDebug('ClientSessionSyncProcessor:pull', payload)
188
+
189
+ if (clientSession.devtools.enabled) {
190
+ yield* clientSession.devtools.pullLatch.await
191
+ }
118
192
 
119
- const updateResult = updateSyncState({
193
+ const mergeResult = SyncState.merge({
120
194
  syncState: syncStateRef.current,
121
195
  payload,
122
- isLocalEvent,
123
- isEqualEvent: MutationEvent.isEqualEncoded,
196
+ isClientEvent,
197
+ isEqualEvent: LiveStoreEvent.isEqualEncoded,
124
198
  })
125
199
 
126
- if (updateResult._tag === 'reject') {
127
- debugger
128
- throw new Error('TODO: implement reject in client-session-sync-queue for pull')
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)
129
204
  }
130
205
 
131
- syncStateRef.current = updateResult.newSyncState
206
+ syncStateRef.current = mergeResult.newSyncState
207
+ syncStateUpdateQueue.offer(mergeResult.newSyncState).pipe(Effect.runSync)
132
208
 
133
- if (updateResult._tag === 'rebase') {
134
- span.addEvent('pull:rebase', {
209
+ if (mergeResult._tag === 'rebase') {
210
+ span.addEvent('merge:pull:rebase', {
135
211
  payloadTag: payload._tag,
136
212
  payload: TRACE_VERBOSE ? JSON.stringify(payload) : undefined,
137
- newEventsCount: updateResult.newEvents.length,
138
- rollbackCount: updateResult.eventsToRollback.length,
139
- res: TRACE_VERBOSE ? JSON.stringify(updateResult) : undefined,
140
- remaining,
213
+ newEventsCount: mergeResult.newEvents.length,
214
+ rollbackCount: mergeResult.rollbackEvents.length,
215
+ res: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
216
+ leaderMergeCounter,
141
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
+
142
228
  if (LS_DEV) {
143
- console.debug(
144
- 'pull:rebase: rollback',
145
- updateResult.eventsToRollback.length,
146
- ...updateResult.eventsToRollback.map((_) => _.toJSON()),
147
- )
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)
148
235
  }
149
236
 
150
- for (let i = updateResult.eventsToRollback.length - 1; i >= 0; i--) {
151
- const event = updateResult.eventsToRollback[i]!
152
- if (event.meta.sessionChangeset) {
153
- rollback(event.meta.sessionChangeset)
154
- event.meta.sessionChangeset = undefined
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' }
155
242
  }
156
243
  }
244
+
245
+ yield* BucketQueue.offerAll(leaderPushQueue, mergeResult.newSyncState.pending)
157
246
  } else {
158
- span.addEvent('pull:advance', {
247
+ span.addEvent('merge:pull:advance', {
159
248
  payloadTag: payload._tag,
160
249
  payload: TRACE_VERBOSE ? JSON.stringify(payload) : undefined,
161
- newEventsCount: updateResult.newEvents.length,
162
- res: TRACE_VERBOSE ? JSON.stringify(updateResult) : undefined,
163
- remaining,
250
+ newEventsCount: mergeResult.newEvents.length,
251
+ res: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
252
+ leaderMergeCounter,
164
253
  })
254
+
255
+ debugInfo.advanceCount++
165
256
  }
166
257
 
167
- if (updateResult.newEvents.length === 0) return
258
+ if (mergeResult.newEvents.length === 0) return
168
259
 
169
260
  const writeTables = new Set<string>()
170
- for (const mutationEvent of updateResult.newEvents) {
171
- const decodedMutationEvent = Schema.decodeSync(mutationEventSchema)(mutationEvent)
172
- const res = applyMutation(decodedMutationEvent, { otelContext, withChangeset: true })
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 = materializeEvent(decodedEventDef, { otelContext, withChangeset: true })
173
265
  for (const table of res.writeTables) {
174
266
  writeTables.add(table)
175
267
  }
176
268
 
177
- mutationEvent.meta.sessionChangeset = res.sessionChangeset
269
+ event.meta.sessionChangeset = res.sessionChangeset
178
270
  }
179
271
 
180
272
  refreshTables(writeTables)
181
- }),
273
+ }).pipe(
274
+ Effect.tapCauseLogPretty,
275
+ Effect.catchAllCause((cause) => clientSession.shutdown(cause)),
276
+ ),
182
277
  ),
183
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'),
184
282
  Effect.tapCauseLogPretty,
185
283
  Effect.forkScoped,
186
284
  )
@@ -189,18 +287,46 @@ export const makeClientSessionSyncProcessor = ({
189
287
  return {
190
288
  push,
191
289
  boot,
192
- syncStateRef,
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
+ },
193
313
  } satisfies ClientSessionSyncProcessor
194
314
  }
195
315
 
196
316
  export interface ClientSessionSyncProcessor {
197
317
  push: (
198
- batch: ReadonlyArray<MutationEvent.PartialAnyDecoded>,
318
+ batch: ReadonlyArray<LiveStoreEvent.PartialAnyDecoded>,
199
319
  options: { otelContext: otel.Context },
200
320
  ) => {
201
321
  writeTables: Set<string>
202
322
  }
203
323
  boot: Effect.Effect<void, UnexpectedError, Scope.Scope>
204
-
205
- syncStateRef: { current: SyncState }
324
+ syncState: Subscribable.Subscribable<SyncState.SyncState>
325
+ debug: {
326
+ print: () => void
327
+ debugInfo: () => {
328
+ rebaseCount: number
329
+ advanceCount: number
330
+ }
331
+ }
206
332
  }
@@ -1,6 +1,6 @@
1
+ import { EventSequenceNumber } from '../../schema/mod.js'
1
2
  import { replacesFacts } from './facts.js'
2
3
  import { graphologyDag } from './graphology_.js'
3
- import { eventIdToString } from './history-dag.js'
4
4
  import type { HistoryDag } from './history-dag-common.js'
5
5
  import { emptyHistoryDag } from './history-dag-common.js'
6
6
 
@@ -17,25 +17,25 @@ export const compactEvents = (inputDag: HistoryDag): { dag: HistoryDag; compacte
17
17
  const dag = inputDag.copy()
18
18
  const compactedEventCount = 0
19
19
 
20
- const orderedEventIdStrs = graphologyDag.topologicalSort(dag).reverse()
20
+ const orderedEventSequenceNumberStrs = graphologyDag.topologicalSort(dag).reverse()
21
21
 
22
22
  // drop root
23
- orderedEventIdStrs.pop()
23
+ orderedEventSequenceNumberStrs.pop()
24
24
 
25
- for (const eventIdStr of orderedEventIdStrs) {
26
- if (dag.hasNode(eventIdStr) === false) {
25
+ for (const eventNumStr of orderedEventSequenceNumberStrs) {
26
+ if (dag.hasNode(eventNumStr) === false) {
27
27
  continue
28
28
  }
29
29
 
30
- const subDagsForEvent = Array.from(makeSubDagsForEvent(dag, eventIdStr))
30
+ const subDagsForEvent = Array.from(makeSubDagsForEvent(dag, eventNumStr))
31
31
  for (const subDag of subDagsForEvent) {
32
32
  let shouldRetry = true
33
33
  while (shouldRetry) {
34
- const subDagsInHistory = findSubDagsInHistory(dag, subDag, eventIdStr)
34
+ const subDagsInHistory = findSubDagsInHistory(dag, subDag, eventNumStr)
35
35
 
36
36
  // console.debug(
37
37
  // 'subDagsInHistory',
38
- // eventIdStr,
38
+ // eventNumStr,
39
39
  // 'target',
40
40
  // subDag.nodes(),
41
41
  // 'found',
@@ -65,9 +65,9 @@ export const compactEvents = (inputDag: HistoryDag): { dag: HistoryDag; compacte
65
65
  return { dag, compactedEventCount }
66
66
  }
67
67
 
68
- function* makeSubDagsForEvent(inputDag: HistoryDag, eventIdStr: string): Generator<HistoryDag> {
69
- /** Map from eventIdStr to array of eventIdStrs that are dependencies */
70
- let nextIterationEls: Map<string, string[]> = new Map([[eventIdStr, []]])
68
+ function* makeSubDagsForEvent(inputDag: HistoryDag, eventNumStr: string): Generator<HistoryDag> {
69
+ /** Map from eventNumStr to array of eventNumStrs that are dependencies */
70
+ let nextIterationEls: Map<string, string[]> = new Map([[eventNumStr, []]])
71
71
  let previousDag: HistoryDag | undefined
72
72
 
73
73
  while (nextIterationEls.size > 0) {
@@ -77,19 +77,22 @@ function* makeSubDagsForEvent(inputDag: HistoryDag, eventIdStr: string): Generat
77
77
  const currentIterationEls = new Map(nextIterationEls)
78
78
  nextIterationEls = new Map()
79
79
 
80
- for (const [currentEventIdStr, edgeTargetIdStrs] of currentIterationEls) {
81
- const node = inputDag.getNodeAttributes(currentEventIdStr)
82
- if (subDag.hasNode(currentEventIdStr) === false) {
83
- subDag.addNode(currentEventIdStr, { ...node })
80
+ for (const [currentEventSequenceNumberStr, edgeTargetIdStrs] of currentIterationEls) {
81
+ const node = inputDag.getNodeAttributes(currentEventSequenceNumberStr)
82
+ if (subDag.hasNode(currentEventSequenceNumberStr) === false) {
83
+ subDag.addNode(currentEventSequenceNumberStr, { ...node })
84
84
  }
85
85
  for (const edgeTargetIdStr of edgeTargetIdStrs) {
86
- subDag.addEdge(currentEventIdStr, edgeTargetIdStr, { type: 'facts' })
86
+ subDag.addEdge(currentEventSequenceNumberStr, edgeTargetIdStr, { type: 'facts' })
87
87
  }
88
88
 
89
- for (const depEdge of inputDag.outboundEdgeEntries(currentEventIdStr)) {
89
+ for (const depEdge of inputDag.outboundEdgeEntries(currentEventSequenceNumberStr)) {
90
90
  if (depEdge.attributes.type === 'facts') {
91
- const depEventIdStr = depEdge.target
92
- nextIterationEls.set(depEventIdStr, [...(nextIterationEls.get(depEventIdStr) ?? []), currentEventIdStr])
91
+ const depEventSequenceNumberStr = depEdge.target
92
+ nextIterationEls.set(depEventSequenceNumberStr, [
93
+ ...(nextIterationEls.get(depEventSequenceNumberStr) ?? []),
94
+ currentEventSequenceNumberStr,
95
+ ])
93
96
  }
94
97
  }
95
98
  }
@@ -102,23 +105,23 @@ function* makeSubDagsForEvent(inputDag: HistoryDag, eventIdStr: string): Generat
102
105
  }
103
106
 
104
107
  /**
105
- * Iterates over all events from root to `upToExclEventIdStr`
108
+ * Iterates over all events from root to `upToExclEventSequenceNumberStr`
106
109
  * and collects all valid sub dags that are replaced by `targetSubDag`.
107
110
  */
108
111
  const findSubDagsInHistory = (
109
112
  inputDag: HistoryDag,
110
113
  targetSubDag: HistoryDag,
111
- upToExclEventIdStr: string,
114
+ upToExclEventSequenceNumberStr: string,
112
115
  ): { subDags: HistoryDag[]; allOutsideDependencies: string[][] } => {
113
116
  const subDags: HistoryDag[] = []
114
117
  const allOutsideDependencies: string[][] = []
115
118
 
116
- for (const eventIdStr of graphologyDag.topologicalSort(inputDag)) {
117
- if (eventIdStr === upToExclEventIdStr) {
119
+ for (const eventNumStr of graphologyDag.topologicalSort(inputDag)) {
120
+ if (eventNumStr === upToExclEventSequenceNumberStr) {
118
121
  break
119
122
  }
120
123
 
121
- for (const subDag of makeSubDagsForEvent(inputDag, eventIdStr)) {
124
+ for (const subDag of makeSubDagsForEvent(inputDag, eventNumStr)) {
122
125
  // console.debug('findSubDagsInHistory', 'target', targetSubDag.nodes(), 'subDag', subDag.nodes())
123
126
  if (subDag.size < targetSubDag.size) {
124
127
  continue
@@ -152,9 +155,9 @@ const outsideDependenciesForDag = (subDag: HistoryDag, inputDag: HistoryDag) =>
152
155
  for (const nodeIdStr of subDag.nodes()) {
153
156
  for (const edgeEntry of inputDag.outboundEdgeEntries(nodeIdStr)) {
154
157
  if (edgeEntry.attributes.type === 'facts') {
155
- const depEventIdStr = edgeEntry.target
156
- if (subDag.hasNode(depEventIdStr) === false) {
157
- outsideDependencies.push(depEventIdStr)
158
+ const depEventSequenceNumberStr = edgeEntry.target
159
+ if (subDag.hasNode(depEventSequenceNumberStr) === false) {
160
+ outsideDependencies.push(depEventSequenceNumberStr)
158
161
  }
159
162
  }
160
163
  }
@@ -201,19 +204,19 @@ const dagReplacesDag = (dagA: HistoryDag, dagB: HistoryDag): boolean => {
201
204
  return true
202
205
  }
203
206
 
204
- const removeEvent = (dag: HistoryDag, eventIdStr: string) => {
205
- // console.debug('removing event', eventIdStr)
206
- const event = dag.getNodeAttributes(eventIdStr)
207
- const parentIdStr = eventIdToString(event.parentId)
208
- const childEdges = dag.outboundEdgeEntries(eventIdStr)
207
+ const removeEvent = (dag: HistoryDag, eventNumStr: string) => {
208
+ // console.debug('removing event', eventNumStr)
209
+ const event = dag.getNodeAttributes(eventNumStr)
210
+ const parentSeqNumStr = EventSequenceNumber.toString(event.parentSeqNum)
211
+ const childEdges = dag.outboundEdgeEntries(eventNumStr)
209
212
 
210
213
  for (const childEdge of childEdges) {
211
214
  if (childEdge.attributes.type === 'parent') {
212
215
  const childEvent = dag.getNodeAttributes(childEdge.target)
213
- childEvent.parentId = { ...event.parentId }
214
- dag.addEdge(parentIdStr, eventIdToString(childEvent.id), { type: 'parent' })
216
+ childEvent.parentSeqNum = { ...event.parentSeqNum }
217
+ dag.addEdge(parentSeqNumStr, EventSequenceNumber.toString(childEvent.seqNum), { type: 'parent' })
215
218
  }
216
219
  }
217
220
 
218
- dag.dropNode(eventIdStr)
221
+ dag.dropNode(eventNumStr)
219
222
  }