@livestore/common 0.4.0-dev.22 → 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 (313) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ClientSessionLeaderThreadProxy.d.ts +9 -9
  3. package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
  4. package/dist/WorkerTransportError.d.ts +11 -0
  5. package/dist/WorkerTransportError.d.ts.map +1 -0
  6. package/dist/WorkerTransportError.js +11 -0
  7. package/dist/WorkerTransportError.js.map +1 -0
  8. package/dist/adapter-types.d.ts +3 -3
  9. package/dist/adapter-types.d.ts.map +1 -1
  10. package/dist/adapter-types.js.map +1 -1
  11. package/dist/bounded-collections.d.ts.map +1 -1
  12. package/dist/bounded-collections.js +6 -4
  13. package/dist/bounded-collections.js.map +1 -1
  14. package/dist/debug-info.js +4 -4
  15. package/dist/debug-info.js.map +1 -1
  16. package/dist/devtools/devtools-messages-common.js +1 -1
  17. package/dist/devtools/devtools-messages-common.js.map +1 -1
  18. package/dist/devtools/mod.js +1 -1
  19. package/dist/devtools/mod.js.map +1 -1
  20. package/dist/errors.d.ts +15 -15
  21. package/dist/errors.d.ts.map +1 -1
  22. package/dist/errors.js +11 -11
  23. package/dist/errors.js.map +1 -1
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/leader-thread/LeaderSyncProcessor.d.ts +20 -6
  29. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  30. package/dist/leader-thread/LeaderSyncProcessor.js +287 -257
  31. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  32. package/dist/leader-thread/RejectedPushError.d.ts +107 -0
  33. package/dist/leader-thread/RejectedPushError.d.ts.map +1 -0
  34. package/dist/leader-thread/RejectedPushError.js +78 -0
  35. package/dist/leader-thread/RejectedPushError.js.map +1 -0
  36. package/dist/leader-thread/connection.js +1 -1
  37. package/dist/leader-thread/connection.js.map +1 -1
  38. package/dist/leader-thread/eventlog.d.ts.map +1 -1
  39. package/dist/leader-thread/eventlog.js +12 -11
  40. package/dist/leader-thread/eventlog.js.map +1 -1
  41. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -2
  42. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  43. package/dist/leader-thread/leader-worker-devtools.js +25 -14
  44. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  45. package/dist/leader-thread/make-leader-thread-layer.d.ts +8 -3
  46. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  47. package/dist/leader-thread/make-leader-thread-layer.js +7 -10
  48. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  49. package/dist/leader-thread/make-leader-thread-layer.test.js +1 -1
  50. package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -1
  51. package/dist/leader-thread/materialize-event.js +4 -4
  52. package/dist/leader-thread/materialize-event.js.map +1 -1
  53. package/dist/leader-thread/recreate-db.js +1 -1
  54. package/dist/leader-thread/recreate-db.js.map +1 -1
  55. package/dist/leader-thread/shutdown-channel.d.ts +2 -2
  56. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  57. package/dist/leader-thread/shutdown-channel.js +2 -2
  58. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  59. package/dist/leader-thread/stream-events.d.ts.map +1 -1
  60. package/dist/leader-thread/stream-events.js +4 -3
  61. package/dist/leader-thread/stream-events.js.map +1 -1
  62. package/dist/leader-thread/types.d.ts +7 -6
  63. package/dist/leader-thread/types.d.ts.map +1 -1
  64. package/dist/leader-thread/types.js.map +1 -1
  65. package/dist/logging.js +4 -4
  66. package/dist/logging.js.map +1 -1
  67. package/dist/make-client-session.js +2 -2
  68. package/dist/make-client-session.js.map +1 -1
  69. package/dist/materializer-helper.js +6 -6
  70. package/dist/materializer-helper.js.map +1 -1
  71. package/dist/otel.d.ts +1 -1
  72. package/dist/otel.d.ts.map +1 -1
  73. package/dist/otel.js +2 -2
  74. package/dist/otel.js.map +1 -1
  75. package/dist/rematerialize-from-eventlog.d.ts +1 -1
  76. package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
  77. package/dist/rematerialize-from-eventlog.js +11 -9
  78. package/dist/rematerialize-from-eventlog.js.map +1 -1
  79. package/dist/schema/EventDef/define.d.ts +2 -2
  80. package/dist/schema/EventDef/define.d.ts.map +1 -1
  81. package/dist/schema/EventDef/define.js +4 -4
  82. package/dist/schema/EventDef/define.js.map +1 -1
  83. package/dist/schema/EventDef/deprecated.js +3 -3
  84. package/dist/schema/EventDef/deprecated.js.map +1 -1
  85. package/dist/schema/EventDef/deprecated.test.js +1 -1
  86. package/dist/schema/EventDef/deprecated.test.js.map +1 -1
  87. package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -1
  88. package/dist/schema/EventSequenceNumber/client.js +11 -11
  89. package/dist/schema/EventSequenceNumber/client.js.map +1 -1
  90. package/dist/schema/EventSequenceNumber.test.js +1 -1
  91. package/dist/schema/EventSequenceNumber.test.js.map +1 -1
  92. package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -1
  93. package/dist/schema/LiveStoreEvent/client.js +6 -3
  94. package/dist/schema/LiveStoreEvent/client.js.map +1 -1
  95. package/dist/schema/LiveStoreEvent/client.test.d.ts +2 -0
  96. package/dist/schema/LiveStoreEvent/client.test.d.ts.map +1 -0
  97. package/dist/schema/LiveStoreEvent/client.test.js +83 -0
  98. package/dist/schema/LiveStoreEvent/client.test.js.map +1 -0
  99. package/dist/schema/schema.d.ts.map +1 -1
  100. package/dist/schema/schema.js +7 -4
  101. package/dist/schema/schema.js.map +1 -1
  102. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
  103. package/dist/schema/state/sqlite/client-document-def.js +18 -6
  104. package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
  105. package/dist/schema/state/sqlite/client-document-def.test.js +1 -1
  106. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  107. package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
  108. package/dist/schema/state/sqlite/column-annotations.js +1 -1
  109. package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
  110. package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
  111. package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
  112. package/dist/schema/state/sqlite/column-def.d.ts.map +1 -1
  113. package/dist/schema/state/sqlite/column-def.js +36 -34
  114. package/dist/schema/state/sqlite/column-def.js.map +1 -1
  115. package/dist/schema/state/sqlite/column-def.test.js +7 -6
  116. package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
  117. package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
  118. package/dist/schema/state/sqlite/column-spec.js +8 -8
  119. package/dist/schema/state/sqlite/column-spec.js.map +1 -1
  120. package/dist/schema/state/sqlite/column-spec.test.js +1 -1
  121. package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
  122. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +2 -2
  123. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
  124. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +2 -2
  125. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
  126. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +11 -2
  127. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
  128. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js +1 -1
  129. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js.map +1 -1
  130. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts +1 -1
  131. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
  132. package/dist/schema/state/sqlite/db-schema/dsl/mod.js +1 -1
  133. package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
  134. package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
  135. package/dist/schema/state/sqlite/mod.js +3 -5
  136. package/dist/schema/state/sqlite/mod.js.map +1 -1
  137. package/dist/schema/state/sqlite/query-builder/api.d.ts +10 -2
  138. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  139. package/dist/schema/state/sqlite/query-builder/astToSql.js +11 -11
  140. package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
  141. package/dist/schema/state/sqlite/query-builder/impl.d.ts +1 -1
  142. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  143. package/dist/schema/state/sqlite/query-builder/impl.js +28 -14
  144. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  145. package/dist/schema/state/sqlite/query-builder/impl.test.js +3 -2
  146. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  147. package/dist/schema/state/sqlite/schema-helpers.js +2 -2
  148. package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
  149. package/dist/schema/state/sqlite/table-def.d.ts +5 -3
  150. package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
  151. package/dist/schema/state/sqlite/table-def.js +1 -1
  152. package/dist/schema/state/sqlite/table-def.js.map +1 -1
  153. package/dist/schema/state/sqlite/table-def.test.js +57 -4
  154. package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
  155. package/dist/schema/unknown-events.d.ts +1 -1
  156. package/dist/schema/unknown-events.d.ts.map +1 -1
  157. package/dist/schema/unknown-events.js +1 -1
  158. package/dist/schema/unknown-events.js.map +1 -1
  159. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +1 -1
  160. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -1
  161. package/dist/schema-management/common.js +2 -2
  162. package/dist/schema-management/common.js.map +1 -1
  163. package/dist/schema-management/migrations.js +1 -1
  164. package/dist/schema-management/migrations.js.map +1 -1
  165. package/dist/sql-queries/sql-queries.js +8 -6
  166. package/dist/sql-queries/sql-queries.js.map +1 -1
  167. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  168. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  169. package/dist/sqlite-db-helper.js +3 -3
  170. package/dist/sqlite-db-helper.js.map +1 -1
  171. package/dist/sqlite-types.d.ts +2 -2
  172. package/dist/sqlite-types.d.ts.map +1 -1
  173. package/dist/sqlite-types.js.map +1 -1
  174. package/dist/sync/ClientSessionSyncProcessor.d.ts +8 -9
  175. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  176. package/dist/sync/ClientSessionSyncProcessor.js +95 -113
  177. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  178. package/dist/sync/errors.d.ts +0 -38
  179. package/dist/sync/errors.d.ts.map +1 -1
  180. package/dist/sync/errors.js +3 -20
  181. package/dist/sync/errors.js.map +1 -1
  182. package/dist/sync/mock-sync-backend.d.ts +5 -3
  183. package/dist/sync/mock-sync-backend.d.ts.map +1 -1
  184. package/dist/sync/mock-sync-backend.js +70 -68
  185. package/dist/sync/mock-sync-backend.js.map +1 -1
  186. package/dist/sync/next/compact-events.js +6 -6
  187. package/dist/sync/next/compact-events.js.map +1 -1
  188. package/dist/sync/next/facts.d.ts.map +1 -1
  189. package/dist/sync/next/facts.js +6 -6
  190. package/dist/sync/next/facts.js.map +1 -1
  191. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  192. package/dist/sync/next/history-dag-common.js +6 -6
  193. package/dist/sync/next/history-dag-common.js.map +1 -1
  194. package/dist/sync/next/history-dag.js +3 -3
  195. package/dist/sync/next/history-dag.js.map +1 -1
  196. package/dist/sync/next/rebase-events.js +1 -1
  197. package/dist/sync/next/rebase-events.js.map +1 -1
  198. package/dist/sync/next/test/compact-events.calculator.test.js +2 -2
  199. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  200. package/dist/sync/next/test/compact-events.test.d.ts.map +1 -1
  201. package/dist/sync/next/test/compact-events.test.js +2 -2
  202. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  203. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
  204. package/dist/sync/next/test/event-fixtures.js +2 -2
  205. package/dist/sync/next/test/event-fixtures.js.map +1 -1
  206. package/dist/sync/sync-backend-kv.d.ts.map +1 -1
  207. package/dist/sync/sync-backend-kv.js.map +1 -1
  208. package/dist/sync/sync-backend.d.ts +3 -3
  209. package/dist/sync/sync-backend.d.ts.map +1 -1
  210. package/dist/sync/sync-backend.js +1 -1
  211. package/dist/sync/sync-backend.js.map +1 -1
  212. package/dist/sync/sync.d.ts +20 -0
  213. package/dist/sync/sync.d.ts.map +1 -1
  214. package/dist/sync/syncstate.d.ts +4 -17
  215. package/dist/sync/syncstate.d.ts.map +1 -1
  216. package/dist/sync/syncstate.js +51 -74
  217. package/dist/sync/syncstate.js.map +1 -1
  218. package/dist/sync/syncstate.test.js +112 -96
  219. package/dist/sync/syncstate.test.js.map +1 -1
  220. package/dist/sync/transport-chunking.js +3 -3
  221. package/dist/sync/transport-chunking.js.map +1 -1
  222. package/dist/sync/validate-push-payload.d.ts +2 -2
  223. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  224. package/dist/sync/validate-push-payload.js +4 -6
  225. package/dist/sync/validate-push-payload.js.map +1 -1
  226. package/dist/util.js +2 -2
  227. package/dist/util.js.map +1 -1
  228. package/dist/version.d.ts.map +1 -1
  229. package/dist/version.js +2 -5
  230. package/dist/version.js.map +1 -1
  231. package/package.json +66 -12
  232. package/src/ClientSessionLeaderThreadProxy.ts +9 -9
  233. package/src/WorkerTransportError.ts +12 -0
  234. package/src/adapter-types.ts +9 -3
  235. package/src/bounded-collections.ts +6 -5
  236. package/src/debug-info.ts +4 -4
  237. package/src/devtools/devtools-messages-common.ts +1 -1
  238. package/src/devtools/mod.ts +1 -1
  239. package/src/errors.ts +18 -17
  240. package/src/index.ts +2 -0
  241. package/src/leader-thread/LeaderSyncProcessor.ts +421 -392
  242. package/src/leader-thread/RejectedPushError.ts +106 -0
  243. package/src/leader-thread/connection.ts +1 -1
  244. package/src/leader-thread/eventlog.ts +16 -14
  245. package/src/leader-thread/leader-worker-devtools.ts +96 -66
  246. package/src/leader-thread/make-leader-thread-layer.test.ts +1 -1
  247. package/src/leader-thread/make-leader-thread-layer.ts +33 -31
  248. package/src/leader-thread/materialize-event.ts +4 -4
  249. package/src/leader-thread/recreate-db.ts +1 -1
  250. package/src/leader-thread/shutdown-channel.ts +2 -6
  251. package/src/leader-thread/stream-events.ts +10 -5
  252. package/src/leader-thread/types.ts +7 -6
  253. package/src/logging.ts +4 -4
  254. package/src/make-client-session.ts +2 -2
  255. package/src/materializer-helper.ts +9 -9
  256. package/src/otel.ts +3 -2
  257. package/src/rematerialize-from-eventlog.ts +60 -60
  258. package/src/schema/EventDef/define.ts +6 -6
  259. package/src/schema/EventDef/deprecated.test.ts +2 -1
  260. package/src/schema/EventDef/deprecated.ts +3 -3
  261. package/src/schema/EventSequenceNumber/client.ts +11 -11
  262. package/src/schema/EventSequenceNumber.test.ts +2 -1
  263. package/src/schema/LiveStoreEvent/client.test.ts +97 -0
  264. package/src/schema/LiveStoreEvent/client.ts +6 -3
  265. package/src/schema/schema.ts +9 -4
  266. package/src/schema/state/sqlite/client-document-def.test.ts +2 -1
  267. package/src/schema/state/sqlite/client-document-def.ts +20 -6
  268. package/src/schema/state/sqlite/column-annotations.test.ts +2 -1
  269. package/src/schema/state/sqlite/column-annotations.ts +2 -1
  270. package/src/schema/state/sqlite/column-def.test.ts +8 -6
  271. package/src/schema/state/sqlite/column-def.ts +41 -36
  272. package/src/schema/state/sqlite/column-spec.test.ts +3 -1
  273. package/src/schema/state/sqlite/column-spec.ts +9 -8
  274. package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +2 -2
  275. package/src/schema/state/sqlite/db-schema/dsl/field-defs.test.ts +2 -1
  276. package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +13 -4
  277. package/src/schema/state/sqlite/db-schema/dsl/mod.ts +3 -3
  278. package/src/schema/state/sqlite/mod.ts +4 -5
  279. package/src/schema/state/sqlite/query-builder/api.ts +12 -5
  280. package/src/schema/state/sqlite/query-builder/astToSql.ts +11 -11
  281. package/src/schema/state/sqlite/query-builder/impl.test.ts +4 -2
  282. package/src/schema/state/sqlite/query-builder/impl.ts +26 -12
  283. package/src/schema/state/sqlite/schema-helpers.ts +2 -2
  284. package/src/schema/state/sqlite/table-def.test.ts +67 -4
  285. package/src/schema/state/sqlite/table-def.ts +8 -15
  286. package/src/schema/unknown-events.ts +2 -2
  287. package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +3 -1
  288. package/src/schema-management/common.ts +2 -2
  289. package/src/schema-management/migrations.ts +1 -1
  290. package/src/sql-queries/sql-queries.ts +10 -6
  291. package/src/sql-queries/sql-query-builder.ts +1 -0
  292. package/src/sqlite-db-helper.ts +3 -3
  293. package/src/sqlite-types.ts +3 -2
  294. package/src/sync/ClientSessionSyncProcessor.ts +148 -152
  295. package/src/sync/errors.ts +10 -22
  296. package/src/sync/mock-sync-backend.ts +139 -97
  297. package/src/sync/next/compact-events.ts +5 -5
  298. package/src/sync/next/facts.ts +7 -6
  299. package/src/sync/next/history-dag-common.ts +9 -6
  300. package/src/sync/next/history-dag.ts +3 -3
  301. package/src/sync/next/rebase-events.ts +1 -1
  302. package/src/sync/next/test/compact-events.calculator.test.ts +3 -2
  303. package/src/sync/next/test/compact-events.test.ts +4 -3
  304. package/src/sync/next/test/event-fixtures.ts +2 -2
  305. package/src/sync/sync-backend-kv.ts +1 -0
  306. package/src/sync/sync-backend.ts +5 -4
  307. package/src/sync/sync.ts +21 -0
  308. package/src/sync/syncstate.test.ts +513 -435
  309. package/src/sync/syncstate.ts +80 -86
  310. package/src/sync/transport-chunking.ts +3 -3
  311. package/src/sync/validate-push-payload.ts +4 -6
  312. package/src/util.ts +2 -2
  313. package/src/version.ts +2 -6
@@ -1,5 +1,6 @@
1
1
  import type { Subscribable } from '@livestore/utils/effect'
2
2
  import { Chunk, Effect, Option, Queue, Stream } from '@livestore/utils/effect'
3
+
3
4
  import { EventSequenceNumber, type LiveStoreEvent } from '../schema/mod.ts'
4
5
  import type * as SyncState from '../sync/syncstate.ts'
5
6
  import * as Eventlog from './eventlog.ts'
@@ -109,7 +110,10 @@ export const streamEventsWithSyncState = ({
109
110
  * since === until : Prevent empty query
110
111
  * since > until : Incorrectly inverted interval
111
112
  */
112
- if (options.until && EventSequenceNumber.Client.isGreaterThanOrEqual(cursor, options.until)) {
113
+ if (
114
+ options.until !== undefined &&
115
+ EventSequenceNumber.Client.isGreaterThanOrEqual(cursor, options.until) === true
116
+ ) {
113
117
  return [Chunk.empty(), Option.none()]
114
118
  }
115
119
 
@@ -144,9 +148,10 @@ export const streamEventsWithSyncState = ({
144
148
  * nextHead: The latest head from headQueue
145
149
  */
146
150
  const waitForHead = EventSequenceNumber.Client.isGreaterThanOrEqual(cursor, head)
147
- const maybeHead = waitForHead
148
- ? yield* Queue.take(headQueue).pipe(Effect.map(Option.some))
149
- : yield* Queue.poll(headQueue)
151
+ const maybeHead =
152
+ waitForHead === true
153
+ ? yield* Queue.take(headQueue).pipe(Effect.map(Option.some))
154
+ : yield* Queue.poll(headQueue)
150
155
  const nextHead = Option.getOrElse(maybeHead, () => head)
151
156
  const hardStop = options.until?.global ?? Number.POSITIVE_INFINITY
152
157
  const target = EventSequenceNumber.Client.Composite.make({
@@ -181,7 +186,7 @@ export const streamEventsWithSyncState = ({
181
186
  const nextState: Option.Option<{
182
187
  cursor: EventSequenceNumber.Client.Composite
183
188
  head: EventSequenceNumber.Client.Composite
184
- }> = reachedUntil ? Option.none() : Option.some({ cursor: target, head: nextHead })
189
+ }> = reachedUntil === true ? Option.none() : Option.some({ cursor: target, head: nextHead })
185
190
 
186
191
  const spanAttributes = {
187
192
  'livestore.streamEvents.cursor.global': cursor.global,
@@ -17,13 +17,14 @@ import type { MaterializeError } from '../errors.ts'
17
17
  import type {
18
18
  BootStatus,
19
19
  Devtools,
20
- LeaderAheadError,
21
20
  MakeSqliteDb,
22
21
  PersistenceInfo,
23
22
  SqliteDb,
24
23
  SyncBackend,
25
24
  UnknownError,
25
+ UnknownEventError,
26
26
  } from '../index.ts'
27
+ import type { RejectedPushError } from './RejectedPushError.ts'
27
28
  import { EventSequenceNumber, type LiveStoreEvent, type LiveStoreSchema } from '../schema/mod.ts'
28
29
  import type * as SyncState from '../sync/syncstate.ts'
29
30
  import type { ShutdownChannel } from './shutdown-channel.ts'
@@ -186,11 +187,11 @@ export interface LeaderSyncProcessor {
186
187
  /** Used by client sessions to subscribe to upstream sync state changes */
187
188
  pull: (args: {
188
189
  cursor: EventSequenceNumber.Client.Composite
189
- }) => Stream.Stream<{ payload: typeof SyncState.PayloadUpstream.Type }, UnknownError>
190
+ }) => Stream.Stream<{ payload: typeof SyncState.PayloadUpstream.Type }>
190
191
  /** The `pullQueue` API can be used instead of `pull` when more convenient */
191
192
  pullQueue: (args: {
192
193
  cursor: EventSequenceNumber.Client.Composite
193
- }) => Effect.Effect<Queue.Queue<{ payload: typeof SyncState.PayloadUpstream.Type }>, UnknownError, Scope.Scope>
194
+ }) => Effect.Effect<Queue.Queue<{ payload: typeof SyncState.PayloadUpstream.Type }>, never, Scope.Scope>
194
195
 
195
196
  /** Used by client sessions to push events to the leader thread */
196
197
  push: (
@@ -204,18 +205,18 @@ export interface LeaderSyncProcessor {
204
205
  */
205
206
  waitForProcessing?: boolean
206
207
  },
207
- ) => Effect.Effect<void, LeaderAheadError>
208
+ ) => Effect.Effect<void, RejectedPushError>
208
209
 
209
210
  /** Currently only used by devtools which don't provide their own event numbers */
210
211
  pushPartial: (args: {
211
212
  event: LiveStoreEvent.Input.Encoded
212
213
  clientId: string
213
214
  sessionId: string
214
- }) => Effect.Effect<void, UnknownError>
215
+ }) => Effect.Effect<void, UnknownEventError>
215
216
 
216
217
  boot: Effect.Effect<
217
218
  { initialLeaderHead: EventSequenceNumber.Client.Composite },
218
- UnknownError,
219
+ never,
219
220
  LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient
220
221
  >
221
222
  syncState: Subscribable.Subscribable<SyncState.SyncState>
package/src/logging.ts CHANGED
@@ -33,11 +33,11 @@ export type LoggerDefaults = {
33
33
  * Resolve the logger layer to provide to the Effect runtime.
34
34
  */
35
35
  export const resolveLoggerLayer = (config?: WithLoggerOptions, defaults?: LoggerDefaults): Layer.Layer<never> => {
36
- if (config?.logger) return config.logger
37
- if (defaults?.defaultLogger) return defaults.defaultLogger
36
+ if (config?.logger !== undefined) return config.logger
37
+ if (defaults?.defaultLogger !== undefined) return defaults.defaultLogger
38
38
  const threadName = defaults?.threadName ?? 'livestore'
39
39
  const mode = defaults?.mode
40
- return Logger.prettyWithThread(threadName, mode ? { mode } : {})
40
+ return Logger.prettyWithThread(threadName, mode !== undefined ? { mode } : {})
41
41
  }
42
42
 
43
43
  /**
@@ -46,7 +46,7 @@ export const resolveLoggerLayer = (config?: WithLoggerOptions, defaults?: Logger
46
46
  export const resolveLogLevel = (config?: WithLoggerOptions, defaults?: LoggerDefaults): LogLevel.LogLevel => {
47
47
  if (config?.logLevel !== undefined) return config.logLevel
48
48
  if (defaults?.defaultLogLevel !== undefined) return defaults.defaultLogLevel
49
- return isDevEnv() ? LogLevel.Debug : LogLevel.Info
49
+ return isDevEnv() === true ? LogLevel.Debug : LogLevel.Info
50
50
  }
51
51
 
52
52
  /**
@@ -51,11 +51,11 @@ export const makeClientSession = <R>({
51
51
  origin: string | undefined
52
52
  }): Effect.Effect<ClientSession, never, Scope.Scope | R> =>
53
53
  Effect.gen(function* () {
54
- const devtools: ClientSession['devtools'] = devtoolsEnabled
54
+ const devtools: ClientSession['devtools'] = devtoolsEnabled === true
55
55
  ? { enabled: true, pullLatch: yield* Effect.makeLatch(true), pushLatch: yield* Effect.makeLatch(true) }
56
56
  : { enabled: false }
57
57
 
58
- if (devtoolsEnabled) {
58
+ if (devtoolsEnabled === true) {
59
59
  yield* Effect.gen(function* () {
60
60
  const webmeshNode = yield* Webmesh.makeMeshNode(
61
61
  Devtools.makeNodeName.client.session({ storeId, clientId, sessionId }),
@@ -34,14 +34,14 @@ export const getExecStatementsFromMaterializer = ({
34
34
  const eventDecoded =
35
35
  event.decoded === undefined
36
36
  ? {
37
- ...event.encoded!,
38
- args: Schema.decodeUnknownSync(eventDef.schema)(event.encoded!.args),
37
+ ...event.encoded,
38
+ args: Schema.decodeUnknownSync(eventDef.schema)(event.encoded.args),
39
39
  }
40
40
  : event.decoded
41
41
 
42
- const eventArgsEncoded = isNil(event.decoded?.args)
42
+ const eventArgsEncoded = isNil(event.decoded?.args) === true
43
43
  ? undefined
44
- : Schema.encodeUnknownSync(eventDef.schema)(event.decoded!.args)
44
+ : Schema.encodeUnknownSync(eventDef.schema)(event.decoded.args)
45
45
 
46
46
  const query: MaterializerContextQuery = (
47
47
  rawQueryOrQueryBuilder:
@@ -51,7 +51,7 @@ export const getExecStatementsFromMaterializer = ({
51
51
  }
52
52
  | QueryBuilder.Any,
53
53
  ) => {
54
- if (isQueryBuilder(rawQueryOrQueryBuilder)) {
54
+ if (isQueryBuilder(rawQueryOrQueryBuilder) === true) {
55
55
  const { query, bindValues } = rawQueryOrQueryBuilder.asSql()
56
56
  const rawResults = dbState.select(query, prepareBindValues(bindValues, query))
57
57
  const resultSchema = getResultSchema(rawQueryOrQueryBuilder)
@@ -86,7 +86,7 @@ export const getExecStatementsFromMaterializer = ({
86
86
  export const makeMaterializerHash =
87
87
  ({ schema, dbState }: { schema: LiveStoreSchema; dbState: SqliteDb }) =>
88
88
  (event: LiveStoreEvent.Client.Encoded): Option.Option<number> => {
89
- if (isDevEnv()) {
89
+ if (isDevEnv() === true) {
90
90
  // Hashing is only needed during dev-mode diagnostics. Skip work entirely for
91
91
  // unknown events (no definition/materializer) so we do not introduce noisy
92
92
  // warnings while still returning `Option.none()` to disable hash checks.
@@ -126,10 +126,10 @@ const fromMaterializerResult = (
126
126
  bindValues: BindValues
127
127
  writeTables: ReadonlySet<string> | undefined
128
128
  }> => {
129
- if (isReadonlyArray(materializerResult)) {
129
+ if (isReadonlyArray(materializerResult) === true) {
130
130
  return materializerResult.flatMap(fromMaterializerResult)
131
131
  }
132
- if (isQueryBuilder(materializerResult)) {
132
+ if (isQueryBuilder(materializerResult) === true) {
133
133
  const { query, bindValues, usedTables } = materializerResult.asSql()
134
134
  return [{ sql: query, bindValues: bindValues as BindValues, writeTables: usedTables }]
135
135
  } else if (typeof materializerResult === 'string') {
@@ -155,7 +155,7 @@ export const replaceSessionIdSymbol = (
155
155
  }
156
156
 
157
157
  const deepReplaceValue = <S, R>(input: any, searchValue: S, replaceValue: R): void => {
158
- if (Array.isArray(input)) {
158
+ if (Array.isArray(input) === true) {
159
159
  for (const i in input) {
160
160
  if (input[i] === searchValue) {
161
161
  input[i] = replaceValue
package/src/otel.ts CHANGED
@@ -1,6 +1,7 @@
1
+ import * as otel from '@opentelemetry/api'
2
+
1
3
  import { makeNoopTracer } from '@livestore/utils'
2
4
  import { Effect, identity, Layer, OtelTracer } from '@livestore/utils/effect'
3
- import * as otel from '@opentelemetry/api'
4
5
 
5
6
  export const OtelLiveDummy: Layer.Layer<OtelTracer.OtelTracer> = Layer.suspend(() => {
6
7
  const OtelTracerLive = Layer.succeed(OtelTracer.OtelTracer, makeNoopTracer())
@@ -22,7 +23,7 @@ export const provideOtel =
22
23
  ) as any as Layer.Layer<OtelTracer.OtelTracer>
23
24
 
24
25
  return effect.pipe(
25
- parentSpanContext
26
+ parentSpanContext !== undefined
26
27
  ? Effect.withParentSpan(OtelTracer.makeExternalSpan(otel.trace.getSpanContext(parentSpanContext)!))
27
28
  : identity,
28
29
  Effect.provide(TracingLive),
@@ -8,7 +8,10 @@ import { EventSequenceNumber, LiveStoreEvent, resolveEventDef, SystemTables } fr
8
8
  import type { PreparedBindValues } from './util.ts'
9
9
  import { sql } from './util.ts'
10
10
 
11
- export const rematerializeFromEventlog = ({
11
+ /** Parse JSON string to unknown value */
12
+ const jsonParse = Schema.decodeUnknownSync(Schema.parseJson())
13
+
14
+ export const rematerializeFromEventlog = Effect.fn('@livestore/common:rematerializeFromEventlog')(function* ({
12
15
  dbEventlog,
13
16
  // TODO re-use this db when bringing back the boot in-memory db implementation
14
17
  // db,
@@ -21,69 +24,69 @@ export const rematerializeFromEventlog = ({
21
24
  schema: LiveStoreSchema
22
25
  onProgress: (_: { done: number; total: number }) => Effect.Effect<void>
23
26
  materializeEvent: MaterializeEvent
24
- }) =>
25
- Effect.gen(function* () {
27
+ }) {
26
28
  const eventsCount = dbEventlog.select<{ count: number }>(
27
29
  `SELECT COUNT(*) AS count FROM ${SystemTables.EVENTLOG_META_TABLE}`,
28
30
  )[0]!.count
29
31
 
30
32
  const hashEventDef = memoizeByRef((event: EventDef.AnyWithoutFn) => Schema.hash(event.schema))
31
33
 
32
- const processEvent = (row: SystemTables.EventlogMetaRow) =>
33
- Effect.gen(function* () {
34
- const args = JSON.parse(row.argsJson)
35
- const eventEncoded = LiveStoreEvent.Client.EncodedWithMeta.make({
36
- name: row.name,
37
- args,
38
- seqNum: {
39
- global: row.seqNumGlobal,
40
- client: row.seqNumClient,
41
- rebaseGeneration: row.seqNumRebaseGeneration,
42
- },
43
- parentSeqNum: {
44
- global: row.parentSeqNumGlobal,
45
- client: row.parentSeqNumClient,
46
- rebaseGeneration: row.parentSeqNumRebaseGeneration,
47
- },
48
- clientId: row.clientId,
49
- sessionId: row.sessionId,
50
- })
51
-
52
- const resolution = yield* resolveEventDef(schema, {
53
- operation: '@livestore/common:rematerializeFromEventlog:processEvent',
54
- event: eventEncoded,
55
- }).pipe(UnknownError.mapToUnknownError)
56
-
57
- if (resolution._tag === 'unknown') {
58
- // Old snapshots can contain newer events. Skip until the runtime has
59
- // been updated; the event stays in the log for future replays.
60
- return
61
- }
62
-
63
- const { eventDef } = resolution
64
-
65
- if (hashEventDef(eventDef) !== row.schemaHash) {
66
- yield* Effect.logWarning(
67
- `Schema hash mismatch for event definition ${row.name}. Trying to materialize event anyway.`,
68
- )
69
- }
70
-
71
- // Checking whether the schema has changed in an incompatible way
72
- yield* Schema.decodeUnknown(eventDef.schema)(args).pipe(
73
- Effect.mapError((cause) =>
74
- UnknownError.make({
75
- cause,
76
- note: `\
34
+ const processEvent = Effect.fn(`@livestore/common:rematerializeFromEventlog:processEvent`)(function* (
35
+ row: SystemTables.EventlogMetaRow,
36
+ ) {
37
+ const args = jsonParse(row.argsJson)
38
+ const eventEncoded = LiveStoreEvent.Client.EncodedWithMeta.make({
39
+ name: row.name,
40
+ args,
41
+ seqNum: {
42
+ global: row.seqNumGlobal,
43
+ client: row.seqNumClient,
44
+ rebaseGeneration: row.seqNumRebaseGeneration,
45
+ },
46
+ parentSeqNum: {
47
+ global: row.parentSeqNumGlobal,
48
+ client: row.parentSeqNumClient,
49
+ rebaseGeneration: row.parentSeqNumRebaseGeneration,
50
+ },
51
+ clientId: row.clientId,
52
+ sessionId: row.sessionId,
53
+ })
54
+
55
+ const resolution = yield* resolveEventDef(schema, {
56
+ operation: '@livestore/common:rematerializeFromEventlog:processEvent',
57
+ event: eventEncoded,
58
+ }).pipe(UnknownError.mapToUnknownError)
59
+
60
+ if (resolution._tag === 'unknown') {
61
+ // Old snapshots can contain newer events. Skip until the runtime has
62
+ // been updated; the event stays in the log for future replays.
63
+ return
64
+ }
65
+
66
+ const { eventDef } = resolution
67
+
68
+ if (hashEventDef(eventDef) !== row.schemaHash) {
69
+ yield* Effect.logWarning(
70
+ `Schema hash mismatch for event definition ${row.name}. Trying to materialize event anyway.`,
71
+ )
72
+ }
73
+
74
+ // Checking whether the schema has changed in an incompatible way
75
+ yield* Schema.decodeUnknown(eventDef.schema)(args).pipe(
76
+ Effect.mapError((cause) =>
77
+ UnknownError.make({
78
+ cause,
79
+ note: `\
77
80
  There was an error during rematerializing from the eventlog while decoding
78
81
  the persisted event args for event definition "${row.name}".
79
82
  This likely means the schema has changed in an incompatible way.
80
83
  `,
81
- }),
82
- ),
83
- )
84
+ }),
85
+ ),
86
+ )
84
87
 
85
- yield* materializeEvent(eventEncoded, { skipEventlog: true })
86
- }).pipe(Effect.withSpan(`@livestore/common:rematerializeFromEventlog:processEvent`))
88
+ yield* materializeEvent(eventEncoded, { skipEventlog: true })
89
+ })
87
90
 
88
91
  const CHUNK_SIZE = 100
89
92
 
@@ -101,9 +104,9 @@ LIMIT ${CHUNK_SIZE}
101
104
  SystemTables.EventlogMetaRow
102
105
  >({ _tag: 'Initial' }, (item) => {
103
106
  // End stream if no more rows
104
- if (Chunk.isChunk(item) && item.length === 0) return Option.none()
107
+ if (Chunk.isChunk(item) === true && item.length === 0) return Option.none()
105
108
 
106
- const lastId = Chunk.isChunk(item)
109
+ const lastId = Chunk.isChunk(item) === true
107
110
  ? Chunk.last(item).pipe(
108
111
  Option.map((_) => ({ global: _.seqNumGlobal, client: _.seqNumClient })),
109
112
  Option.getOrElse(() => EventSequenceNumber.Client.ROOT),
@@ -115,7 +118,7 @@ LIMIT ${CHUNK_SIZE}
115
118
  $seqNumClient: lastId?.client,
116
119
  } as any as PreparedBindValues),
117
120
  )
118
- const prevItem = Chunk.isChunk(item) ? item : Chunk.empty()
121
+ const prevItem = Chunk.isChunk(item) === true ? item : Chunk.empty()
119
122
  return Option.some([prevItem, nextItem])
120
123
  }).pipe(
121
124
  Stream.bufferChunks({ capacity: 2 }),
@@ -129,7 +132,4 @@ LIMIT ${CHUNK_SIZE}
129
132
  ),
130
133
  Stream.runDrain,
131
134
  )
132
- }).pipe(
133
- Effect.withPerformanceMeasure('@livestore/common:rematerializeFromEventlog'),
134
- Effect.withSpan('@livestore/common:rematerializeFromEventlog'),
135
- )
135
+ }, Effect.withPerformanceMeasure('@livestore/common:rematerializeFromEventlog'))
@@ -127,15 +127,15 @@ export const defineEvent = <TName extends string, TType, TEncoded = TType, TDeri
127
127
  Object.defineProperty(makePartialEvent, 'options', {
128
128
  value: {
129
129
  clientOnly: options?.clientOnly ?? false,
130
- facts: options?.facts
130
+ facts: options?.facts !== undefined
131
131
  ? (args, currentFacts) => {
132
132
  const res = options.facts!(args, currentFacts)
133
133
  return {
134
134
  modify: {
135
- set: res.modify?.set ? new Set(res.modify.set) : new Set(),
136
- unset: res.modify?.unset ? new Set(res.modify.unset) : new Set(),
135
+ set: res.modify?.set !== undefined ? new Set(res.modify.set) : new Set(),
136
+ unset: res.modify?.unset !== undefined ? new Set(res.modify.unset) : new Set(),
137
137
  },
138
- require: res.require ? new Set(res.require) : new Set(),
138
+ require: res.require !== undefined ? new Set(res.require) : new Set(),
139
139
  }
140
140
  }
141
141
  : undefined,
@@ -179,7 +179,7 @@ export const synced = <TName extends string, TType, TEncoded = TType>(
179
179
  args: {
180
180
  name: TName
181
181
  schema: Schema.Schema<TType, TEncoded>
182
- } & Omit<DefineEventOptions<TType, false>, 'derived' | 'clientOnly'>,
182
+ } & Omit<DefineEventOptions<TType>, 'derived' | 'clientOnly'>,
183
183
  ): EventDef<TName, TType, TEncoded> => defineEvent({ ...args, clientOnly: false })
184
184
 
185
185
  /**
@@ -213,5 +213,5 @@ export const clientOnly = <TName extends string, TType, TEncoded = TType>(
213
213
  args: {
214
214
  name: TName
215
215
  schema: Schema.Schema<TType, TEncoded>
216
- } & Omit<DefineEventOptions<TType, false>, 'derived' | 'clientOnly'>,
216
+ } & Omit<DefineEventOptions<TType>, 'derived' | 'clientOnly'>,
217
217
  ): EventDef<TName, TType, TEncoded> => defineEvent({ ...args, clientOnly: true })
@@ -1,6 +1,7 @@
1
- import { Effect, Logger, Schema } from '@livestore/utils/effect'
2
1
  import { afterEach, beforeEach, describe, expect, test } from 'vitest'
3
2
 
3
+ import { Effect, Logger, Schema } from '@livestore/utils/effect'
4
+
4
5
  import { synced } from './define.ts'
5
6
  import {
6
7
  deprecated,
@@ -109,7 +109,7 @@ export const findDeprecatedFieldsWithValues = (
109
109
  // Also check deprecation on the type (for direct field deprecation)
110
110
  const typeDeprecation = SchemaAST.getAnnotation<string>(DeprecatedId)(prop.type)
111
111
 
112
- const reason = deprecationReason ?? (Option.isSome(typeDeprecation) ? typeDeprecation.value : undefined)
112
+ const reason = deprecationReason ?? (Option.isSome(typeDeprecation) === true ? typeDeprecation.value : undefined)
113
113
  if (reason !== undefined) {
114
114
  result.push({ field: fieldName, reason })
115
115
  }
@@ -143,7 +143,7 @@ export const logDeprecationWarnings = (
143
143
 
144
144
  // Check for event-level deprecation
145
145
  const eventDeprecation = eventDef.options.deprecated
146
- if (eventDeprecation !== undefined && !warnedDeprecatedEvents.has(eventName)) {
146
+ if (eventDeprecation !== undefined && warnedDeprecatedEvents.has(eventName) === false) {
147
147
  warnedDeprecatedEvents.add(eventName)
148
148
  yield* Effect.logWarning('@livestore/schema:deprecated-event', {
149
149
  event: eventName,
@@ -155,7 +155,7 @@ export const logDeprecationWarnings = (
155
155
  const deprecatedFields = findDeprecatedFieldsWithValues(eventDef.schema, args)
156
156
  for (const { field, reason } of deprecatedFields) {
157
157
  const key = `${eventName}:${field}`
158
- if (!warnedDeprecatedFields.has(key)) {
158
+ if (warnedDeprecatedFields.has(key) === false) {
159
159
  warnedDeprecatedFields.add(key)
160
160
  yield* Effect.logWarning('@livestore/schema:deprecated-field', {
161
161
  event: eventName,
@@ -28,7 +28,7 @@ export const make = ClientBrand
28
28
  * const defaultSeq = EventSequenceNumber.Client.DEFAULT // 0
29
29
  * ```
30
30
  */
31
- export const DEFAULT = 0 as any as Type
31
+ export const DEFAULT = make(0)
32
32
 
33
33
  /** Default rebase generation (0). Increments each time the client rebases unconfirmed events. */
34
34
  export const REBASE_GENERATION_DEFAULT = 0
@@ -91,7 +91,7 @@ export const toString = (seqNum: Composite) => {
91
91
  * For full notation documentation, see: contributor-docs/events-notation.md
92
92
  */
93
93
  export const fromString = (str: string): Composite => {
94
- if (!str.startsWith('e')) {
94
+ if (str.startsWith('e') === false) {
95
95
  throw new Error('Invalid event sequence number string: must start with "e"')
96
96
  }
97
97
 
@@ -111,24 +111,24 @@ export const fromString = (str: string): Composite => {
111
111
  const parts = withoutRebase.split('.')
112
112
 
113
113
  // Validate that parts contain only digits (and possibly empty for client)
114
- if (parts[0] === '' || !/^\d+$/.test(parts[0]!)) {
114
+ if (parts[0] === '' || /^\d+$/.test(parts[0]!) === false) {
115
115
  throw new Error('Invalid event sequence number string: invalid number format')
116
116
  }
117
117
 
118
- if (parts.length > 1 && parts[1] !== undefined && (parts[1] === '' || !/^\d+$/.test(parts[1]))) {
118
+ if (parts.length > 1 && parts[1] !== undefined && (parts[1] === '' || /^\d+$/.test(parts[1]) === false)) {
119
119
  throw new Error('Invalid event sequence number string: invalid number format')
120
120
  }
121
121
 
122
122
  const global = Number.parseInt(parts[0]!, 10)
123
123
  const client = parts.length > 1 && parts[1] !== undefined ? Number.parseInt(parts[1], 10) : 0
124
124
 
125
- if (Number.isNaN(global) || Number.isNaN(client) || Number.isNaN(rebaseGeneration)) {
125
+ if (Number.isNaN(global) === true || Number.isNaN(client) === true || Number.isNaN(rebaseGeneration) === true) {
126
126
  throw new TypeError('Invalid event sequence number string: invalid number format')
127
127
  }
128
128
 
129
129
  return {
130
- global: global as any as Global,
131
- client: client as any as Type,
130
+ global: makeGlobal(global),
131
+ client: make(client),
132
132
  rebaseGeneration,
133
133
  }
134
134
  }
@@ -187,7 +187,7 @@ const CompositeSchema = S.Struct({
187
187
  * If rebaseGeneration is omitted, defaults to REBASE_GENERATION_DEFAULT (0).
188
188
  */
189
189
  const makeComposite = (seqNum: CompositeInput): Composite => {
190
- return S.is(CompositeSchema)(seqNum)
190
+ return S.is(CompositeSchema)(seqNum) === true
191
191
  ? seqNum
192
192
  : S.decodeSync(CompositeSchema)({
193
193
  ...seqNum,
@@ -234,11 +234,11 @@ export const nextPair = ({
234
234
  isClient: boolean
235
235
  rebaseGeneration?: number
236
236
  }): CompositePair => {
237
- if (isClient) {
237
+ if (isClient === true) {
238
238
  return {
239
239
  seqNum: {
240
240
  global: seqNum.global,
241
- client: (seqNum.client + 1) as any as Type,
241
+ client: make(seqNum.client + 1),
242
242
  rebaseGeneration: rebaseGeneration ?? seqNum.rebaseGeneration,
243
243
  },
244
244
  parentSeqNum: seqNum,
@@ -247,7 +247,7 @@ export const nextPair = ({
247
247
 
248
248
  return {
249
249
  seqNum: {
250
- global: (seqNum.global + 1) as any as Global,
250
+ global: makeGlobal(seqNum.global + 1),
251
251
  client: DEFAULT,
252
252
  rebaseGeneration: rebaseGeneration ?? seqNum.rebaseGeneration,
253
253
  },
@@ -1,6 +1,7 @@
1
- import { Vitest } from '@livestore/utils-dev/node-vitest'
2
1
  import { expect } from 'vitest'
3
2
 
3
+ import { Vitest } from '@livestore/utils-dev/node-vitest'
4
+
4
5
  import { EventSequenceNumber } from './mod.ts'
5
6
 
6
7
  Vitest.describe('EventSequenceNumber', () => {
@@ -0,0 +1,97 @@
1
+ import { expect } from 'vitest'
2
+
3
+ import { Option } from '@livestore/utils/effect'
4
+ import { Vitest } from '@livestore/utils-dev/node-vitest'
5
+
6
+ import * as EventSequenceNumber from '../EventSequenceNumber/mod.ts'
7
+ import { EncodedWithMeta, isEqualEncoded, type Encoded } from './client.ts'
8
+
9
+ Vitest.describe('EncodedWithMeta', () => {
10
+ Vitest.test('toGlobal() produces numeric seqNums through JSON.stringify', () => {
11
+ const event = new EncodedWithMeta({
12
+ name: 'test-v1',
13
+ args: { id: '1' },
14
+ seqNum: EventSequenceNumber.Client.Composite.make({ global: 5, client: 0 }),
15
+ parentSeqNum: EventSequenceNumber.Client.Composite.make({ global: 4, client: 0 }),
16
+ clientId: 'client-1',
17
+ sessionId: 'session-1',
18
+ meta: {
19
+ sessionChangeset: { _tag: 'unset' },
20
+ syncMetadata: Option.none(),
21
+ materializerHashLeader: Option.none(),
22
+ materializerHashSession: Option.none(),
23
+ },
24
+ })
25
+
26
+ const global = event.toGlobal()
27
+ const parsed = JSON.parse(JSON.stringify(global))
28
+
29
+ expect(parsed.seqNum).toBe(5)
30
+ expect(parsed.parentSeqNum).toBe(4)
31
+ })
32
+ })
33
+
34
+ Vitest.describe('isEqualEncoded', () => {
35
+ const makeEncodedEvent = (args: unknown): Encoded => ({
36
+ name: 'testEvent-v1',
37
+ args,
38
+ seqNum: EventSequenceNumber.Client.Composite.make({ global: 1, client: 0 }),
39
+ parentSeqNum: EventSequenceNumber.Client.Composite.make(EventSequenceNumber.Client.ROOT),
40
+ clientId: 'client-1',
41
+ sessionId: 'session-1',
42
+ })
43
+
44
+ Vitest.it('should consider events with identical args as equal', () => {
45
+ const a = makeEncodedEvent({ id: 'abc', text: 'hello' })
46
+ const b = makeEncodedEvent({ id: 'abc', text: 'hello' })
47
+ expect(isEqualEncoded(a, b)).toBe(true)
48
+ })
49
+
50
+ Vitest.it('should consider events with different key order in args as equal', () => {
51
+ const a = makeEncodedEvent({ b: 2, a: 1 })
52
+ const b = makeEncodedEvent({ a: 1, b: 2 })
53
+ expect(isEqualEncoded(a, b)).toBe(true)
54
+ })
55
+
56
+ Vitest.it('should consider events with different key order in nested args as equal', () => {
57
+ const a = makeEncodedEvent({ outer: { b: 2, a: 1 }, x: 'y' })
58
+ const b = makeEncodedEvent({ x: 'y', outer: { a: 1, b: 2 } })
59
+ expect(isEqualEncoded(a, b)).toBe(true)
60
+ })
61
+
62
+ Vitest.it('should consider events with different args values as not equal', () => {
63
+ const a = makeEncodedEvent({ id: 'abc' })
64
+ const b = makeEncodedEvent({ id: 'def' })
65
+ expect(isEqualEncoded(a, b)).toBe(false)
66
+ })
67
+
68
+ Vitest.it('should consider events with different args keys as not equal', () => {
69
+ const a = makeEncodedEvent({ a: 1 })
70
+ const b = makeEncodedEvent({ b: 1 })
71
+ expect(isEqualEncoded(a, b)).toBe(false)
72
+ })
73
+
74
+ Vitest.it('should handle null args', () => {
75
+ const a = makeEncodedEvent(null)
76
+ const b = makeEncodedEvent(null)
77
+ expect(isEqualEncoded(a, b)).toBe(true)
78
+ })
79
+
80
+ Vitest.it('should handle array args', () => {
81
+ const a = makeEncodedEvent([1, 2, 3])
82
+ const b = makeEncodedEvent([1, 2, 3])
83
+ expect(isEqualEncoded(a, b)).toBe(true)
84
+ })
85
+
86
+ Vitest.it('should handle empty object args', () => {
87
+ const a = makeEncodedEvent({})
88
+ const b = makeEncodedEvent({})
89
+ expect(isEqualEncoded(a, b)).toBe(true)
90
+ })
91
+
92
+ Vitest.it('should consider events with different names as not equal', () => {
93
+ const a = { ...makeEncodedEvent({ id: 'abc' }), name: 'eventA' }
94
+ const b = { ...makeEncodedEvent({ id: 'abc' }), name: 'eventB' }
95
+ expect(isEqualEncoded(a, b)).toBe(false)
96
+ })
97
+ })