@livestore/common 0.4.0-dev.9 → 0.5.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (580) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ClientSessionLeaderThreadProxy.d.ts +27 -12
  3. package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
  4. package/dist/ClientSessionLeaderThreadProxy.js.map +1 -1
  5. package/dist/MaterializationJournal.d.ts +44 -0
  6. package/dist/MaterializationJournal.d.ts.map +1 -0
  7. package/dist/MaterializationJournal.js +112 -0
  8. package/dist/MaterializationJournal.js.map +1 -0
  9. package/dist/StateHead.d.ts +26 -0
  10. package/dist/StateHead.d.ts.map +1 -0
  11. package/dist/StateHead.js +50 -0
  12. package/dist/StateHead.js.map +1 -0
  13. package/dist/WorkerTransportError.d.ts +11 -0
  14. package/dist/WorkerTransportError.d.ts.map +1 -0
  15. package/dist/WorkerTransportError.js +11 -0
  16. package/dist/WorkerTransportError.js.map +1 -0
  17. package/dist/__tests__/fixture.d.ts +1 -1
  18. package/dist/__tests__/fixture.d.ts.map +1 -1
  19. package/dist/__tests__/fixture.js +3 -3
  20. package/dist/__tests__/fixture.js.map +1 -1
  21. package/dist/adapter-types.d.ts +59 -57
  22. package/dist/adapter-types.d.ts.map +1 -1
  23. package/dist/adapter-types.js +31 -22
  24. package/dist/adapter-types.js.map +1 -1
  25. package/dist/bounded-collections.d.ts.map +1 -1
  26. package/dist/bounded-collections.js +6 -4
  27. package/dist/bounded-collections.js.map +1 -1
  28. package/dist/debug-info.d.ts +56 -56
  29. package/dist/debug-info.d.ts.map +1 -1
  30. package/dist/debug-info.js +46 -32
  31. package/dist/debug-info.js.map +1 -1
  32. package/dist/defs.d.ts +9 -9
  33. package/dist/defs.js +2 -2
  34. package/dist/devtools/devtools-compatibility.test.d.ts +2 -0
  35. package/dist/devtools/devtools-compatibility.test.d.ts.map +1 -0
  36. package/dist/devtools/devtools-compatibility.test.js +16 -0
  37. package/dist/devtools/devtools-compatibility.test.js.map +1 -0
  38. package/dist/devtools/devtools-messages-client-session.d.ts +531 -312
  39. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
  40. package/dist/devtools/devtools-messages-client-session.js +86 -67
  41. package/dist/devtools/devtools-messages-client-session.js.map +1 -1
  42. package/dist/devtools/devtools-messages-common.d.ts +32 -35
  43. package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
  44. package/dist/devtools/devtools-messages-common.js +12 -14
  45. package/dist/devtools/devtools-messages-common.js.map +1 -1
  46. package/dist/devtools/devtools-messages-leader.d.ts +417 -320
  47. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  48. package/dist/devtools/devtools-messages-leader.js +117 -87
  49. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  50. package/dist/devtools/devtools-sessioninfo.d.ts +28 -17
  51. package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -1
  52. package/dist/devtools/devtools-sessioninfo.js +12 -6
  53. package/dist/devtools/devtools-sessioninfo.js.map +1 -1
  54. package/dist/devtools/mod.d.ts +17 -7
  55. package/dist/devtools/mod.d.ts.map +1 -1
  56. package/dist/devtools/mod.js +19 -8
  57. package/dist/devtools/mod.js.map +1 -1
  58. package/dist/errors.d.ts +52 -46
  59. package/dist/errors.d.ts.map +1 -1
  60. package/dist/errors.js +31 -21
  61. package/dist/errors.js.map +1 -1
  62. package/dist/index.d.ts +7 -1
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +7 -1
  65. package/dist/index.js.map +1 -1
  66. package/dist/leader-thread/LeaderSyncProcessor.d.ts +116 -21
  67. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  68. package/dist/leader-thread/LeaderSyncProcessor.js +596 -470
  69. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  70. package/dist/leader-thread/RejectedPushError.d.ts +138 -0
  71. package/dist/leader-thread/RejectedPushError.d.ts.map +1 -0
  72. package/dist/leader-thread/RejectedPushError.js +97 -0
  73. package/dist/leader-thread/RejectedPushError.js.map +1 -0
  74. package/dist/leader-thread/connection.d.ts +1 -0
  75. package/dist/leader-thread/connection.d.ts.map +1 -1
  76. package/dist/leader-thread/connection.js +10 -9
  77. package/dist/leader-thread/connection.js.map +1 -1
  78. package/dist/leader-thread/eventlog.d.ts +20 -15
  79. package/dist/leader-thread/eventlog.d.ts.map +1 -1
  80. package/dist/leader-thread/eventlog.js +80 -20
  81. package/dist/leader-thread/eventlog.js.map +1 -1
  82. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -2
  83. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  84. package/dist/leader-thread/leader-worker-devtools.js +110 -62
  85. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  86. package/dist/leader-thread/make-leader-thread-layer.d.ts +19 -7
  87. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  88. package/dist/leader-thread/make-leader-thread-layer.js +67 -45
  89. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  90. package/dist/leader-thread/make-leader-thread-layer.test.d.ts +2 -0
  91. package/dist/leader-thread/make-leader-thread-layer.test.d.ts.map +1 -0
  92. package/dist/leader-thread/make-leader-thread-layer.test.js +32 -0
  93. package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -0
  94. package/dist/leader-thread/materialize-event.d.ts +3 -2
  95. package/dist/leader-thread/materialize-event.d.ts.map +1 -1
  96. package/dist/leader-thread/materialize-event.js +32 -9
  97. package/dist/leader-thread/materialize-event.js.map +1 -1
  98. package/dist/leader-thread/mod.d.ts +1 -0
  99. package/dist/leader-thread/mod.d.ts.map +1 -1
  100. package/dist/leader-thread/mod.js +1 -0
  101. package/dist/leader-thread/mod.js.map +1 -1
  102. package/dist/leader-thread/recreate-db.d.ts +2 -2
  103. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  104. package/dist/leader-thread/recreate-db.js +19 -40
  105. package/dist/leader-thread/recreate-db.js.map +1 -1
  106. package/dist/leader-thread/shutdown-channel.d.ts +3 -7
  107. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  108. package/dist/leader-thread/shutdown-channel.js +2 -3
  109. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  110. package/dist/leader-thread/stream-events.d.ts +53 -0
  111. package/dist/leader-thread/stream-events.d.ts.map +1 -0
  112. package/dist/leader-thread/stream-events.js +164 -0
  113. package/dist/leader-thread/stream-events.js.map +1 -0
  114. package/dist/leader-thread/types.d.ts +92 -51
  115. package/dist/leader-thread/types.d.ts.map +1 -1
  116. package/dist/leader-thread/types.js +17 -4
  117. package/dist/leader-thread/types.js.map +1 -1
  118. package/dist/logging.d.ts +15 -0
  119. package/dist/logging.d.ts.map +1 -0
  120. package/dist/logging.js +2 -0
  121. package/dist/logging.js.map +1 -0
  122. package/dist/make-client-session.d.ts +6 -5
  123. package/dist/make-client-session.d.ts.map +1 -1
  124. package/dist/make-client-session.js +10 -7
  125. package/dist/make-client-session.js.map +1 -1
  126. package/dist/materializer-helper.d.ts +6 -7
  127. package/dist/materializer-helper.d.ts.map +1 -1
  128. package/dist/materializer-helper.js +22 -40
  129. package/dist/materializer-helper.js.map +1 -1
  130. package/dist/otel.d.ts +4 -4
  131. package/dist/otel.d.ts.map +1 -1
  132. package/dist/otel.js +8 -8
  133. package/dist/otel.js.map +1 -1
  134. package/dist/rematerialize-from-eventlog.d.ts +3 -3
  135. package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
  136. package/dist/rematerialize-from-eventlog.js +52 -39
  137. package/dist/rematerialize-from-eventlog.js.map +1 -1
  138. package/dist/schema/EventDef/define.d.ts +161 -0
  139. package/dist/schema/EventDef/define.d.ts.map +1 -0
  140. package/dist/schema/EventDef/define.js +140 -0
  141. package/dist/schema/EventDef/define.js.map +1 -0
  142. package/dist/schema/EventDef/define.test.d.ts +2 -0
  143. package/dist/schema/EventDef/define.test.d.ts.map +1 -0
  144. package/dist/schema/EventDef/define.test.js +23 -0
  145. package/dist/schema/EventDef/define.test.js.map +1 -0
  146. package/dist/schema/EventDef/deprecated.d.ts +94 -0
  147. package/dist/schema/EventDef/deprecated.d.ts.map +1 -0
  148. package/dist/schema/EventDef/deprecated.js +143 -0
  149. package/dist/schema/EventDef/deprecated.js.map +1 -0
  150. package/dist/schema/EventDef/deprecated.test.d.ts +2 -0
  151. package/dist/schema/EventDef/deprecated.test.d.ts.map +1 -0
  152. package/dist/schema/EventDef/deprecated.test.js +95 -0
  153. package/dist/schema/EventDef/deprecated.test.js.map +1 -0
  154. package/dist/schema/EventDef/event-def.d.ts +110 -0
  155. package/dist/schema/EventDef/event-def.d.ts.map +1 -0
  156. package/dist/schema/EventDef/event-def.js +2 -0
  157. package/dist/schema/EventDef/event-def.js.map +1 -0
  158. package/dist/schema/EventDef/facts.d.ts +118 -0
  159. package/dist/schema/EventDef/facts.d.ts.map +1 -0
  160. package/dist/schema/EventDef/facts.js +53 -0
  161. package/dist/schema/EventDef/facts.js.map +1 -0
  162. package/dist/schema/EventDef/materializer.d.ts +155 -0
  163. package/dist/schema/EventDef/materializer.d.ts.map +1 -0
  164. package/dist/schema/EventDef/materializer.js +83 -0
  165. package/dist/schema/EventDef/materializer.js.map +1 -0
  166. package/dist/schema/EventDef/mod.d.ts +6 -0
  167. package/dist/schema/EventDef/mod.d.ts.map +1 -0
  168. package/dist/schema/EventDef/mod.js +6 -0
  169. package/dist/schema/EventDef/mod.js.map +1 -0
  170. package/dist/schema/EventSequenceNumber/client.d.ts +136 -0
  171. package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -0
  172. package/dist/schema/EventSequenceNumber/client.js +192 -0
  173. package/dist/schema/EventSequenceNumber/client.js.map +1 -0
  174. package/dist/schema/EventSequenceNumber/global.d.ts +15 -0
  175. package/dist/schema/EventSequenceNumber/global.d.ts.map +1 -0
  176. package/dist/schema/EventSequenceNumber/global.js +14 -0
  177. package/dist/schema/EventSequenceNumber/global.js.map +1 -0
  178. package/dist/schema/EventSequenceNumber/mod.d.ts +37 -0
  179. package/dist/schema/EventSequenceNumber/mod.d.ts.map +1 -0
  180. package/dist/schema/EventSequenceNumber/mod.js +37 -0
  181. package/dist/schema/EventSequenceNumber/mod.js.map +1 -0
  182. package/dist/schema/EventSequenceNumber.test.js +44 -44
  183. package/dist/schema/EventSequenceNumber.test.js.map +1 -1
  184. package/dist/schema/LiveStoreEvent/client.d.ts +168 -0
  185. package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -0
  186. package/dist/schema/LiveStoreEvent/client.js +179 -0
  187. package/dist/schema/LiveStoreEvent/client.js.map +1 -0
  188. package/dist/schema/LiveStoreEvent/client.test.d.ts +2 -0
  189. package/dist/schema/LiveStoreEvent/client.test.d.ts.map +1 -0
  190. package/dist/schema/LiveStoreEvent/client.test.js +120 -0
  191. package/dist/schema/LiveStoreEvent/client.test.js.map +1 -0
  192. package/dist/schema/LiveStoreEvent/for-event-def.d.ts +52 -0
  193. package/dist/schema/LiveStoreEvent/for-event-def.d.ts.map +1 -0
  194. package/dist/schema/LiveStoreEvent/for-event-def.js +2 -0
  195. package/dist/schema/LiveStoreEvent/for-event-def.js.map +1 -0
  196. package/dist/schema/LiveStoreEvent/global.d.ts +36 -0
  197. package/dist/schema/LiveStoreEvent/global.d.ts.map +1 -0
  198. package/dist/schema/LiveStoreEvent/global.js +31 -0
  199. package/dist/schema/LiveStoreEvent/global.js.map +1 -0
  200. package/dist/schema/LiveStoreEvent/input.d.ts +46 -0
  201. package/dist/schema/LiveStoreEvent/input.d.ts.map +1 -0
  202. package/dist/schema/LiveStoreEvent/input.js +26 -0
  203. package/dist/schema/LiveStoreEvent/input.js.map +1 -0
  204. package/dist/schema/LiveStoreEvent/mod.d.ts +5 -0
  205. package/dist/schema/LiveStoreEvent/mod.d.ts.map +1 -0
  206. package/dist/schema/LiveStoreEvent/mod.js +5 -0
  207. package/dist/schema/LiveStoreEvent/mod.js.map +1 -0
  208. package/dist/schema/events.d.ts +1 -1
  209. package/dist/schema/events.d.ts.map +1 -1
  210. package/dist/schema/events.js +1 -1
  211. package/dist/schema/events.js.map +1 -1
  212. package/dist/schema/mod.d.ts +7 -4
  213. package/dist/schema/mod.d.ts.map +1 -1
  214. package/dist/schema/mod.js +6 -4
  215. package/dist/schema/mod.js.map +1 -1
  216. package/dist/schema/schema.d.ts +16 -1
  217. package/dist/schema/schema.d.ts.map +1 -1
  218. package/dist/schema/schema.js +34 -5
  219. package/dist/schema/schema.js.map +1 -1
  220. package/dist/schema/state/sqlite/client-document-def.d.ts +14 -18
  221. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
  222. package/dist/schema/state/sqlite/client-document-def.js +54 -30
  223. package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
  224. package/dist/schema/state/sqlite/client-document-def.test.js +146 -6
  225. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  226. package/dist/schema/state/sqlite/column-annotations.d.ts +13 -13
  227. package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
  228. package/dist/schema/state/sqlite/column-annotations.js +13 -15
  229. package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
  230. package/dist/schema/state/sqlite/column-annotations.test.js +19 -43
  231. package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
  232. package/dist/schema/state/sqlite/column-def.d.ts +1 -1
  233. package/dist/schema/state/sqlite/column-def.d.ts.map +1 -1
  234. package/dist/schema/state/sqlite/column-def.js +132 -57
  235. package/dist/schema/state/sqlite/column-def.js.map +1 -1
  236. package/dist/schema/state/sqlite/column-def.test.js +155 -70
  237. package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
  238. package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
  239. package/dist/schema/state/sqlite/column-spec.js +30 -12
  240. package/dist/schema/state/sqlite/column-spec.js.map +1 -1
  241. package/dist/schema/state/sqlite/column-spec.test.js +26 -17
  242. package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
  243. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +2 -2
  244. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -1
  245. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +15 -6
  246. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
  247. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +25 -19
  248. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
  249. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +22 -16
  250. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
  251. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js +28 -17
  252. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js.map +1 -1
  253. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts +14 -12
  254. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
  255. package/dist/schema/state/sqlite/db-schema/dsl/mod.js +6 -4
  256. package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
  257. package/dist/schema/state/sqlite/mod.d.ts +3 -5
  258. package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
  259. package/dist/schema/state/sqlite/mod.js +6 -8
  260. package/dist/schema/state/sqlite/mod.js.map +1 -1
  261. package/dist/schema/state/sqlite/persistence.d.ts +11 -0
  262. package/dist/schema/state/sqlite/persistence.d.ts.map +1 -0
  263. package/dist/schema/state/sqlite/persistence.js +10 -0
  264. package/dist/schema/state/sqlite/persistence.js.map +1 -0
  265. package/dist/schema/state/sqlite/query-builder/api.d.ts +58 -29
  266. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  267. package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -1
  268. package/dist/schema/state/sqlite/query-builder/astToSql.js +105 -24
  269. package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
  270. package/dist/schema/state/sqlite/query-builder/impl.d.ts +4 -2
  271. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  272. package/dist/schema/state/sqlite/query-builder/impl.js +42 -27
  273. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  274. package/dist/schema/state/sqlite/query-builder/impl.test.js +402 -498
  275. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  276. package/dist/schema/state/sqlite/schema-helpers.d.ts +2 -2
  277. package/dist/schema/state/sqlite/schema-helpers.d.ts.map +1 -1
  278. package/dist/schema/state/sqlite/schema-helpers.js +24 -14
  279. package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
  280. package/dist/schema/state/sqlite/schema-helpers.test.d.ts +2 -0
  281. package/dist/schema/state/sqlite/schema-helpers.test.d.ts.map +1 -0
  282. package/dist/schema/state/sqlite/schema-helpers.test.js +36 -0
  283. package/dist/schema/state/sqlite/schema-helpers.test.js.map +1 -0
  284. package/dist/schema/state/sqlite/system-tables/eventlog-tables.d.ts +515 -0
  285. package/dist/schema/state/sqlite/system-tables/eventlog-tables.d.ts.map +1 -0
  286. package/dist/schema/state/sqlite/system-tables/eventlog-tables.js +54 -0
  287. package/dist/schema/state/sqlite/system-tables/eventlog-tables.js.map +1 -0
  288. package/dist/schema/state/sqlite/system-tables/mod.d.ts +3 -0
  289. package/dist/schema/state/sqlite/system-tables/mod.d.ts.map +1 -0
  290. package/dist/schema/state/sqlite/system-tables/mod.js +3 -0
  291. package/dist/schema/state/sqlite/system-tables/mod.js.map +1 -0
  292. package/dist/schema/state/sqlite/system-tables/state-tables.d.ts +678 -0
  293. package/dist/schema/state/sqlite/system-tables/state-tables.d.ts.map +1 -0
  294. package/dist/schema/state/sqlite/system-tables/state-tables.js +87 -0
  295. package/dist/schema/state/sqlite/system-tables/state-tables.js.map +1 -0
  296. package/dist/schema/state/sqlite/table-def.d.ts +19 -20
  297. package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
  298. package/dist/schema/state/sqlite/table-def.js +54 -4
  299. package/dist/schema/state/sqlite/table-def.js.map +1 -1
  300. package/dist/schema/state/sqlite/table-def.test.js +226 -20
  301. package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
  302. package/dist/schema/unknown-events.d.ts +47 -0
  303. package/dist/schema/unknown-events.d.ts.map +1 -0
  304. package/dist/schema/unknown-events.js +70 -0
  305. package/dist/schema/unknown-events.js.map +1 -0
  306. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.d.ts +2 -0
  307. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.d.ts.map +1 -0
  308. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +73 -0
  309. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -0
  310. package/dist/schema-management/common.js +2 -2
  311. package/dist/schema-management/common.js.map +1 -1
  312. package/dist/schema-management/migrations.d.ts +32 -2
  313. package/dist/schema-management/migrations.d.ts.map +1 -1
  314. package/dist/schema-management/migrations.js +38 -6
  315. package/dist/schema-management/migrations.js.map +1 -1
  316. package/dist/schema-management/validate-schema.d.ts +3 -3
  317. package/dist/schema-management/validate-schema.d.ts.map +1 -1
  318. package/dist/schema-management/validate-schema.js +2 -2
  319. package/dist/schema-management/validate-schema.js.map +1 -1
  320. package/dist/session-id-symbol.d.ts +29 -0
  321. package/dist/session-id-symbol.d.ts.map +1 -0
  322. package/dist/session-id-symbol.js +44 -0
  323. package/dist/session-id-symbol.js.map +1 -0
  324. package/dist/sql-queries/sql-queries.d.ts.map +1 -1
  325. package/dist/sql-queries/sql-queries.js +26 -16
  326. package/dist/sql-queries/sql-queries.js.map +1 -1
  327. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  328. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  329. package/dist/sql-queries/types.d.ts +6 -7
  330. package/dist/sql-queries/types.d.ts.map +1 -1
  331. package/dist/sql-queries/types.js.map +1 -1
  332. package/dist/sqlite-db-helper.d.ts +21 -1
  333. package/dist/sqlite-db-helper.d.ts.map +1 -1
  334. package/dist/sqlite-db-helper.js +40 -5
  335. package/dist/sqlite-db-helper.js.map +1 -1
  336. package/dist/sqlite-types.d.ts +8 -11
  337. package/dist/sqlite-types.d.ts.map +1 -1
  338. package/dist/sqlite-types.js +3 -3
  339. package/dist/sqlite-types.js.map +1 -1
  340. package/dist/sync/ClientSessionSyncProcessor.d.ts +47 -25
  341. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  342. package/dist/sync/ClientSessionSyncProcessor.js +269 -154
  343. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  344. package/dist/sync/errors.d.ts +12 -51
  345. package/dist/sync/errors.d.ts.map +1 -1
  346. package/dist/sync/errors.js +7 -24
  347. package/dist/sync/errors.js.map +1 -1
  348. package/dist/sync/index.d.ts +2 -0
  349. package/dist/sync/index.d.ts.map +1 -1
  350. package/dist/sync/index.js +2 -0
  351. package/dist/sync/index.js.map +1 -1
  352. package/dist/sync/mock-sync-backend.d.ts +11 -10
  353. package/dist/sync/mock-sync-backend.d.ts.map +1 -1
  354. package/dist/sync/mock-sync-backend.js +97 -74
  355. package/dist/sync/mock-sync-backend.js.map +1 -1
  356. package/dist/sync/mock-sync-backend.test.d.ts +2 -0
  357. package/dist/sync/mock-sync-backend.test.d.ts.map +1 -0
  358. package/dist/sync/mock-sync-backend.test.js +49 -0
  359. package/dist/sync/mock-sync-backend.test.js.map +1 -0
  360. package/dist/sync/next/compact-events.d.ts.map +1 -1
  361. package/dist/sync/next/compact-events.js +11 -12
  362. package/dist/sync/next/compact-events.js.map +1 -1
  363. package/dist/sync/next/facts.d.ts +5 -5
  364. package/dist/sync/next/facts.d.ts.map +1 -1
  365. package/dist/sync/next/facts.js +7 -8
  366. package/dist/sync/next/facts.js.map +1 -1
  367. package/dist/sync/next/history-dag-common.d.ts +58 -15
  368. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  369. package/dist/sync/next/history-dag-common.js +219 -9
  370. package/dist/sync/next/history-dag-common.js.map +1 -1
  371. package/dist/sync/next/history-dag.d.ts.map +1 -1
  372. package/dist/sync/next/history-dag.js +12 -11
  373. package/dist/sync/next/history-dag.js.map +1 -1
  374. package/dist/sync/next/rebase-events.d.ts +5 -5
  375. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  376. package/dist/sync/next/rebase-events.js +6 -6
  377. package/dist/sync/next/rebase-events.js.map +1 -1
  378. package/dist/sync/next/test/compact-events.calculator.test.js +4 -4
  379. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  380. package/dist/sync/next/test/compact-events.test.d.ts.map +1 -1
  381. package/dist/sync/next/test/compact-events.test.js +2 -2
  382. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  383. package/dist/sync/next/test/event-fixtures.d.ts +9 -9
  384. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
  385. package/dist/sync/next/test/event-fixtures.js +12 -12
  386. package/dist/sync/next/test/event-fixtures.js.map +1 -1
  387. package/dist/sync/next/test/history-dag-common.test.d.ts +2 -0
  388. package/dist/sync/next/test/history-dag-common.test.d.ts.map +1 -0
  389. package/dist/sync/next/test/history-dag-common.test.js +73 -0
  390. package/dist/sync/next/test/history-dag-common.test.js.map +1 -0
  391. package/dist/sync/sync-backend-kv.d.ts +3 -3
  392. package/dist/sync/sync-backend-kv.d.ts.map +1 -1
  393. package/dist/sync/sync-backend-kv.js +6 -4
  394. package/dist/sync/sync-backend-kv.js.map +1 -1
  395. package/dist/sync/sync-backend.d.ts +41 -21
  396. package/dist/sync/sync-backend.d.ts.map +1 -1
  397. package/dist/sync/sync-backend.js +45 -4
  398. package/dist/sync/sync-backend.js.map +1 -1
  399. package/dist/sync/sync.d.ts +23 -2
  400. package/dist/sync/sync.d.ts.map +1 -1
  401. package/dist/sync/syncstate.d.ts +115 -191
  402. package/dist/sync/syncstate.d.ts.map +1 -1
  403. package/dist/sync/syncstate.js +108 -129
  404. package/dist/sync/syncstate.js.map +1 -1
  405. package/dist/sync/syncstate.test.js +289 -161
  406. package/dist/sync/syncstate.test.js.map +1 -1
  407. package/dist/sync/transport-chunking.d.ts +35 -0
  408. package/dist/sync/transport-chunking.d.ts.map +1 -0
  409. package/dist/sync/transport-chunking.js +47 -0
  410. package/dist/sync/transport-chunking.js.map +1 -0
  411. package/dist/sync/validate-push-payload.d.ts +2 -2
  412. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  413. package/dist/sync/validate-push-payload.js +4 -6
  414. package/dist/sync/validate-push-payload.js.map +1 -1
  415. package/dist/testing/event-factory.d.ts +3 -3
  416. package/dist/testing/event-factory.d.ts.map +1 -1
  417. package/dist/testing/event-factory.js +5 -7
  418. package/dist/testing/event-factory.js.map +1 -1
  419. package/dist/util.d.ts +11 -4
  420. package/dist/util.d.ts.map +1 -1
  421. package/dist/util.js +21 -4
  422. package/dist/util.js.map +1 -1
  423. package/dist/version.d.ts +24 -5
  424. package/dist/version.d.ts.map +1 -1
  425. package/dist/version.js +25 -8
  426. package/dist/version.js.map +1 -1
  427. package/package.json +50 -16
  428. package/src/ClientSessionLeaderThreadProxy.ts +27 -12
  429. package/src/MaterializationJournal.ts +184 -0
  430. package/src/StateHead.ts +80 -0
  431. package/src/WorkerTransportError.ts +12 -0
  432. package/src/__tests__/fixture.ts +3 -3
  433. package/src/adapter-types.ts +62 -56
  434. package/src/bounded-collections.ts +6 -5
  435. package/src/debug-info.ts +54 -43
  436. package/src/defs.ts +2 -2
  437. package/src/devtools/devtools-compatibility.test.ts +19 -0
  438. package/src/devtools/devtools-messages-client-session.ts +72 -63
  439. package/src/devtools/devtools-messages-common.ts +18 -22
  440. package/src/devtools/devtools-messages-leader.ts +89 -68
  441. package/src/devtools/devtools-sessioninfo.ts +17 -12
  442. package/src/devtools/mod.ts +15 -7
  443. package/src/errors.ts +58 -38
  444. package/src/index.ts +11 -1
  445. package/src/leader-thread/LeaderSyncProcessor.ts +927 -674
  446. package/src/leader-thread/RejectedPushError.ts +119 -0
  447. package/src/leader-thread/connection.ts +13 -9
  448. package/src/leader-thread/eventlog.ts +114 -41
  449. package/src/leader-thread/leader-worker-devtools.ts +223 -124
  450. package/src/leader-thread/make-leader-thread-layer.test.ts +44 -0
  451. package/src/leader-thread/make-leader-thread-layer.ts +170 -82
  452. package/src/leader-thread/materialize-event.ts +51 -16
  453. package/src/leader-thread/mod.ts +1 -0
  454. package/src/leader-thread/recreate-db.ts +26 -61
  455. package/src/leader-thread/shutdown-channel.ts +3 -18
  456. package/src/leader-thread/stream-events.ts +209 -0
  457. package/src/leader-thread/types.ts +77 -65
  458. package/src/logging.ts +15 -0
  459. package/src/make-client-session.ts +16 -10
  460. package/src/materializer-helper.ts +31 -49
  461. package/src/otel.ts +15 -13
  462. package/src/rematerialize-from-eventlog.ts +106 -93
  463. package/src/schema/EventDef/define.test.ts +28 -0
  464. package/src/schema/EventDef/define.ts +218 -0
  465. package/src/schema/EventDef/deprecated.test.ts +122 -0
  466. package/src/schema/EventDef/deprecated.ts +172 -0
  467. package/src/schema/EventDef/event-def.ts +123 -0
  468. package/src/schema/EventDef/facts.ts +135 -0
  469. package/src/schema/EventDef/materializer.ts +172 -0
  470. package/src/schema/EventDef/mod.ts +5 -0
  471. package/src/schema/EventSequenceNumber/client.ts +256 -0
  472. package/src/schema/EventSequenceNumber/global.ts +19 -0
  473. package/src/schema/EventSequenceNumber/mod.ts +37 -0
  474. package/src/schema/EventSequenceNumber.test.ts +72 -53
  475. package/src/schema/LiveStoreEvent/client.test.ts +142 -0
  476. package/src/schema/LiveStoreEvent/client.ts +236 -0
  477. package/src/schema/LiveStoreEvent/for-event-def.ts +60 -0
  478. package/src/schema/LiveStoreEvent/global.ts +45 -0
  479. package/src/schema/LiveStoreEvent/input.ts +63 -0
  480. package/src/schema/LiveStoreEvent/mod.ts +4 -0
  481. package/src/schema/events.ts +1 -1
  482. package/src/schema/mod.ts +7 -4
  483. package/src/schema/schema.ts +48 -6
  484. package/src/schema/state/sqlite/client-document-def.test.ts +172 -14
  485. package/src/schema/state/sqlite/client-document-def.ts +126 -98
  486. package/src/schema/state/sqlite/column-annotations.test.ts +27 -45
  487. package/src/schema/state/sqlite/column-annotations.ts +27 -30
  488. package/src/schema/state/sqlite/column-def.test.ts +186 -77
  489. package/src/schema/state/sqlite/column-def.ts +169 -62
  490. package/src/schema/state/sqlite/column-spec.test.ts +34 -19
  491. package/src/schema/state/sqlite/column-spec.ts +38 -11
  492. package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +17 -7
  493. package/src/schema/state/sqlite/db-schema/dsl/__snapshots__/field-defs.test.ts.snap +123 -63
  494. package/src/schema/state/sqlite/db-schema/dsl/field-defs.test.ts +37 -17
  495. package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +65 -45
  496. package/src/schema/state/sqlite/db-schema/dsl/mod.ts +48 -40
  497. package/src/schema/state/sqlite/mod.ts +9 -12
  498. package/src/schema/state/sqlite/persistence.ts +11 -0
  499. package/src/schema/state/sqlite/query-builder/api.ts +61 -23
  500. package/src/schema/state/sqlite/query-builder/astToSql.ts +117 -23
  501. package/src/schema/state/sqlite/query-builder/impl.test.ts +489 -551
  502. package/src/schema/state/sqlite/query-builder/impl.ts +43 -26
  503. package/src/schema/state/sqlite/schema-helpers.test.ts +44 -0
  504. package/src/schema/state/sqlite/schema-helpers.ts +30 -22
  505. package/src/schema/state/sqlite/system-tables/eventlog-tables.ts +64 -0
  506. package/src/schema/state/sqlite/system-tables/mod.ts +2 -0
  507. package/src/schema/state/sqlite/system-tables/state-tables.ts +109 -0
  508. package/src/schema/state/sqlite/table-def.test.ts +295 -46
  509. package/src/schema/state/sqlite/table-def.ts +109 -64
  510. package/src/schema/unknown-events.ts +132 -0
  511. package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +88 -0
  512. package/src/schema-management/common.ts +2 -2
  513. package/src/schema-management/migrations.ts +42 -9
  514. package/src/schema-management/validate-schema.ts +3 -3
  515. package/src/session-id-symbol.ts +59 -0
  516. package/src/sql-queries/sql-queries.ts +26 -18
  517. package/src/sql-queries/sql-query-builder.ts +1 -0
  518. package/src/sql-queries/types.ts +6 -7
  519. package/src/sqlite-db-helper.ts +67 -5
  520. package/src/sqlite-types.ts +9 -11
  521. package/src/sync/ClientSessionSyncProcessor.ts +388 -194
  522. package/src/sync/errors.ts +18 -28
  523. package/src/sync/index.ts +2 -0
  524. package/src/sync/mock-sync-backend.test.ts +78 -0
  525. package/src/sync/mock-sync-backend.ts +196 -108
  526. package/src/sync/next/compact-events.ts +10 -11
  527. package/src/sync/next/facts.ts +13 -14
  528. package/src/sync/next/history-dag-common.ts +306 -26
  529. package/src/sync/next/history-dag.ts +20 -13
  530. package/src/sync/next/rebase-events.ts +12 -12
  531. package/src/sync/next/test/compact-events.calculator.test.ts +5 -4
  532. package/src/sync/next/test/compact-events.test.ts +4 -3
  533. package/src/sync/next/test/event-fixtures.ts +14 -14
  534. package/src/sync/next/test/history-dag-common.test.ts +87 -0
  535. package/src/sync/sync-backend-kv.ts +7 -4
  536. package/src/sync/sync-backend.ts +75 -26
  537. package/src/sync/sync.ts +24 -2
  538. package/src/sync/syncstate.test.ts +657 -442
  539. package/src/sync/syncstate.ts +175 -160
  540. package/src/sync/transport-chunking.ts +85 -0
  541. package/src/sync/validate-push-payload.ts +6 -8
  542. package/src/testing/event-factory.ts +10 -12
  543. package/src/util.ts +20 -11
  544. package/src/version.ts +32 -8
  545. package/dist/schema/EventDef.d.ts +0 -126
  546. package/dist/schema/EventDef.d.ts.map +0 -1
  547. package/dist/schema/EventDef.js +0 -46
  548. package/dist/schema/EventDef.js.map +0 -1
  549. package/dist/schema/EventSequenceNumber.d.ts +0 -80
  550. package/dist/schema/EventSequenceNumber.d.ts.map +0 -1
  551. package/dist/schema/EventSequenceNumber.js +0 -139
  552. package/dist/schema/EventSequenceNumber.js.map +0 -1
  553. package/dist/schema/LiveStoreEvent.d.ts +0 -306
  554. package/dist/schema/LiveStoreEvent.d.ts.map +0 -1
  555. package/dist/schema/LiveStoreEvent.js +0 -147
  556. package/dist/schema/LiveStoreEvent.js.map +0 -1
  557. package/dist/schema/state/sqlite/system-tables.d.ts +0 -976
  558. package/dist/schema/state/sqlite/system-tables.d.ts.map +0 -1
  559. package/dist/schema/state/sqlite/system-tables.js +0 -81
  560. package/dist/schema/state/sqlite/system-tables.js.map +0 -1
  561. package/dist/sql-queries/misc.d.ts +0 -2
  562. package/dist/sql-queries/misc.d.ts.map +0 -1
  563. package/dist/sql-queries/misc.js +0 -2
  564. package/dist/sql-queries/misc.js.map +0 -1
  565. package/dist/sync/next/graphology.d.ts +0 -8
  566. package/dist/sync/next/graphology.d.ts.map +0 -1
  567. package/dist/sync/next/graphology.js +0 -30
  568. package/dist/sync/next/graphology.js.map +0 -1
  569. package/dist/sync/next/graphology_.d.ts +0 -3
  570. package/dist/sync/next/graphology_.d.ts.map +0 -1
  571. package/dist/sync/next/graphology_.js +0 -3
  572. package/dist/sync/next/graphology_.js.map +0 -1
  573. package/src/schema/EventDef.ts +0 -222
  574. package/src/schema/EventSequenceNumber.ts +0 -199
  575. package/src/schema/LiveStoreEvent.ts +0 -286
  576. package/src/schema/state/sqlite/system-tables.ts +0 -106
  577. package/src/sql-queries/misc.ts +0 -2
  578. package/src/sync/next/ambient.d.ts +0 -3
  579. package/src/sync/next/graphology.ts +0 -41
  580. package/src/sync/next/graphology_.ts +0 -2
@@ -1,461 +1,676 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { assert, expect } from 'vitest'
2
2
 
3
- import * as EventSequenceNumber from '../schema/EventSequenceNumber.ts'
4
- import * as LiveStoreEvent from '../schema/LiveStoreEvent.ts'
5
- import * as SyncState from './syncstate.ts'
6
-
7
- class TestEvent extends LiveStoreEvent.EncodedWithMeta {
8
- public readonly payload: string
9
- public readonly isClient: boolean
10
- constructor(
11
- seqNum: EventSequenceNumber.EventSequenceNumberInput,
12
- parentSeqNum: EventSequenceNumber.EventSequenceNumberInput,
13
- payload: string,
14
- isClient: boolean,
15
- ) {
16
- super({
17
- seqNum: EventSequenceNumber.make(seqNum),
18
- parentSeqNum: EventSequenceNumber.make(parentSeqNum),
19
- name: 'a',
20
- args: payload,
21
- clientId: 'static-local-id',
22
- sessionId: 'static-session-id',
23
- })
24
- this.payload = payload
25
- this.isClient = isClient
26
- }
27
-
28
- rebase_ = (parentSeqNum: EventSequenceNumber.EventSequenceNumber, rebaseGeneration: number) => {
29
- return this.rebase({ parentSeqNum, isClient: this.isClient, rebaseGeneration })
30
- }
31
-
32
- // Only used for Vitest printing
33
- // toJSON = () => `(${this.seqNum.global},${this.seqNum.client},${this.payload})`
34
- // toString = () => this.toJSON()
35
- }
3
+ import { Vitest } from '@livestore/utils-dev/node-vitest'
4
+ import { Cause, Effect, Exit, Schema } from '@livestore/utils/effect'
36
5
 
37
- const e0_1 = new TestEvent({ global: 0, client: 1 }, EventSequenceNumber.ROOT, 'a', true)
38
- const e1_0 = new TestEvent({ global: 1, client: 0 }, EventSequenceNumber.ROOT, 'a', false)
39
- const e1_1 = new TestEvent({ global: 1, client: 1 }, e1_0.seqNum, 'a', true)
40
- const e1_2 = new TestEvent({ global: 1, client: 2 }, e1_1.seqNum, 'a', true)
41
- const e1_3 = new TestEvent({ global: 1, client: 3 }, e1_2.seqNum, 'a', true)
42
- const e2_0 = new TestEvent({ global: 2, client: 0 }, e1_0.seqNum, 'a', false)
43
- const e2_1 = new TestEvent({ global: 2, client: 1 }, e2_0.seqNum, 'a', true)
6
+ import * as EventSequenceNumber from '../schema/EventSequenceNumber/mod.ts'
7
+ import * as LiveStoreEvent from '../schema/LiveStoreEvent/mod.ts'
8
+ import * as SyncState from './syncstate.ts'
44
9
 
45
- const isEqualEvent = LiveStoreEvent.isEqualEncoded
10
+ /** Module-scoped JSON codecs; keeping the sync codecs out of Effect generators avoids `schemaSyncInEffect`. */
11
+ const jsonStringify = Schema.encodeSync(Schema.fromJsonString(Schema.Unknown))
12
+ const jsonParse = Schema.decodeUnknownSync(Schema.fromJsonString(Schema.Unknown))
13
+
14
+ const makeTestEvent = ({
15
+ seqNum,
16
+ parentSeqNum,
17
+ payload,
18
+ isClientOnly,
19
+ }: {
20
+ seqNum: EventSequenceNumber.Client.CompositeInput
21
+ parentSeqNum: EventSequenceNumber.Client.CompositeInput
22
+ payload: string
23
+ isClientOnly: boolean
24
+ }) =>
25
+ new LiveStoreEvent.Client.EncodedWithMeta({
26
+ seqNum: EventSequenceNumber.Client.Composite.make(seqNum),
27
+ parentSeqNum: EventSequenceNumber.Client.Composite.make(parentSeqNum),
28
+ name: 'a',
29
+ // Effect v4 normalizes nested Schema.Class values to their declared schema fields.
30
+ // Keep this test-only flag inside `args`, which is part of EncodedWithMeta,
31
+ // instead of relying on subclass fields that are stripped during parsing.
32
+ args: { payload, isClientOnly },
33
+ clientId: 'static-local-id',
34
+ sessionId: 'static-session-id',
35
+ })
46
36
 
47
- const isClientEvent = (event: LiveStoreEvent.EncodedWithMeta) => (event as TestEvent).isClient
37
+ const e0_1 = makeTestEvent({
38
+ seqNum: { global: 0, client: 1 },
39
+ parentSeqNum: EventSequenceNumber.Client.ROOT,
40
+ payload: 'a',
41
+ isClientOnly: true,
42
+ })
43
+ const e1_0 = makeTestEvent({
44
+ seqNum: { global: 1, client: 0 },
45
+ parentSeqNum: EventSequenceNumber.Client.ROOT,
46
+ payload: 'a',
47
+ isClientOnly: false,
48
+ })
49
+ const e1_1 = makeTestEvent({
50
+ seqNum: { global: 1, client: 1 },
51
+ parentSeqNum: e1_0.seqNum,
52
+ payload: 'a',
53
+ isClientOnly: true,
54
+ })
55
+ const e1_2 = makeTestEvent({
56
+ seqNum: { global: 1, client: 2 },
57
+ parentSeqNum: e1_1.seqNum,
58
+ payload: 'a',
59
+ isClientOnly: true,
60
+ })
61
+ const e1_3 = makeTestEvent({
62
+ seqNum: { global: 1, client: 3 },
63
+ parentSeqNum: e1_2.seqNum,
64
+ payload: 'a',
65
+ isClientOnly: true,
66
+ })
67
+ const e2_0 = makeTestEvent({
68
+ seqNum: { global: 2, client: 0 },
69
+ parentSeqNum: e1_0.seqNum,
70
+ payload: 'a',
71
+ isClientOnly: false,
72
+ })
73
+ const e2_1 = makeTestEvent({
74
+ seqNum: { global: 2, client: 1 },
75
+ parentSeqNum: e2_0.seqNum,
76
+ payload: 'a',
77
+ isClientOnly: true,
78
+ })
48
79
 
49
- describe('syncstate', () => {
50
- describe('merge', () => {
80
+ const isEqualEvent = LiveStoreEvent.Client.isEqualEncoded
81
+
82
+ const isClientOnlyEvent = (event: LiveStoreEvent.Client.EncodedWithMeta) =>
83
+ typeof event.args === 'object' &&
84
+ event.args !== null &&
85
+ 'isClientOnly' in event.args &&
86
+ event.args.isClientOnly === true
87
+
88
+ const rebaseTestEvent = ({
89
+ event,
90
+ parentSeqNum,
91
+ rebaseGeneration,
92
+ }: {
93
+ event: LiveStoreEvent.Client.EncodedWithMeta
94
+ parentSeqNum: EventSequenceNumber.Client.Composite
95
+ rebaseGeneration: number
96
+ }) => event.rebase({ parentSeqNum, isClientOnly: isClientOnlyEvent(event), rebaseGeneration })
97
+
98
+ /** Verifies: LS.SYS.SYNC.SS-R01, LS.SYS.SYNC.SS-R02, LS.SYS.SYNC.SS-R03, LS.SYS.SYNC.SS-R05, LS.SYS.SYNC.SS-R06 */
99
+ Vitest.describe('syncstate', () => {
100
+ Vitest.describe('merge', () => {
51
101
  const merge = ({
52
102
  syncState,
53
103
  payload,
54
- ignoreClientEvents = false,
104
+ ignoreClientOnlyEvents = false,
55
105
  }: {
56
106
  syncState: SyncState.SyncState
57
107
  payload: typeof SyncState.Payload.Type
58
- ignoreClientEvents?: boolean
59
- }) => SyncState.merge({ syncState, payload, isClientEvent, isEqualEvent, ignoreClientEvents })
60
-
61
- describe('upstream-rebase', () => {
62
- it('should rollback until start', () => {
63
- const syncState = new SyncState.SyncState({
64
- pending: [e2_0],
65
- upstreamHead: EventSequenceNumber.ROOT,
66
- localHead: e2_0.seqNum,
67
- })
68
- const e1_0_e2_0 = e1_0.rebase_(e2_0.seqNum, 0)
69
- const e1_1_e2_1 = e1_1.rebase_(e1_0_e2_0.seqNum, 0)
70
- const result = merge({
71
- syncState,
72
- payload: SyncState.PayloadUpstreamRebase.make({
73
- rollbackEvents: [e1_0, e1_1],
74
- newEvents: [e1_0_e2_0, e1_1_e2_1],
75
- }),
76
- })
77
- const e2_0_e3_0 = e2_0.rebase_(e1_0_e2_0.seqNum, 1)
78
- expectRebase(result)
79
- expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0])
80
- expect(result.newSyncState.upstreamHead).toMatchObject(e1_1_e2_1.seqNum)
81
- expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.seqNum)
82
- expectEventArraysEqual(result.newEvents, [e1_0_e2_0, e1_1_e2_1, e2_0_e3_0])
83
- expectEventArraysEqual(result.rollbackEvents, [e1_0, e1_1, e2_0])
84
- })
85
-
86
- it('should rollback only to specified point', () => {
87
- const syncState = new SyncState.SyncState({
88
- pending: [e2_0],
89
- upstreamHead: EventSequenceNumber.ROOT,
90
- localHead: e2_0.seqNum,
91
- })
92
- const e1_1_e2_0 = e1_1.rebase_(e1_0.seqNum, 0)
93
- const result = merge({
94
- syncState,
95
- payload: SyncState.PayloadUpstreamRebase.make({
96
- newEvents: [e1_1_e2_0],
97
- rollbackEvents: [e1_1],
98
- }),
99
- })
100
- const e2_0_e3_0 = e2_0.rebase_(e1_1_e2_0.seqNum, 1)
101
- expectRebase(result)
102
- expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0])
103
- expect(result.newSyncState.upstreamHead).toMatchObject(e1_1_e2_0.seqNum)
104
- expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.seqNum)
105
- expectEventArraysEqual(result.newEvents, [e1_1_e2_0, e2_0_e3_0])
106
- expectEventArraysEqual(result.rollbackEvents, [e1_1, e2_0])
107
- })
108
-
109
- it('should work for empty pending', () => {
110
- const syncState = new SyncState.SyncState({
111
- pending: [],
112
- upstreamHead: EventSequenceNumber.ROOT,
113
- localHead: e1_0.seqNum,
114
- })
115
- const result = merge({
116
- syncState,
117
- payload: SyncState.PayloadUpstreamRebase.make({ rollbackEvents: [e1_0], newEvents: [e2_0] }),
118
- })
119
- expectRebase(result)
120
- expectEventArraysEqual(result.newSyncState.pending, [])
121
- expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
122
- expect(result.newSyncState.localHead).toMatchObject(e2_0.seqNum)
123
- expect(result.newEvents).toStrictEqual([e2_0])
124
- })
125
- })
126
-
127
- describe('upstream-advance: advance', () => {
128
- it('should throw error if newEvents are not sorted in ascending order by event number (client)', () => {
129
- const syncState = new SyncState.SyncState({
130
- pending: [e1_0],
131
- upstreamHead: EventSequenceNumber.ROOT,
132
- localHead: e1_0.seqNum,
133
- })
134
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_1, e1_0] } })
135
- expect(result).toMatchObject({ _tag: 'unexpected-error' })
136
- })
137
-
138
- it('should throw error if newEvents are not sorted in ascending order by event number (global)', () => {
139
- const syncState = new SyncState.SyncState({
140
- pending: [e1_0],
141
- upstreamHead: EventSequenceNumber.ROOT,
142
- localHead: e1_0.seqNum,
143
- })
144
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e2_0, e1_0] } })
145
- expect(result).toMatchObject({ _tag: 'unexpected-error' })
146
- })
147
-
148
- it('should throw error if incoming event is < expected upstream head', () => {
149
- const syncState = new SyncState.SyncState({
150
- pending: [],
151
- upstreamHead: e2_0.seqNum,
152
- localHead: e2_0.seqNum,
153
- })
154
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } })
155
- expect(result).toMatchObject({ _tag: 'unexpected-error' })
156
- })
157
-
158
- it('should throw error if incoming event is = expected upstream head', () => {
159
- const syncState = new SyncState.SyncState({
160
- pending: [],
161
- upstreamHead: e2_0.seqNum,
162
- localHead: e2_0.seqNum,
163
- })
164
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e2_0] } })
165
- expect(result).toMatchObject({ _tag: 'unexpected-error' })
166
- })
167
-
168
- it('should confirm pending event when receiving matching event', () => {
169
- const syncState = new SyncState.SyncState({
170
- pending: [e1_0],
171
- upstreamHead: EventSequenceNumber.ROOT,
172
- localHead: e1_0.seqNum,
173
- })
174
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } })
175
-
176
- expectAdvance(result)
177
- expectEventArraysEqual(result.newSyncState.pending, [])
178
- expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.seqNum)
179
- expect(result.newSyncState.localHead).toMatchObject(e1_0.seqNum)
180
- expectEventArraysEqual(result.newEvents, [])
181
- expectEventArraysEqual(result.confirmedEvents, [e1_0])
182
- })
183
-
184
- it('should confirm partial pending event when receiving matching event', () => {
185
- const syncState = new SyncState.SyncState({
186
- pending: [e1_0, e2_0],
187
- upstreamHead: EventSequenceNumber.ROOT,
188
- localHead: e2_0.seqNum,
189
- })
190
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } })
191
-
192
- expectAdvance(result)
193
- expectEventArraysEqual(result.newSyncState.pending, [e2_0])
194
- expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.seqNum)
195
- expect(result.newSyncState.localHead).toMatchObject(e2_0.seqNum)
196
- expectEventArraysEqual(result.newEvents, [])
197
- expectEventArraysEqual(result.confirmedEvents, [e1_0])
198
- })
199
-
200
- it('should confirm pending event and add new event', () => {
201
- const syncState = new SyncState.SyncState({
202
- pending: [e1_0],
203
- upstreamHead: EventSequenceNumber.ROOT,
204
- localHead: e1_0.seqNum,
205
- })
206
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0, e1_1] } })
207
-
208
- expectAdvance(result)
209
- expectEventArraysEqual(result.newSyncState.pending, [])
210
- expect(result.newSyncState.upstreamHead).toMatchObject(e1_1.seqNum)
211
- expect(result.newSyncState.localHead).toMatchObject(e1_1.seqNum)
212
- expect(result.newEvents).toStrictEqual([e1_1])
213
- expectEventArraysEqual(result.confirmedEvents, [e1_0])
214
- })
215
-
216
- it('should confirm pending event and add multiple new events', () => {
217
- const syncState = new SyncState.SyncState({
218
- pending: [e1_1],
219
- upstreamHead: e1_0.seqNum,
220
- localHead: e1_1.seqNum,
221
- })
222
- const result = merge({
223
- syncState,
224
- payload: { _tag: 'upstream-advance', newEvents: [e1_1, e1_2, e1_3, e2_0, e2_1] },
225
- })
226
-
227
- expectAdvance(result)
228
- expectEventArraysEqual(result.newSyncState.pending, [])
229
- expect(result.newSyncState.upstreamHead).toMatchObject(e2_1.seqNum)
230
- expect(result.newSyncState.localHead).toMatchObject(e2_1.seqNum)
231
- expect(result.newEvents).toStrictEqual([e1_2, e1_3, e2_0, e2_1])
232
- expectEventArraysEqual(result.confirmedEvents, [e1_1])
233
- })
234
-
235
- it('should confirm pending global event while keep pending client events', () => {
236
- const syncState = new SyncState.SyncState({
237
- pending: [e1_0, e1_1],
238
- upstreamHead: EventSequenceNumber.ROOT,
239
- localHead: e1_1.seqNum,
240
- })
241
- const result = merge({
242
- syncState,
243
- payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
244
- })
245
-
246
- expectAdvance(result)
247
- expectEventArraysEqual(result.newSyncState.pending, [e1_1])
248
- expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.seqNum)
249
- expect(result.newSyncState.localHead).toMatchObject(e1_1.seqNum)
250
- expectEventArraysEqual(result.newEvents, [])
251
- expectEventArraysEqual(result.confirmedEvents, [e1_0])
252
- })
253
-
254
- it('should ignore client events (incoming is subset of pending)', () => {
255
- const syncState = new SyncState.SyncState({
256
- pending: [e0_1, e1_0],
257
- upstreamHead: EventSequenceNumber.ROOT,
258
- localHead: e1_0.seqNum,
259
- })
260
- const result = merge({
261
- syncState,
262
- payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
263
- ignoreClientEvents: true,
264
- })
265
- expectAdvance(result)
266
- expectEventArraysEqual(result.newSyncState.pending, [])
267
- expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.seqNum)
268
- expect(result.newSyncState.localHead).toMatchObject(e1_0.seqNum)
269
- expectEventArraysEqual(result.newEvents, [])
270
- expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0])
271
- })
272
-
273
- it('should ignore client events (incoming is subset of pending case 2)', () => {
274
- const syncState = new SyncState.SyncState({
275
- pending: [e0_1, e1_0, e2_0],
276
- upstreamHead: EventSequenceNumber.ROOT,
277
- localHead: e1_0.seqNum,
278
- })
279
- const result = merge({
280
- syncState,
281
- payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
282
- ignoreClientEvents: true,
283
- })
284
- expectAdvance(result)
285
- expectEventArraysEqual(result.newSyncState.pending, [e2_0])
286
- expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.seqNum)
287
- expect(result.newSyncState.localHead).toMatchObject(e2_0.seqNum)
288
- expectEventArraysEqual(result.newEvents, [])
289
- expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0])
290
- })
291
-
292
- it('should ignore client events (incoming goes beyond pending)', () => {
293
- const syncState = new SyncState.SyncState({
294
- pending: [e0_1, e1_0, e1_1],
295
- upstreamHead: EventSequenceNumber.ROOT,
296
- localHead: e1_1.seqNum,
297
- })
298
- const result = merge({
299
- syncState,
300
- payload: { _tag: 'upstream-advance', newEvents: [e1_0, e2_0] },
301
- ignoreClientEvents: true,
302
- })
303
-
304
- expectAdvance(result)
305
- expectEventArraysEqual(result.newSyncState.pending, [])
306
- expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
307
- expect(result.newSyncState.localHead).toMatchObject(e2_0.seqNum)
308
- expect(result.newEvents).toStrictEqual([e2_0])
309
- expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0, e1_1])
310
- })
311
-
312
- it('should fail if incoming event is ≤ local head', () => {
313
- const syncState = new SyncState.SyncState({
314
- pending: [],
315
- upstreamHead: e2_0.seqNum,
316
- localHead: e2_0.seqNum,
317
- })
318
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } })
319
- expect(result).toMatchObject({ _tag: 'unexpected-error' })
320
- })
108
+ ignoreClientOnlyEvents?: boolean
109
+ }) => SyncState.merge({ syncState, payload, isClientOnlyEvent, isEqualEvent, ignoreClientOnlyEvents })
110
+
111
+ Vitest.describe('upstream-rebase', () => {
112
+ Vitest.it.effect('should rollback until start', () =>
113
+ Effect.gen(function* () {
114
+ const syncState = new SyncState.SyncState({
115
+ pending: [e2_0],
116
+ upstreamHead: EventSequenceNumber.Client.ROOT,
117
+ localHead: e2_0.seqNum,
118
+ })
119
+ const e1_0_e2_0 = rebaseTestEvent({ event: e1_0, parentSeqNum: e2_0.seqNum, rebaseGeneration: 0 })
120
+ const e1_1_e2_1 = rebaseTestEvent({ event: e1_1, parentSeqNum: e1_0_e2_0.seqNum, rebaseGeneration: 0 })
121
+ const result = yield* merge({
122
+ syncState,
123
+ payload: SyncState.PayloadUpstreamRebase.make({
124
+ rollbackEvents: [e1_0, e1_1],
125
+ newEvents: [e1_0_e2_0, e1_1_e2_1],
126
+ }),
127
+ })
128
+ const e2_0_e3_0 = rebaseTestEvent({ event: e2_0, parentSeqNum: e1_0_e2_0.seqNum, rebaseGeneration: 1 })
129
+ expectRebase(result)
130
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0])
131
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1_e2_1.seqNum)
132
+ expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.seqNum)
133
+ expectEventArraysEqual(result.newEvents, [e1_0_e2_0, e1_1_e2_1, e2_0_e3_0])
134
+ expectEventArraysEqual(result.rollbackEvents, [e1_0, e1_1, e2_0])
135
+ }),
136
+ )
137
+
138
+ Vitest.it.effect('should rollback only to specified point', () =>
139
+ Effect.gen(function* () {
140
+ const syncState = new SyncState.SyncState({
141
+ pending: [e2_0],
142
+ upstreamHead: EventSequenceNumber.Client.ROOT,
143
+ localHead: e2_0.seqNum,
144
+ })
145
+ const e1_1_e2_0 = rebaseTestEvent({ event: e1_1, parentSeqNum: e1_0.seqNum, rebaseGeneration: 0 })
146
+ const result = yield* merge({
147
+ syncState,
148
+ payload: SyncState.PayloadUpstreamRebase.make({
149
+ newEvents: [e1_1_e2_0],
150
+ rollbackEvents: [e1_1],
151
+ }),
152
+ })
153
+ const e2_0_e3_0 = rebaseTestEvent({ event: e2_0, parentSeqNum: e1_1_e2_0.seqNum, rebaseGeneration: 1 })
154
+ expectRebase(result)
155
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0])
156
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1_e2_0.seqNum)
157
+ expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.seqNum)
158
+ expectEventArraysEqual(result.newEvents, [e1_1_e2_0, e2_0_e3_0])
159
+ expectEventArraysEqual(result.rollbackEvents, [e1_1, e2_0])
160
+ }),
161
+ )
162
+
163
+ Vitest.it.effect('should work for empty pending', () =>
164
+ Effect.gen(function* () {
165
+ const syncState = new SyncState.SyncState({
166
+ pending: [],
167
+ upstreamHead: EventSequenceNumber.Client.ROOT,
168
+ localHead: e1_0.seqNum,
169
+ })
170
+ const result = yield* merge({
171
+ syncState,
172
+ payload: SyncState.PayloadUpstreamRebase.make({ rollbackEvents: [e1_0], newEvents: [e2_0] }),
173
+ })
174
+ expectRebase(result)
175
+ expectEventArraysEqual(result.newSyncState.pending, [])
176
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
177
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.seqNum)
178
+ expectEventArraysEqual(result.newEvents, [e2_0])
179
+ }),
180
+ )
321
181
  })
322
182
 
323
- describe('upstream-advance: rebase', () => {
324
- it('should rebase single client event to end', () => {
325
- const syncState = new SyncState.SyncState({
326
- pending: [e1_0],
327
- upstreamHead: EventSequenceNumber.ROOT,
328
- localHead: e1_0.seqNum,
329
- })
330
- const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1] }) })
331
-
332
- const e1_0_e1_2 = e1_0.rebase_(e1_1.seqNum, 1)
333
-
334
- expectRebase(result)
335
- expectEventArraysEqual(result.newSyncState.pending, [e1_0_e1_2])
336
- expect(result.newSyncState.upstreamHead).toMatchObject(e1_1.seqNum)
337
- expect(result.newSyncState.localHead).toMatchObject(e1_0_e1_2.seqNum)
338
- expectEventArraysEqual(result.rollbackEvents, [e1_0])
339
- expectEventArraysEqual(result.newEvents, [e1_1, e1_0_e1_2])
340
- })
341
-
342
- it('should rebase different event with same id', () => {
343
- const e2_0_b = new TestEvent({ global: 1, client: 0 }, e1_0.seqNum, '1_0_b', false)
344
- const syncState = new SyncState.SyncState({
345
- pending: [e2_0_b],
346
- upstreamHead: EventSequenceNumber.ROOT,
347
- localHead: e2_0_b.seqNum,
348
- })
349
- const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e2_0] }) })
350
- const e2_0_e3_0 = e2_0_b.rebase_(e2_0.seqNum, 1)
351
-
352
- expectRebase(result)
353
- expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0])
354
- expectEventArraysEqual(result.newEvents, [e2_0, e2_0_e3_0])
355
- expectEventArraysEqual(result.rollbackEvents, [e2_0_b])
356
- expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
357
- expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.seqNum)
358
- })
359
-
360
- it('should rebase single client event to end (more incoming events)', () => {
361
- const syncState = new SyncState.SyncState({
362
- pending: [e1_0],
363
- upstreamHead: EventSequenceNumber.ROOT,
364
- localHead: e1_0.seqNum,
365
- })
366
- const result = merge({
367
- syncState,
368
- payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1, e1_2, e1_3, e2_0] }),
369
- })
370
-
371
- const e1_0_e3_0 = e1_0.rebase_(e2_0.seqNum, 1)
372
-
373
- expectRebase(result)
374
- expectEventArraysEqual(result.newSyncState.pending, [e1_0_e3_0])
375
- expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
376
- expect(result.newSyncState.localHead).toMatchObject(e1_0_e3_0.seqNum)
377
- })
378
-
379
- it('should only rebase divergent events when first event matches', () => {
380
- const syncState = new SyncState.SyncState({
381
- pending: [e1_0, e1_1],
382
- upstreamHead: EventSequenceNumber.ROOT,
383
- localHead: e1_0.seqNum,
384
- })
385
- const result = merge({
386
- syncState,
387
- payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_0, e1_2, e1_3, e2_0] }),
388
- })
389
-
390
- const e1_1_e2_1 = e1_1.rebase_(e2_0.seqNum, 1)
183
+ Vitest.describe('upstream-advance: advance', () => {
184
+ Vitest.it.effect('should die if newEvents are not sorted in ascending order by event number (client)', () =>
185
+ Effect.gen(function* () {
186
+ const syncState = new SyncState.SyncState({
187
+ pending: [e1_0],
188
+ upstreamHead: EventSequenceNumber.Client.ROOT,
189
+ localHead: e1_0.seqNum,
190
+ })
191
+ const exit = yield* merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_1, e1_0] } }).pipe(
192
+ Effect.exit,
193
+ )
194
+ assert(Exit.isFailure(exit))
195
+ expect(Cause.hasDies(exit.cause)).toBe(true)
196
+ }),
197
+ )
198
+
199
+ Vitest.it.effect('should die if newEvents are not sorted in ascending order by event number (global)', () =>
200
+ Effect.gen(function* () {
201
+ const syncState = new SyncState.SyncState({
202
+ pending: [e1_0],
203
+ upstreamHead: EventSequenceNumber.Client.ROOT,
204
+ localHead: e1_0.seqNum,
205
+ })
206
+ const exit = yield* merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e2_0, e1_0] } }).pipe(
207
+ Effect.exit,
208
+ )
209
+ assert(Exit.isFailure(exit))
210
+ expect(Cause.hasDies(exit.cause)).toBe(true)
211
+ }),
212
+ )
213
+
214
+ Vitest.it.effect('should die if incoming event is < expected upstream head', () =>
215
+ Effect.gen(function* () {
216
+ const syncState = new SyncState.SyncState({
217
+ pending: [],
218
+ upstreamHead: e2_0.seqNum,
219
+ localHead: e2_0.seqNum,
220
+ })
221
+ const exit = yield* merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } }).pipe(
222
+ Effect.exit,
223
+ )
224
+ assert(Exit.isFailure(exit))
225
+ expect(Cause.hasDies(exit.cause)).toBe(true)
226
+ }),
227
+ )
228
+
229
+ Vitest.it.effect('should die if incoming event is = expected upstream head', () =>
230
+ Effect.gen(function* () {
231
+ const syncState = new SyncState.SyncState({
232
+ pending: [],
233
+ upstreamHead: e2_0.seqNum,
234
+ localHead: e2_0.seqNum,
235
+ })
236
+ const exit = yield* merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e2_0] } }).pipe(
237
+ Effect.exit,
238
+ )
239
+ assert(Exit.isFailure(exit))
240
+ expect(Cause.hasDies(exit.cause)).toBe(true)
241
+ }),
242
+ )
243
+
244
+ Vitest.it.effect('should confirm pending event when receiving matching event', () =>
245
+ Effect.gen(function* () {
246
+ const syncState = new SyncState.SyncState({
247
+ pending: [e1_0],
248
+ upstreamHead: EventSequenceNumber.Client.ROOT,
249
+ localHead: e1_0.seqNum,
250
+ })
251
+ const result = yield* merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } })
252
+
253
+ expectAdvance(result)
254
+ expectEventArraysEqual(result.newSyncState.pending, [])
255
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.seqNum)
256
+ expect(result.newSyncState.localHead).toMatchObject(e1_0.seqNum)
257
+ expectEventArraysEqual(result.newEvents, [])
258
+ expectEventArraysEqual(result.confirmedEvents, [e1_0])
259
+ }),
260
+ )
261
+
262
+ Vitest.it.effect('should confirm partial pending event when receiving matching event', () =>
263
+ Effect.gen(function* () {
264
+ const syncState = new SyncState.SyncState({
265
+ pending: [e1_0, e2_0],
266
+ upstreamHead: EventSequenceNumber.Client.ROOT,
267
+ localHead: e2_0.seqNum,
268
+ })
269
+ const result = yield* merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } })
270
+
271
+ expectAdvance(result)
272
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0])
273
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.seqNum)
274
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.seqNum)
275
+ expectEventArraysEqual(result.newEvents, [])
276
+ expectEventArraysEqual(result.confirmedEvents, [e1_0])
277
+ }),
278
+ )
279
+
280
+ Vitest.it.effect('should confirm pending event and add new event', () =>
281
+ Effect.gen(function* () {
282
+ const syncState = new SyncState.SyncState({
283
+ pending: [e1_0],
284
+ upstreamHead: EventSequenceNumber.Client.ROOT,
285
+ localHead: e1_0.seqNum,
286
+ })
287
+ const result = yield* merge({
288
+ syncState,
289
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0, e1_1] },
290
+ })
391
291
 
392
- expectRebase(result)
393
- expectEventArraysEqual(result.newSyncState.pending, [e1_1_e2_1])
394
- expectEventArraysEqual(result.rollbackEvents, [e1_1])
395
- expectEventArraysEqual(result.newEvents, [e1_2, e1_3, e2_0, e1_1_e2_1])
396
- expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
397
- expect(result.newSyncState.localHead).toMatchObject(e1_1_e2_1.seqNum)
398
- })
292
+ expectAdvance(result)
293
+ expectEventArraysEqual(result.newSyncState.pending, [])
294
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1.seqNum)
295
+ expect(result.newSyncState.localHead).toMatchObject(e1_1.seqNum)
296
+ expectEventArraysEqual(result.newEvents, [e1_1])
297
+ expectEventArraysEqual(result.confirmedEvents, [e1_0])
298
+ }),
299
+ )
300
+
301
+ Vitest.it.effect('should confirm pending event and add multiple new events', () =>
302
+ Effect.gen(function* () {
303
+ const syncState = new SyncState.SyncState({
304
+ pending: [e1_1],
305
+ upstreamHead: e1_0.seqNum,
306
+ localHead: e1_1.seqNum,
307
+ })
308
+ const result = yield* merge({
309
+ syncState,
310
+ payload: { _tag: 'upstream-advance', newEvents: [e1_1, e1_2, e1_3, e2_0, e2_1] },
311
+ })
399
312
 
400
- it('should rebase all client events when incoming chain starts differently', () => {
401
- const syncState = new SyncState.SyncState({
402
- pending: [e1_0, e1_1],
403
- upstreamHead: EventSequenceNumber.ROOT,
404
- localHead: e1_1.seqNum,
405
- })
406
- const result = merge({
407
- syncState,
408
- payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1, e1_2, e1_3, e2_0] }),
409
- })
313
+ expectAdvance(result)
314
+ expectEventArraysEqual(result.newSyncState.pending, [])
315
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_1.seqNum)
316
+ expect(result.newSyncState.localHead).toMatchObject(e2_1.seqNum)
317
+ expectEventArraysEqual(result.newEvents, [e1_2, e1_3, e2_0, e2_1])
318
+ expectEventArraysEqual(result.confirmedEvents, [e1_1])
319
+ }),
320
+ )
321
+
322
+ Vitest.it.effect('should confirm pending global event while keep pending client events', () =>
323
+ Effect.gen(function* () {
324
+ const syncState = new SyncState.SyncState({
325
+ pending: [e1_0, e1_1],
326
+ upstreamHead: EventSequenceNumber.Client.ROOT,
327
+ localHead: e1_1.seqNum,
328
+ })
329
+ const result = yield* merge({
330
+ syncState,
331
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
332
+ })
410
333
 
411
- const e1_0_e2_1 = e1_0.rebase_(e2_0.seqNum, 1)
412
- const e1_1_e2_2 = e1_1.rebase_(e1_0_e2_1.seqNum, 1)
334
+ expectAdvance(result)
335
+ expectEventArraysEqual(result.newSyncState.pending, [e1_1])
336
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.seqNum)
337
+ expect(result.newSyncState.localHead).toMatchObject(e1_1.seqNum)
338
+ expectEventArraysEqual(result.newEvents, [])
339
+ expectEventArraysEqual(result.confirmedEvents, [e1_0])
340
+ }),
341
+ )
342
+
343
+ Vitest.it.effect('should ignore client events (incoming is subset of pending)', () =>
344
+ Effect.gen(function* () {
345
+ const syncState = new SyncState.SyncState({
346
+ pending: [e0_1, e1_0],
347
+ upstreamHead: EventSequenceNumber.Client.ROOT,
348
+ localHead: e1_0.seqNum,
349
+ })
350
+ const result = yield* merge({
351
+ syncState,
352
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
353
+ ignoreClientOnlyEvents: true,
354
+ })
355
+ expectAdvance(result)
356
+ expectEventArraysEqual(result.newSyncState.pending, [])
357
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.seqNum)
358
+ expect(result.newSyncState.localHead).toMatchObject(e1_0.seqNum)
359
+ expectEventArraysEqual(result.newEvents, [])
360
+ expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0])
361
+ }),
362
+ )
363
+
364
+ Vitest.it.effect('should ignore client events (incoming is subset of pending case 2)', () =>
365
+ Effect.gen(function* () {
366
+ const syncState = new SyncState.SyncState({
367
+ pending: [e0_1, e1_0, e2_0],
368
+ upstreamHead: EventSequenceNumber.Client.ROOT,
369
+ localHead: e1_0.seqNum,
370
+ })
371
+ const result = yield* merge({
372
+ syncState,
373
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
374
+ ignoreClientOnlyEvents: true,
375
+ })
376
+ expectAdvance(result)
377
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0])
378
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.seqNum)
379
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.seqNum)
380
+ expectEventArraysEqual(result.newEvents, [])
381
+ expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0])
382
+ }),
383
+ )
384
+
385
+ Vitest.it.effect('should ignore client events (incoming goes beyond pending)', () =>
386
+ Effect.gen(function* () {
387
+ const syncState = new SyncState.SyncState({
388
+ pending: [e0_1, e1_0, e1_1],
389
+ upstreamHead: EventSequenceNumber.Client.ROOT,
390
+ localHead: e1_1.seqNum,
391
+ })
392
+ const result = yield* merge({
393
+ syncState,
394
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0, e2_0] },
395
+ ignoreClientOnlyEvents: true,
396
+ })
413
397
 
414
- expectRebase(result)
415
- expectEventArraysEqual(result.newSyncState.pending, [e1_0_e2_1, e1_1_e2_2])
416
- expectEventArraysEqual(result.newEvents, [e1_1, e1_2, e1_3, e2_0, e1_0_e2_1, e1_1_e2_2])
417
- expectEventArraysEqual(result.rollbackEvents, [e1_0, e1_1])
418
- expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
419
- expect(result.newSyncState.localHead).toMatchObject(e1_1_e2_2.seqNum)
420
- })
398
+ expectAdvance(result)
399
+ expectEventArraysEqual(result.newSyncState.pending, [])
400
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
401
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.seqNum)
402
+ expectEventArraysEqual(result.newEvents, [e2_0])
403
+ expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0, e1_1])
404
+ }),
405
+ )
406
+
407
+ Vitest.it.effect('should die if incoming event is ≤ local head', () =>
408
+ Effect.gen(function* () {
409
+ const syncState = new SyncState.SyncState({
410
+ pending: [],
411
+ upstreamHead: e2_0.seqNum,
412
+ localHead: e2_0.seqNum,
413
+ })
414
+ const exit = yield* merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } }).pipe(
415
+ Effect.exit,
416
+ )
417
+ assert(Exit.isFailure(exit))
418
+ expect(Cause.hasDies(exit.cause)).toBe(true)
419
+ }),
420
+ )
421
+
422
+ Vitest.it.effect(
423
+ 'should advance (not rebase) when pending event has undefined-valued key dropped by JSON wire round-trip',
424
+ () =>
425
+ Effect.gen(function* () {
426
+ const argsSchema = Schema.Struct({
427
+ id: Schema.String,
428
+ flag: Schema.optional(Schema.Boolean),
429
+ })
430
+ const localArgs = yield* Schema.encodeUnknownEffect(argsSchema)({ id: 'abc' } as any).pipe(Effect.orDie)
431
+ const wireArgs = jsonParse(jsonStringify(localArgs))
432
+
433
+ const localPending = new LiveStoreEvent.Client.EncodedWithMeta({
434
+ seqNum: e1_0.seqNum,
435
+ parentSeqNum: e1_0.parentSeqNum,
436
+ name: e1_0.name,
437
+ args: localArgs,
438
+ clientId: e1_0.clientId,
439
+ sessionId: e1_0.sessionId,
440
+ })
441
+ const fromUpstream = new LiveStoreEvent.Client.EncodedWithMeta({
442
+ seqNum: e1_0.seqNum,
443
+ parentSeqNum: e1_0.parentSeqNum,
444
+ name: e1_0.name,
445
+ args: wireArgs,
446
+ clientId: e1_0.clientId,
447
+ sessionId: e1_0.sessionId,
448
+ })
421
449
 
422
- describe('local-push', () => {
423
- describe('advance', () => {
424
- it('should advance with new events', () => {
425
450
  const syncState = new SyncState.SyncState({
426
- pending: [e1_0],
427
- upstreamHead: EventSequenceNumber.ROOT,
428
- localHead: e1_0.seqNum,
451
+ pending: [localPending],
452
+ upstreamHead: EventSequenceNumber.Client.ROOT,
453
+ localHead: localPending.seqNum,
429
454
  })
430
- const result = merge({
455
+ const result = yield* merge({
431
456
  syncState,
432
- payload: SyncState.PayloadLocalPush.make({ newEvents: [e1_1, e1_2, e1_3] }),
457
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [fromUpstream] }),
433
458
  })
434
459
 
435
460
  expectAdvance(result)
436
- expectEventArraysEqual(result.newSyncState.pending, [e1_0, e1_1, e1_2, e1_3])
437
- expect(result.newSyncState.upstreamHead).toMatchObject(EventSequenceNumber.ROOT)
438
- expect(result.newSyncState.localHead).toMatchObject(e1_3.seqNum)
439
- expectEventArraysEqual(result.newEvents, [e1_1, e1_2, e1_3])
440
- expectEventArraysEqual(result.confirmedEvents, [])
461
+ expect(result.confirmedEvents).toHaveLength(1)
462
+ expect(result.newSyncState.pending).toHaveLength(0)
463
+ }),
464
+ )
465
+ })
466
+
467
+ Vitest.describe('upstream-advance: rebase', () => {
468
+ Vitest.it.effect('should rebase single client event to end', () =>
469
+ Effect.gen(function* () {
470
+ const syncState = new SyncState.SyncState({
471
+ pending: [e1_0],
472
+ upstreamHead: EventSequenceNumber.Client.ROOT,
473
+ localHead: e1_0.seqNum,
474
+ })
475
+ const result = yield* merge({
476
+ syncState,
477
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1] }),
441
478
  })
442
- })
443
479
 
444
- describe('reject', () => {
445
- it('should reject when new events are greater than pending events', () => {
446
- const syncState = new SyncState.SyncState({
447
- pending: [e1_0, e1_1],
448
- upstreamHead: EventSequenceNumber.ROOT,
449
- localHead: e1_1.seqNum,
450
- })
451
- const result = merge({
452
- syncState,
453
- payload: SyncState.PayloadLocalPush.make({ newEvents: [e1_1, e1_2] }),
454
- })
480
+ const e1_0_e1_2 = rebaseTestEvent({ event: e1_0, parentSeqNum: e1_1.seqNum, rebaseGeneration: 1 })
481
+
482
+ expectRebase(result)
483
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0_e1_2])
484
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1.seqNum)
485
+ expect(result.newSyncState.localHead).toMatchObject(e1_0_e1_2.seqNum)
486
+ expectEventArraysEqual(result.rollbackEvents, [e1_0])
487
+ expectEventArraysEqual(result.newEvents, [e1_1, e1_0_e1_2])
488
+ }),
489
+ )
490
+
491
+ Vitest.it.effect('should rebase different event with same id', () =>
492
+ Effect.gen(function* () {
493
+ const e2_0_b = makeTestEvent({
494
+ seqNum: { global: 1, client: 0 },
495
+ parentSeqNum: e1_0.seqNum,
496
+ payload: '1_0_b',
497
+ isClientOnly: false,
498
+ })
499
+ const syncState = new SyncState.SyncState({
500
+ pending: [e2_0_b],
501
+ upstreamHead: EventSequenceNumber.Client.ROOT,
502
+ localHead: e2_0_b.seqNum,
503
+ })
504
+ const result = yield* merge({
505
+ syncState,
506
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e2_0] }),
507
+ })
508
+ const e2_0_e3_0 = rebaseTestEvent({ event: e2_0_b, parentSeqNum: e2_0.seqNum, rebaseGeneration: 1 })
509
+
510
+ expectRebase(result)
511
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0])
512
+ expectEventArraysEqual(result.newEvents, [e2_0, e2_0_e3_0])
513
+ expectEventArraysEqual(result.rollbackEvents, [e2_0_b])
514
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
515
+ expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.seqNum)
516
+ }),
517
+ )
518
+
519
+ Vitest.it.effect('should rebase single client event to end (more incoming events)', () =>
520
+ Effect.gen(function* () {
521
+ const syncState = new SyncState.SyncState({
522
+ pending: [e1_0],
523
+ upstreamHead: EventSequenceNumber.Client.ROOT,
524
+ localHead: e1_0.seqNum,
525
+ })
526
+ const result = yield* merge({
527
+ syncState,
528
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1, e1_2, e1_3, e2_0] }),
529
+ })
455
530
 
456
- expectReject(result)
457
- expect(result.expectedMinimumId).toMatchObject(e1_2.seqNum)
531
+ const e1_0_e3_0 = rebaseTestEvent({ event: e1_0, parentSeqNum: e2_0.seqNum, rebaseGeneration: 1 })
532
+
533
+ expectRebase(result)
534
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0_e3_0])
535
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
536
+ expect(result.newSyncState.localHead).toMatchObject(e1_0_e3_0.seqNum)
537
+ }),
538
+ )
539
+
540
+ Vitest.it.effect('should only rebase divergent events when first event matches', () =>
541
+ Effect.gen(function* () {
542
+ const syncState = new SyncState.SyncState({
543
+ pending: [e1_0, e1_1],
544
+ upstreamHead: EventSequenceNumber.Client.ROOT,
545
+ localHead: e1_0.seqNum,
546
+ })
547
+ const result = yield* merge({
548
+ syncState,
549
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_0, e1_2, e1_3, e2_0] }),
550
+ })
551
+
552
+ const e1_1_e2_1 = rebaseTestEvent({ event: e1_1, parentSeqNum: e2_0.seqNum, rebaseGeneration: 1 })
553
+
554
+ expectRebase(result)
555
+ expectEventArraysEqual(result.newSyncState.pending, [e1_1_e2_1])
556
+ expectEventArraysEqual(result.rollbackEvents, [e1_1])
557
+ expectEventArraysEqual(result.newEvents, [e1_2, e1_3, e2_0, e1_1_e2_1])
558
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
559
+ expect(result.newSyncState.localHead).toMatchObject(e1_1_e2_1.seqNum)
560
+ }),
561
+ )
562
+
563
+ Vitest.it.effect('should rebase all client events when incoming chain starts differently', () =>
564
+ Effect.gen(function* () {
565
+ const syncState = new SyncState.SyncState({
566
+ pending: [e1_0, e1_1],
567
+ upstreamHead: EventSequenceNumber.Client.ROOT,
568
+ localHead: e1_1.seqNum,
569
+ })
570
+ const result = yield* merge({
571
+ syncState,
572
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1, e1_2, e1_3, e2_0] }),
458
573
  })
574
+
575
+ const e1_0_e2_1 = rebaseTestEvent({ event: e1_0, parentSeqNum: e2_0.seqNum, rebaseGeneration: 1 })
576
+ const e1_1_e2_2 = rebaseTestEvent({ event: e1_1, parentSeqNum: e1_0_e2_1.seqNum, rebaseGeneration: 1 })
577
+
578
+ expectRebase(result)
579
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0_e2_1, e1_1_e2_2])
580
+ expectEventArraysEqual(result.newEvents, [e1_1, e1_2, e1_3, e2_0, e1_0_e2_1, e1_1_e2_2])
581
+ expectEventArraysEqual(result.rollbackEvents, [e1_0, e1_1])
582
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.seqNum)
583
+ expect(result.newSyncState.localHead).toMatchObject(e1_1_e2_2.seqNum)
584
+ }),
585
+ )
586
+
587
+ Vitest.describe('local-push', () => {
588
+ Vitest.describe('advance', () => {
589
+ Vitest.it.effect('should advance with new events', () =>
590
+ Effect.gen(function* () {
591
+ const syncState = new SyncState.SyncState({
592
+ pending: [e1_0],
593
+ upstreamHead: EventSequenceNumber.Client.ROOT,
594
+ localHead: e1_0.seqNum,
595
+ })
596
+ const result = yield* merge({
597
+ syncState,
598
+ payload: SyncState.PayloadLocalPush.make({ newEvents: [e1_1, e1_2, e1_3] }),
599
+ })
600
+
601
+ expectAdvance(result)
602
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0, e1_1, e1_2, e1_3])
603
+ expect(result.newSyncState.upstreamHead).toMatchObject(EventSequenceNumber.Client.ROOT)
604
+ expect(result.newSyncState.localHead).toMatchObject(e1_3.seqNum)
605
+ expectEventArraysEqual(result.newEvents, [e1_1, e1_2, e1_3])
606
+ expectEventArraysEqual(result.confirmedEvents, [])
607
+ }),
608
+ )
609
+
610
+ // Leaders can choose to ignore client-only events while still returning them for broadcast.
611
+ // Ensure pending/local head only reflects events that must be pushed upstream.
612
+ Vitest.it.effect('keeps pending empty when pushing only client-only events that are being ignored', () =>
613
+ Effect.gen(function* () {
614
+ const syncState = new SyncState.SyncState({
615
+ pending: [],
616
+ upstreamHead: EventSequenceNumber.Client.ROOT,
617
+ localHead: EventSequenceNumber.Client.ROOT,
618
+ })
619
+
620
+ const result = yield* merge({
621
+ syncState,
622
+ payload: SyncState.PayloadLocalPush.make({ newEvents: [e0_1] }),
623
+ ignoreClientOnlyEvents: true,
624
+ })
625
+
626
+ expectAdvance(result)
627
+ expectEventArraysEqual(result.newSyncState.pending, [])
628
+ expect(result.newSyncState.upstreamHead).toMatchObject(EventSequenceNumber.Client.ROOT)
629
+ expect(result.newSyncState.localHead).toMatchObject(EventSequenceNumber.Client.ROOT)
630
+ expectEventArraysEqual(result.newEvents, [e0_1])
631
+ }),
632
+ )
633
+
634
+ Vitest.it.effect('appends only upstream-bound events to pending when ignoring client-only pushes', () =>
635
+ Effect.gen(function* () {
636
+ const syncState = new SyncState.SyncState({
637
+ pending: [],
638
+ upstreamHead: EventSequenceNumber.Client.ROOT,
639
+ localHead: EventSequenceNumber.Client.ROOT,
640
+ })
641
+
642
+ const result = yield* merge({
643
+ syncState,
644
+ payload: SyncState.PayloadLocalPush.make({ newEvents: [e0_1, e1_0] }),
645
+ ignoreClientOnlyEvents: true,
646
+ })
647
+
648
+ expectAdvance(result)
649
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0])
650
+ expect(result.newSyncState.upstreamHead).toMatchObject(EventSequenceNumber.Client.ROOT)
651
+ expect(result.newSyncState.localHead).toMatchObject(e1_0.seqNum)
652
+ expectEventArraysEqual(result.newEvents, [e0_1, e1_0])
653
+ }),
654
+ )
655
+ })
656
+
657
+ Vitest.describe('reject', () => {
658
+ Vitest.it.effect('should reject when new events are greater than pending events', () =>
659
+ Effect.gen(function* () {
660
+ const syncState = new SyncState.SyncState({
661
+ pending: [e1_0, e1_1],
662
+ upstreamHead: EventSequenceNumber.Client.ROOT,
663
+ localHead: e1_1.seqNum,
664
+ })
665
+ const result = yield* merge({
666
+ syncState,
667
+ payload: SyncState.PayloadLocalPush.make({ newEvents: [e1_1, e1_2] }),
668
+ })
669
+
670
+ expectReject(result)
671
+ expect(result.expectedMinimumId).toMatchObject(e1_2.seqNum)
672
+ }),
673
+ )
459
674
  })
460
675
  })
461
676
  })
@@ -463,8 +678,8 @@ describe('syncstate', () => {
463
678
  })
464
679
 
465
680
  const expectEventArraysEqual = (
466
- actual: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>,
467
- expected: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>,
681
+ actual: ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>,
682
+ expected: ReadonlyArray<LiveStoreEvent.Client.EncodedWithMeta>,
468
683
  ) => {
469
684
  expect(actual.length).toBe(expected.length)
470
685
  actual.forEach((event, i) => {
@@ -475,20 +690,20 @@ const expectEventArraysEqual = (
475
690
  })
476
691
  }
477
692
 
478
- function expectAdvance(
479
- result: typeof SyncState.MergeResult.Type,
480
- ): asserts result is typeof SyncState.MergeResultAdvance.Type {
693
+ const expectAdvance: (result: typeof SyncState.MergeResult.Type) => asserts result is SyncState.MergeResultAdvance = (
694
+ result,
695
+ ) => {
481
696
  expect(result._tag).toBe('advance')
482
697
  }
483
698
 
484
- function expectRebase(
485
- result: typeof SyncState.MergeResult.Type,
486
- ): asserts result is typeof SyncState.MergeResultRebase.Type {
487
- expect(result._tag, `Expected rebase, got ${result}`).toBe('rebase')
699
+ const expectRebase: (result: typeof SyncState.MergeResult.Type) => asserts result is SyncState.MergeResultRebase = (
700
+ result,
701
+ ) => {
702
+ expect(result._tag, `Expected rebase, got ${result._tag}`).toBe('rebase')
488
703
  }
489
704
 
490
- function expectReject(
491
- result: typeof SyncState.MergeResult.Type,
492
- ): asserts result is typeof SyncState.MergeResultReject.Type {
705
+ const expectReject: (result: typeof SyncState.MergeResult.Type) => asserts result is SyncState.MergeResultReject = (
706
+ result,
707
+ ) => {
493
708
  expect(result._tag).toBe('reject')
494
709
  }