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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ClientSessionLeaderThreadProxy.d.ts +16 -9
  3. package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
  4. package/dist/ClientSessionLeaderThreadProxy.js.map +1 -1
  5. package/dist/WorkerTransportError.d.ts +11 -0
  6. package/dist/WorkerTransportError.d.ts.map +1 -0
  7. package/dist/WorkerTransportError.js +11 -0
  8. package/dist/WorkerTransportError.js.map +1 -0
  9. package/dist/adapter-types.d.ts +26 -3
  10. package/dist/adapter-types.d.ts.map +1 -1
  11. package/dist/adapter-types.js +27 -1
  12. package/dist/adapter-types.js.map +1 -1
  13. package/dist/bounded-collections.d.ts.map +1 -1
  14. package/dist/bounded-collections.js +6 -4
  15. package/dist/bounded-collections.js.map +1 -1
  16. package/dist/debug-info.js +4 -4
  17. package/dist/debug-info.js.map +1 -1
  18. package/dist/devtools/devtools-messages-client-session.d.ts +42 -22
  19. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
  20. package/dist/devtools/devtools-messages-client-session.js +12 -1
  21. package/dist/devtools/devtools-messages-client-session.js.map +1 -1
  22. package/dist/devtools/devtools-messages-common.d.ts +12 -6
  23. package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
  24. package/dist/devtools/devtools-messages-common.js +8 -3
  25. package/dist/devtools/devtools-messages-common.js.map +1 -1
  26. package/dist/devtools/devtools-messages-leader.d.ts +45 -25
  27. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  28. package/dist/devtools/devtools-messages-leader.js +12 -1
  29. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  30. package/dist/devtools/mod.js +1 -1
  31. package/dist/devtools/mod.js.map +1 -1
  32. package/dist/errors.d.ts +15 -15
  33. package/dist/errors.d.ts.map +1 -1
  34. package/dist/errors.js +11 -11
  35. package/dist/errors.js.map +1 -1
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +2 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/leader-thread/LeaderSyncProcessor.d.ts +20 -6
  41. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  42. package/dist/leader-thread/LeaderSyncProcessor.js +283 -253
  43. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  44. package/dist/leader-thread/RejectedPushError.d.ts +107 -0
  45. package/dist/leader-thread/RejectedPushError.d.ts.map +1 -0
  46. package/dist/leader-thread/RejectedPushError.js +78 -0
  47. package/dist/leader-thread/RejectedPushError.js.map +1 -0
  48. package/dist/leader-thread/connection.js +1 -1
  49. package/dist/leader-thread/connection.js.map +1 -1
  50. package/dist/leader-thread/eventlog.d.ts.map +1 -1
  51. package/dist/leader-thread/eventlog.js +12 -11
  52. package/dist/leader-thread/eventlog.js.map +1 -1
  53. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -2
  54. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  55. package/dist/leader-thread/leader-worker-devtools.js +34 -14
  56. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  57. package/dist/leader-thread/make-leader-thread-layer.d.ts +12 -5
  58. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  59. package/dist/leader-thread/make-leader-thread-layer.js +12 -11
  60. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  61. package/dist/leader-thread/make-leader-thread-layer.test.js +1 -1
  62. package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -1
  63. package/dist/leader-thread/materialize-event.d.ts.map +1 -1
  64. package/dist/leader-thread/materialize-event.js +7 -4
  65. package/dist/leader-thread/materialize-event.js.map +1 -1
  66. package/dist/leader-thread/recreate-db.js +1 -1
  67. package/dist/leader-thread/recreate-db.js.map +1 -1
  68. package/dist/leader-thread/shutdown-channel.d.ts +2 -2
  69. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  70. package/dist/leader-thread/shutdown-channel.js +2 -2
  71. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  72. package/dist/leader-thread/stream-events.d.ts.map +1 -1
  73. package/dist/leader-thread/stream-events.js +4 -3
  74. package/dist/leader-thread/stream-events.js.map +1 -1
  75. package/dist/leader-thread/types.d.ts +7 -6
  76. package/dist/leader-thread/types.d.ts.map +1 -1
  77. package/dist/leader-thread/types.js.map +1 -1
  78. package/dist/logging.js +4 -4
  79. package/dist/logging.js.map +1 -1
  80. package/dist/make-client-session.js +2 -2
  81. package/dist/make-client-session.js.map +1 -1
  82. package/dist/materializer-helper.js +6 -6
  83. package/dist/materializer-helper.js.map +1 -1
  84. package/dist/otel.d.ts +1 -1
  85. package/dist/otel.d.ts.map +1 -1
  86. package/dist/otel.js +2 -2
  87. package/dist/otel.js.map +1 -1
  88. package/dist/rematerialize-from-eventlog.d.ts +1 -1
  89. package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
  90. package/dist/rematerialize-from-eventlog.js +11 -9
  91. package/dist/rematerialize-from-eventlog.js.map +1 -1
  92. package/dist/schema/EventDef/define.d.ts +16 -2
  93. package/dist/schema/EventDef/define.d.ts.map +1 -1
  94. package/dist/schema/EventDef/define.js +5 -4
  95. package/dist/schema/EventDef/define.js.map +1 -1
  96. package/dist/schema/EventDef/deprecated.d.ts +99 -0
  97. package/dist/schema/EventDef/deprecated.d.ts.map +1 -0
  98. package/dist/schema/EventDef/deprecated.js +144 -0
  99. package/dist/schema/EventDef/deprecated.js.map +1 -0
  100. package/dist/schema/EventDef/deprecated.test.d.ts +2 -0
  101. package/dist/schema/EventDef/deprecated.test.d.ts.map +1 -0
  102. package/dist/schema/EventDef/deprecated.test.js +95 -0
  103. package/dist/schema/EventDef/deprecated.test.js.map +1 -0
  104. package/dist/schema/EventDef/event-def.d.ts +4 -0
  105. package/dist/schema/EventDef/event-def.d.ts.map +1 -1
  106. package/dist/schema/EventDef/mod.d.ts +1 -0
  107. package/dist/schema/EventDef/mod.d.ts.map +1 -1
  108. package/dist/schema/EventDef/mod.js +1 -0
  109. package/dist/schema/EventDef/mod.js.map +1 -1
  110. package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -1
  111. package/dist/schema/EventSequenceNumber/client.js +11 -11
  112. package/dist/schema/EventSequenceNumber/client.js.map +1 -1
  113. package/dist/schema/EventSequenceNumber.test.js +1 -1
  114. package/dist/schema/EventSequenceNumber.test.js.map +1 -1
  115. package/dist/schema/LiveStoreEvent/client.d.ts +6 -6
  116. package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -1
  117. package/dist/schema/LiveStoreEvent/client.js +6 -3
  118. package/dist/schema/LiveStoreEvent/client.js.map +1 -1
  119. package/dist/schema/LiveStoreEvent/client.test.d.ts +2 -0
  120. package/dist/schema/LiveStoreEvent/client.test.d.ts.map +1 -0
  121. package/dist/schema/LiveStoreEvent/client.test.js +83 -0
  122. package/dist/schema/LiveStoreEvent/client.test.js.map +1 -0
  123. package/dist/schema/schema.d.ts.map +1 -1
  124. package/dist/schema/schema.js +7 -4
  125. package/dist/schema/schema.js.map +1 -1
  126. package/dist/schema/state/sqlite/client-document-def.d.ts +1 -0
  127. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
  128. package/dist/schema/state/sqlite/client-document-def.js +34 -13
  129. package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
  130. package/dist/schema/state/sqlite/client-document-def.test.js +121 -2
  131. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  132. package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
  133. package/dist/schema/state/sqlite/column-annotations.js +1 -1
  134. package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
  135. package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
  136. package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
  137. package/dist/schema/state/sqlite/column-def.d.ts.map +1 -1
  138. package/dist/schema/state/sqlite/column-def.js +36 -34
  139. package/dist/schema/state/sqlite/column-def.js.map +1 -1
  140. package/dist/schema/state/sqlite/column-def.test.js +7 -6
  141. package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
  142. package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
  143. package/dist/schema/state/sqlite/column-spec.js +8 -8
  144. package/dist/schema/state/sqlite/column-spec.js.map +1 -1
  145. package/dist/schema/state/sqlite/column-spec.test.js +1 -1
  146. package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
  147. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +2 -2
  148. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
  149. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +2 -2
  150. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
  151. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +11 -2
  152. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
  153. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js +1 -1
  154. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js.map +1 -1
  155. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts +1 -1
  156. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
  157. package/dist/schema/state/sqlite/db-schema/dsl/mod.js +1 -1
  158. package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
  159. package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
  160. package/dist/schema/state/sqlite/mod.js +3 -5
  161. package/dist/schema/state/sqlite/mod.js.map +1 -1
  162. package/dist/schema/state/sqlite/query-builder/api.d.ts +37 -13
  163. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  164. package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -1
  165. package/dist/schema/state/sqlite/query-builder/astToSql.js +77 -7
  166. package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
  167. package/dist/schema/state/sqlite/query-builder/impl.d.ts +1 -1
  168. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  169. package/dist/schema/state/sqlite/query-builder/impl.js +28 -14
  170. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  171. package/dist/schema/state/sqlite/query-builder/impl.test.js +112 -3
  172. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  173. package/dist/schema/state/sqlite/schema-helpers.js +2 -2
  174. package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
  175. package/dist/schema/state/sqlite/table-def.d.ts +5 -3
  176. package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
  177. package/dist/schema/state/sqlite/table-def.js +1 -1
  178. package/dist/schema/state/sqlite/table-def.js.map +1 -1
  179. package/dist/schema/state/sqlite/table-def.test.js +57 -4
  180. package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
  181. package/dist/schema/unknown-events.d.ts +1 -1
  182. package/dist/schema/unknown-events.d.ts.map +1 -1
  183. package/dist/schema/unknown-events.js +1 -1
  184. package/dist/schema/unknown-events.js.map +1 -1
  185. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +1 -1
  186. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -1
  187. package/dist/schema-management/common.js +2 -2
  188. package/dist/schema-management/common.js.map +1 -1
  189. package/dist/schema-management/migrations.js +1 -1
  190. package/dist/schema-management/migrations.js.map +1 -1
  191. package/dist/sql-queries/sql-queries.js +8 -6
  192. package/dist/sql-queries/sql-queries.js.map +1 -1
  193. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  194. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  195. package/dist/sqlite-db-helper.js +3 -3
  196. package/dist/sqlite-db-helper.js.map +1 -1
  197. package/dist/sqlite-types.d.ts +2 -2
  198. package/dist/sqlite-types.d.ts.map +1 -1
  199. package/dist/sqlite-types.js.map +1 -1
  200. package/dist/sync/ClientSessionSyncProcessor.d.ts +8 -9
  201. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  202. package/dist/sync/ClientSessionSyncProcessor.js +93 -107
  203. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  204. package/dist/sync/errors.d.ts +0 -38
  205. package/dist/sync/errors.d.ts.map +1 -1
  206. package/dist/sync/errors.js +3 -20
  207. package/dist/sync/errors.js.map +1 -1
  208. package/dist/sync/mock-sync-backend.d.ts +5 -3
  209. package/dist/sync/mock-sync-backend.d.ts.map +1 -1
  210. package/dist/sync/mock-sync-backend.js +70 -68
  211. package/dist/sync/mock-sync-backend.js.map +1 -1
  212. package/dist/sync/next/compact-events.js +6 -6
  213. package/dist/sync/next/compact-events.js.map +1 -1
  214. package/dist/sync/next/facts.d.ts.map +1 -1
  215. package/dist/sync/next/facts.js +6 -6
  216. package/dist/sync/next/facts.js.map +1 -1
  217. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  218. package/dist/sync/next/history-dag-common.js +6 -6
  219. package/dist/sync/next/history-dag-common.js.map +1 -1
  220. package/dist/sync/next/history-dag.js +3 -3
  221. package/dist/sync/next/history-dag.js.map +1 -1
  222. package/dist/sync/next/rebase-events.js +1 -1
  223. package/dist/sync/next/rebase-events.js.map +1 -1
  224. package/dist/sync/next/test/compact-events.calculator.test.js +2 -2
  225. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  226. package/dist/sync/next/test/compact-events.test.d.ts.map +1 -1
  227. package/dist/sync/next/test/compact-events.test.js +2 -2
  228. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  229. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
  230. package/dist/sync/next/test/event-fixtures.js +2 -2
  231. package/dist/sync/next/test/event-fixtures.js.map +1 -1
  232. package/dist/sync/sync-backend-kv.d.ts.map +1 -1
  233. package/dist/sync/sync-backend-kv.js.map +1 -1
  234. package/dist/sync/sync-backend.d.ts +3 -3
  235. package/dist/sync/sync-backend.d.ts.map +1 -1
  236. package/dist/sync/sync-backend.js +1 -1
  237. package/dist/sync/sync-backend.js.map +1 -1
  238. package/dist/sync/sync.d.ts +20 -0
  239. package/dist/sync/sync.d.ts.map +1 -1
  240. package/dist/sync/syncstate.d.ts +4 -17
  241. package/dist/sync/syncstate.d.ts.map +1 -1
  242. package/dist/sync/syncstate.js +51 -74
  243. package/dist/sync/syncstate.js.map +1 -1
  244. package/dist/sync/syncstate.test.js +112 -96
  245. package/dist/sync/syncstate.test.js.map +1 -1
  246. package/dist/sync/transport-chunking.js +3 -3
  247. package/dist/sync/transport-chunking.js.map +1 -1
  248. package/dist/sync/validate-push-payload.d.ts +2 -2
  249. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  250. package/dist/sync/validate-push-payload.js +4 -6
  251. package/dist/sync/validate-push-payload.js.map +1 -1
  252. package/dist/util.js +2 -2
  253. package/dist/util.js.map +1 -1
  254. package/dist/version.d.ts +7 -1
  255. package/dist/version.d.ts.map +1 -1
  256. package/dist/version.js +8 -4
  257. package/dist/version.js.map +1 -1
  258. package/package.json +66 -12
  259. package/src/ClientSessionLeaderThreadProxy.ts +16 -9
  260. package/src/WorkerTransportError.ts +12 -0
  261. package/src/adapter-types.ts +39 -3
  262. package/src/bounded-collections.ts +6 -5
  263. package/src/debug-info.ts +4 -4
  264. package/src/devtools/devtools-messages-client-session.ts +12 -0
  265. package/src/devtools/devtools-messages-common.ts +8 -4
  266. package/src/devtools/devtools-messages-leader.ts +12 -0
  267. package/src/devtools/mod.ts +1 -1
  268. package/src/errors.ts +18 -17
  269. package/src/index.ts +2 -0
  270. package/src/leader-thread/LeaderSyncProcessor.ts +417 -347
  271. package/src/leader-thread/RejectedPushError.ts +106 -0
  272. package/src/leader-thread/connection.ts +1 -1
  273. package/src/leader-thread/eventlog.ts +16 -14
  274. package/src/leader-thread/leader-worker-devtools.ts +107 -66
  275. package/src/leader-thread/make-leader-thread-layer.test.ts +1 -1
  276. package/src/leader-thread/make-leader-thread-layer.ts +41 -31
  277. package/src/leader-thread/materialize-event.ts +8 -4
  278. package/src/leader-thread/recreate-db.ts +1 -1
  279. package/src/leader-thread/shutdown-channel.ts +2 -6
  280. package/src/leader-thread/stream-events.ts +10 -5
  281. package/src/leader-thread/types.ts +7 -6
  282. package/src/logging.ts +4 -4
  283. package/src/make-client-session.ts +2 -2
  284. package/src/materializer-helper.ts +9 -9
  285. package/src/otel.ts +3 -2
  286. package/src/rematerialize-from-eventlog.ts +60 -60
  287. package/src/schema/EventDef/define.ts +22 -6
  288. package/src/schema/EventDef/deprecated.test.ts +129 -0
  289. package/src/schema/EventDef/deprecated.ts +175 -0
  290. package/src/schema/EventDef/event-def.ts +5 -0
  291. package/src/schema/EventDef/mod.ts +1 -0
  292. package/src/schema/EventSequenceNumber/client.ts +11 -11
  293. package/src/schema/EventSequenceNumber.test.ts +2 -1
  294. package/src/schema/LiveStoreEvent/client.test.ts +97 -0
  295. package/src/schema/LiveStoreEvent/client.ts +6 -3
  296. package/src/schema/schema.ts +9 -4
  297. package/src/schema/state/sqlite/client-document-def.test.ts +142 -3
  298. package/src/schema/state/sqlite/client-document-def.ts +37 -14
  299. package/src/schema/state/sqlite/column-annotations.test.ts +2 -1
  300. package/src/schema/state/sqlite/column-annotations.ts +2 -1
  301. package/src/schema/state/sqlite/column-def.test.ts +8 -6
  302. package/src/schema/state/sqlite/column-def.ts +41 -36
  303. package/src/schema/state/sqlite/column-spec.test.ts +3 -1
  304. package/src/schema/state/sqlite/column-spec.ts +9 -8
  305. package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +2 -2
  306. package/src/schema/state/sqlite/db-schema/dsl/field-defs.test.ts +2 -1
  307. package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +13 -4
  308. package/src/schema/state/sqlite/db-schema/dsl/mod.ts +3 -3
  309. package/src/schema/state/sqlite/mod.ts +4 -5
  310. package/src/schema/state/sqlite/query-builder/api.ts +37 -8
  311. package/src/schema/state/sqlite/query-builder/astToSql.ts +87 -7
  312. package/src/schema/state/sqlite/query-builder/impl.test.ts +145 -3
  313. package/src/schema/state/sqlite/query-builder/impl.ts +26 -12
  314. package/src/schema/state/sqlite/schema-helpers.ts +2 -2
  315. package/src/schema/state/sqlite/table-def.test.ts +67 -4
  316. package/src/schema/state/sqlite/table-def.ts +8 -15
  317. package/src/schema/unknown-events.ts +2 -2
  318. package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +3 -1
  319. package/src/schema-management/common.ts +2 -2
  320. package/src/schema-management/migrations.ts +1 -1
  321. package/src/sql-queries/sql-queries.ts +10 -6
  322. package/src/sql-queries/sql-query-builder.ts +1 -0
  323. package/src/sqlite-db-helper.ts +3 -3
  324. package/src/sqlite-types.ts +3 -2
  325. package/src/sync/ClientSessionSyncProcessor.ts +142 -133
  326. package/src/sync/errors.ts +10 -22
  327. package/src/sync/mock-sync-backend.ts +139 -97
  328. package/src/sync/next/compact-events.ts +5 -5
  329. package/src/sync/next/facts.ts +7 -6
  330. package/src/sync/next/history-dag-common.ts +9 -6
  331. package/src/sync/next/history-dag.ts +3 -3
  332. package/src/sync/next/rebase-events.ts +1 -1
  333. package/src/sync/next/test/compact-events.calculator.test.ts +3 -2
  334. package/src/sync/next/test/compact-events.test.ts +4 -3
  335. package/src/sync/next/test/event-fixtures.ts +2 -2
  336. package/src/sync/sync-backend-kv.ts +1 -0
  337. package/src/sync/sync-backend.ts +5 -4
  338. package/src/sync/sync.ts +21 -0
  339. package/src/sync/syncstate.test.ts +513 -435
  340. package/src/sync/syncstate.ts +80 -86
  341. package/src/sync/transport-chunking.ts +3 -3
  342. package/src/sync/validate-push-payload.ts +4 -6
  343. package/src/util.ts +2 -2
  344. package/src/version.ts +8 -4
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Deprecation Annotations for Events
3
+ *
4
+ * This module provides utilities for marking event fields and entire events as deprecated.
5
+ * When a deprecated field is used or a deprecated event is committed, a warning is logged.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { Events } from '@livestore/livestore'
10
+ * import { Schema } from 'effect'
11
+ * import { deprecated } from '@livestore/common/schema'
12
+ *
13
+ * // Field-level deprecation
14
+ * const todoUpdated = Events.synced({
15
+ * name: 'v1.TodoUpdated',
16
+ * schema: Schema.Struct({
17
+ * id: Schema.String,
18
+ * title: Schema.optional(Schema.String).pipe(deprecated("Use 'text' instead")),
19
+ * text: Schema.optional(Schema.String),
20
+ * }),
21
+ * })
22
+ *
23
+ * // Event-level deprecation
24
+ * const todoRenamed = Events.synced({
25
+ * name: 'v1.TodoRenamed',
26
+ * schema: Schema.Struct({ id: Schema.String, name: Schema.String }),
27
+ * deprecated: "Use 'v1.TodoUpdated' instead",
28
+ * })
29
+ * ```
30
+ * @module
31
+ */
32
+
33
+ import type { Schema } from '@livestore/utils/effect'
34
+ import { Effect, Option, SchemaAST } from '@livestore/utils/effect'
35
+
36
+ import type { EventDef } from './event-def.ts'
37
+
38
+ /** Symbol used to mark schemas as deprecated. */
39
+ export const DeprecatedId = Symbol.for('livestore/schema/annotations/deprecated')
40
+
41
+ /**
42
+ * Marks a schema field as deprecated with a reason message.
43
+ * When an event is committed with a deprecated field that has a value,
44
+ * a warning will be logged.
45
+ *
46
+ * Works with both Schema types and PropertySignatures (from Schema.optional).
47
+ *
48
+ * @param reason - Explanation of why this field is deprecated and what to use instead
49
+ * @returns A function that adds the deprecation annotation to the schema
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * const schema = Schema.Struct({
54
+ * oldField: Schema.optional(Schema.String).pipe(deprecated("Use 'newField' instead")),
55
+ * newField: Schema.optional(Schema.String),
56
+ * })
57
+ * ```
58
+ */
59
+ export const deprecated =
60
+ (reason: string) =>
61
+ <T extends { annotations: (annotations: { readonly [DeprecatedId]?: string }) => T }>(schema: T): T =>
62
+ schema.annotations({ [DeprecatedId]: reason })
63
+
64
+ /**
65
+ * Checks if a schema has a deprecation annotation.
66
+ *
67
+ * @param schema - The schema to check
68
+ * @returns The deprecation reason if deprecated, None otherwise
69
+ */
70
+ export const getDeprecatedReason = <A, I, R>(schema: Schema.Schema<A, I, R>): Option.Option<string> =>
71
+ SchemaAST.getAnnotation<string>(DeprecatedId)(schema.ast)
72
+
73
+ /**
74
+ * Checks if a schema is deprecated.
75
+ *
76
+ * @param schema - The schema to check
77
+ * @returns true if the schema is deprecated
78
+ */
79
+ export const isDeprecated = <A, I, R>(schema: Schema.Schema<A, I, R>): boolean =>
80
+ Option.isSome(getDeprecatedReason(schema))
81
+
82
+ /**
83
+ * Finds deprecated fields with values in the given event arguments.
84
+ * This walks through a Struct schema and checks each property for deprecation.
85
+ *
86
+ * @param schema - The event schema (expected to be a Struct)
87
+ * @param args - The event arguments
88
+ * @returns Array of objects containing field name and deprecation reason
89
+ */
90
+ export const findDeprecatedFieldsWithValues = (
91
+ schema: Schema.Schema.All,
92
+ args: Record<string, unknown>,
93
+ ): Array<{ field: string; reason: string }> => {
94
+ const result: Array<{ field: string; reason: string }> = []
95
+ const ast = schema.ast
96
+
97
+ // Handle TypeLiteral (Struct) schemas
98
+ if (ast._tag === 'TypeLiteral') {
99
+ for (const prop of ast.propertySignatures) {
100
+ const fieldName = String(prop.name)
101
+ const fieldValue = args[fieldName]
102
+
103
+ // Only check fields that have a value (not undefined)
104
+ if (fieldValue !== undefined) {
105
+ // Check deprecation on the property signature itself (for Schema.optional(...).pipe(deprecated(...)))
106
+ const propAnnotations = prop.annotations as Record<symbol, unknown> | undefined
107
+ const deprecationReason = propAnnotations?.[DeprecatedId] as string | undefined
108
+
109
+ // Also check deprecation on the type (for direct field deprecation)
110
+ const typeDeprecation = SchemaAST.getAnnotation<string>(DeprecatedId)(prop.type)
111
+
112
+ const reason = deprecationReason ?? (Option.isSome(typeDeprecation) === true ? typeDeprecation.value : undefined)
113
+ if (reason !== undefined) {
114
+ result.push({ field: fieldName, reason })
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ return result
121
+ }
122
+
123
+ /** Set of event names that have already logged deprecation warnings. */
124
+ const warnedDeprecatedEvents = new Set<string>()
125
+
126
+ /** Map of event+field combinations that have already logged deprecation warnings. */
127
+ const warnedDeprecatedFields = new Set<string>()
128
+
129
+ /**
130
+ * Logs deprecation warnings for an event using Effect.logWarning.
131
+ * Checks both event-level and field-level deprecation, with deduplication.
132
+ *
133
+ * @param eventDef - The event definition to check
134
+ * @param args - The event arguments
135
+ * @returns An Effect that logs warnings for any deprecations found
136
+ */
137
+ export const logDeprecationWarnings = (
138
+ eventDef: EventDef.AnyWithoutFn,
139
+ args: Record<string, unknown>,
140
+ ): Effect.Effect<void> =>
141
+ Effect.gen(function* () {
142
+ const eventName = eventDef.name
143
+
144
+ // Check for event-level deprecation
145
+ const eventDeprecation = eventDef.options.deprecated
146
+ if (eventDeprecation !== undefined && warnedDeprecatedEvents.has(eventName) === false) {
147
+ warnedDeprecatedEvents.add(eventName)
148
+ yield* Effect.logWarning('@livestore/schema:deprecated-event', {
149
+ event: eventName,
150
+ reason: eventDeprecation,
151
+ })
152
+ }
153
+
154
+ // Check for deprecated fields with values
155
+ const deprecatedFields = findDeprecatedFieldsWithValues(eventDef.schema, args)
156
+ for (const { field, reason } of deprecatedFields) {
157
+ const key = `${eventName}:${field}`
158
+ if (warnedDeprecatedFields.has(key) === false) {
159
+ warnedDeprecatedFields.add(key)
160
+ yield* Effect.logWarning('@livestore/schema:deprecated-field', {
161
+ event: eventName,
162
+ field,
163
+ reason,
164
+ })
165
+ }
166
+ }
167
+ })
168
+
169
+ /**
170
+ * Resets the deprecation warning state. Useful for testing.
171
+ */
172
+ export const resetDeprecationWarnings = (): void => {
173
+ warnedDeprecatedEvents.clear()
174
+ warnedDeprecatedFields.clear()
175
+ }
@@ -51,6 +51,11 @@ export type EventDef<TName extends string, TType, TEncoded = TType, TDerived ext
51
51
 
52
52
  /** Whether this is a derived event. Derived events cannot have materializers. */
53
53
  derived: TDerived
54
+
55
+ /**
56
+ * Deprecation reason for this event. When set, a warning is logged at commit time.
57
+ */
58
+ deprecated: string | undefined
54
59
  }
55
60
 
56
61
  /**
@@ -1,4 +1,5 @@
1
1
  export * from './define.ts'
2
+ export * from './deprecated.ts'
2
3
  export * from './event-def.ts'
3
4
  export * from './facts.ts'
4
5
  export * from './materializer.ts'
@@ -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
+ })
@@ -1,4 +1,4 @@
1
- import { memoizeByRef } from '@livestore/utils'
1
+ import { deepEqual, memoizeByRef } from '@livestore/utils'
2
2
  import { Option, Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import type { EventDef } from '../EventDef/mod.ts'
@@ -175,9 +175,12 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('LiveStoreEve
175
175
  })
176
176
 
177
177
  toGlobal = (): Global.Encoded => ({
178
- ...this,
178
+ name: this.name,
179
+ args: this.args,
179
180
  seqNum: this.seqNum.global,
180
181
  parentSeqNum: this.parentSeqNum.global,
182
+ clientId: this.clientId,
183
+ sessionId: this.sessionId,
181
184
  })
182
185
  }
183
186
 
@@ -191,7 +194,7 @@ export const isEqualEncoded = (a: Encoded, b: Encoded) =>
191
194
  a.name === b.name &&
192
195
  a.clientId === b.clientId &&
193
196
  a.sessionId === b.sessionId &&
194
- JSON.stringify(a.args) === JSON.stringify(b.args) // TODO use schema equality here
197
+ deepEqual(a.args, b.args) // TODO use schema equality here
195
198
 
196
199
  /**
197
200
  * Creates an Effect Schema union for all event types in a schema (with composite sequence numbers).
@@ -58,7 +58,12 @@ export const isLiveStoreSchema = (value: unknown): value is LiveStoreSchema<any,
58
58
  const hasStateMaterializers = v.state?.materializers instanceof Map
59
59
  const hasDevtoolsAlias = typeof v.devtools?.alias === 'string'
60
60
 
61
- return hasEventsMap && hasStateSqliteTables && hasStateMaterializers && hasDevtoolsAlias
61
+ return (
62
+ hasEventsMap === true &&
63
+ hasStateSqliteTables === true &&
64
+ hasStateMaterializers === true &&
65
+ hasDevtoolsAlias === true
66
+ )
62
67
  }
63
68
 
64
69
  // TODO abstract this further away from sqlite/tables
@@ -103,13 +108,13 @@ export const makeSchema = <TInputSchema extends InputSchema>(
103
108
 
104
109
  const eventsDefsMap = new Map<string, EventDef.AnyWithoutFn>()
105
110
 
106
- if (isReadonlyArray(inputSchema.events)) {
111
+ if (isReadonlyArray(inputSchema.events) === true) {
107
112
  for (const eventDef of inputSchema.events) {
108
113
  eventsDefsMap.set(eventDef.name, eventDef)
109
114
  }
110
115
  } else {
111
116
  for (const eventDef of Object.values(inputSchema.events ?? {})) {
112
- if (eventsDefsMap.has(eventDef.name)) {
117
+ if (eventsDefsMap.has(eventDef.name) === true) {
113
118
  shouldNeverHappen(`Duplicate event name: ${eventDef.name}. Please use unique names for events.`)
114
119
  }
115
120
  eventsDefsMap.set(eventDef.name, eventDef)
@@ -117,7 +122,7 @@ export const makeSchema = <TInputSchema extends InputSchema>(
117
122
  }
118
123
 
119
124
  for (const tableDef of tables.values()) {
120
- if (tableIsClientDocumentTable(tableDef) && eventsDefsMap.has(tableDef.set.name) === false) {
125
+ if (tableIsClientDocumentTable(tableDef) === true && eventsDefsMap.has(tableDef.set.name) === false) {
121
126
  eventsDefsMap.set(tableDef.set.name, tableDef.set)
122
127
  }
123
128
  }
@@ -1,9 +1,16 @@
1
- import { Schema } from '@livestore/utils/effect'
2
1
  import { describe, expect, test } from 'vitest'
3
2
 
3
+ import { Schema } from '@livestore/utils/effect'
4
+
4
5
  import { tables } from '../../../__tests__/fixture.ts'
5
6
  import type * as LiveStoreEvent from '../../LiveStoreEvent/mod.ts'
6
- import { ClientDocumentTableDefSymbol, clientDocument, mergeDefaultValues } from './client-document-def.ts'
7
+ import {
8
+ ClientDocumentTableDefSymbol,
9
+ clientDocument,
10
+ createOptimisticEventSchema,
11
+ mergeDefaultValues,
12
+ } from './client-document-def.ts'
13
+ import { getResultSchema } from './query-builder/impl.ts'
7
14
 
8
15
  describe('client document table', () => {
9
16
  test('set event', () => {
@@ -248,6 +255,139 @@ describe('client document table', () => {
248
255
  `)
249
256
  })
250
257
  })
258
+
259
+ /** Ensures optimistic decoding stays robust when persisted JSON is incompatible. */
260
+ describe('optimistic schema', () => {
261
+ /** Models persisted JSON using epoch numbers + base64 while app code expects Date + Uint8Array. */
262
+ const valueSchema = Schema.Struct({
263
+ createdAt: Schema.DateFromNumber,
264
+ avatar: Schema.Uint8ArrayFromBase64,
265
+ })
266
+ const defaultValue = {
267
+ createdAt: new Date(0),
268
+ avatar: new Uint8Array(),
269
+ }
270
+ const invalidPayloads: Array<{ label: string; value: unknown }> = [
271
+ { label: 'decoded-shape JSON', value: { createdAt: new Date(0), avatar: new Uint8Array([1, 2]) } },
272
+ { label: 'wrong types', value: { createdAt: 'not-a-number', avatar: { nested: 'bad' } } },
273
+ { label: 'missing required fields', value: {} },
274
+ ]
275
+ const validPayload = { createdAt: 42, avatar: 'AQI=' }
276
+ const extraFieldsPayload = { createdAt: 42, avatar: 'AQI=', extra: 'ignored' }
277
+
278
+ test.each(invalidPayloads)('decodes invalid persisted JSON ($label)', ({ value }) => {
279
+ const optimisticSchema = createOptimisticEventSchema({
280
+ valueSchema,
281
+ defaultValue,
282
+ partialSet: false,
283
+ })
284
+ const rowSchema = Schema.parseJson(optimisticSchema)
285
+
286
+ expect(Schema.decodeUnknownSync(rowSchema)(JSON.stringify(value))).toEqual(defaultValue)
287
+ })
288
+
289
+ test('decodes valid persisted JSON (encoded shape)', () => {
290
+ const optimisticSchema = createOptimisticEventSchema({
291
+ valueSchema,
292
+ defaultValue,
293
+ partialSet: false,
294
+ })
295
+ const rowSchema = Schema.parseJson(optimisticSchema)
296
+
297
+ expect(Schema.decodeUnknownSync(rowSchema)(JSON.stringify(validPayload))).toEqual({
298
+ createdAt: new Date(42),
299
+ avatar: new Uint8Array([1, 2]),
300
+ })
301
+ })
302
+
303
+ test('decodes valid persisted JSON with extra fields', () => {
304
+ const optimisticSchema = createOptimisticEventSchema({
305
+ valueSchema,
306
+ defaultValue,
307
+ partialSet: false,
308
+ })
309
+ const rowSchema = Schema.parseJson(optimisticSchema)
310
+
311
+ expect(Schema.decodeUnknownSync(rowSchema)(JSON.stringify(extraFieldsPayload))).toEqual({
312
+ createdAt: new Date(42),
313
+ avatar: new Uint8Array([1, 2]),
314
+ })
315
+ })
316
+
317
+ test.each(invalidPayloads)('decodes clientDocument rowSchema with invalid JSON ($label)', ({ value }) => {
318
+ const Doc = clientDocument({
319
+ name: 'test_numbers',
320
+ schema: valueSchema,
321
+ default: { value: defaultValue },
322
+ partialSet: false,
323
+ })
324
+ const row = {
325
+ id: 'row-1',
326
+ value: JSON.stringify(value),
327
+ }
328
+
329
+ expect(Schema.decodeUnknownSync(Doc.rowSchema)(row)).toEqual({ id: 'row-1', value: defaultValue })
330
+ })
331
+
332
+ test('decodes clientDocument rowSchema with valid encoded JSON', () => {
333
+ const Doc = clientDocument({
334
+ name: 'test_numbers',
335
+ schema: valueSchema,
336
+ default: { value: defaultValue },
337
+ partialSet: false,
338
+ })
339
+ const row = {
340
+ id: 'row-1',
341
+ value: JSON.stringify(validPayload),
342
+ }
343
+
344
+ expect(Schema.decodeUnknownSync(Doc.rowSchema)(row)).toEqual({
345
+ id: 'row-1',
346
+ value: { createdAt: new Date(42), avatar: new Uint8Array([1, 2]) },
347
+ })
348
+ })
349
+
350
+ test.each(invalidPayloads)('decodes RowQuery result schema with invalid JSON ($label)', ({ value }) => {
351
+ const Doc = clientDocument({
352
+ name: 'test_numbers',
353
+ schema: valueSchema,
354
+ default: { value: defaultValue },
355
+ partialSet: false,
356
+ })
357
+ const query = Doc.get('row-1')
358
+ const resultSchema = getResultSchema(query)
359
+ const rawDbResults = [
360
+ {
361
+ id: 'row-1',
362
+ value: JSON.stringify(value),
363
+ },
364
+ ]
365
+
366
+ expect(Schema.decodeUnknownSync(resultSchema)(rawDbResults)).toEqual(defaultValue)
367
+ })
368
+
369
+ test('decodes RowQuery result schema with valid encoded JSON', () => {
370
+ const Doc = clientDocument({
371
+ name: 'test_numbers',
372
+ schema: valueSchema,
373
+ default: { value: defaultValue },
374
+ partialSet: false,
375
+ })
376
+ const query = Doc.get('row-1')
377
+ const resultSchema = getResultSchema(query)
378
+ const rawDbResults = [
379
+ {
380
+ id: 'row-1',
381
+ value: JSON.stringify(validPayload),
382
+ },
383
+ ]
384
+
385
+ expect(Schema.decodeUnknownSync(resultSchema)(rawDbResults)).toEqual({
386
+ createdAt: new Date(42),
387
+ avatar: new Uint8Array([1, 2]),
388
+ })
389
+ })
390
+ })
251
391
  })
252
392
 
253
393
  const patchId = (muationEvent: LiveStoreEvent.Input.Decoded) => {
@@ -255,7 +395,6 @@ const patchId = (muationEvent: LiveStoreEvent.Input.Decoded) => {
255
395
  const id = `00000000-0000-0000-0000-000000000000`
256
396
  return { ...muationEvent, id }
257
397
  }
258
-
259
398
  describe('mergeDefaultValues', () => {
260
399
  test('merges values from both objects', () => {
261
400
  const defaults = { a: 1, b: 2 }