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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ClientSessionLeaderThreadProxy.d.ts +16 -9
  3. package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
  4. package/dist/ClientSessionLeaderThreadProxy.js.map +1 -1
  5. package/dist/WorkerTransportError.d.ts +11 -0
  6. package/dist/WorkerTransportError.d.ts.map +1 -0
  7. package/dist/WorkerTransportError.js +11 -0
  8. package/dist/WorkerTransportError.js.map +1 -0
  9. package/dist/adapter-types.d.ts +26 -3
  10. package/dist/adapter-types.d.ts.map +1 -1
  11. package/dist/adapter-types.js +27 -1
  12. package/dist/adapter-types.js.map +1 -1
  13. package/dist/bounded-collections.d.ts.map +1 -1
  14. package/dist/bounded-collections.js +6 -4
  15. package/dist/bounded-collections.js.map +1 -1
  16. package/dist/debug-info.js +4 -4
  17. package/dist/debug-info.js.map +1 -1
  18. package/dist/devtools/devtools-messages-client-session.d.ts +42 -22
  19. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
  20. package/dist/devtools/devtools-messages-client-session.js +12 -1
  21. package/dist/devtools/devtools-messages-client-session.js.map +1 -1
  22. package/dist/devtools/devtools-messages-common.d.ts +12 -6
  23. package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
  24. package/dist/devtools/devtools-messages-common.js +8 -3
  25. package/dist/devtools/devtools-messages-common.js.map +1 -1
  26. package/dist/devtools/devtools-messages-leader.d.ts +45 -25
  27. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  28. package/dist/devtools/devtools-messages-leader.js +12 -1
  29. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  30. package/dist/devtools/mod.js +1 -1
  31. package/dist/devtools/mod.js.map +1 -1
  32. package/dist/errors.d.ts +15 -15
  33. package/dist/errors.d.ts.map +1 -1
  34. package/dist/errors.js +11 -11
  35. package/dist/errors.js.map +1 -1
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +2 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/leader-thread/LeaderSyncProcessor.d.ts +20 -6
  41. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  42. package/dist/leader-thread/LeaderSyncProcessor.js +283 -253
  43. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  44. package/dist/leader-thread/RejectedPushError.d.ts +107 -0
  45. package/dist/leader-thread/RejectedPushError.d.ts.map +1 -0
  46. package/dist/leader-thread/RejectedPushError.js +78 -0
  47. package/dist/leader-thread/RejectedPushError.js.map +1 -0
  48. package/dist/leader-thread/connection.js +1 -1
  49. package/dist/leader-thread/connection.js.map +1 -1
  50. package/dist/leader-thread/eventlog.d.ts.map +1 -1
  51. package/dist/leader-thread/eventlog.js +12 -11
  52. package/dist/leader-thread/eventlog.js.map +1 -1
  53. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -2
  54. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  55. package/dist/leader-thread/leader-worker-devtools.js +34 -14
  56. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  57. package/dist/leader-thread/make-leader-thread-layer.d.ts +12 -5
  58. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  59. package/dist/leader-thread/make-leader-thread-layer.js +12 -11
  60. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  61. package/dist/leader-thread/make-leader-thread-layer.test.js +1 -1
  62. package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -1
  63. package/dist/leader-thread/materialize-event.d.ts.map +1 -1
  64. package/dist/leader-thread/materialize-event.js +7 -4
  65. package/dist/leader-thread/materialize-event.js.map +1 -1
  66. package/dist/leader-thread/recreate-db.js +1 -1
  67. package/dist/leader-thread/recreate-db.js.map +1 -1
  68. package/dist/leader-thread/shutdown-channel.d.ts +2 -2
  69. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  70. package/dist/leader-thread/shutdown-channel.js +2 -2
  71. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  72. package/dist/leader-thread/stream-events.d.ts.map +1 -1
  73. package/dist/leader-thread/stream-events.js +4 -3
  74. package/dist/leader-thread/stream-events.js.map +1 -1
  75. package/dist/leader-thread/types.d.ts +7 -6
  76. package/dist/leader-thread/types.d.ts.map +1 -1
  77. package/dist/leader-thread/types.js.map +1 -1
  78. package/dist/logging.js +4 -4
  79. package/dist/logging.js.map +1 -1
  80. package/dist/make-client-session.js +2 -2
  81. package/dist/make-client-session.js.map +1 -1
  82. package/dist/materializer-helper.js +6 -6
  83. package/dist/materializer-helper.js.map +1 -1
  84. package/dist/otel.d.ts +1 -1
  85. package/dist/otel.d.ts.map +1 -1
  86. package/dist/otel.js +2 -2
  87. package/dist/otel.js.map +1 -1
  88. package/dist/rematerialize-from-eventlog.d.ts +1 -1
  89. package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
  90. package/dist/rematerialize-from-eventlog.js +11 -9
  91. package/dist/rematerialize-from-eventlog.js.map +1 -1
  92. package/dist/schema/EventDef/define.d.ts +16 -2
  93. package/dist/schema/EventDef/define.d.ts.map +1 -1
  94. package/dist/schema/EventDef/define.js +5 -4
  95. package/dist/schema/EventDef/define.js.map +1 -1
  96. package/dist/schema/EventDef/deprecated.d.ts +99 -0
  97. package/dist/schema/EventDef/deprecated.d.ts.map +1 -0
  98. package/dist/schema/EventDef/deprecated.js +144 -0
  99. package/dist/schema/EventDef/deprecated.js.map +1 -0
  100. package/dist/schema/EventDef/deprecated.test.d.ts +2 -0
  101. package/dist/schema/EventDef/deprecated.test.d.ts.map +1 -0
  102. package/dist/schema/EventDef/deprecated.test.js +95 -0
  103. package/dist/schema/EventDef/deprecated.test.js.map +1 -0
  104. package/dist/schema/EventDef/event-def.d.ts +4 -0
  105. package/dist/schema/EventDef/event-def.d.ts.map +1 -1
  106. package/dist/schema/EventDef/mod.d.ts +1 -0
  107. package/dist/schema/EventDef/mod.d.ts.map +1 -1
  108. package/dist/schema/EventDef/mod.js +1 -0
  109. package/dist/schema/EventDef/mod.js.map +1 -1
  110. package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -1
  111. package/dist/schema/EventSequenceNumber/client.js +11 -11
  112. package/dist/schema/EventSequenceNumber/client.js.map +1 -1
  113. package/dist/schema/EventSequenceNumber.test.js +1 -1
  114. package/dist/schema/EventSequenceNumber.test.js.map +1 -1
  115. package/dist/schema/LiveStoreEvent/client.d.ts +6 -6
  116. package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -1
  117. package/dist/schema/LiveStoreEvent/client.js +6 -3
  118. package/dist/schema/LiveStoreEvent/client.js.map +1 -1
  119. package/dist/schema/LiveStoreEvent/client.test.d.ts +2 -0
  120. package/dist/schema/LiveStoreEvent/client.test.d.ts.map +1 -0
  121. package/dist/schema/LiveStoreEvent/client.test.js +83 -0
  122. package/dist/schema/LiveStoreEvent/client.test.js.map +1 -0
  123. package/dist/schema/schema.d.ts.map +1 -1
  124. package/dist/schema/schema.js +7 -4
  125. package/dist/schema/schema.js.map +1 -1
  126. package/dist/schema/state/sqlite/client-document-def.d.ts +1 -0
  127. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
  128. package/dist/schema/state/sqlite/client-document-def.js +34 -13
  129. package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
  130. package/dist/schema/state/sqlite/client-document-def.test.js +121 -2
  131. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  132. package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
  133. package/dist/schema/state/sqlite/column-annotations.js +1 -1
  134. package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
  135. package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
  136. package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
  137. package/dist/schema/state/sqlite/column-def.d.ts.map +1 -1
  138. package/dist/schema/state/sqlite/column-def.js +36 -34
  139. package/dist/schema/state/sqlite/column-def.js.map +1 -1
  140. package/dist/schema/state/sqlite/column-def.test.js +7 -6
  141. package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
  142. package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
  143. package/dist/schema/state/sqlite/column-spec.js +8 -8
  144. package/dist/schema/state/sqlite/column-spec.js.map +1 -1
  145. package/dist/schema/state/sqlite/column-spec.test.js +1 -1
  146. package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
  147. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +2 -2
  148. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
  149. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +2 -2
  150. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
  151. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +11 -2
  152. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
  153. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js +1 -1
  154. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js.map +1 -1
  155. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts +1 -1
  156. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
  157. package/dist/schema/state/sqlite/db-schema/dsl/mod.js +1 -1
  158. package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
  159. package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
  160. package/dist/schema/state/sqlite/mod.js +3 -5
  161. package/dist/schema/state/sqlite/mod.js.map +1 -1
  162. package/dist/schema/state/sqlite/query-builder/api.d.ts +37 -13
  163. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  164. package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -1
  165. package/dist/schema/state/sqlite/query-builder/astToSql.js +77 -7
  166. package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
  167. package/dist/schema/state/sqlite/query-builder/impl.d.ts +1 -1
  168. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  169. package/dist/schema/state/sqlite/query-builder/impl.js +28 -14
  170. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  171. package/dist/schema/state/sqlite/query-builder/impl.test.js +112 -3
  172. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  173. package/dist/schema/state/sqlite/schema-helpers.js +2 -2
  174. package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
  175. package/dist/schema/state/sqlite/table-def.d.ts +5 -3
  176. package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
  177. package/dist/schema/state/sqlite/table-def.js +1 -1
  178. package/dist/schema/state/sqlite/table-def.js.map +1 -1
  179. package/dist/schema/state/sqlite/table-def.test.js +57 -4
  180. package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
  181. package/dist/schema/unknown-events.d.ts +1 -1
  182. package/dist/schema/unknown-events.d.ts.map +1 -1
  183. package/dist/schema/unknown-events.js +1 -1
  184. package/dist/schema/unknown-events.js.map +1 -1
  185. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +1 -1
  186. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -1
  187. package/dist/schema-management/common.js +2 -2
  188. package/dist/schema-management/common.js.map +1 -1
  189. package/dist/schema-management/migrations.js +1 -1
  190. package/dist/schema-management/migrations.js.map +1 -1
  191. package/dist/sql-queries/sql-queries.js +8 -6
  192. package/dist/sql-queries/sql-queries.js.map +1 -1
  193. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  194. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  195. package/dist/sqlite-db-helper.js +3 -3
  196. package/dist/sqlite-db-helper.js.map +1 -1
  197. package/dist/sqlite-types.d.ts +2 -2
  198. package/dist/sqlite-types.d.ts.map +1 -1
  199. package/dist/sqlite-types.js.map +1 -1
  200. package/dist/sync/ClientSessionSyncProcessor.d.ts +8 -9
  201. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  202. package/dist/sync/ClientSessionSyncProcessor.js +93 -107
  203. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  204. package/dist/sync/errors.d.ts +0 -38
  205. package/dist/sync/errors.d.ts.map +1 -1
  206. package/dist/sync/errors.js +3 -20
  207. package/dist/sync/errors.js.map +1 -1
  208. package/dist/sync/mock-sync-backend.d.ts +5 -3
  209. package/dist/sync/mock-sync-backend.d.ts.map +1 -1
  210. package/dist/sync/mock-sync-backend.js +70 -68
  211. package/dist/sync/mock-sync-backend.js.map +1 -1
  212. package/dist/sync/next/compact-events.js +6 -6
  213. package/dist/sync/next/compact-events.js.map +1 -1
  214. package/dist/sync/next/facts.d.ts.map +1 -1
  215. package/dist/sync/next/facts.js +6 -6
  216. package/dist/sync/next/facts.js.map +1 -1
  217. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  218. package/dist/sync/next/history-dag-common.js +6 -6
  219. package/dist/sync/next/history-dag-common.js.map +1 -1
  220. package/dist/sync/next/history-dag.js +3 -3
  221. package/dist/sync/next/history-dag.js.map +1 -1
  222. package/dist/sync/next/rebase-events.js +1 -1
  223. package/dist/sync/next/rebase-events.js.map +1 -1
  224. package/dist/sync/next/test/compact-events.calculator.test.js +2 -2
  225. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  226. package/dist/sync/next/test/compact-events.test.d.ts.map +1 -1
  227. package/dist/sync/next/test/compact-events.test.js +2 -2
  228. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  229. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
  230. package/dist/sync/next/test/event-fixtures.js +2 -2
  231. package/dist/sync/next/test/event-fixtures.js.map +1 -1
  232. package/dist/sync/sync-backend-kv.d.ts.map +1 -1
  233. package/dist/sync/sync-backend-kv.js.map +1 -1
  234. package/dist/sync/sync-backend.d.ts +3 -3
  235. package/dist/sync/sync-backend.d.ts.map +1 -1
  236. package/dist/sync/sync-backend.js +1 -1
  237. package/dist/sync/sync-backend.js.map +1 -1
  238. package/dist/sync/sync.d.ts +20 -0
  239. package/dist/sync/sync.d.ts.map +1 -1
  240. package/dist/sync/syncstate.d.ts +4 -17
  241. package/dist/sync/syncstate.d.ts.map +1 -1
  242. package/dist/sync/syncstate.js +51 -74
  243. package/dist/sync/syncstate.js.map +1 -1
  244. package/dist/sync/syncstate.test.js +112 -96
  245. package/dist/sync/syncstate.test.js.map +1 -1
  246. package/dist/sync/transport-chunking.js +3 -3
  247. package/dist/sync/transport-chunking.js.map +1 -1
  248. package/dist/sync/validate-push-payload.d.ts +2 -2
  249. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  250. package/dist/sync/validate-push-payload.js +4 -6
  251. package/dist/sync/validate-push-payload.js.map +1 -1
  252. package/dist/util.js +2 -2
  253. package/dist/util.js.map +1 -1
  254. package/dist/version.d.ts +7 -1
  255. package/dist/version.d.ts.map +1 -1
  256. package/dist/version.js +8 -4
  257. package/dist/version.js.map +1 -1
  258. package/package.json +66 -12
  259. package/src/ClientSessionLeaderThreadProxy.ts +16 -9
  260. package/src/WorkerTransportError.ts +12 -0
  261. package/src/adapter-types.ts +39 -3
  262. package/src/bounded-collections.ts +6 -5
  263. package/src/debug-info.ts +4 -4
  264. package/src/devtools/devtools-messages-client-session.ts +12 -0
  265. package/src/devtools/devtools-messages-common.ts +8 -4
  266. package/src/devtools/devtools-messages-leader.ts +12 -0
  267. package/src/devtools/mod.ts +1 -1
  268. package/src/errors.ts +18 -17
  269. package/src/index.ts +2 -0
  270. package/src/leader-thread/LeaderSyncProcessor.ts +417 -347
  271. package/src/leader-thread/RejectedPushError.ts +106 -0
  272. package/src/leader-thread/connection.ts +1 -1
  273. package/src/leader-thread/eventlog.ts +16 -14
  274. package/src/leader-thread/leader-worker-devtools.ts +107 -66
  275. package/src/leader-thread/make-leader-thread-layer.test.ts +1 -1
  276. package/src/leader-thread/make-leader-thread-layer.ts +41 -31
  277. package/src/leader-thread/materialize-event.ts +8 -4
  278. package/src/leader-thread/recreate-db.ts +1 -1
  279. package/src/leader-thread/shutdown-channel.ts +2 -6
  280. package/src/leader-thread/stream-events.ts +10 -5
  281. package/src/leader-thread/types.ts +7 -6
  282. package/src/logging.ts +4 -4
  283. package/src/make-client-session.ts +2 -2
  284. package/src/materializer-helper.ts +9 -9
  285. package/src/otel.ts +3 -2
  286. package/src/rematerialize-from-eventlog.ts +60 -60
  287. package/src/schema/EventDef/define.ts +22 -6
  288. package/src/schema/EventDef/deprecated.test.ts +129 -0
  289. package/src/schema/EventDef/deprecated.ts +175 -0
  290. package/src/schema/EventDef/event-def.ts +5 -0
  291. package/src/schema/EventDef/mod.ts +1 -0
  292. package/src/schema/EventSequenceNumber/client.ts +11 -11
  293. package/src/schema/EventSequenceNumber.test.ts +2 -1
  294. package/src/schema/LiveStoreEvent/client.test.ts +97 -0
  295. package/src/schema/LiveStoreEvent/client.ts +6 -3
  296. package/src/schema/schema.ts +9 -4
  297. package/src/schema/state/sqlite/client-document-def.test.ts +142 -3
  298. package/src/schema/state/sqlite/client-document-def.ts +37 -14
  299. package/src/schema/state/sqlite/column-annotations.test.ts +2 -1
  300. package/src/schema/state/sqlite/column-annotations.ts +2 -1
  301. package/src/schema/state/sqlite/column-def.test.ts +8 -6
  302. package/src/schema/state/sqlite/column-def.ts +41 -36
  303. package/src/schema/state/sqlite/column-spec.test.ts +3 -1
  304. package/src/schema/state/sqlite/column-spec.ts +9 -8
  305. package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +2 -2
  306. package/src/schema/state/sqlite/db-schema/dsl/field-defs.test.ts +2 -1
  307. package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +13 -4
  308. package/src/schema/state/sqlite/db-schema/dsl/mod.ts +3 -3
  309. package/src/schema/state/sqlite/mod.ts +4 -5
  310. package/src/schema/state/sqlite/query-builder/api.ts +37 -8
  311. package/src/schema/state/sqlite/query-builder/astToSql.ts +87 -7
  312. package/src/schema/state/sqlite/query-builder/impl.test.ts +145 -3
  313. package/src/schema/state/sqlite/query-builder/impl.ts +26 -12
  314. package/src/schema/state/sqlite/schema-helpers.ts +2 -2
  315. package/src/schema/state/sqlite/table-def.test.ts +67 -4
  316. package/src/schema/state/sqlite/table-def.ts +8 -15
  317. package/src/schema/unknown-events.ts +2 -2
  318. package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +3 -1
  319. package/src/schema-management/common.ts +2 -2
  320. package/src/schema-management/migrations.ts +1 -1
  321. package/src/sql-queries/sql-queries.ts +10 -6
  322. package/src/sql-queries/sql-query-builder.ts +1 -0
  323. package/src/sqlite-db-helper.ts +3 -3
  324. package/src/sqlite-types.ts +3 -2
  325. package/src/sync/ClientSessionSyncProcessor.ts +142 -133
  326. package/src/sync/errors.ts +10 -22
  327. package/src/sync/mock-sync-backend.ts +139 -97
  328. package/src/sync/next/compact-events.ts +5 -5
  329. package/src/sync/next/facts.ts +7 -6
  330. package/src/sync/next/history-dag-common.ts +9 -6
  331. package/src/sync/next/history-dag.ts +3 -3
  332. package/src/sync/next/rebase-events.ts +1 -1
  333. package/src/sync/next/test/compact-events.calculator.test.ts +3 -2
  334. package/src/sync/next/test/compact-events.test.ts +4 -3
  335. package/src/sync/next/test/event-fixtures.ts +2 -2
  336. package/src/sync/sync-backend-kv.ts +1 -0
  337. package/src/sync/sync-backend.ts +5 -4
  338. package/src/sync/sync.ts +21 -0
  339. package/src/sync/syncstate.test.ts +513 -435
  340. package/src/sync/syncstate.ts +80 -86
  341. package/src/sync/transport-chunking.ts +3 -3
  342. package/src/sync/validate-push-payload.ts +4 -6
  343. package/src/util.ts +2 -2
  344. package/src/version.ts +8 -4
@@ -2,10 +2,8 @@ import type { WebChannel } from '@livestore/utils/effect'
2
2
  import { Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import {
5
+ BackendIdMismatchError,
5
6
  IntentionalShutdownCause,
6
- InvalidPullError,
7
- InvalidPushError,
8
- IsOfflineError,
9
7
  MaterializeError,
10
8
  UnknownError,
11
9
  } from '../index.ts'
@@ -13,9 +11,7 @@ import {
13
11
  export class All extends Schema.Union(
14
12
  IntentionalShutdownCause,
15
13
  UnknownError,
16
- IsOfflineError,
17
- InvalidPushError,
18
- InvalidPullError,
14
+ BackendIdMismatchError,
19
15
  MaterializeError,
20
16
  ) {}
21
17
 
@@ -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'))
@@ -69,6 +69,21 @@ export type DefineEventOptions<TTo, TDerived extends boolean = false> = {
69
69
  * @default false
70
70
  */
71
71
  derived?: TDerived
72
+
73
+ /**
74
+ * Marks the entire event as deprecated with a reason message.
75
+ * When this event is committed, a warning will be logged.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * Events.synced({
80
+ * name: 'v1.TodoRenamed',
81
+ * schema: Schema.Struct({ id: Schema.String, name: Schema.String }),
82
+ * deprecated: "Use 'v1.TodoUpdated' instead",
83
+ * })
84
+ * ```
85
+ */
86
+ deprecated?: string
72
87
  }
73
88
 
74
89
  /**
@@ -112,19 +127,20 @@ export const defineEvent = <TName extends string, TType, TEncoded = TType, TDeri
112
127
  Object.defineProperty(makePartialEvent, 'options', {
113
128
  value: {
114
129
  clientOnly: options?.clientOnly ?? false,
115
- facts: options?.facts
130
+ facts: options?.facts !== undefined
116
131
  ? (args, currentFacts) => {
117
132
  const res = options.facts!(args, currentFacts)
118
133
  return {
119
134
  modify: {
120
- set: res.modify?.set ? new Set(res.modify.set) : new Set(),
121
- 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(),
122
137
  },
123
- require: res.require ? new Set(res.require) : new Set(),
138
+ require: res.require !== undefined ? new Set(res.require) : new Set(),
124
139
  }
125
140
  }
126
141
  : undefined,
127
142
  derived: options?.derived ?? false,
143
+ deprecated: options?.deprecated,
128
144
  } satisfies EventDef.Any['options'],
129
145
  })
130
146
 
@@ -163,7 +179,7 @@ export const synced = <TName extends string, TType, TEncoded = TType>(
163
179
  args: {
164
180
  name: TName
165
181
  schema: Schema.Schema<TType, TEncoded>
166
- } & Omit<DefineEventOptions<TType, false>, 'derived' | 'clientOnly'>,
182
+ } & Omit<DefineEventOptions<TType>, 'derived' | 'clientOnly'>,
167
183
  ): EventDef<TName, TType, TEncoded> => defineEvent({ ...args, clientOnly: false })
168
184
 
169
185
  /**
@@ -197,5 +213,5 @@ export const clientOnly = <TName extends string, TType, TEncoded = TType>(
197
213
  args: {
198
214
  name: TName
199
215
  schema: Schema.Schema<TType, TEncoded>
200
- } & Omit<DefineEventOptions<TType, false>, 'derived' | 'clientOnly'>,
216
+ } & Omit<DefineEventOptions<TType>, 'derived' | 'clientOnly'>,
201
217
  ): EventDef<TName, TType, TEncoded> => defineEvent({ ...args, clientOnly: true })
@@ -0,0 +1,129 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from 'vitest'
2
+
3
+ import { Effect, Logger, Schema } from '@livestore/utils/effect'
4
+
5
+ import { synced } from './define.ts'
6
+ import {
7
+ deprecated,
8
+ findDeprecatedFieldsWithValues,
9
+ getDeprecatedReason,
10
+ isDeprecated,
11
+ logDeprecationWarnings,
12
+ resetDeprecationWarnings,
13
+ } from './deprecated.ts'
14
+
15
+ describe('deprecated annotations', () => {
16
+ test('adds deprecation annotation to schema', () => {
17
+ const schema = Schema.String.pipe(deprecated('Use newField instead'))
18
+ expect(isDeprecated(schema)).toBe(true)
19
+ expect(getDeprecatedReason(schema)._tag).toBe('Some')
20
+ })
21
+
22
+ test('works with optional fields in Struct', () => {
23
+ const struct = Schema.Struct({
24
+ oldField: Schema.optional(Schema.String).pipe(deprecated('Legacy')),
25
+ })
26
+ expect(findDeprecatedFieldsWithValues(struct, { oldField: 'x' })).toEqual([{ field: 'oldField', reason: 'Legacy' }])
27
+ })
28
+
29
+ test('non-deprecated schemas return false', () => {
30
+ expect(isDeprecated(Schema.String)).toBe(false)
31
+ })
32
+
33
+ test('ignores deprecated fields without values', () => {
34
+ const schema = Schema.Struct({
35
+ id: Schema.String,
36
+ old: Schema.optional(Schema.String).pipe(deprecated('x')),
37
+ })
38
+ expect(findDeprecatedFieldsWithValues(schema, { id: '1' })).toEqual([])
39
+ })
40
+
41
+ test('finds multiple deprecated fields', () => {
42
+ const schema = Schema.Struct({
43
+ a: Schema.optional(Schema.String).pipe(deprecated('A')),
44
+ b: Schema.optional(Schema.String).pipe(deprecated('B')),
45
+ })
46
+ const result = findDeprecatedFieldsWithValues(schema, { a: '1', b: '2' })
47
+ expect(result).toHaveLength(2)
48
+ })
49
+ })
50
+
51
+ describe('logDeprecationWarnings', () => {
52
+ let logs: unknown[][]
53
+
54
+ beforeEach(() => {
55
+ resetDeprecationWarnings()
56
+ logs = []
57
+ })
58
+
59
+ afterEach(() => resetDeprecationWarnings())
60
+
61
+ const run = (effect: Effect.Effect<void>) =>
62
+ Effect.runSync(
63
+ effect.pipe(
64
+ Effect.provide(
65
+ Logger.replace(
66
+ Logger.defaultLogger,
67
+ Logger.make(({ message }) => logs.push(message as unknown[])),
68
+ ),
69
+ ),
70
+ ),
71
+ )
72
+
73
+ test('logs event deprecation warning', () => {
74
+ const event = synced({ name: 'Old', schema: Schema.Struct({ id: Schema.String }), deprecated: 'Use New' })
75
+ run(logDeprecationWarnings(event, { id: '1' }))
76
+ expect(logs).toEqual([['@livestore/schema:deprecated-event', { event: 'Old', reason: 'Use New' }]])
77
+ })
78
+
79
+ test('logs field deprecation warning', () => {
80
+ const event = synced({
81
+ name: 'Ev',
82
+ schema: Schema.Struct({ old: Schema.optional(Schema.String).pipe(deprecated('Use new')) }),
83
+ })
84
+ run(logDeprecationWarnings(event, { old: 'x' }))
85
+ expect(logs).toEqual([['@livestore/schema:deprecated-field', { event: 'Ev', field: 'old', reason: 'Use new' }]])
86
+ })
87
+
88
+ test('deduplicates event warnings', () => {
89
+ const event = synced({ name: 'Dup', schema: Schema.Struct({ id: Schema.String }), deprecated: 'x' })
90
+ run(logDeprecationWarnings(event, { id: '1' }))
91
+ run(logDeprecationWarnings(event, { id: '2' }))
92
+ expect(logs).toHaveLength(1)
93
+ })
94
+
95
+ test('deduplicates field warnings', () => {
96
+ const event = synced({
97
+ name: 'DupField',
98
+ schema: Schema.Struct({ old: Schema.optional(Schema.String).pipe(deprecated('x')) }),
99
+ })
100
+ run(logDeprecationWarnings(event, { old: 'a' }))
101
+ run(logDeprecationWarnings(event, { old: 'b' }))
102
+ expect(logs).toHaveLength(1)
103
+ })
104
+
105
+ test('no warning for non-deprecated event', () => {
106
+ const event = synced({ name: 'Normal', schema: Schema.Struct({ id: Schema.String }) })
107
+ run(logDeprecationWarnings(event, { id: '1' }))
108
+ expect(logs).toHaveLength(0)
109
+ })
110
+
111
+ test('no warning when deprecated field is undefined', () => {
112
+ const event = synced({
113
+ name: 'Unused',
114
+ schema: Schema.Struct({ old: Schema.optional(Schema.String).pipe(deprecated('x')) }),
115
+ })
116
+ run(logDeprecationWarnings(event, {}))
117
+ expect(logs).toHaveLength(0)
118
+ })
119
+
120
+ test('logs both event and field warnings', () => {
121
+ const event = synced({
122
+ name: 'Both',
123
+ schema: Schema.Struct({ old: Schema.optional(Schema.String).pipe(deprecated('F')) }),
124
+ deprecated: 'E',
125
+ })
126
+ run(logDeprecationWarnings(event, { old: 'x' }))
127
+ expect(logs).toHaveLength(2)
128
+ })
129
+ })