@livestore/common 0.4.0-dev.2 → 0.4.0-dev.20

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 (449) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ClientSessionLeaderThreadProxy.d.ts +17 -12
  3. package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
  4. package/dist/ClientSessionLeaderThreadProxy.js.map +1 -1
  5. package/dist/adapter-types.d.ts +14 -6
  6. package/dist/adapter-types.d.ts.map +1 -1
  7. package/dist/adapter-types.js.map +1 -1
  8. package/dist/debug-info.d.ts.map +1 -1
  9. package/dist/debug-info.js +33 -6
  10. package/dist/debug-info.js.map +1 -1
  11. package/dist/devtools/devtools-messages-client-session.d.ts +28 -23
  12. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
  13. package/dist/devtools/devtools-messages-client-session.js +2 -2
  14. package/dist/devtools/devtools-messages-client-session.js.map +1 -1
  15. package/dist/devtools/devtools-messages-common.d.ts +7 -14
  16. package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
  17. package/dist/devtools/devtools-messages-common.js +1 -6
  18. package/dist/devtools/devtools-messages-common.js.map +1 -1
  19. package/dist/devtools/devtools-messages-leader.d.ts +36 -29
  20. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  21. package/dist/devtools/devtools-messages-leader.js +8 -8
  22. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  23. package/dist/devtools/devtools-sessioninfo.d.ts +14 -2
  24. package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -1
  25. package/dist/devtools/devtools-sessioninfo.js +7 -4
  26. package/dist/devtools/devtools-sessioninfo.js.map +1 -1
  27. package/dist/devtools/mod.d.ts +13 -2
  28. package/dist/devtools/mod.d.ts.map +1 -1
  29. package/dist/devtools/mod.js +10 -3
  30. package/dist/devtools/mod.js.map +1 -1
  31. package/dist/errors.d.ts +52 -10
  32. package/dist/errors.d.ts.map +1 -1
  33. package/dist/errors.js +25 -6
  34. package/dist/errors.js.map +1 -1
  35. package/dist/index.d.ts +2 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +2 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/leader-thread/LeaderSyncProcessor.d.ts +8 -4
  40. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  41. package/dist/leader-thread/LeaderSyncProcessor.js +156 -73
  42. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  43. package/dist/leader-thread/eventlog.d.ts +15 -21
  44. package/dist/leader-thread/eventlog.d.ts.map +1 -1
  45. package/dist/leader-thread/eventlog.js +18 -18
  46. package/dist/leader-thread/eventlog.js.map +1 -1
  47. package/dist/leader-thread/leader-worker-devtools.d.ts +2 -2
  48. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  49. package/dist/leader-thread/leader-worker-devtools.js +30 -42
  50. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  51. package/dist/leader-thread/make-leader-thread-layer.d.ts +6 -6
  52. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  53. package/dist/leader-thread/make-leader-thread-layer.js +79 -27
  54. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  55. package/dist/leader-thread/make-leader-thread-layer.test.d.ts +2 -0
  56. package/dist/leader-thread/make-leader-thread-layer.test.d.ts.map +1 -0
  57. package/dist/leader-thread/make-leader-thread-layer.test.js +32 -0
  58. package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -0
  59. package/dist/leader-thread/materialize-event.d.ts +3 -3
  60. package/dist/leader-thread/materialize-event.d.ts.map +1 -1
  61. package/dist/leader-thread/materialize-event.js +25 -11
  62. package/dist/leader-thread/materialize-event.js.map +1 -1
  63. package/dist/leader-thread/recreate-db.d.ts +2 -3
  64. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  65. package/dist/leader-thread/recreate-db.js +5 -5
  66. package/dist/leader-thread/recreate-db.js.map +1 -1
  67. package/dist/leader-thread/shutdown-channel.d.ts +2 -2
  68. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  69. package/dist/leader-thread/shutdown-channel.js +2 -2
  70. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  71. package/dist/leader-thread/types.d.ts +21 -19
  72. package/dist/leader-thread/types.d.ts.map +1 -1
  73. package/dist/leader-thread/types.js.map +1 -1
  74. package/dist/logging.d.ts +40 -0
  75. package/dist/logging.d.ts.map +1 -0
  76. package/dist/logging.js +33 -0
  77. package/dist/logging.js.map +1 -0
  78. package/dist/make-client-session.d.ts +5 -3
  79. package/dist/make-client-session.d.ts.map +1 -1
  80. package/dist/make-client-session.js +5 -2
  81. package/dist/make-client-session.js.map +1 -1
  82. package/dist/materializer-helper.d.ts +6 -6
  83. package/dist/materializer-helper.d.ts.map +1 -1
  84. package/dist/materializer-helper.js +20 -4
  85. package/dist/materializer-helper.js.map +1 -1
  86. package/dist/rematerialize-from-eventlog.d.ts +2 -2
  87. package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
  88. package/dist/rematerialize-from-eventlog.js +29 -20
  89. package/dist/rematerialize-from-eventlog.js.map +1 -1
  90. package/dist/schema/EventDef/define.d.ts +147 -0
  91. package/dist/schema/EventDef/define.d.ts.map +1 -0
  92. package/dist/schema/EventDef/define.js +139 -0
  93. package/dist/schema/EventDef/define.js.map +1 -0
  94. package/dist/schema/EventDef/event-def.d.ts +106 -0
  95. package/dist/schema/EventDef/event-def.d.ts.map +1 -0
  96. package/dist/schema/EventDef/event-def.js +2 -0
  97. package/dist/schema/EventDef/event-def.js.map +1 -0
  98. package/dist/schema/EventDef/facts.d.ts +118 -0
  99. package/dist/schema/EventDef/facts.d.ts.map +1 -0
  100. package/dist/schema/EventDef/facts.js +53 -0
  101. package/dist/schema/EventDef/facts.js.map +1 -0
  102. package/dist/schema/EventDef/materializer.d.ts +155 -0
  103. package/dist/schema/EventDef/materializer.d.ts.map +1 -0
  104. package/dist/schema/EventDef/materializer.js +83 -0
  105. package/dist/schema/EventDef/materializer.js.map +1 -0
  106. package/dist/schema/EventDef/mod.d.ts +5 -0
  107. package/dist/schema/EventDef/mod.d.ts.map +1 -0
  108. package/dist/schema/EventDef/mod.js +5 -0
  109. package/dist/schema/EventDef/mod.js.map +1 -0
  110. package/dist/schema/EventSequenceNumber/client.d.ts +136 -0
  111. package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -0
  112. package/dist/schema/EventSequenceNumber/client.js +193 -0
  113. package/dist/schema/EventSequenceNumber/client.js.map +1 -0
  114. package/dist/schema/EventSequenceNumber/global.d.ts +15 -0
  115. package/dist/schema/EventSequenceNumber/global.d.ts.map +1 -0
  116. package/dist/schema/EventSequenceNumber/global.js +14 -0
  117. package/dist/schema/EventSequenceNumber/global.js.map +1 -0
  118. package/dist/schema/EventSequenceNumber/mod.d.ts +37 -0
  119. package/dist/schema/EventSequenceNumber/mod.d.ts.map +1 -0
  120. package/dist/schema/EventSequenceNumber/mod.js +37 -0
  121. package/dist/schema/EventSequenceNumber/mod.js.map +1 -0
  122. package/dist/schema/EventSequenceNumber.test.js +43 -43
  123. package/dist/schema/EventSequenceNumber.test.js.map +1 -1
  124. package/dist/schema/{LiveStoreEvent.d.ts → LiveStoreEvent/client.d.ts} +89 -106
  125. package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -0
  126. package/dist/schema/{LiveStoreEvent.js → LiveStoreEvent/client.js} +74 -58
  127. package/dist/schema/LiveStoreEvent/client.js.map +1 -0
  128. package/dist/schema/LiveStoreEvent/for-event-def.d.ts +52 -0
  129. package/dist/schema/LiveStoreEvent/for-event-def.d.ts.map +1 -0
  130. package/dist/schema/LiveStoreEvent/for-event-def.js +2 -0
  131. package/dist/schema/LiveStoreEvent/for-event-def.js.map +1 -0
  132. package/dist/schema/LiveStoreEvent/global.d.ts +36 -0
  133. package/dist/schema/LiveStoreEvent/global.d.ts.map +1 -0
  134. package/dist/schema/LiveStoreEvent/global.js +31 -0
  135. package/dist/schema/LiveStoreEvent/global.js.map +1 -0
  136. package/dist/schema/LiveStoreEvent/input.d.ts +46 -0
  137. package/dist/schema/LiveStoreEvent/input.d.ts.map +1 -0
  138. package/dist/schema/LiveStoreEvent/input.js +26 -0
  139. package/dist/schema/LiveStoreEvent/input.js.map +1 -0
  140. package/dist/schema/LiveStoreEvent/mod.d.ts +5 -0
  141. package/dist/schema/LiveStoreEvent/mod.d.ts.map +1 -0
  142. package/dist/schema/LiveStoreEvent/mod.js +5 -0
  143. package/dist/schema/LiveStoreEvent/mod.js.map +1 -0
  144. package/dist/schema/events.d.ts +1 -1
  145. package/dist/schema/events.d.ts.map +1 -1
  146. package/dist/schema/events.js +1 -1
  147. package/dist/schema/events.js.map +1 -1
  148. package/dist/schema/mod.d.ts +6 -4
  149. package/dist/schema/mod.d.ts.map +1 -1
  150. package/dist/schema/mod.js +5 -4
  151. package/dist/schema/mod.js.map +1 -1
  152. package/dist/schema/schema.d.ts +16 -1
  153. package/dist/schema/schema.d.ts.map +1 -1
  154. package/dist/schema/schema.js +27 -2
  155. package/dist/schema/schema.js.map +1 -1
  156. package/dist/schema/state/sqlite/client-document-def.d.ts +36 -6
  157. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
  158. package/dist/schema/state/sqlite/client-document-def.js +97 -6
  159. package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
  160. package/dist/schema/state/sqlite/client-document-def.test.js +16 -0
  161. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  162. package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
  163. package/dist/schema/state/sqlite/column-annotations.js +14 -6
  164. package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
  165. package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
  166. package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
  167. package/dist/schema/state/sqlite/column-def.js +69 -22
  168. package/dist/schema/state/sqlite/column-def.js.map +1 -1
  169. package/dist/schema/state/sqlite/column-def.test.js +46 -7
  170. package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
  171. package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
  172. package/dist/schema/state/sqlite/column-spec.js +30 -12
  173. package/dist/schema/state/sqlite/column-spec.js.map +1 -1
  174. package/dist/schema/state/sqlite/column-spec.test.js +23 -14
  175. package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
  176. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +2 -1
  177. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -1
  178. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +23 -6
  179. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
  180. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +14 -8
  181. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
  182. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +5 -3
  183. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
  184. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
  185. package/dist/schema/state/sqlite/db-schema/dsl/mod.js +2 -1
  186. package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
  187. package/dist/schema/state/sqlite/mod.d.ts +3 -3
  188. package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
  189. package/dist/schema/state/sqlite/mod.js +3 -3
  190. package/dist/schema/state/sqlite/mod.js.map +1 -1
  191. package/dist/schema/state/sqlite/query-builder/api.d.ts +17 -10
  192. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  193. package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -1
  194. package/dist/schema/state/sqlite/query-builder/astToSql.js +22 -15
  195. package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
  196. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  197. package/dist/schema/state/sqlite/query-builder/impl.js +6 -3
  198. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  199. package/dist/schema/state/sqlite/query-builder/impl.test.js +252 -88
  200. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  201. package/dist/schema/state/sqlite/schema-helpers.d.ts +2 -2
  202. package/dist/schema/state/sqlite/schema-helpers.d.ts.map +1 -1
  203. package/dist/schema/state/sqlite/schema-helpers.js +22 -12
  204. package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
  205. package/dist/schema/state/sqlite/schema-helpers.test.d.ts +2 -0
  206. package/dist/schema/state/sqlite/schema-helpers.test.d.ts.map +1 -0
  207. package/dist/schema/state/sqlite/schema-helpers.test.js +36 -0
  208. package/dist/schema/state/sqlite/schema-helpers.test.js.map +1 -0
  209. package/dist/schema/state/sqlite/{system-tables.d.ts → system-tables/eventlog-tables.d.ts} +63 -456
  210. package/dist/schema/state/sqlite/system-tables/eventlog-tables.d.ts.map +1 -0
  211. package/dist/schema/state/sqlite/system-tables/eventlog-tables.js +54 -0
  212. package/dist/schema/state/sqlite/system-tables/eventlog-tables.js.map +1 -0
  213. package/dist/schema/state/sqlite/system-tables/mod.d.ts +3 -0
  214. package/dist/schema/state/sqlite/system-tables/mod.d.ts.map +1 -0
  215. package/dist/schema/state/sqlite/system-tables/mod.js +3 -0
  216. package/dist/schema/state/sqlite/system-tables/mod.js.map +1 -0
  217. package/dist/schema/state/sqlite/system-tables/state-tables.d.ts +456 -0
  218. package/dist/schema/state/sqlite/system-tables/state-tables.d.ts.map +1 -0
  219. package/dist/schema/state/sqlite/system-tables/state-tables.js +55 -0
  220. package/dist/schema/state/sqlite/system-tables/state-tables.js.map +1 -0
  221. package/dist/schema/state/sqlite/table-def.d.ts +4 -4
  222. package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
  223. package/dist/schema/state/sqlite/table-def.js +2 -2
  224. package/dist/schema/state/sqlite/table-def.js.map +1 -1
  225. package/dist/schema/state/sqlite/table-def.test.js +80 -0
  226. package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
  227. package/dist/schema/unknown-events.d.ts +47 -0
  228. package/dist/schema/unknown-events.d.ts.map +1 -0
  229. package/dist/schema/unknown-events.js +69 -0
  230. package/dist/schema/unknown-events.js.map +1 -0
  231. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.d.ts +2 -0
  232. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.d.ts.map +1 -0
  233. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +73 -0
  234. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -0
  235. package/dist/schema-management/migrations.d.ts +32 -2
  236. package/dist/schema-management/migrations.d.ts.map +1 -1
  237. package/dist/schema-management/migrations.js +37 -5
  238. package/dist/schema-management/migrations.js.map +1 -1
  239. package/dist/schema-management/validate-schema.d.ts +3 -3
  240. package/dist/schema-management/validate-schema.d.ts.map +1 -1
  241. package/dist/schema-management/validate-schema.js +2 -2
  242. package/dist/schema-management/validate-schema.js.map +1 -1
  243. package/dist/sql-queries/sql-queries.d.ts.map +1 -1
  244. package/dist/sql-queries/sql-queries.js +11 -1
  245. package/dist/sql-queries/sql-queries.js.map +1 -1
  246. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  247. package/dist/sql-queries/sql-query-builder.js +2 -1
  248. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  249. package/dist/sqlite-types.d.ts +3 -3
  250. package/dist/sqlite-types.d.ts.map +1 -1
  251. package/dist/sync/ClientSessionSyncProcessor.d.ts +11 -13
  252. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  253. package/dist/sync/ClientSessionSyncProcessor.js +45 -42
  254. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  255. package/dist/sync/errors.d.ts +66 -0
  256. package/dist/sync/errors.d.ts.map +1 -0
  257. package/dist/sync/errors.js +36 -0
  258. package/dist/sync/errors.js.map +1 -0
  259. package/dist/sync/index.d.ts +3 -0
  260. package/dist/sync/index.d.ts.map +1 -1
  261. package/dist/sync/index.js +3 -0
  262. package/dist/sync/index.js.map +1 -1
  263. package/dist/sync/mock-sync-backend.d.ts +23 -0
  264. package/dist/sync/mock-sync-backend.d.ts.map +1 -0
  265. package/dist/sync/mock-sync-backend.js +114 -0
  266. package/dist/sync/mock-sync-backend.js.map +1 -0
  267. package/dist/sync/next/compact-events.d.ts.map +1 -1
  268. package/dist/sync/next/compact-events.js +6 -7
  269. package/dist/sync/next/compact-events.js.map +1 -1
  270. package/dist/sync/next/facts.d.ts +5 -5
  271. package/dist/sync/next/facts.d.ts.map +1 -1
  272. package/dist/sync/next/facts.js +1 -2
  273. package/dist/sync/next/facts.js.map +1 -1
  274. package/dist/sync/next/history-dag-common.d.ts +54 -15
  275. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  276. package/dist/sync/next/history-dag-common.js +198 -9
  277. package/dist/sync/next/history-dag-common.js.map +1 -1
  278. package/dist/sync/next/history-dag.d.ts.map +1 -1
  279. package/dist/sync/next/history-dag.js +10 -8
  280. package/dist/sync/next/history-dag.js.map +1 -1
  281. package/dist/sync/next/rebase-events.d.ts +5 -5
  282. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  283. package/dist/sync/next/rebase-events.js +5 -5
  284. package/dist/sync/next/rebase-events.js.map +1 -1
  285. package/dist/sync/next/test/event-fixtures.d.ts +2 -2
  286. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
  287. package/dist/sync/next/test/event-fixtures.js +9 -9
  288. package/dist/sync/next/test/event-fixtures.js.map +1 -1
  289. package/dist/sync/sync-backend-kv.d.ts +7 -0
  290. package/dist/sync/sync-backend-kv.d.ts.map +1 -0
  291. package/dist/sync/sync-backend-kv.js +18 -0
  292. package/dist/sync/sync-backend-kv.js.map +1 -0
  293. package/dist/sync/sync-backend.d.ts +105 -0
  294. package/dist/sync/sync-backend.d.ts.map +1 -0
  295. package/dist/sync/sync-backend.js +61 -0
  296. package/dist/sync/sync-backend.js.map +1 -0
  297. package/dist/sync/sync.d.ts +9 -86
  298. package/dist/sync/sync.d.ts.map +1 -1
  299. package/dist/sync/sync.js +2 -27
  300. package/dist/sync/sync.js.map +1 -1
  301. package/dist/sync/syncstate.d.ts +57 -44
  302. package/dist/sync/syncstate.d.ts.map +1 -1
  303. package/dist/sync/syncstate.js +50 -45
  304. package/dist/sync/syncstate.js.map +1 -1
  305. package/dist/sync/syncstate.test.js +83 -46
  306. package/dist/sync/syncstate.test.js.map +1 -1
  307. package/dist/sync/transport-chunking.d.ts +36 -0
  308. package/dist/sync/transport-chunking.d.ts.map +1 -0
  309. package/dist/sync/transport-chunking.js +56 -0
  310. package/dist/sync/transport-chunking.js.map +1 -0
  311. package/dist/sync/validate-push-payload.d.ts +2 -2
  312. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  313. package/dist/sync/validate-push-payload.js +6 -6
  314. package/dist/sync/validate-push-payload.js.map +1 -1
  315. package/dist/testing/event-factory.d.ts +68 -0
  316. package/dist/testing/event-factory.d.ts.map +1 -0
  317. package/dist/testing/event-factory.js +78 -0
  318. package/dist/testing/event-factory.js.map +1 -0
  319. package/dist/testing/mod.d.ts +2 -0
  320. package/dist/testing/mod.d.ts.map +1 -0
  321. package/dist/testing/mod.js +2 -0
  322. package/dist/testing/mod.js.map +1 -0
  323. package/dist/version.d.ts +16 -6
  324. package/dist/version.d.ts.map +1 -1
  325. package/dist/version.js +16 -6
  326. package/dist/version.js.map +1 -1
  327. package/package.json +7 -8
  328. package/src/ClientSessionLeaderThreadProxy.ts +17 -12
  329. package/src/adapter-types.ts +18 -6
  330. package/src/debug-info.ts +37 -6
  331. package/src/devtools/devtools-messages-client-session.ts +2 -2
  332. package/src/devtools/devtools-messages-common.ts +1 -8
  333. package/src/devtools/devtools-messages-leader.ts +8 -8
  334. package/src/devtools/devtools-sessioninfo.ts +8 -5
  335. package/src/devtools/mod.ts +11 -2
  336. package/src/errors.ts +38 -11
  337. package/src/index.ts +2 -1
  338. package/src/leader-thread/LeaderSyncProcessor.ts +242 -103
  339. package/src/leader-thread/eventlog.ts +33 -34
  340. package/src/leader-thread/leader-worker-devtools.ts +50 -54
  341. package/src/leader-thread/make-leader-thread-layer.test.ts +44 -0
  342. package/src/leader-thread/make-leader-thread-layer.ts +156 -37
  343. package/src/leader-thread/materialize-event.ts +37 -12
  344. package/src/leader-thread/recreate-db.ts +15 -7
  345. package/src/leader-thread/shutdown-channel.ts +16 -2
  346. package/src/leader-thread/types.ts +21 -19
  347. package/src/logging.ts +62 -0
  348. package/src/make-client-session.ts +9 -3
  349. package/src/materializer-helper.ts +27 -10
  350. package/src/rematerialize-from-eventlog.ts +37 -27
  351. package/src/schema/EventDef/define.ts +201 -0
  352. package/src/schema/EventDef/event-def.ts +120 -0
  353. package/src/schema/EventDef/facts.ts +135 -0
  354. package/src/schema/EventDef/materializer.ts +172 -0
  355. package/src/schema/EventDef/mod.ts +4 -0
  356. package/src/schema/EventSequenceNumber/client.ts +257 -0
  357. package/src/schema/EventSequenceNumber/global.ts +19 -0
  358. package/src/schema/EventSequenceNumber/mod.ts +37 -0
  359. package/src/schema/EventSequenceNumber.test.ts +70 -52
  360. package/src/schema/LiveStoreEvent/client.ts +221 -0
  361. package/src/schema/LiveStoreEvent/for-event-def.ts +60 -0
  362. package/src/schema/LiveStoreEvent/global.ts +45 -0
  363. package/src/schema/LiveStoreEvent/input.ts +63 -0
  364. package/src/schema/LiveStoreEvent/mod.ts +4 -0
  365. package/src/schema/events.ts +1 -1
  366. package/src/schema/mod.ts +6 -4
  367. package/src/schema/schema.ts +39 -3
  368. package/src/schema/state/sqlite/client-document-def.test.ts +19 -2
  369. package/src/schema/state/sqlite/client-document-def.ts +120 -8
  370. package/src/schema/state/sqlite/column-annotations.test.ts +1 -1
  371. package/src/schema/state/sqlite/column-annotations.ts +16 -6
  372. package/src/schema/state/sqlite/column-def.test.ts +60 -7
  373. package/src/schema/state/sqlite/column-def.ts +88 -21
  374. package/src/schema/state/sqlite/column-spec.test.ts +29 -16
  375. package/src/schema/state/sqlite/column-spec.ts +36 -11
  376. package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +26 -6
  377. package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +29 -12
  378. package/src/schema/state/sqlite/db-schema/dsl/mod.ts +2 -1
  379. package/src/schema/state/sqlite/mod.ts +4 -3
  380. package/src/schema/state/sqlite/query-builder/api.ts +19 -10
  381. package/src/schema/state/sqlite/query-builder/astToSql.ts +23 -14
  382. package/src/schema/state/sqlite/query-builder/impl.test.ts +305 -92
  383. package/src/schema/state/sqlite/query-builder/impl.ts +8 -3
  384. package/src/schema/state/sqlite/schema-helpers.test.ts +44 -0
  385. package/src/schema/state/sqlite/schema-helpers.ts +28 -20
  386. package/src/schema/state/sqlite/system-tables/eventlog-tables.ts +64 -0
  387. package/src/schema/state/sqlite/system-tables/mod.ts +2 -0
  388. package/src/schema/state/sqlite/system-tables/state-tables.ts +69 -0
  389. package/src/schema/state/sqlite/table-def.test.ts +101 -0
  390. package/src/schema/state/sqlite/table-def.ts +9 -8
  391. package/src/schema/unknown-events.ts +131 -0
  392. package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +86 -0
  393. package/src/schema-management/migrations.ts +41 -8
  394. package/src/schema-management/validate-schema.ts +3 -3
  395. package/src/sql-queries/sql-queries.ts +9 -1
  396. package/src/sql-queries/sql-query-builder.ts +2 -1
  397. package/src/sqlite-types.ts +3 -3
  398. package/src/sync/ClientSessionSyncProcessor.ts +69 -62
  399. package/src/sync/errors.ts +38 -0
  400. package/src/sync/index.ts +3 -0
  401. package/src/sync/mock-sync-backend.ts +184 -0
  402. package/src/sync/next/compact-events.ts +6 -7
  403. package/src/sync/next/facts.ts +7 -9
  404. package/src/sync/next/history-dag-common.ts +277 -26
  405. package/src/sync/next/history-dag.ts +16 -10
  406. package/src/sync/next/rebase-events.ts +11 -11
  407. package/src/sync/next/test/event-fixtures.ts +11 -11
  408. package/src/sync/sync-backend-kv.ts +22 -0
  409. package/src/sync/sync-backend.ts +185 -0
  410. package/src/sync/sync.ts +9 -91
  411. package/src/sync/syncstate.test.ts +96 -52
  412. package/src/sync/syncstate.ts +69 -58
  413. package/src/sync/transport-chunking.ts +90 -0
  414. package/src/sync/validate-push-payload.ts +8 -9
  415. package/src/testing/event-factory.ts +131 -0
  416. package/src/testing/mod.ts +1 -0
  417. package/src/version.ts +16 -6
  418. package/dist/schema/EventDef.d.ts +0 -123
  419. package/dist/schema/EventDef.d.ts.map +0 -1
  420. package/dist/schema/EventDef.js +0 -46
  421. package/dist/schema/EventDef.js.map +0 -1
  422. package/dist/schema/EventSequenceNumber.d.ts +0 -80
  423. package/dist/schema/EventSequenceNumber.d.ts.map +0 -1
  424. package/dist/schema/EventSequenceNumber.js +0 -139
  425. package/dist/schema/EventSequenceNumber.js.map +0 -1
  426. package/dist/schema/LiveStoreEvent.d.ts.map +0 -1
  427. package/dist/schema/LiveStoreEvent.js.map +0 -1
  428. package/dist/schema/state/sqlite/system-tables.d.ts.map +0 -1
  429. package/dist/schema/state/sqlite/system-tables.js +0 -79
  430. package/dist/schema/state/sqlite/system-tables.js.map +0 -1
  431. package/dist/schema-management/migrations.test.d.ts +0 -2
  432. package/dist/schema-management/migrations.test.d.ts.map +0 -1
  433. package/dist/schema-management/migrations.test.js +0 -52
  434. package/dist/schema-management/migrations.test.js.map +0 -1
  435. package/dist/sync/next/graphology.d.ts +0 -8
  436. package/dist/sync/next/graphology.d.ts.map +0 -1
  437. package/dist/sync/next/graphology.js +0 -30
  438. package/dist/sync/next/graphology.js.map +0 -1
  439. package/dist/sync/next/graphology_.d.ts +0 -3
  440. package/dist/sync/next/graphology_.d.ts.map +0 -1
  441. package/dist/sync/next/graphology_.js +0 -3
  442. package/dist/sync/next/graphology_.js.map +0 -1
  443. package/src/schema/EventDef.ts +0 -219
  444. package/src/schema/EventSequenceNumber.ts +0 -199
  445. package/src/schema/LiveStoreEvent.ts +0 -287
  446. package/src/schema/state/sqlite/system-tables.ts +0 -104
  447. package/src/sync/next/ambient.d.ts +0 -3
  448. package/src/sync/next/graphology.ts +0 -41
  449. package/src/sync/next/graphology_.ts +0 -2
package/dist/errors.js CHANGED
@@ -1,14 +1,21 @@
1
- import { Effect, Schema, Stream } from '@livestore/utils/effect';
2
- export class UnexpectedError extends Schema.TaggedError()('LiveStore.UnexpectedError', {
1
+ import { Cause, Effect, Layer, Schema, Stream } from '@livestore/utils/effect';
2
+ import * as LiveStoreEvent from "./schema/LiveStoreEvent/mod.js";
3
+ export class UnknownError extends Schema.TaggedError()('LiveStore.UnknownError', {
3
4
  cause: Schema.Defect,
4
5
  note: Schema.optional(Schema.String),
5
6
  payload: Schema.optional(Schema.Any),
6
7
  }) {
7
- static mapToUnexpectedError = (effect) => effect.pipe(Effect.mapError((cause) => (Schema.is(UnexpectedError)(cause) ? cause : new UnexpectedError({ cause }))), Effect.catchAllDefect((cause) => new UnexpectedError({ cause })));
8
- static mapToUnexpectedErrorStream = (stream) => stream.pipe(Stream.mapError((cause) => (Schema.is(UnexpectedError)(cause) ? cause : new UnexpectedError({ cause }))));
8
+ static mapToUnknownError = (effect) => effect.pipe(Effect.mapError((cause) => (Schema.is(UnknownError)(cause) ? cause : new UnknownError({ cause }))), Effect.catchAllDefect((cause) => new UnknownError({ cause })));
9
+ static mapToUnknownErrorLayer = (layer) => layer.pipe(Layer.catchAllCause((cause) => Cause.isFailType(cause) && Schema.is(UnknownError)(cause.error)
10
+ ? Layer.fail(cause.error)
11
+ : Layer.fail(new UnknownError({ cause: cause }))));
12
+ static mapToUnknownErrorStream = (stream) => stream.pipe(Stream.mapError((cause) => (Schema.is(UnknownError)(cause) ? cause : new UnknownError({ cause }))));
9
13
  }
10
- export class SyncError extends Schema.TaggedError()('LiveStore.SyncError', {
11
- cause: Schema.Defect,
14
+ export class MaterializerHashMismatchError extends Schema.TaggedError()('LiveStore.MaterializerHashMismatchError', {
15
+ eventName: Schema.String,
16
+ note: Schema.optionalWith(Schema.String, {
17
+ default: () => 'Please make sure your event materializer is a pure function without side effects.',
18
+ }),
12
19
  }) {
13
20
  }
14
21
  export class IntentionalShutdownCause extends Schema.TaggedError()('LiveStore.IntentionalShutdownCause', {
@@ -33,4 +40,16 @@ export class SqliteError extends Schema.TaggedError()('LiveStore.SqliteError', {
33
40
  note: Schema.optional(Schema.String),
34
41
  }) {
35
42
  }
43
+ export class UnknownEventError extends Schema.TaggedError()('LiveStore.UnknownEventError', {
44
+ event: LiveStoreEvent.Client.Encoded.pipe(Schema.pick('name', 'args', 'seqNum', 'clientId', 'sessionId')),
45
+ reason: Schema.Literal('event-definition-missing', 'materializer-missing'),
46
+ operation: Schema.String,
47
+ note: Schema.optional(Schema.String),
48
+ }) {
49
+ }
50
+ export class MaterializeError extends Schema.TaggedError()('LiveStore.MaterializeError', {
51
+ cause: Schema.Union(MaterializerHashMismatchError, SqliteError, UnknownEventError),
52
+ note: Schema.optional(Schema.String),
53
+ }) {
54
+ }
36
55
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEhE,MAAM,OAAO,eAAgB,SAAQ,MAAM,CAAC,WAAW,EAAmB,CAAC,2BAA2B,EAAE;IACtG,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC;CACrC,CAAC;IACA,MAAM,CAAC,oBAAoB,GAAG,CAAU,MAA8B,EAAE,EAAE,CACxE,MAAM,CAAC,IAAI,CACT,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EACxG,MAAM,CAAC,cAAc,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CACjE,CAAA;IAEH,MAAM,CAAC,0BAA0B,GAAG,CAAU,MAA8B,EAAE,EAAE,CAC9E,MAAM,CAAC,IAAI,CACT,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CACzG,CAAA;;AAGL,MAAM,OAAO,SAAU,SAAQ,MAAM,CAAC,WAAW,EAAa,CAAC,qBAAqB,EAAE;IACpF,KAAK,EAAE,MAAM,CAAC,MAAM;CACrB,CAAC;CAAG;AAEL,MAAM,OAAO,wBAAyB,SAAQ,MAAM,CAAC,WAAW,EAA4B,CAC1F,oCAAoC,EACpC;IACE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,eAAe,EAAE,QAAQ,CAAC;CACvF,CACF;CAAG;AAEJ,MAAM,OAAO,gBAAiB,SAAQ,MAAM,CAAC,WAAW,EAAoB,CAAC,4BAA4B,EAAE;IACzG,MAAM,EAAE,MAAM,CAAC,MAAM;CACtB,CAAC;CAAG;AAEL,MAAM,OAAO,WAAY,SAAQ,MAAM,CAAC,WAAW,EAAe,CAAC,uBAAuB,EAAE;IAC1F,KAAK,EAAE,MAAM,CAAC,QAAQ,CACpB,MAAM,CAAC,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC,MAAM;QAClB,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;KAC7G,CAAC,CACH;IACD,6BAA6B;IAC7B,wCAAwC;IACxC,8FAA8F;IAC9F,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACjE,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;CACrC,CAAC;CAAG"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,12 +2,13 @@ export * from './adapter-types.ts';
2
2
  export * from './bounded-collections.ts';
3
3
  export * from './debug-info.ts';
4
4
  export * as Devtools from './devtools/mod.ts';
5
+ export * as LogConfig from './logging.ts';
5
6
  export * from './make-client-session.ts';
6
7
  export * from './materializer-helper.ts';
7
8
  export * from './otel.ts';
8
9
  export * from './rematerialize-from-eventlog.ts';
9
10
  export * from './schema/state/sqlite/query-builder/mod.ts';
10
- export * from './schema/state/sqlite/system-tables.ts';
11
+ export * from './schema/state/sqlite/system-tables/mod.ts';
11
12
  export * from './schema-management/migrations.ts';
12
13
  export * as SqliteDbHelper from './sqlite-db-helper.ts';
13
14
  export * from './sync/index.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,WAAW,CAAA;AACzB,cAAc,kCAAkC,CAAA;AAChD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,wCAAwC,CAAA;AACtD,cAAc,mCAAmC,CAAA;AACjD,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AACvD,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,SAAS,MAAM,qBAAqB,CAAA;AAChD,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,SAAS,MAAM,cAAc,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,WAAW,CAAA;AACzB,cAAc,kCAAkC,CAAA;AAChD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,4CAA4C,CAAA;AAC1D,cAAc,mCAAmC,CAAA;AACjD,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AACvD,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,SAAS,MAAM,qBAAqB,CAAA;AAChD,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA"}
package/dist/index.js CHANGED
@@ -2,12 +2,13 @@ export * from "./adapter-types.js";
2
2
  export * from "./bounded-collections.js";
3
3
  export * from "./debug-info.js";
4
4
  export * as Devtools from "./devtools/mod.js";
5
+ export * as LogConfig from "./logging.js";
5
6
  export * from "./make-client-session.js";
6
7
  export * from "./materializer-helper.js";
7
8
  export * from "./otel.js";
8
9
  export * from "./rematerialize-from-eventlog.js";
9
10
  export * from "./schema/state/sqlite/query-builder/mod.js";
10
- export * from "./schema/state/sqlite/system-tables.js";
11
+ export * from "./schema/state/sqlite/system-tables/mod.js";
11
12
  export * from "./schema-management/migrations.js";
12
13
  export * as SqliteDbHelper from "./sqlite-db-helper.js";
13
14
  export * from "./sync/index.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,WAAW,CAAA;AACzB,cAAc,kCAAkC,CAAA;AAChD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,wCAAwC,CAAA;AACtD,cAAc,mCAAmC,CAAA;AACjD,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AACvD,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,SAAS,MAAM,qBAAqB,CAAA;AAChD,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,0BAA0B,CAAA;AACxC,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,SAAS,MAAM,cAAc,CAAA;AACzC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA;AACxC,cAAc,WAAW,CAAA;AACzB,cAAc,kCAAkC,CAAA;AAChD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,4CAA4C,CAAA;AAC1D,cAAc,mCAAmC,CAAA;AACjD,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AACvD,cAAc,iBAAiB,CAAA;AAC/B,OAAO,KAAK,SAAS,MAAM,qBAAqB,CAAA;AAChD,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA"}
@@ -1,7 +1,6 @@
1
1
  import type { Scope } from '@livestore/utils/effect';
2
2
  import { Effect } from '@livestore/utils/effect';
3
- import type { SqliteDb } from '../adapter-types.ts';
4
- import { UnexpectedError } from '../adapter-types.ts';
3
+ import { type SqliteDb, UnknownError } from '../adapter-types.ts';
5
4
  import type { LiveStoreSchema } from '../schema/mod.ts';
6
5
  import * as SyncState from '../sync/syncstate.ts';
7
6
  import type { InitialBlockingSyncContext, LeaderSyncProcessor } from './types.ts';
@@ -35,7 +34,7 @@ import type { InitialBlockingSyncContext, LeaderSyncProcessor } from './types.ts
35
34
  *
36
35
  * See ClientSessionSyncProcessor for how the leader and session sync processors are similar/different.
37
36
  */
38
- export declare const makeLeaderSyncProcessor: ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, params, testing, }: {
37
+ export declare const makeLeaderSyncProcessor: ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, livePull, params, testing, }: {
39
38
  schema: LiveStoreSchema;
40
39
  dbState: SqliteDb;
41
40
  initialBlockingSyncContext: InitialBlockingSyncContext;
@@ -52,10 +51,15 @@ export declare const makeLeaderSyncProcessor: ({ schema, dbState, initialBlockin
52
51
  */
53
52
  backendPushBatchSize?: number;
54
53
  };
54
+ /**
55
+ * Whether the sync backend should reactively pull new events from the sync backend
56
+ * When `false`, the sync processor will only do an initial pull
57
+ */
58
+ livePull: boolean;
55
59
  testing: {
56
60
  delays?: {
57
61
  localPushProcessing?: Effect.Effect<void>;
58
62
  };
59
63
  };
60
- }) => Effect.Effect<LeaderSyncProcessor, UnexpectedError, Scope.Scope>;
64
+ }) => Effect.Effect<LeaderSyncProcessor, UnknownError, Scope.Scope>;
61
65
  //# sourceMappingURL=LeaderSyncProcessor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LeaderSyncProcessor.d.ts","sourceRoot":"","sources":["../../src/leader-thread/LeaderSyncProcessor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAuB,KAAK,EAAU,MAAM,yBAAyB,CAAA;AACjF,OAAO,EAGL,MAAM,EAWP,MAAM,yBAAyB,CAAA;AAGhC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAa,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAEhE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAGvD,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAIjD,OAAO,KAAK,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAQjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,uBAAuB,GAAI,8FAQrC;IACD,MAAM,EAAE,eAAe,CAAA;IACvB,OAAO,EAAE,QAAQ,CAAA;IACjB,0BAA0B,EAAE,0BAA0B,CAAA;IACtD,sFAAsF;IACtF,gBAAgB,EAAE,SAAS,CAAC,SAAS,CAAA;IACrC,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAA;IAC9B,MAAM,EAAE;QACN;;WAEG;QACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B;;WAEG;QACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAC9B,CAAA;IACD,OAAO,EAAE;QACP,MAAM,CAAC,EAAE;YACP,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;SAC1C,CAAA;KACF,CAAA;CACF,KAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,eAAe,EAAE,KAAK,CAAC,KAAK,CA0O/D,CAAA"}
1
+ {"version":3,"file":"LeaderSyncProcessor.d.ts","sourceRoot":"","sources":["../../src/leader-thread/LeaderSyncProcessor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAuB,KAAK,EAAU,MAAM,yBAAyB,CAAA;AACjF,OAAO,EAKL,MAAM,EAYP,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAwD,KAAK,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEvH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AASvD,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAA;AAIjD,OAAO,KAAK,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAQjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,uBAAuB,GAAI,wGASrC;IACD,MAAM,EAAE,eAAe,CAAA;IACvB,OAAO,EAAE,QAAQ,CAAA;IACjB,0BAA0B,EAAE,0BAA0B,CAAA;IACtD,sFAAsF;IACtF,gBAAgB,EAAE,SAAS,CAAC,SAAS,CAAA;IACrC,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAA;IAC9B,MAAM,EAAE;QACN;;WAEG;QACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B;;WAEG;QACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAC9B,CAAA;IACD;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE;QACP,MAAM,CAAC,EAAE;YACP,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;SAC1C,CAAA;KACF,CAAA;CACF,KAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,YAAY,EAAE,KAAK,CAAC,KAAK,CAuR5D,CAAA"}
@@ -1,9 +1,9 @@
1
1
  import { casesHandled, isNotUndefined, LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils';
2
- import { BucketQueue, Deferred, Effect, Exit, FiberHandle, Option, OtelTracer, pipe, Queue, ReadonlyArray, Stream, Subscribable, SubscriptionRef, } from '@livestore/utils/effect';
3
- import { SyncError, UnexpectedError } from "../adapter-types.js";
2
+ import { BucketQueue, Cause, Deferred, Duration, Effect, Exit, FiberHandle, Layer, Option, OtelTracer, Queue, ReadonlyArray, Schedule, Stream, Subscribable, SubscriptionRef, } from '@livestore/utils/effect';
3
+ import { UnknownError } from "../adapter-types.js";
4
4
  import { makeMaterializerHash } from "../materializer-helper.js";
5
- import { EventSequenceNumber, getEventDef, LiveStoreEvent, SystemTables } from "../schema/mod.js";
6
- import { LeaderAheadError } from "../sync/sync.js";
5
+ import { EventSequenceNumber, LiveStoreEvent, resolveEventDef, SystemTables } from "../schema/mod.js";
6
+ import { LeaderAheadError, } from "../sync/sync.js";
7
7
  import * as SyncState from "../sync/syncstate.js";
8
8
  import { sql } from "../util.js";
9
9
  import * as Eventlog from "./eventlog.js";
@@ -39,15 +39,12 @@ import { LeaderThreadCtx } from "./types.js";
39
39
  *
40
40
  * See ClientSessionSyncProcessor for how the leader and session sync processors are similar/different.
41
41
  */
42
- export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, params, testing, }) => Effect.gen(function* () {
42
+ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncContext, initialSyncState, onError, livePull, params, testing, }) => Effect.gen(function* () {
43
43
  const syncBackendPushQueue = yield* BucketQueue.make();
44
44
  const localPushBatchSize = params.localPushBatchSize ?? 1;
45
45
  const backendPushBatchSize = params.backendPushBatchSize ?? 2;
46
46
  const syncStateSref = yield* SubscriptionRef.make(undefined);
47
- const isClientEvent = (eventEncoded) => {
48
- const { eventDef } = getEventDef(schema, eventEncoded.name);
49
- return eventDef.options.clientOnly;
50
- };
47
+ const isClientEvent = (eventEncoded) => schema.eventsDefsMap.get(eventEncoded.name)?.options.clientOnly ?? false;
51
48
  const connectedClientSessionPullQueues = yield* makePullQueueSet;
52
49
  // This context depends on data from `boot`, we should find a better implementation to avoid this ref indirection.
53
50
  const ctxRef = {
@@ -65,9 +62,9 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
65
62
  *
66
63
  * Thus the purpose of the pushHeadRef is the guard the integrity of the local push queue
67
64
  */
68
- const pushHeadRef = { current: EventSequenceNumber.ROOT };
65
+ const pushHeadRef = { current: EventSequenceNumber.Client.ROOT };
69
66
  const advancePushHead = (eventNum) => {
70
- pushHeadRef.current = EventSequenceNumber.max(pushHeadRef.current, eventNum);
67
+ pushHeadRef.current = EventSequenceNumber.Client.max(pushHeadRef.current, eventNum);
71
68
  };
72
69
  // NOTE: New events are only pushed to sync backend after successful local push processing
73
70
  const push = (newEvents, options) => Effect.gen(function* () {
@@ -98,13 +95,30 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
98
95
  const syncState = yield* syncStateSref;
99
96
  if (syncState === undefined)
100
97
  return shouldNeverHappen('Not initialized');
101
- const { eventDef } = getEventDef(schema, name);
102
- const eventEncoded = new LiveStoreEvent.EncodedWithMeta({
98
+ const resolution = yield* resolveEventDef(schema, {
99
+ operation: '@livestore/common:LeaderSyncProcessor:pushPartial',
100
+ event: {
101
+ name,
102
+ args,
103
+ clientId,
104
+ sessionId,
105
+ seqNum: syncState.localHead,
106
+ },
107
+ }).pipe(UnknownError.mapToUnknownError);
108
+ if (resolution._tag === 'unknown') {
109
+ // Ignore partial pushes for unrecognised events – they are still
110
+ // persisted server-side once a schema update ships.
111
+ return;
112
+ }
113
+ const eventEncoded = new LiveStoreEvent.Client.EncodedWithMeta({
103
114
  name,
104
115
  args,
105
116
  clientId,
106
117
  sessionId,
107
- ...EventSequenceNumber.nextPair({ seqNum: syncState.localHead, isClient: eventDef.options.clientOnly }),
118
+ ...EventSequenceNumber.Client.nextPair({
119
+ seqNum: syncState.localHead,
120
+ isClient: resolution.eventDef.options.clientOnly,
121
+ }),
108
122
  });
109
123
  yield* push([eventEncoded]);
110
124
  }).pipe(Effect.catchTag('LeaderAheadError', Effect.orDie));
@@ -125,20 +139,25 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
125
139
  // Rehydrate sync queue
126
140
  if (initialSyncState.pending.length > 0) {
127
141
  const globalPendingEvents = initialSyncState.pending
128
- // Don't sync clientOnly events
142
+ // Don't sync client-local events
129
143
  .filter((eventEncoded) => {
130
- const { eventDef } = getEventDef(schema, eventEncoded.name);
131
- return eventDef.options.clientOnly === false;
144
+ const eventDef = schema.eventsDefsMap.get(eventEncoded.name);
145
+ return eventDef === undefined ? true : eventDef.options.clientOnly === false;
132
146
  });
133
147
  if (globalPendingEvents.length > 0) {
134
148
  yield* BucketQueue.offerAll(syncBackendPushQueue, globalPendingEvents);
135
149
  }
136
150
  }
137
- const shutdownOnError = (cause) => Effect.gen(function* () {
138
- if (onError === 'shutdown') {
139
- yield* shutdownChannel.send(UnexpectedError.make({ cause }));
140
- yield* Effect.die(cause);
151
+ const maybeShutdownOnError = (cause) => Effect.gen(function* () {
152
+ if (onError === 'ignore') {
153
+ if (LS_DEV) {
154
+ yield* Effect.logDebug(`Ignoring sync error (${cause._tag === 'Fail' ? cause.error._tag : cause._tag})`, Cause.pretty(cause));
155
+ }
156
+ return;
141
157
  }
158
+ const errorToSend = Cause.isFailType(cause) ? cause.error : UnknownError.make({ cause });
159
+ yield* shutdownChannel.send(errorToSend).pipe(Effect.orDie);
160
+ return yield* Effect.die(cause);
142
161
  });
143
162
  yield* backgroundApplyLocalPushes({
144
163
  localPushesLatch,
@@ -154,17 +173,16 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
154
173
  testing: {
155
174
  delay: testing?.delays?.localPushProcessing,
156
175
  },
157
- }).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(shutdownOnError), Effect.forkScoped);
176
+ }).pipe(Effect.catchAllCause(maybeShutdownOnError), Effect.forkScoped);
158
177
  const backendPushingFiberHandle = yield* FiberHandle.make();
159
178
  const backendPushingEffect = backgroundBackendPushing({
160
179
  syncBackendPushQueue,
161
180
  otelSpan,
162
181
  devtoolsLatch: ctxRef.current?.devtoolsLatch,
163
182
  backendPushBatchSize,
164
- }).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(shutdownOnError));
183
+ }).pipe(Effect.catchAllCause(maybeShutdownOnError));
165
184
  yield* FiberHandle.run(backendPushingFiberHandle, backendPushingEffect);
166
185
  yield* backgroundBackendPulling({
167
- initialBackendHead: initialSyncState.upstreamHead.global,
168
186
  isClientEvent,
169
187
  restartBackendPushing: (filteredRebasedPending) => Effect.gen(function* () {
170
188
  // Stop current pushing fiber
@@ -178,13 +196,20 @@ export const makeLeaderSyncProcessor = ({ schema, dbState, initialBlockingSyncCo
178
196
  syncStateSref,
179
197
  localPushesLatch,
180
198
  pullLatch,
199
+ livePull,
181
200
  dbState,
182
201
  otelSpan,
183
202
  initialBlockingSyncContext,
184
203
  devtoolsLatch: ctxRef.current?.devtoolsLatch,
185
204
  connectedClientSessionPullQueues,
186
205
  advancePushHead,
187
- }).pipe(Effect.tapCauseLogPretty, Effect.catchAllCause(shutdownOnError), Effect.forkScoped);
206
+ }).pipe(Effect.retry({
207
+ // We want to retry pulling if we've lost connection to the sync backend
208
+ while: (cause) => cause._tag === 'IsOfflineError',
209
+ }), Effect.catchAllCause(maybeShutdownOnError),
210
+ // Needed to avoid `Fiber terminated with an unhandled error` logs which seem to happen because of the `Effect.retry` above.
211
+ // This might be a bug in Effect. Only seems to happen in the browser.
212
+ Effect.provide(Layer.setUnhandledErrorLogLevel(Option.none())), Effect.forkScoped);
188
213
  return { initialLeaderHead: initialSyncState.localHead };
189
214
  }).pipe(Effect.withSpanScoped('@livestore/common:LeaderSyncProcessor:boot'));
190
215
  const pull = ({ cursor }) => Effect.gen(function* () {
@@ -243,26 +268,39 @@ const backgroundApplyLocalPushes = ({ localPushesLatch, localPushesQueue, pullLa
243
268
  const currentRebaseGeneration = syncState.localHead.rebaseGeneration;
244
269
  // Since the rebase generation might have changed since enqueuing, we need to filter out items with older generation
245
270
  // It's important that we filter after we got localPushesLatch, otherwise we might filter with the old generation
246
- const [newEvents, deferreds] = pipe(batchItems, ReadonlyArray.filter(([eventEncoded]) => eventEncoded.seqNum.rebaseGeneration === currentRebaseGeneration), ReadonlyArray.unzip);
247
- if (newEvents.length === 0) {
248
- // console.log('dropping old-gen batch', currentLocalPushGenerationRef.current)
249
- // Allow the backend pulling to start
271
+ const [droppedItems, filteredItems] = ReadonlyArray.partition(batchItems, ([eventEncoded]) => eventEncoded.seqNum.rebaseGeneration >= currentRebaseGeneration);
272
+ if (droppedItems.length > 0) {
273
+ otelSpan?.addEvent(`push:drop-old-generation`, {
274
+ droppedCount: droppedItems.length,
275
+ currentRebaseGeneration,
276
+ });
277
+ /**
278
+ * Dropped pushes may still have a deferred awaiting completion.
279
+ * Fail it so the caller learns the leader advanced and resubmits with the updated generation.
280
+ */
281
+ yield* Effect.forEach(droppedItems.filter((item) => item[1] !== undefined), ([eventEncoded, deferred]) => Deferred.fail(deferred, LeaderAheadError.make({
282
+ minimumExpectedNum: syncState.localHead,
283
+ providedNum: eventEncoded.seqNum,
284
+ })));
285
+ }
286
+ if (filteredItems.length === 0) {
250
287
  yield* pullLatch.open;
251
288
  continue;
252
289
  }
290
+ const [newEvents, deferreds] = ReadonlyArray.unzip(filteredItems);
253
291
  const mergeResult = SyncState.merge({
254
292
  syncState,
255
293
  payload: { _tag: 'local-push', newEvents },
256
294
  isClientEvent,
257
- isEqualEvent: LiveStoreEvent.isEqualEncoded,
295
+ isEqualEvent: LiveStoreEvent.Client.isEqualEncoded,
258
296
  });
259
297
  switch (mergeResult._tag) {
260
- case 'unexpected-error': {
261
- otelSpan?.addEvent(`push:unexpected-error`, {
298
+ case 'unknown-error': {
299
+ otelSpan?.addEvent(`push:unknown-error`, {
262
300
  batchSize: newEvents.length,
263
301
  newEvents: TRACE_VERBOSE ? JSON.stringify(newEvents) : undefined,
264
302
  });
265
- return yield* new SyncError({ cause: mergeResult.message });
303
+ return yield* new UnknownError({ cause: mergeResult.message });
266
304
  }
267
305
  case 'rebase': {
268
306
  return shouldNeverHappen('The leader thread should never have to rebase due to a local push');
@@ -312,10 +350,10 @@ const backgroundApplyLocalPushes = ({ localPushesLatch, localPushesQueue, pullLa
312
350
  batchSize: newEvents.length,
313
351
  mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
314
352
  });
315
- // Don't sync clientOnly events
353
+ // Don't sync client-local events
316
354
  const filteredBatch = mergeResult.newEvents.filter((eventEncoded) => {
317
- const { eventDef } = getEventDef(schema, eventEncoded.name);
318
- return eventDef.options.clientOnly === false;
355
+ const eventDef = schema.eventsDefsMap.get(eventEncoded.name);
356
+ return eventDef === undefined ? true : eventDef.options.clientOnly === false;
319
357
  });
320
358
  yield* BucketQueue.offerAll(syncBackendPushQueue, filteredBatch);
321
359
  yield* materializeEventsBatch({ batchItems: mergeResult.newEvents, deferreds });
@@ -348,12 +386,12 @@ const materializeEventsBatch = ({ batchItems, deferreds }) => Effect.gen(functio
348
386
  dbEventlog.execute('COMMIT', undefined); // Commit the transaction
349
387
  }).pipe(Effect.uninterruptible, Effect.scoped, Effect.withSpan('@livestore/common:LeaderSyncProcessor:materializeEventItems', {
350
388
  attributes: { batchSize: batchItems.length },
351
- }), Effect.tapCauseLogPretty, UnexpectedError.mapToUnexpectedError);
352
- const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBackendPushing, otelSpan, dbState, syncStateSref, localPushesLatch, pullLatch, devtoolsLatch, initialBlockingSyncContext, connectedClientSessionPullQueues, advancePushHead, }) => Effect.gen(function* () {
389
+ }), Effect.tapCauseLogPretty);
390
+ const backgroundBackendPulling = ({ isClientEvent, restartBackendPushing, otelSpan, dbState, syncStateSref, localPushesLatch, livePull, pullLatch, devtoolsLatch, initialBlockingSyncContext, connectedClientSessionPullQueues, advancePushHead, }) => Effect.gen(function* () {
353
391
  const { syncBackend, dbState: db, dbEventlog, schema } = yield* LeaderThreadCtx;
354
392
  if (syncBackend === undefined)
355
393
  return;
356
- const onNewPullChunk = (newEvents, remaining) => Effect.gen(function* () {
394
+ const onNewPullChunk = (newEvents, pageInfo) => Effect.gen(function* () {
357
395
  if (newEvents.length === 0)
358
396
  return;
359
397
  if (devtoolsLatch !== undefined) {
@@ -370,18 +408,18 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
370
408
  syncState,
371
409
  payload: SyncState.PayloadUpstreamAdvance.make({ newEvents }),
372
410
  isClientEvent,
373
- isEqualEvent: LiveStoreEvent.isEqualEncoded,
411
+ isEqualEvent: LiveStoreEvent.Client.isEqualEncoded,
374
412
  ignoreClientEvents: true,
375
413
  });
376
414
  if (mergeResult._tag === 'reject') {
377
415
  return shouldNeverHappen('The leader thread should never reject upstream advances');
378
416
  }
379
- else if (mergeResult._tag === 'unexpected-error') {
380
- otelSpan?.addEvent(`pull:unexpected-error`, {
417
+ else if (mergeResult._tag === 'unknown-error') {
418
+ otelSpan?.addEvent(`pull:unknown-error`, {
381
419
  newEventsCount: newEvents.length,
382
420
  newEvents: TRACE_VERBOSE ? JSON.stringify(newEvents) : undefined,
383
421
  });
384
- return yield* new SyncError({ cause: mergeResult.message });
422
+ return yield* new UnknownError({ cause: mergeResult.message });
385
423
  }
386
424
  const newBackendHead = newEvents.at(-1).seqNum;
387
425
  Eventlog.updateBackendHead(dbEventlog, newBackendHead);
@@ -393,8 +431,8 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
393
431
  mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
394
432
  });
395
433
  const globalRebasedPendingEvents = mergeResult.newSyncState.pending.filter((event) => {
396
- const { eventDef } = getEventDef(schema, event.name);
397
- return eventDef.options.clientOnly === false;
434
+ const eventDef = schema.eventsDefsMap.get(event.name);
435
+ return eventDef === undefined ? true : eventDef.options.clientOnly === false;
398
436
  });
399
437
  yield* restartBackendPushing(globalRebasedPendingEvents);
400
438
  if (mergeResult.rollbackEvents.length > 0) {
@@ -414,6 +452,12 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
414
452
  newEventsCount: newEvents.length,
415
453
  mergeResult: TRACE_VERBOSE ? JSON.stringify(mergeResult) : undefined,
416
454
  });
455
+ // Ensure push fiber is active after advance by restarting with current pending (non-client) events
456
+ const globalPendingEvents = mergeResult.newSyncState.pending.filter((event) => {
457
+ const eventDef = schema.eventsDefsMap.get(event.name);
458
+ return eventDef === undefined ? true : eventDef.options.clientOnly === false;
459
+ });
460
+ yield* restartBackendPushing(globalPendingEvents);
417
461
  yield* connectedClientSessionPullQueues.offer({
418
462
  payload: SyncState.payloadFromMergeResult(mergeResult),
419
463
  leaderHead: mergeResult.newSyncState.localHead,
@@ -421,8 +465,8 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
421
465
  if (mergeResult.confirmedEvents.length > 0) {
422
466
  // `mergeResult.confirmedEvents` don't contain the correct sync metadata, so we need to use
423
467
  // `newEvents` instead which we filter via `mergeResult.confirmedEvents`
424
- const confirmedNewEvents = newEvents.filter((event) => mergeResult.confirmedEvents.some((confirmedEvent) => EventSequenceNumber.isEqual(event.seqNum, confirmedEvent.seqNum)));
425
- yield* Eventlog.updateSyncMetadata(confirmedNewEvents);
468
+ const confirmedNewEvents = newEvents.filter((event) => mergeResult.confirmedEvents.some((confirmedEvent) => EventSequenceNumber.Client.isEqual(event.seqNum, confirmedEvent.seqNum)));
469
+ yield* Eventlog.updateSyncMetadata(confirmedNewEvents).pipe(UnknownError.mapToUnknownError);
426
470
  }
427
471
  }
428
472
  // Removes the changeset rows which are no longer needed as we'll never have to rollback beyond this point
@@ -431,15 +475,18 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
431
475
  yield* materializeEventsBatch({ batchItems: mergeResult.newEvents, deferreds: undefined });
432
476
  yield* SubscriptionRef.set(syncStateSref, mergeResult.newSyncState);
433
477
  // Allow local pushes to be processed again
434
- if (remaining === 0) {
478
+ if (pageInfo._tag === 'NoMore') {
435
479
  yield* localPushesLatch.open;
436
480
  }
437
481
  });
438
- const cursorInfo = yield* Eventlog.getSyncBackendCursorInfo({ remoteHead: initialBackendHead });
482
+ const syncState = yield* syncStateSref;
483
+ if (syncState === undefined)
484
+ return shouldNeverHappen('Not initialized');
485
+ const cursorInfo = yield* Eventlog.getSyncBackendCursorInfo({ remoteHead: syncState.upstreamHead.global });
439
486
  const hashMaterializerResult = makeMaterializerHash({ schema, dbState });
440
- yield* syncBackend.pull(cursorInfo).pipe(
487
+ yield* syncBackend.pull(cursorInfo, { live: livePull }).pipe(
441
488
  // TODO only take from queue while connected
442
- Stream.tap(({ batch, remaining }) => Effect.gen(function* () {
489
+ Stream.tap(({ batch, pageInfo }) => Effect.gen(function* () {
443
490
  // yield* Effect.spanEvent('batch', {
444
491
  // attributes: {
445
492
  // batchSize: batch.length,
@@ -450,15 +497,17 @@ const backgroundBackendPulling = ({ initialBackendHead, isClientEvent, restartBa
450
497
  // (e.g. needed for simulating being offline)
451
498
  // TODO remove when there's a better way to handle this in stream above
452
499
  yield* SubscriptionRef.waitUntil(syncBackend.isConnected, (isConnected) => isConnected === true);
453
- yield* onNewPullChunk(batch.map((_) => LiveStoreEvent.EncodedWithMeta.fromGlobal(_.eventEncoded, {
500
+ yield* onNewPullChunk(batch.map((_) => LiveStoreEvent.Client.EncodedWithMeta.fromGlobal(_.eventEncoded, {
454
501
  syncMetadata: _.metadata,
455
502
  // TODO we can't really know the materializer result here yet beyond the first event batch item as we need to materialize it one by one first
456
503
  // This is a bug and needs to be fixed https://github.com/livestorejs/livestore/issues/503#issuecomment-3114533165
457
- materializerHashLeader: hashMaterializerResult(LiveStoreEvent.encodedFromGlobal(_.eventEncoded)),
504
+ materializerHashLeader: hashMaterializerResult(LiveStoreEvent.Global.toClientEncoded(_.eventEncoded)),
458
505
  materializerHashSession: Option.none(),
459
- })), remaining);
460
- yield* initialBlockingSyncContext.update({ processed: batch.length, remaining });
506
+ })), pageInfo);
507
+ yield* initialBlockingSyncContext.update({ processed: batch.length, pageInfo });
461
508
  })), Stream.runDrain, Effect.interruptible);
509
+ // Should only ever happen when livePull is false
510
+ yield* Effect.logDebug('backend-pulling finished', { livePull });
462
511
  }).pipe(Effect.withSpan('@livestore/common:LeaderSyncProcessor:backend-pulling'));
463
512
  const backgroundBackendPushing = ({ syncBackendPushQueue, otelSpan, devtoolsLatch, backendPushBatchSize, }) => Effect.gen(function* () {
464
513
  const { syncBackend } = yield* LeaderThreadCtx;
@@ -475,16 +524,39 @@ const backgroundBackendPushing = ({ syncBackendPushQueue, otelSpan, devtoolsLatc
475
524
  batchSize: queueItems.length,
476
525
  batch: TRACE_VERBOSE ? JSON.stringify(queueItems) : undefined,
477
526
  });
478
- // TODO handle push errors (should only happen during concurrent pull+push)
479
- const pushResult = yield* syncBackend.push(queueItems.map((_) => _.toGlobal())).pipe(Effect.either);
480
- if (pushResult._tag === 'Left') {
481
- if (LS_DEV) {
482
- yield* Effect.logDebug('handled backend-push-error', { error: pushResult.left.toString() });
527
+ // Push with declarative retry/backoff using Effect schedules
528
+ // - Exponential backoff starting at 1s and doubling (1s, 2s, 4s, 8s, 16s, 30s ...)
529
+ // - Delay clamped at 30s (continues retrying at 30s)
530
+ // - Resets automatically after successful push
531
+ // TODO(metrics): expose counters/gauges for retry attempts and queue health via devtools/metrics
532
+ // Only retry for transient UnknownError cases
533
+ const isRetryable = (err) => err._tag === 'InvalidPushError' && err.cause._tag === 'LiveStore.UnknownError';
534
+ // Input: InvalidPushError | IsOfflineError, Output: Duration
535
+ const retrySchedule = Schedule.exponential(Duration.seconds(1)).pipe(Schedule.andThenEither(Schedule.spaced(Duration.seconds(30))), // clamp at 30 second intervals
536
+ Schedule.compose(Schedule.elapsed), Schedule.whileInput(isRetryable));
537
+ yield* Effect.gen(function* () {
538
+ const iteration = yield* Schedule.CurrentIterationMetadata;
539
+ const pushResult = yield* syncBackend.push(queueItems.map((_) => _.toGlobal())).pipe(Effect.either);
540
+ const retries = iteration.recurrence;
541
+ if (retries > 0 && pushResult._tag === 'Right') {
542
+ otelSpan?.addEvent('backend-push-retry-success', { retries, batchSize: queueItems.length });
483
543
  }
484
- otelSpan?.addEvent('backend-push-error', { error: pushResult.left.toString() });
485
- // wait for interrupt caused by background pulling which will then restart pushing
486
- return yield* Effect.never;
487
- }
544
+ if (pushResult._tag === 'Left') {
545
+ otelSpan?.addEvent('backend-push-error', {
546
+ error: pushResult.left.toString(),
547
+ retries,
548
+ batchSize: queueItems.length,
549
+ });
550
+ const error = pushResult.left;
551
+ if (error._tag === 'IsOfflineError' ||
552
+ (error._tag === 'InvalidPushError' && error.cause._tag === 'ServerAheadError')) {
553
+ // It's a core part of the sync protocol that the sync backend will emit a new pull chunk alongside the ServerAheadError
554
+ yield* Effect.logDebug('handled backend-push-error (waiting for interupt caused by pull)', { error });
555
+ return yield* Effect.never;
556
+ }
557
+ return yield* error;
558
+ }
559
+ }).pipe(Effect.retry(retrySchedule));
488
560
  }
489
561
  }).pipe(Effect.interruptible, Effect.withSpan('@livestore/common:LeaderSyncProcessor:backend-pushing'));
490
562
  const trimChangesetRows = (db, newHead) => {
@@ -506,15 +578,15 @@ const makePullQueueSet = Effect.gen(function* () {
506
578
  const queue = yield* Queue.unbounded().pipe(Effect.acquireRelease(Queue.shutdown));
507
579
  yield* Effect.addFinalizer(() => Effect.sync(() => set.delete(queue)));
508
580
  const payloadsSinceCursor = Array.from(cachedPayloads.entries())
509
- .flatMap(([seqNumStr, payloads]) => payloads.map((payload) => ({ payload, seqNum: EventSequenceNumber.fromString(seqNumStr) })))
510
- .filter(({ seqNum }) => EventSequenceNumber.isGreaterThan(seqNum, cursor))
511
- .toSorted((a, b) => EventSequenceNumber.compare(a.seqNum, b.seqNum))
581
+ .flatMap(([seqNumStr, payloads]) => payloads.map((payload) => ({ payload, seqNum: EventSequenceNumber.Client.fromString(seqNumStr) })))
582
+ .filter(({ seqNum }) => EventSequenceNumber.Client.isGreaterThan(seqNum, cursor))
583
+ .toSorted((a, b) => EventSequenceNumber.Client.compare(a.seqNum, b.seqNum))
512
584
  .map(({ payload }) => {
513
585
  if (payload._tag === 'upstream-advance') {
514
586
  return {
515
587
  payload: {
516
588
  _tag: 'upstream-advance',
517
- newEvents: ReadonlyArray.dropWhile(payload.newEvents, (eventEncoded) => EventSequenceNumber.isGreaterThanOrEqual(cursor, eventEncoded.seqNum)),
589
+ newEvents: ReadonlyArray.dropWhile(payload.newEvents, (eventEncoded) => EventSequenceNumber.Client.isGreaterThanOrEqual(cursor, eventEncoded.seqNum)),
518
590
  },
519
591
  };
520
592
  }
@@ -554,7 +626,7 @@ const makePullQueueSet = Effect.gen(function* () {
554
626
  return queue;
555
627
  });
556
628
  const offer = (item) => Effect.gen(function* () {
557
- const seqNumStr = EventSequenceNumber.toString(item.leaderHead);
629
+ const seqNumStr = EventSequenceNumber.Client.toString(item.leaderHead);
558
630
  if (cachedPayloads.has(seqNumStr)) {
559
631
  cachedPayloads.get(seqNumStr).push(item.payload);
560
632
  }
@@ -575,18 +647,29 @@ const makePullQueueSet = Effect.gen(function* () {
575
647
  offer,
576
648
  };
577
649
  });
650
+ /**
651
+ * Validate a client-provided batch before it is admitted to the leader queue.
652
+ * Ensures the numbers form a strictly increasing chain and that the first
653
+ * event sits ahead of the current push head.
654
+ */
578
655
  const validatePushBatch = (batch, pushHead) => Effect.gen(function* () {
579
656
  if (batch.length === 0) {
580
657
  return;
581
658
  }
582
- // Make sure batch is monotonically increasing
659
+ // Example: session A already enqueued e1…e6 while session B (same client, different
660
+ // session) still believes the head is e1 and submits [e2, e7, e8]. The numbers look
661
+ // monotonic from B’s perspective, but we must reject and force B to rebase locally
662
+ // so the leader never regresses.
583
663
  for (let i = 1; i < batch.length; i++) {
584
- if (EventSequenceNumber.isGreaterThanOrEqual(batch[i - 1].seqNum, batch[i].seqNum)) {
585
- shouldNeverHappen(`Events must be ordered in monotonically ascending order by eventNum. Received: [${batch.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`);
664
+ if (EventSequenceNumber.Client.isGreaterThanOrEqual(batch[i - 1].seqNum, batch[i].seqNum)) {
665
+ return yield* LeaderAheadError.make({
666
+ minimumExpectedNum: batch[i - 1].seqNum,
667
+ providedNum: batch[i].seqNum,
668
+ });
586
669
  }
587
670
  }
588
671
  // Make sure smallest sequence number is > pushHead
589
- if (EventSequenceNumber.isGreaterThanOrEqual(pushHead, batch[0].seqNum)) {
672
+ if (EventSequenceNumber.Client.isGreaterThanOrEqual(pushHead, batch[0].seqNum)) {
590
673
  return yield* LeaderAheadError.make({
591
674
  minimumExpectedNum: pushHead,
592
675
  providedNum: batch[0].seqNum,