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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ClientSessionLeaderThreadProxy.d.ts +16 -9
  3. package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
  4. package/dist/ClientSessionLeaderThreadProxy.js.map +1 -1
  5. package/dist/WorkerTransportError.d.ts +11 -0
  6. package/dist/WorkerTransportError.d.ts.map +1 -0
  7. package/dist/WorkerTransportError.js +11 -0
  8. package/dist/WorkerTransportError.js.map +1 -0
  9. package/dist/adapter-types.d.ts +26 -3
  10. package/dist/adapter-types.d.ts.map +1 -1
  11. package/dist/adapter-types.js +27 -1
  12. package/dist/adapter-types.js.map +1 -1
  13. package/dist/bounded-collections.d.ts.map +1 -1
  14. package/dist/bounded-collections.js +6 -4
  15. package/dist/bounded-collections.js.map +1 -1
  16. package/dist/debug-info.js +4 -4
  17. package/dist/debug-info.js.map +1 -1
  18. package/dist/devtools/devtools-messages-client-session.d.ts +42 -22
  19. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
  20. package/dist/devtools/devtools-messages-client-session.js +12 -1
  21. package/dist/devtools/devtools-messages-client-session.js.map +1 -1
  22. package/dist/devtools/devtools-messages-common.d.ts +12 -6
  23. package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
  24. package/dist/devtools/devtools-messages-common.js +8 -3
  25. package/dist/devtools/devtools-messages-common.js.map +1 -1
  26. package/dist/devtools/devtools-messages-leader.d.ts +45 -25
  27. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  28. package/dist/devtools/devtools-messages-leader.js +12 -1
  29. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  30. package/dist/devtools/mod.js +1 -1
  31. package/dist/devtools/mod.js.map +1 -1
  32. package/dist/errors.d.ts +15 -15
  33. package/dist/errors.d.ts.map +1 -1
  34. package/dist/errors.js +11 -11
  35. package/dist/errors.js.map +1 -1
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +2 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/leader-thread/LeaderSyncProcessor.d.ts +20 -6
  41. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  42. package/dist/leader-thread/LeaderSyncProcessor.js +283 -253
  43. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  44. package/dist/leader-thread/RejectedPushError.d.ts +107 -0
  45. package/dist/leader-thread/RejectedPushError.d.ts.map +1 -0
  46. package/dist/leader-thread/RejectedPushError.js +78 -0
  47. package/dist/leader-thread/RejectedPushError.js.map +1 -0
  48. package/dist/leader-thread/connection.js +1 -1
  49. package/dist/leader-thread/connection.js.map +1 -1
  50. package/dist/leader-thread/eventlog.d.ts.map +1 -1
  51. package/dist/leader-thread/eventlog.js +12 -11
  52. package/dist/leader-thread/eventlog.js.map +1 -1
  53. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -2
  54. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  55. package/dist/leader-thread/leader-worker-devtools.js +34 -14
  56. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  57. package/dist/leader-thread/make-leader-thread-layer.d.ts +12 -5
  58. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  59. package/dist/leader-thread/make-leader-thread-layer.js +12 -11
  60. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  61. package/dist/leader-thread/make-leader-thread-layer.test.js +1 -1
  62. package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -1
  63. package/dist/leader-thread/materialize-event.d.ts.map +1 -1
  64. package/dist/leader-thread/materialize-event.js +7 -4
  65. package/dist/leader-thread/materialize-event.js.map +1 -1
  66. package/dist/leader-thread/recreate-db.js +1 -1
  67. package/dist/leader-thread/recreate-db.js.map +1 -1
  68. package/dist/leader-thread/shutdown-channel.d.ts +2 -2
  69. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  70. package/dist/leader-thread/shutdown-channel.js +2 -2
  71. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  72. package/dist/leader-thread/stream-events.d.ts.map +1 -1
  73. package/dist/leader-thread/stream-events.js +4 -3
  74. package/dist/leader-thread/stream-events.js.map +1 -1
  75. package/dist/leader-thread/types.d.ts +7 -6
  76. package/dist/leader-thread/types.d.ts.map +1 -1
  77. package/dist/leader-thread/types.js.map +1 -1
  78. package/dist/logging.js +4 -4
  79. package/dist/logging.js.map +1 -1
  80. package/dist/make-client-session.js +2 -2
  81. package/dist/make-client-session.js.map +1 -1
  82. package/dist/materializer-helper.js +6 -6
  83. package/dist/materializer-helper.js.map +1 -1
  84. package/dist/otel.d.ts +1 -1
  85. package/dist/otel.d.ts.map +1 -1
  86. package/dist/otel.js +2 -2
  87. package/dist/otel.js.map +1 -1
  88. package/dist/rematerialize-from-eventlog.d.ts +1 -1
  89. package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
  90. package/dist/rematerialize-from-eventlog.js +11 -9
  91. package/dist/rematerialize-from-eventlog.js.map +1 -1
  92. package/dist/schema/EventDef/define.d.ts +16 -2
  93. package/dist/schema/EventDef/define.d.ts.map +1 -1
  94. package/dist/schema/EventDef/define.js +5 -4
  95. package/dist/schema/EventDef/define.js.map +1 -1
  96. package/dist/schema/EventDef/deprecated.d.ts +99 -0
  97. package/dist/schema/EventDef/deprecated.d.ts.map +1 -0
  98. package/dist/schema/EventDef/deprecated.js +144 -0
  99. package/dist/schema/EventDef/deprecated.js.map +1 -0
  100. package/dist/schema/EventDef/deprecated.test.d.ts +2 -0
  101. package/dist/schema/EventDef/deprecated.test.d.ts.map +1 -0
  102. package/dist/schema/EventDef/deprecated.test.js +95 -0
  103. package/dist/schema/EventDef/deprecated.test.js.map +1 -0
  104. package/dist/schema/EventDef/event-def.d.ts +4 -0
  105. package/dist/schema/EventDef/event-def.d.ts.map +1 -1
  106. package/dist/schema/EventDef/mod.d.ts +1 -0
  107. package/dist/schema/EventDef/mod.d.ts.map +1 -1
  108. package/dist/schema/EventDef/mod.js +1 -0
  109. package/dist/schema/EventDef/mod.js.map +1 -1
  110. package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -1
  111. package/dist/schema/EventSequenceNumber/client.js +11 -11
  112. package/dist/schema/EventSequenceNumber/client.js.map +1 -1
  113. package/dist/schema/EventSequenceNumber.test.js +1 -1
  114. package/dist/schema/EventSequenceNumber.test.js.map +1 -1
  115. package/dist/schema/LiveStoreEvent/client.d.ts +6 -6
  116. package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -1
  117. package/dist/schema/LiveStoreEvent/client.js +6 -3
  118. package/dist/schema/LiveStoreEvent/client.js.map +1 -1
  119. package/dist/schema/LiveStoreEvent/client.test.d.ts +2 -0
  120. package/dist/schema/LiveStoreEvent/client.test.d.ts.map +1 -0
  121. package/dist/schema/LiveStoreEvent/client.test.js +83 -0
  122. package/dist/schema/LiveStoreEvent/client.test.js.map +1 -0
  123. package/dist/schema/schema.d.ts.map +1 -1
  124. package/dist/schema/schema.js +7 -4
  125. package/dist/schema/schema.js.map +1 -1
  126. package/dist/schema/state/sqlite/client-document-def.d.ts +1 -0
  127. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
  128. package/dist/schema/state/sqlite/client-document-def.js +34 -13
  129. package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
  130. package/dist/schema/state/sqlite/client-document-def.test.js +121 -2
  131. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  132. package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
  133. package/dist/schema/state/sqlite/column-annotations.js +1 -1
  134. package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
  135. package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
  136. package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
  137. package/dist/schema/state/sqlite/column-def.d.ts.map +1 -1
  138. package/dist/schema/state/sqlite/column-def.js +36 -34
  139. package/dist/schema/state/sqlite/column-def.js.map +1 -1
  140. package/dist/schema/state/sqlite/column-def.test.js +7 -6
  141. package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
  142. package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
  143. package/dist/schema/state/sqlite/column-spec.js +8 -8
  144. package/dist/schema/state/sqlite/column-spec.js.map +1 -1
  145. package/dist/schema/state/sqlite/column-spec.test.js +1 -1
  146. package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
  147. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +2 -2
  148. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
  149. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +2 -2
  150. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
  151. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +11 -2
  152. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
  153. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js +1 -1
  154. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js.map +1 -1
  155. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts +1 -1
  156. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
  157. package/dist/schema/state/sqlite/db-schema/dsl/mod.js +1 -1
  158. package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
  159. package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
  160. package/dist/schema/state/sqlite/mod.js +3 -5
  161. package/dist/schema/state/sqlite/mod.js.map +1 -1
  162. package/dist/schema/state/sqlite/query-builder/api.d.ts +37 -13
  163. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  164. package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -1
  165. package/dist/schema/state/sqlite/query-builder/astToSql.js +77 -7
  166. package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
  167. package/dist/schema/state/sqlite/query-builder/impl.d.ts +1 -1
  168. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  169. package/dist/schema/state/sqlite/query-builder/impl.js +28 -14
  170. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  171. package/dist/schema/state/sqlite/query-builder/impl.test.js +112 -3
  172. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  173. package/dist/schema/state/sqlite/schema-helpers.js +2 -2
  174. package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
  175. package/dist/schema/state/sqlite/table-def.d.ts +5 -3
  176. package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
  177. package/dist/schema/state/sqlite/table-def.js +1 -1
  178. package/dist/schema/state/sqlite/table-def.js.map +1 -1
  179. package/dist/schema/state/sqlite/table-def.test.js +57 -4
  180. package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
  181. package/dist/schema/unknown-events.d.ts +1 -1
  182. package/dist/schema/unknown-events.d.ts.map +1 -1
  183. package/dist/schema/unknown-events.js +1 -1
  184. package/dist/schema/unknown-events.js.map +1 -1
  185. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +1 -1
  186. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -1
  187. package/dist/schema-management/common.js +2 -2
  188. package/dist/schema-management/common.js.map +1 -1
  189. package/dist/schema-management/migrations.js +1 -1
  190. package/dist/schema-management/migrations.js.map +1 -1
  191. package/dist/sql-queries/sql-queries.js +8 -6
  192. package/dist/sql-queries/sql-queries.js.map +1 -1
  193. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  194. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  195. package/dist/sqlite-db-helper.js +3 -3
  196. package/dist/sqlite-db-helper.js.map +1 -1
  197. package/dist/sqlite-types.d.ts +2 -2
  198. package/dist/sqlite-types.d.ts.map +1 -1
  199. package/dist/sqlite-types.js.map +1 -1
  200. package/dist/sync/ClientSessionSyncProcessor.d.ts +8 -9
  201. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  202. package/dist/sync/ClientSessionSyncProcessor.js +93 -107
  203. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  204. package/dist/sync/errors.d.ts +0 -38
  205. package/dist/sync/errors.d.ts.map +1 -1
  206. package/dist/sync/errors.js +3 -20
  207. package/dist/sync/errors.js.map +1 -1
  208. package/dist/sync/mock-sync-backend.d.ts +5 -3
  209. package/dist/sync/mock-sync-backend.d.ts.map +1 -1
  210. package/dist/sync/mock-sync-backend.js +70 -68
  211. package/dist/sync/mock-sync-backend.js.map +1 -1
  212. package/dist/sync/next/compact-events.js +6 -6
  213. package/dist/sync/next/compact-events.js.map +1 -1
  214. package/dist/sync/next/facts.d.ts.map +1 -1
  215. package/dist/sync/next/facts.js +6 -6
  216. package/dist/sync/next/facts.js.map +1 -1
  217. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  218. package/dist/sync/next/history-dag-common.js +6 -6
  219. package/dist/sync/next/history-dag-common.js.map +1 -1
  220. package/dist/sync/next/history-dag.js +3 -3
  221. package/dist/sync/next/history-dag.js.map +1 -1
  222. package/dist/sync/next/rebase-events.js +1 -1
  223. package/dist/sync/next/rebase-events.js.map +1 -1
  224. package/dist/sync/next/test/compact-events.calculator.test.js +2 -2
  225. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  226. package/dist/sync/next/test/compact-events.test.d.ts.map +1 -1
  227. package/dist/sync/next/test/compact-events.test.js +2 -2
  228. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  229. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
  230. package/dist/sync/next/test/event-fixtures.js +2 -2
  231. package/dist/sync/next/test/event-fixtures.js.map +1 -1
  232. package/dist/sync/sync-backend-kv.d.ts.map +1 -1
  233. package/dist/sync/sync-backend-kv.js.map +1 -1
  234. package/dist/sync/sync-backend.d.ts +3 -3
  235. package/dist/sync/sync-backend.d.ts.map +1 -1
  236. package/dist/sync/sync-backend.js +1 -1
  237. package/dist/sync/sync-backend.js.map +1 -1
  238. package/dist/sync/sync.d.ts +20 -0
  239. package/dist/sync/sync.d.ts.map +1 -1
  240. package/dist/sync/syncstate.d.ts +4 -17
  241. package/dist/sync/syncstate.d.ts.map +1 -1
  242. package/dist/sync/syncstate.js +51 -74
  243. package/dist/sync/syncstate.js.map +1 -1
  244. package/dist/sync/syncstate.test.js +112 -96
  245. package/dist/sync/syncstate.test.js.map +1 -1
  246. package/dist/sync/transport-chunking.js +3 -3
  247. package/dist/sync/transport-chunking.js.map +1 -1
  248. package/dist/sync/validate-push-payload.d.ts +2 -2
  249. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  250. package/dist/sync/validate-push-payload.js +4 -6
  251. package/dist/sync/validate-push-payload.js.map +1 -1
  252. package/dist/util.js +2 -2
  253. package/dist/util.js.map +1 -1
  254. package/dist/version.d.ts +7 -1
  255. package/dist/version.d.ts.map +1 -1
  256. package/dist/version.js +8 -4
  257. package/dist/version.js.map +1 -1
  258. package/package.json +66 -12
  259. package/src/ClientSessionLeaderThreadProxy.ts +16 -9
  260. package/src/WorkerTransportError.ts +12 -0
  261. package/src/adapter-types.ts +39 -3
  262. package/src/bounded-collections.ts +6 -5
  263. package/src/debug-info.ts +4 -4
  264. package/src/devtools/devtools-messages-client-session.ts +12 -0
  265. package/src/devtools/devtools-messages-common.ts +8 -4
  266. package/src/devtools/devtools-messages-leader.ts +12 -0
  267. package/src/devtools/mod.ts +1 -1
  268. package/src/errors.ts +18 -17
  269. package/src/index.ts +2 -0
  270. package/src/leader-thread/LeaderSyncProcessor.ts +417 -347
  271. package/src/leader-thread/RejectedPushError.ts +106 -0
  272. package/src/leader-thread/connection.ts +1 -1
  273. package/src/leader-thread/eventlog.ts +16 -14
  274. package/src/leader-thread/leader-worker-devtools.ts +107 -66
  275. package/src/leader-thread/make-leader-thread-layer.test.ts +1 -1
  276. package/src/leader-thread/make-leader-thread-layer.ts +41 -31
  277. package/src/leader-thread/materialize-event.ts +8 -4
  278. package/src/leader-thread/recreate-db.ts +1 -1
  279. package/src/leader-thread/shutdown-channel.ts +2 -6
  280. package/src/leader-thread/stream-events.ts +10 -5
  281. package/src/leader-thread/types.ts +7 -6
  282. package/src/logging.ts +4 -4
  283. package/src/make-client-session.ts +2 -2
  284. package/src/materializer-helper.ts +9 -9
  285. package/src/otel.ts +3 -2
  286. package/src/rematerialize-from-eventlog.ts +60 -60
  287. package/src/schema/EventDef/define.ts +22 -6
  288. package/src/schema/EventDef/deprecated.test.ts +129 -0
  289. package/src/schema/EventDef/deprecated.ts +175 -0
  290. package/src/schema/EventDef/event-def.ts +5 -0
  291. package/src/schema/EventDef/mod.ts +1 -0
  292. package/src/schema/EventSequenceNumber/client.ts +11 -11
  293. package/src/schema/EventSequenceNumber.test.ts +2 -1
  294. package/src/schema/LiveStoreEvent/client.test.ts +97 -0
  295. package/src/schema/LiveStoreEvent/client.ts +6 -3
  296. package/src/schema/schema.ts +9 -4
  297. package/src/schema/state/sqlite/client-document-def.test.ts +142 -3
  298. package/src/schema/state/sqlite/client-document-def.ts +37 -14
  299. package/src/schema/state/sqlite/column-annotations.test.ts +2 -1
  300. package/src/schema/state/sqlite/column-annotations.ts +2 -1
  301. package/src/schema/state/sqlite/column-def.test.ts +8 -6
  302. package/src/schema/state/sqlite/column-def.ts +41 -36
  303. package/src/schema/state/sqlite/column-spec.test.ts +3 -1
  304. package/src/schema/state/sqlite/column-spec.ts +9 -8
  305. package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +2 -2
  306. package/src/schema/state/sqlite/db-schema/dsl/field-defs.test.ts +2 -1
  307. package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +13 -4
  308. package/src/schema/state/sqlite/db-schema/dsl/mod.ts +3 -3
  309. package/src/schema/state/sqlite/mod.ts +4 -5
  310. package/src/schema/state/sqlite/query-builder/api.ts +37 -8
  311. package/src/schema/state/sqlite/query-builder/astToSql.ts +87 -7
  312. package/src/schema/state/sqlite/query-builder/impl.test.ts +145 -3
  313. package/src/schema/state/sqlite/query-builder/impl.ts +26 -12
  314. package/src/schema/state/sqlite/schema-helpers.ts +2 -2
  315. package/src/schema/state/sqlite/table-def.test.ts +67 -4
  316. package/src/schema/state/sqlite/table-def.ts +8 -15
  317. package/src/schema/unknown-events.ts +2 -2
  318. package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +3 -1
  319. package/src/schema-management/common.ts +2 -2
  320. package/src/schema-management/migrations.ts +1 -1
  321. package/src/sql-queries/sql-queries.ts +10 -6
  322. package/src/sql-queries/sql-query-builder.ts +1 -0
  323. package/src/sqlite-db-helper.ts +3 -3
  324. package/src/sqlite-types.ts +3 -2
  325. package/src/sync/ClientSessionSyncProcessor.ts +142 -133
  326. package/src/sync/errors.ts +10 -22
  327. package/src/sync/mock-sync-backend.ts +139 -97
  328. package/src/sync/next/compact-events.ts +5 -5
  329. package/src/sync/next/facts.ts +7 -6
  330. package/src/sync/next/history-dag-common.ts +9 -6
  331. package/src/sync/next/history-dag.ts +3 -3
  332. package/src/sync/next/rebase-events.ts +1 -1
  333. package/src/sync/next/test/compact-events.calculator.test.ts +3 -2
  334. package/src/sync/next/test/compact-events.test.ts +4 -3
  335. package/src/sync/next/test/event-fixtures.ts +2 -2
  336. package/src/sync/sync-backend-kv.ts +1 -0
  337. package/src/sync/sync-backend.ts +5 -4
  338. package/src/sync/sync.ts +21 -0
  339. package/src/sync/syncstate.test.ts +513 -435
  340. package/src/sync/syncstate.ts +80 -86
  341. package/src/sync/transport-chunking.ts +3 -3
  342. package/src/sync/validate-push-payload.ts +4 -6
  343. package/src/util.ts +2 -2
  344. package/src/version.ts +8 -4
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Push validation errors returned by {@link LeaderSyncProcessor.push}.
3
+ *
4
+ * All three errors share a common {@link RejectedPushErrorTypeId} so consumers can catch the
5
+ * family as a group via {@link isRejectedPushError} instead of matching individual tags.
6
+ * Recovery is the same in every case: the client should rebase and retry.
7
+ *
8
+ * @module
9
+ */
10
+ import { Predicate, Schema } from '@livestore/utils/effect'
11
+
12
+ import { EventSequenceNumber } from '../schema/mod.ts'
13
+
14
+ export const RejectedPushErrorTypeId = '~@livestore/common/RejectedPushError' as const
15
+
16
+ /**
17
+ * A pushed batch of events failed validation because its sequence numbers are not strictly increasing.
18
+ *
19
+ * @remarks
20
+ *
21
+ * This is a defensive check — callers are expected to construct monotonic event batches.
22
+ * The client should rebase and retry.
23
+ */
24
+ export class NonMonotonicBatchError extends Schema.TaggedError<NonMonotonicBatchError>(
25
+ `${RejectedPushErrorTypeId}/NonMonotonicBatchError`,
26
+ )(
27
+ 'NonMonotonicBatchError',
28
+ {
29
+ /** The sequence number that broke the monotonic invariant (i.e. the one that is >= the next). */
30
+ precedingSeqNum: EventSequenceNumber.Client.Composite,
31
+ /** The sequence number that was expected to be greater than `precedingSeqNum`. */
32
+ violatingSeqNum: EventSequenceNumber.Client.Composite,
33
+ /** The index in the batch where the violation occurred. */
34
+ violationIndex: Schema.Number,
35
+ /** The session that produced the malformed batch. */
36
+ sessionId: Schema.String,
37
+ },
38
+ ) {
39
+ readonly [RejectedPushErrorTypeId] = RejectedPushErrorTypeId
40
+
41
+ override get message(): string {
42
+ return `Pushed events' sequence numbers are not strictly increasing at index ${this.violationIndex} (session ${this.sessionId}): ${EventSequenceNumber.Client.toString(this.precedingSeqNum)} >= ${EventSequenceNumber.Client.toString(this.violatingSeqNum)}`
43
+ }
44
+ }
45
+
46
+ /**
47
+ * A pushed batch of events failed validation because its rebase generation is older than the leader's current rebase generation.
48
+ *
49
+ * @remarks
50
+ *
51
+ * This happens when events were enqueued before a backend-pull-triggered rebase incremented the generation.
52
+ */
53
+ export class StaleRebaseGenerationError extends Schema.TaggedError<StaleRebaseGenerationError>(
54
+ `${RejectedPushErrorTypeId}/StaleRebaseGenerationError`,
55
+ )(
56
+ 'StaleRebaseGenerationError',
57
+ {
58
+ /** The leader's current rebase generation. */
59
+ currentRebaseGeneration: Schema.Number,
60
+ /** The rebase generation carried by the dropped events. */
61
+ providedRebaseGeneration: Schema.Number,
62
+ /** The session that produced the stale batch. */
63
+ sessionId: Schema.String,
64
+ },
65
+ ) {
66
+ readonly [RejectedPushErrorTypeId] = RejectedPushErrorTypeId
67
+
68
+ override get message(): string {
69
+ return `Pushed events have stale rebase generation (session ${this.sessionId}): expected >= ${this.currentRebaseGeneration}, got ${this.providedRebaseGeneration}`
70
+ }
71
+ }
72
+
73
+ /**
74
+ * A pushed batch of events was rejected because the leader's push head has already advanced
75
+ * past the batch's first event.
76
+ *
77
+ * @remarks
78
+ *
79
+ * This occurs when another client session (or a backend pull) has pushed events that the current
80
+ * session hasn't seen yet.
81
+ */
82
+ export class LeaderAheadError extends Schema.TaggedError<LeaderAheadError>(
83
+ `${RejectedPushErrorTypeId}/LeaderAheadError`,
84
+ )('LeaderAheadError', {
85
+ minimumExpectedNum: EventSequenceNumber.Client.Composite,
86
+ providedNum: EventSequenceNumber.Client.Composite,
87
+ /** The session that produced the stale batch. */
88
+ sessionId: Schema.String,
89
+ }) {
90
+ readonly [RejectedPushErrorTypeId] = RejectedPushErrorTypeId
91
+
92
+ override get message(): string {
93
+ return `Leader push head is ahead of batch (session ${this.sessionId}): expected > ${EventSequenceNumber.Client.toString(this.minimumExpectedNum)}, got ${EventSequenceNumber.Client.toString(this.providedNum)}`
94
+ }
95
+ }
96
+
97
+ export const RejectedPushError = Schema.Union(
98
+ LeaderAheadError,
99
+ NonMonotonicBatchError,
100
+ StaleRebaseGenerationError,
101
+ )
102
+
103
+ export type RejectedPushError = typeof RejectedPushError.Type
104
+
105
+ export const isRejectedPushError = (u: unknown): u is RejectedPushError =>
106
+ Predicate.hasProperty(u, RejectedPushErrorTypeId)
@@ -62,7 +62,7 @@ export const configureConnection = (sqliteDb: SqliteDb, { foreignKeys, lockingMo
62
62
  -- disable WAL until we have it working properly
63
63
  -- PRAGMA journal_mode=WAL;
64
64
  PRAGMA page_size=8192;
65
- PRAGMA foreign_keys=${foreignKeys ? 'ON' : 'OFF'};
65
+ PRAGMA foreign_keys=${foreignKeys === true ? 'ON' : 'OFF'};
66
66
  ${lockingMode === undefined ? '' : sql`PRAGMA locking_mode=${lockingMode};`}
67
67
  `,
68
68
  {},
@@ -1,6 +1,8 @@
1
1
  import { LS_DEV, shouldNeverHappen } from '@livestore/utils'
2
2
  import { Chunk, Effect, Option, Schema } from '@livestore/utils/effect'
3
+
3
4
  import type { SqliteDb } from '../adapter-types.ts'
5
+ import { migrateTable } from '../schema-management/migrations.ts'
4
6
  import * as EventSequenceNumber from '../schema/EventSequenceNumber/mod.ts'
5
7
  import * as LiveStoreEvent from '../schema/LiveStoreEvent/mod.ts'
6
8
  import {
@@ -10,7 +12,6 @@ import {
10
12
  SYNC_STATUS_TABLE,
11
13
  } from '../schema/state/sqlite/system-tables/eventlog-tables.ts'
12
14
  import { sessionChangesetMetaTable } from '../schema/state/sqlite/system-tables/state-tables.ts'
13
- import { migrateTable } from '../schema-management/migrations.ts'
14
15
  import { insertRow, updateRows } from '../sql-queries/sql-queries.ts'
15
16
  import type { PreparedBindValues } from '../util.ts'
16
17
  import { sql } from '../util.ts'
@@ -58,13 +59,14 @@ export const getEventsSince = ({
58
59
  sessionChangesetMetaTable.where('seqNumGlobal', '>=', since.global),
59
60
  )
60
61
 
62
+ // Create a Map for O(1) lookup instead of O(n) find
63
+ const sessionChangesetMap = new Map(
64
+ sessionChangesetRowsDecoded.map((row) => [`${row.seqNumGlobal}:${row.seqNumClient}`, row]),
65
+ )
66
+
61
67
  return pendingEvents
62
68
  .map((eventlogEvent) => {
63
- const sessionChangeset = sessionChangesetRowsDecoded.find(
64
- (readModelEvent) =>
65
- readModelEvent.seqNumGlobal === eventlogEvent.seqNumGlobal &&
66
- readModelEvent.seqNumClient === eventlogEvent.seqNumClient,
67
- )
69
+ const sessionChangeset = sessionChangesetMap.get(`${eventlogEvent.seqNumGlobal}:${eventlogEvent.seqNumClient}`)
68
70
  return LiveStoreEvent.Client.EncodedWithMeta.make({
69
71
  name: eventlogEvent.name,
70
72
  args: eventlogEvent.argsJson,
@@ -82,7 +84,7 @@ export const getEventsSince = ({
82
84
  sessionId: eventlogEvent.sessionId,
83
85
  meta: {
84
86
  sessionChangeset:
85
- sessionChangeset && sessionChangeset.changeset !== null
87
+ sessionChangeset !== undefined && sessionChangeset.changeset !== null
86
88
  ? {
87
89
  _tag: 'sessionChangeset' as const,
88
90
  data: sessionChangeset.changeset,
@@ -96,7 +98,7 @@ export const getEventsSince = ({
96
98
  })
97
99
  })
98
100
  .filter((_) => EventSequenceNumber.Client.compare(_.seqNum, since) > 0)
99
- .sort((a, b) => EventSequenceNumber.Client.compare(a.seqNum, b.seqNum))
101
+ .toSorted((a, b) => EventSequenceNumber.Client.compare(a.seqNum, b.seqNum))
100
102
  }
101
103
 
102
104
  export const getEventsFromEventlog = ({
@@ -113,19 +115,19 @@ export const getEventsFromEventlog = ({
113
115
  const makeQuery = () => {
114
116
  let query = eventlogMetaTable.where('seqNumGlobal', '>', since.global)
115
117
 
116
- if (options.until) {
118
+ if (options.until !== undefined) {
117
119
  query = query.where('seqNumGlobal', '<=', options.until.global)
118
120
  }
119
121
 
120
- if (options.filter && options.filter.length > 0) {
122
+ if (options.filter !== undefined && options.filter.length > 0) {
121
123
  query = query.where({ name: { op: 'IN', value: options.filter } })
122
124
  }
123
125
 
124
- if (options.clientIds && options.clientIds.length > 0) {
126
+ if (options.clientIds !== undefined && options.clientIds.length > 0) {
125
127
  query = query.where({ clientId: { op: 'IN', value: options.clientIds } })
126
128
  }
127
129
 
128
- if (options.sessionIds && options.sessionIds.length > 0) {
130
+ if (options.sessionIds !== undefined && options.sessionIds.length > 0) {
129
131
  query = query.where({ sessionId: { op: 'IN', value: options.sessionIds } })
130
132
  }
131
133
 
@@ -185,7 +187,7 @@ export const getClientHeadFromDb = (dbEventlog: SqliteDb): EventSequenceNumber.C
185
187
  sql`select seqNumGlobal, seqNumClient, seqNumRebaseGeneration from ${EVENTLOG_META_TABLE} order by seqNumGlobal DESC, seqNumClient DESC limit 1`,
186
188
  )[0]
187
189
 
188
- return res
190
+ return res !== undefined
189
191
  ? { global: res.seqNumGlobal, client: res.seqNumClient, rebaseGeneration: res.seqNumRebaseGeneration }
190
192
  : EventSequenceNumber.Client.ROOT
191
193
  }
@@ -215,7 +217,7 @@ export const insertIntoEventlog = (
215
217
  ) =>
216
218
  Effect.gen(function* () {
217
219
  // Check history consistency during LS_DEV
218
- if (LS_DEV && eventEncoded.parentSeqNum.global !== EventSequenceNumber.Client.ROOT.global) {
220
+ if (LS_DEV === true && eventEncoded.parentSeqNum.global !== EventSequenceNumber.Client.ROOT.global) {
219
221
  const parentEventExists =
220
222
  dbEventlog.select<{ count: number }>(
221
223
  `SELECT COUNT(*) as count FROM ${EVENTLOG_META_TABLE} WHERE seqNumGlobal = ? AND seqNumClient = ?`,
@@ -8,63 +8,91 @@ import { LeaderThreadCtx } from './types.ts'
8
8
 
9
9
  type SendMessageToDevtools = (message: Devtools.Leader.MessageFromApp) => Effect.Effect<void>
10
10
 
11
- // TODO bind scope to the webchannel lifetime
12
- export const bootDevtools = (options: DevtoolsOptions) =>
13
- Effect.gen(function* () {
14
- if (options.enabled === false) {
15
- return
16
- }
17
-
18
- const { syncProcessor, extraIncomingMessagesQueue, clientId, storeId } = yield* LeaderThreadCtx
19
-
20
- yield* listenToDevtools({
21
- incomingMessages: Stream.fromQueue(extraIncomingMessagesQueue),
22
- sendMessage: () => Effect.void,
23
- }).pipe(Effect.tapCauseLogPretty, Effect.forkScoped)
11
+ /**
12
+ * Type guard for DevtoolsViteNotInstalledError.
13
+ * This error is defined in @livestore/adapter-node but we need to handle it here.
14
+ */
15
+ const isDevtoolsViteNotInstalledError = (
16
+ error: unknown,
17
+ ): error is { _tag: 'DevtoolsViteNotInstalledError'; message: string } =>
18
+ typeof error === 'object' && error !== null && '_tag' in error && error._tag === 'DevtoolsViteNotInstalledError'
24
19
 
25
- const { node, persistenceInfo, mode } = yield* options.boot
26
-
27
- yield* node.listenForChannel.pipe(
28
- Stream.filter(
29
- (res) =>
30
- Devtools.isChannelName.devtoolsClientLeader(res.channelName, { storeId, clientId }) && res.mode === mode,
31
- ),
32
- Stream.tap(({ channelName, source }) =>
33
- Effect.gen(function* () {
34
- const channel = yield* node.makeChannel({
35
- target: source,
36
- channelName,
37
- schema: { listen: Devtools.Leader.MessageToApp, send: Devtools.Leader.MessageFromApp },
38
- mode,
39
- })
40
-
41
- const sendMessage: SendMessageToDevtools = (message) =>
42
- channel
43
- .send(message)
44
- .pipe(
45
- Effect.withSpan('@livestore/common:leader-thread:devtools:sendToDevtools'),
46
- Effect.interruptible,
47
- Effect.ignoreLogged,
48
- )
49
-
50
- const syncState = yield* syncProcessor.syncState
51
-
52
- yield* syncProcessor.pull({ cursor: syncState.localHead }).pipe(
53
- Stream.tap(({ payload }) => sendMessage(Devtools.Leader.SyncPull.make({ payload, liveStoreVersion }))),
54
- Stream.runDrain,
55
- Effect.forkScoped,
56
- )
57
-
58
- yield* listenToDevtools({
59
- incomingMessages: channel.listen.pipe(Stream.flatten(), Stream.orDie),
60
- sendMessage,
61
- persistenceInfo,
62
- })
63
- }).pipe(Effect.tapCauseLogPretty, Effect.forkScoped),
20
+ // TODO bind scope to the webchannel lifetime
21
+ export const bootDevtools = Effect.fn('@livestore/common:leader-thread:devtools:boot')(function* (
22
+ options: DevtoolsOptions,
23
+ ) {
24
+ if (options.enabled === false) {
25
+ return
26
+ }
27
+
28
+ const { syncProcessor, extraIncomingMessagesQueue, clientId, storeId } = yield* LeaderThreadCtx
29
+
30
+ yield* listenToDevtools({
31
+ incomingMessages: Stream.fromQueue(extraIncomingMessagesQueue),
32
+ sendMessage: () => Effect.void,
33
+ }).pipe(Effect.tapCauseLogPretty, Effect.forkScoped)
34
+
35
+ const bootResult = yield* options.boot.pipe(
36
+ Effect.map(Option.some),
37
+ Effect.catchIf(isDevtoolsViteNotInstalledError, (error) =>
38
+ Effect.logWarning(`[@livestore/devtools] ${error.message} Devtools will be disabled.`).pipe(
39
+ Effect.as(Option.none()),
64
40
  ),
65
- Stream.runDrain,
66
- )
67
- }).pipe(Effect.withSpan('@livestore/common:leader-thread:devtools:boot'))
41
+ ),
42
+ Effect.catchAllCause((cause) =>
43
+ Effect.logWarning(
44
+ `[@livestore/devtools] Failed to start devtools server. Devtools will be disabled.`,
45
+ cause,
46
+ ).pipe(Effect.as(Option.none())),
47
+ ),
48
+ )
49
+
50
+ if (Option.isNone(bootResult) === true) {
51
+ return
52
+ }
53
+
54
+ const { node, persistenceInfo, mode } = bootResult.value
55
+
56
+ yield* node.listenForChannel.pipe(
57
+ Stream.filter(
58
+ (res) => Devtools.isChannelName.devtoolsClientLeader(res.channelName, { storeId, clientId }) && res.mode === mode,
59
+ ),
60
+ Stream.tap(({ channelName, source }) =>
61
+ Effect.gen(function* () {
62
+ const channel = yield* node.makeChannel({
63
+ target: source,
64
+ channelName,
65
+ schema: { listen: Devtools.Leader.MessageToApp, send: Devtools.Leader.MessageFromApp },
66
+ mode,
67
+ })
68
+
69
+ const sendMessage: SendMessageToDevtools = (message) =>
70
+ channel
71
+ .send(message)
72
+ .pipe(
73
+ Effect.withSpan('@livestore/common:leader-thread:devtools:sendToDevtools'),
74
+ Effect.interruptible,
75
+ Effect.ignoreLogged,
76
+ )
77
+
78
+ const syncState = yield* syncProcessor.syncState
79
+
80
+ yield* syncProcessor.pull({ cursor: syncState.localHead }).pipe(
81
+ Stream.tap(({ payload }) => sendMessage(Devtools.Leader.SyncPull.make({ payload, liveStoreVersion }))),
82
+ Stream.runDrain,
83
+ Effect.forkScoped,
84
+ )
85
+
86
+ yield* listenToDevtools({
87
+ incomingMessages: channel.listen.pipe(Stream.flatten(), Stream.orDie),
88
+ sendMessage,
89
+ persistenceInfo,
90
+ })
91
+ }).pipe(Effect.tapCauseLogPretty, Effect.forkScoped),
92
+ ),
93
+ Stream.runDrain,
94
+ )
95
+ })
68
96
 
69
97
  const listenToDevtools = ({
70
98
  incomingMessages,
@@ -103,7 +131,7 @@ const listenToDevtools = ({
103
131
  loadDatabaseBatchTracker.set(batchId, entry)
104
132
  const finished = entry.has('state') && entry.has('eventlog')
105
133
 
106
- if (finished) {
134
+ if (finished === true) {
107
135
  loadDatabaseBatchTracker.delete(batchId)
108
136
  }
109
137
 
@@ -129,7 +157,7 @@ const listenToDevtools = ({
129
157
  // So far I could only observe this problem with webmesh proxy channels (e.g. for Expo)
130
158
  // Proof: https://share.cleanshot.com/V9G87B0B
131
159
  // Also see `store/devtools.ts` for same problem
132
- if (handledRequestIds.has(requestId)) {
160
+ if (handledRequestIds.has(requestId) === true) {
133
161
  // yield* Effect.logWarning(`Duplicate message`, decodedEvent)
134
162
  return
135
163
  }
@@ -138,6 +166,17 @@ const listenToDevtools = ({
138
166
 
139
167
  switch (decodedEvent._tag) {
140
168
  case 'LSD.Leader.Ping': {
169
+ // Check version mismatch and respond with VersionMismatch if versions don't match
170
+ if (decodedEvent.liveStoreVersion !== liveStoreVersion) {
171
+ yield* sendMessage(
172
+ Devtools.Leader.VersionMismatch.make({
173
+ ...reqPayload,
174
+ appVersion: liveStoreVersion,
175
+ receivedVersion: decodedEvent.liveStoreVersion,
176
+ }),
177
+ )
178
+ return
179
+ }
141
180
  yield* sendMessage(Devtools.Leader.Pong.make({ ...reqPayload }))
142
181
  return
143
182
  }
@@ -166,24 +205,24 @@ const listenToDevtools = ({
166
205
 
167
206
  let databaseKind: LoadDatabaseKind | undefined
168
207
 
169
- if (tableNames.has(SystemTables.EVENTLOG_META_TABLE)) {
208
+ if (tableNames.has(SystemTables.EVENTLOG_META_TABLE) === true) {
170
209
  databaseKind = 'eventlog'
171
210
  yield* SubscriptionRef.set(shutdownStateSubRef, 'shutting-down')
172
- yield* Effect.try(() => void dbEventlog.import(data))
211
+ yield* Effect.try(() => dbEventlog.import(data))
173
212
 
174
213
  if (batchId === undefined) {
175
- yield* Effect.try(() => void dbState.destroy())
214
+ yield* Effect.try(() => dbState.destroy())
176
215
  }
177
216
  } else if (
178
- tableNames.has(SystemTables.SCHEMA_META_TABLE) &&
179
- tableNames.has(SystemTables.SCHEMA_EVENT_DEFS_META_TABLE)
217
+ tableNames.has(SystemTables.SCHEMA_META_TABLE) === true &&
218
+ tableNames.has(SystemTables.SCHEMA_EVENT_DEFS_META_TABLE) === true
180
219
  ) {
181
220
  databaseKind = 'state'
182
221
  yield* SubscriptionRef.set(shutdownStateSubRef, 'shutting-down')
183
- yield* Effect.try(() => void dbState.import(data))
222
+ yield* Effect.try(() => dbState.import(data))
184
223
 
185
224
  if (batchId === undefined) {
186
- yield* Effect.try(() => void dbEventlog.destroy())
225
+ yield* Effect.try(() => dbEventlog.destroy())
187
226
  }
188
227
  } else {
189
228
  return yield* Effect.fail({ _tag: 'unsupported-database' } as const)
@@ -199,7 +238,7 @@ const listenToDevtools = ({
199
238
 
200
239
  yield* sendMessage(Devtools.Leader.LoadDatabaseFile.Success.make({ ...reqPayload }))
201
240
 
202
- if (shouldShutdown) {
241
+ if (shouldShutdown === true) {
203
242
  yield* shutdownChannel.send(IntentionalShutdownCause.make({ reason: 'devtools-import' }))
204
243
  }
205
244
  })
@@ -341,7 +380,9 @@ const listenToDevtools = ({
341
380
 
342
381
  yield* Stream.zipLatest(
343
382
  syncBackend.isConnected.changes,
344
- devtools.enabled ? devtools.syncBackendLatchState.changes : Stream.make({ latchClosed: false }),
383
+ devtools.enabled === true
384
+ ? devtools.syncBackendLatchState.changes
385
+ : Stream.make({ latchClosed: false }),
345
386
  ).pipe(
346
387
  Stream.tap(([isConnected, { latchClosed }]) =>
347
388
  sendMessage(
@@ -1,5 +1,5 @@
1
- import { Effect, Stream, SubscriptionRef } from '@livestore/utils/effect'
2
1
  import { Vitest } from '@livestore/utils-dev/node-vitest'
2
+ import { Effect, Stream, SubscriptionRef } from '@livestore/utils/effect'
3
3
 
4
4
  import { makeMockSyncBackend } from '../sync/mock-sync-backend.ts'
5
5
  import type { SyncBackend } from '../sync/sync.ts'
@@ -12,19 +12,19 @@ import {
12
12
  Subscribable,
13
13
  SubscriptionRef,
14
14
  } from '@livestore/utils/effect'
15
+
15
16
  import {
16
17
  type BootStatus,
17
18
  type MakeSqliteDb,
18
19
  type MaterializerHashMismatchError,
19
20
  type SqliteDb,
20
- type SqliteError,
21
21
  UnknownError,
22
22
  } from '../adapter-types.ts'
23
23
  import type { MigrationsReport } from '../defs.ts'
24
24
  import type * as Devtools from '../devtools/mod.ts'
25
25
  import type { LiveStoreSchema } from '../schema/mod.ts'
26
26
  import { EventSequenceNumber, LiveStoreEvent, SystemTables } from '../schema/mod.ts'
27
- import type { InvalidPullError, IsOfflineError, SyncBackend, SyncOptions } from '../sync/sync.ts'
27
+ import type { SyncBackend, SyncOptions } from '../sync/sync.ts'
28
28
  import { SyncState } from '../sync/syncstate.ts'
29
29
  import { sql } from '../util.ts'
30
30
  import * as Eventlog from './eventlog.ts'
@@ -55,6 +55,8 @@ export interface MakeLeaderThreadLayerParams {
55
55
  dbEventlog: LeaderSqliteDb
56
56
  devtoolsOptions: DevtoolsOptions
57
57
  shutdownChannel: ShutdownChannel
58
+ /** Boot warning to emit (e.g., OPFS unavailable in private browsing) */
59
+ bootWarning?: BootStatus
58
60
  params?: {
59
61
  localPushBatchSize?: number
60
62
  backendPushBatchSize?: number
@@ -80,6 +82,7 @@ export const makeLeaderThreadLayer = ({
80
82
  dbEventlog,
81
83
  devtoolsOptions,
82
84
  shutdownChannel,
85
+ bootWarning,
83
86
  params,
84
87
  testing,
85
88
  }: MakeLeaderThreadLayerParams): Layer.Layer<LeaderThreadCtx, UnknownError, Scope.Scope | HttpClient.HttpClient> =>
@@ -89,6 +92,11 @@ export const makeLeaderThreadLayer = ({
89
92
 
90
93
  const bootStatusQueue = yield* Queue.unbounded<BootStatus>().pipe(Effect.acquireRelease(Queue.shutdown))
91
94
 
95
+ // Emit boot warning if present (e.g., OPFS unavailable in private browsing)
96
+ if (bootWarning !== undefined) {
97
+ yield* Queue.offer(bootStatusQueue, bootWarning)
98
+ }
99
+
92
100
  const dbEventlogMissing = !hasEventlogTables(dbEventlog)
93
101
 
94
102
  // Either happens on initial boot or if schema changes
@@ -148,9 +156,10 @@ export const makeLeaderThreadLayer = ({
148
156
 
149
157
  // Recreate state database if needed BEFORE creating sync processor
150
158
  // This ensures all system tables exist before any queries are made
151
- const { migrationsReport } = dbStateMissing
152
- ? yield* recreateDb({ dbState, dbEventlog, schema, bootStatusQueue, materializeEvent })
153
- : { migrationsReport: { migrations: [] } }
159
+ const { migrationsReport } =
160
+ dbStateMissing === true
161
+ ? yield* recreateDb({ dbState, dbEventlog, schema, bootStatusQueue, materializeEvent })
162
+ : { migrationsReport: { migrations: [] } }
154
163
 
155
164
  const syncProcessor = yield* makeLeaderSyncProcessor({
156
165
  schema,
@@ -158,6 +167,7 @@ export const makeLeaderThreadLayer = ({
158
167
  initialSyncState: getInitialSyncState({ dbEventlog, dbState, dbEventlogMissing }),
159
168
  initialBlockingSyncContext,
160
169
  onError: syncOptions?.onSyncError ?? 'ignore',
170
+ onBackendIdMismatch: syncOptions?.onBackendIdMismatch ?? 'reset',
161
171
  livePull: syncOptions?.livePull ?? true,
162
172
  params: {
163
173
  ...omitUndefineds({
@@ -174,13 +184,14 @@ export const makeLeaderThreadLayer = ({
174
184
  Effect.acquireRelease(Queue.shutdown),
175
185
  )
176
186
 
177
- const devtoolsContext = devtoolsOptions.enabled
178
- ? {
179
- enabled: true as const,
180
- syncBackendLatch: yield* Effect.makeLatch(true),
181
- syncBackendLatchState: yield* SubscriptionRef.make<{ latchClosed: boolean }>({ latchClosed: false }),
182
- }
183
- : { enabled: false as const }
187
+ const devtoolsContext =
188
+ devtoolsOptions.enabled === true
189
+ ? {
190
+ enabled: true as const,
191
+ syncBackendLatch: yield* Effect.makeLatch(true),
192
+ syncBackendLatchState: yield* SubscriptionRef.make<{ latchClosed: boolean }>({ latchClosed: false }),
193
+ }
194
+ : { enabled: false as const }
184
195
 
185
196
  const networkStatus = yield* makeNetworkStatusSubscribable({ syncBackend, devtoolsContext })
186
197
 
@@ -239,7 +250,7 @@ const hasStateTables = (db: SqliteDb) => {
239
250
 
240
251
  const isSubsetOf = (a: Set<string>, b: Set<string>): boolean => {
241
252
  for (const item of a) {
242
- if (!b.has(item)) {
253
+ if (b.has(item) === false) {
243
254
  return false
244
255
  }
245
256
  }
@@ -256,13 +267,11 @@ const getInitialSyncState = ({
256
267
  dbState: SqliteDb
257
268
  dbEventlogMissing: boolean
258
269
  }) => {
259
- const initialBackendHead = dbEventlogMissing
260
- ? EventSequenceNumber.Client.ROOT.global
261
- : Eventlog.getBackendHeadFromDb(dbEventlog)
270
+ const initialBackendHead =
271
+ dbEventlogMissing === true ? EventSequenceNumber.Client.ROOT.global : Eventlog.getBackendHeadFromDb(dbEventlog)
262
272
 
263
- const initialLocalHead = dbEventlogMissing
264
- ? EventSequenceNumber.Client.ROOT
265
- : Eventlog.getClientHeadFromDb(dbEventlog)
273
+ const initialLocalHead =
274
+ dbEventlogMissing === true ? EventSequenceNumber.Client.ROOT : Eventlog.getClientHeadFromDb(dbEventlog)
266
275
 
267
276
  if (initialBackendHead > initialLocalHead.global) {
268
277
  return shouldNeverHappen(
@@ -277,17 +286,18 @@ const getInitialSyncState = ({
277
286
  client: EventSequenceNumber.Client.DEFAULT,
278
287
  rebaseGeneration: EventSequenceNumber.Client.REBASE_GENERATION_DEFAULT,
279
288
  },
280
- pending: dbEventlogMissing
281
- ? []
282
- : Eventlog.getEventsSince({
283
- dbEventlog,
284
- dbState,
285
- since: {
286
- global: initialBackendHead,
287
- client: EventSequenceNumber.Client.DEFAULT,
288
- rebaseGeneration: initialLocalHead.rebaseGeneration,
289
- },
290
- }),
289
+ pending:
290
+ dbEventlogMissing === true
291
+ ? []
292
+ : Eventlog.getEventsSince({
293
+ dbEventlog,
294
+ dbState,
295
+ since: {
296
+ global: initialBackendHead,
297
+ client: EventSequenceNumber.Client.DEFAULT,
298
+ rebaseGeneration: initialLocalHead.rebaseGeneration,
299
+ },
300
+ }),
291
301
  })
292
302
  }
293
303
 
@@ -352,7 +362,7 @@ const bootLeaderThread = ({
352
362
  devtoolsOptions: DevtoolsOptions
353
363
  }): Effect.Effect<
354
364
  LeaderThreadCtx['Type']['initialState'],
355
- UnknownError | SqliteError | IsOfflineError | InvalidPullError | MaterializerHashMismatchError,
365
+ UnknownError | MaterializerHashMismatchError,
356
366
  LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient
357
367
  > =>
358
368
  Effect.gen(function* () {
@@ -3,6 +3,7 @@ import { Effect, Option, ReadonlyArray, Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import { MaterializeError, MaterializerHashMismatchError, type SqliteDb } from '../adapter-types.ts'
5
5
  import { getExecStatementsFromMaterializer, hashMaterializerResults } from '../materializer-helper.ts'
6
+ import { logDeprecationWarnings } from '../schema/EventDef/deprecated.ts'
6
7
  import type { LiveStoreSchema } from '../schema/mod.ts'
7
8
  import { EventSequenceNumber, resolveEventDef, SystemTables, UNKNOWN_EVENT_SCHEMA_HASH } from '../schema/mod.ts'
8
9
  import { insertRow } from '../sql-queries/index.ts'
@@ -62,6 +63,9 @@ export const makeMaterializeEvent = ({
62
63
 
63
64
  const { eventDef, materializer } = resolution
64
65
 
66
+ // Log deprecation warnings for deprecated events/fields
67
+ yield* logDeprecationWarnings(eventDef, eventEncoded.args as Record<string, unknown>)
68
+
65
69
  const execArgsArr = getExecStatementsFromMaterializer({
66
70
  eventDef,
67
71
  materializer,
@@ -69,7 +73,7 @@ export const makeMaterializeEvent = ({
69
73
  event: { decoded: undefined, encoded: eventEncoded },
70
74
  })
71
75
 
72
- const materializerHash = isDevEnv() ? Option.some(hashMaterializerResults(execArgsArr)) : Option.none()
76
+ const materializerHash = isDevEnv() === true ? Option.some(hashMaterializerResults(execArgsArr)) : Option.none()
73
77
 
74
78
  if (
75
79
  materializerHash._tag === 'Some' &&
@@ -115,7 +119,7 @@ export const makeMaterializeEvent = ({
115
119
  seqNumRebaseGeneration: eventEncoded.seqNum.rebaseGeneration,
116
120
  // NOTE the changeset will be empty (i.e. null) for no-op events
117
121
  changeset: changeset ?? null,
118
- debug: LS_DEV ? execArgsArr : null,
122
+ debug: LS_DEV === true ? execArgsArr : null,
119
123
  },
120
124
  }),
121
125
  )
@@ -140,11 +144,11 @@ export const makeMaterializeEvent = ({
140
144
  }
141
145
 
142
146
  return {
143
- sessionChangeset: changeset
147
+ sessionChangeset: changeset !== undefined
144
148
  ? {
145
149
  _tag: 'sessionChangeset' as const,
146
150
  data: changeset,
147
- debug: LS_DEV ? execArgsArr : null,
151
+ debug: LS_DEV === true ? execArgsArr : null,
148
152
  }
149
153
  : { _tag: 'no-op' as const },
150
154
  hash: materializerHash,
@@ -31,7 +31,7 @@ export const recreateDb = ({
31
31
  }): Effect.Effect<{ migrationsReport: MigrationsReport }, UnknownError | MaterializeError | SqliteError> =>
32
32
  Effect.gen(function* () {
33
33
  const migrationOptions = schema.state.sqlite.migrations
34
- let migrationsReport: MigrationsReport
34
+ let migrationsReport: MigrationsReport = { migrations: [] }
35
35
 
36
36
  yield* Effect.addFinalizer(
37
37
  Effect.fn('recreateDb:finalizer')(function* (ex) {