@livestore/common 0.4.0-dev.2 → 0.4.0-dev.20

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 (449) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ClientSessionLeaderThreadProxy.d.ts +17 -12
  3. package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
  4. package/dist/ClientSessionLeaderThreadProxy.js.map +1 -1
  5. package/dist/adapter-types.d.ts +14 -6
  6. package/dist/adapter-types.d.ts.map +1 -1
  7. package/dist/adapter-types.js.map +1 -1
  8. package/dist/debug-info.d.ts.map +1 -1
  9. package/dist/debug-info.js +33 -6
  10. package/dist/debug-info.js.map +1 -1
  11. package/dist/devtools/devtools-messages-client-session.d.ts +28 -23
  12. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
  13. package/dist/devtools/devtools-messages-client-session.js +2 -2
  14. package/dist/devtools/devtools-messages-client-session.js.map +1 -1
  15. package/dist/devtools/devtools-messages-common.d.ts +7 -14
  16. package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
  17. package/dist/devtools/devtools-messages-common.js +1 -6
  18. package/dist/devtools/devtools-messages-common.js.map +1 -1
  19. package/dist/devtools/devtools-messages-leader.d.ts +36 -29
  20. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  21. package/dist/devtools/devtools-messages-leader.js +8 -8
  22. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  23. package/dist/devtools/devtools-sessioninfo.d.ts +14 -2
  24. package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -1
  25. package/dist/devtools/devtools-sessioninfo.js +7 -4
  26. package/dist/devtools/devtools-sessioninfo.js.map +1 -1
  27. package/dist/devtools/mod.d.ts +13 -2
  28. package/dist/devtools/mod.d.ts.map +1 -1
  29. package/dist/devtools/mod.js +10 -3
  30. package/dist/devtools/mod.js.map +1 -1
  31. package/dist/errors.d.ts +52 -10
  32. package/dist/errors.d.ts.map +1 -1
  33. package/dist/errors.js +25 -6
  34. package/dist/errors.js.map +1 -1
  35. package/dist/index.d.ts +2 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +2 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/leader-thread/LeaderSyncProcessor.d.ts +8 -4
  40. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  41. package/dist/leader-thread/LeaderSyncProcessor.js +156 -73
  42. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  43. package/dist/leader-thread/eventlog.d.ts +15 -21
  44. package/dist/leader-thread/eventlog.d.ts.map +1 -1
  45. package/dist/leader-thread/eventlog.js +18 -18
  46. package/dist/leader-thread/eventlog.js.map +1 -1
  47. package/dist/leader-thread/leader-worker-devtools.d.ts +2 -2
  48. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  49. package/dist/leader-thread/leader-worker-devtools.js +30 -42
  50. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  51. package/dist/leader-thread/make-leader-thread-layer.d.ts +6 -6
  52. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  53. package/dist/leader-thread/make-leader-thread-layer.js +79 -27
  54. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  55. package/dist/leader-thread/make-leader-thread-layer.test.d.ts +2 -0
  56. package/dist/leader-thread/make-leader-thread-layer.test.d.ts.map +1 -0
  57. package/dist/leader-thread/make-leader-thread-layer.test.js +32 -0
  58. package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -0
  59. package/dist/leader-thread/materialize-event.d.ts +3 -3
  60. package/dist/leader-thread/materialize-event.d.ts.map +1 -1
  61. package/dist/leader-thread/materialize-event.js +25 -11
  62. package/dist/leader-thread/materialize-event.js.map +1 -1
  63. package/dist/leader-thread/recreate-db.d.ts +2 -3
  64. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  65. package/dist/leader-thread/recreate-db.js +5 -5
  66. package/dist/leader-thread/recreate-db.js.map +1 -1
  67. package/dist/leader-thread/shutdown-channel.d.ts +2 -2
  68. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  69. package/dist/leader-thread/shutdown-channel.js +2 -2
  70. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  71. package/dist/leader-thread/types.d.ts +21 -19
  72. package/dist/leader-thread/types.d.ts.map +1 -1
  73. package/dist/leader-thread/types.js.map +1 -1
  74. package/dist/logging.d.ts +40 -0
  75. package/dist/logging.d.ts.map +1 -0
  76. package/dist/logging.js +33 -0
  77. package/dist/logging.js.map +1 -0
  78. package/dist/make-client-session.d.ts +5 -3
  79. package/dist/make-client-session.d.ts.map +1 -1
  80. package/dist/make-client-session.js +5 -2
  81. package/dist/make-client-session.js.map +1 -1
  82. package/dist/materializer-helper.d.ts +6 -6
  83. package/dist/materializer-helper.d.ts.map +1 -1
  84. package/dist/materializer-helper.js +20 -4
  85. package/dist/materializer-helper.js.map +1 -1
  86. package/dist/rematerialize-from-eventlog.d.ts +2 -2
  87. package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
  88. package/dist/rematerialize-from-eventlog.js +29 -20
  89. package/dist/rematerialize-from-eventlog.js.map +1 -1
  90. package/dist/schema/EventDef/define.d.ts +147 -0
  91. package/dist/schema/EventDef/define.d.ts.map +1 -0
  92. package/dist/schema/EventDef/define.js +139 -0
  93. package/dist/schema/EventDef/define.js.map +1 -0
  94. package/dist/schema/EventDef/event-def.d.ts +106 -0
  95. package/dist/schema/EventDef/event-def.d.ts.map +1 -0
  96. package/dist/schema/EventDef/event-def.js +2 -0
  97. package/dist/schema/EventDef/event-def.js.map +1 -0
  98. package/dist/schema/EventDef/facts.d.ts +118 -0
  99. package/dist/schema/EventDef/facts.d.ts.map +1 -0
  100. package/dist/schema/EventDef/facts.js +53 -0
  101. package/dist/schema/EventDef/facts.js.map +1 -0
  102. package/dist/schema/EventDef/materializer.d.ts +155 -0
  103. package/dist/schema/EventDef/materializer.d.ts.map +1 -0
  104. package/dist/schema/EventDef/materializer.js +83 -0
  105. package/dist/schema/EventDef/materializer.js.map +1 -0
  106. package/dist/schema/EventDef/mod.d.ts +5 -0
  107. package/dist/schema/EventDef/mod.d.ts.map +1 -0
  108. package/dist/schema/EventDef/mod.js +5 -0
  109. package/dist/schema/EventDef/mod.js.map +1 -0
  110. package/dist/schema/EventSequenceNumber/client.d.ts +136 -0
  111. package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -0
  112. package/dist/schema/EventSequenceNumber/client.js +193 -0
  113. package/dist/schema/EventSequenceNumber/client.js.map +1 -0
  114. package/dist/schema/EventSequenceNumber/global.d.ts +15 -0
  115. package/dist/schema/EventSequenceNumber/global.d.ts.map +1 -0
  116. package/dist/schema/EventSequenceNumber/global.js +14 -0
  117. package/dist/schema/EventSequenceNumber/global.js.map +1 -0
  118. package/dist/schema/EventSequenceNumber/mod.d.ts +37 -0
  119. package/dist/schema/EventSequenceNumber/mod.d.ts.map +1 -0
  120. package/dist/schema/EventSequenceNumber/mod.js +37 -0
  121. package/dist/schema/EventSequenceNumber/mod.js.map +1 -0
  122. package/dist/schema/EventSequenceNumber.test.js +43 -43
  123. package/dist/schema/EventSequenceNumber.test.js.map +1 -1
  124. package/dist/schema/{LiveStoreEvent.d.ts → LiveStoreEvent/client.d.ts} +89 -106
  125. package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -0
  126. package/dist/schema/{LiveStoreEvent.js → LiveStoreEvent/client.js} +74 -58
  127. package/dist/schema/LiveStoreEvent/client.js.map +1 -0
  128. package/dist/schema/LiveStoreEvent/for-event-def.d.ts +52 -0
  129. package/dist/schema/LiveStoreEvent/for-event-def.d.ts.map +1 -0
  130. package/dist/schema/LiveStoreEvent/for-event-def.js +2 -0
  131. package/dist/schema/LiveStoreEvent/for-event-def.js.map +1 -0
  132. package/dist/schema/LiveStoreEvent/global.d.ts +36 -0
  133. package/dist/schema/LiveStoreEvent/global.d.ts.map +1 -0
  134. package/dist/schema/LiveStoreEvent/global.js +31 -0
  135. package/dist/schema/LiveStoreEvent/global.js.map +1 -0
  136. package/dist/schema/LiveStoreEvent/input.d.ts +46 -0
  137. package/dist/schema/LiveStoreEvent/input.d.ts.map +1 -0
  138. package/dist/schema/LiveStoreEvent/input.js +26 -0
  139. package/dist/schema/LiveStoreEvent/input.js.map +1 -0
  140. package/dist/schema/LiveStoreEvent/mod.d.ts +5 -0
  141. package/dist/schema/LiveStoreEvent/mod.d.ts.map +1 -0
  142. package/dist/schema/LiveStoreEvent/mod.js +5 -0
  143. package/dist/schema/LiveStoreEvent/mod.js.map +1 -0
  144. package/dist/schema/events.d.ts +1 -1
  145. package/dist/schema/events.d.ts.map +1 -1
  146. package/dist/schema/events.js +1 -1
  147. package/dist/schema/events.js.map +1 -1
  148. package/dist/schema/mod.d.ts +6 -4
  149. package/dist/schema/mod.d.ts.map +1 -1
  150. package/dist/schema/mod.js +5 -4
  151. package/dist/schema/mod.js.map +1 -1
  152. package/dist/schema/schema.d.ts +16 -1
  153. package/dist/schema/schema.d.ts.map +1 -1
  154. package/dist/schema/schema.js +27 -2
  155. package/dist/schema/schema.js.map +1 -1
  156. package/dist/schema/state/sqlite/client-document-def.d.ts +36 -6
  157. package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
  158. package/dist/schema/state/sqlite/client-document-def.js +97 -6
  159. package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
  160. package/dist/schema/state/sqlite/client-document-def.test.js +16 -0
  161. package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
  162. package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
  163. package/dist/schema/state/sqlite/column-annotations.js +14 -6
  164. package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
  165. package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
  166. package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
  167. package/dist/schema/state/sqlite/column-def.js +69 -22
  168. package/dist/schema/state/sqlite/column-def.js.map +1 -1
  169. package/dist/schema/state/sqlite/column-def.test.js +46 -7
  170. package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
  171. package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
  172. package/dist/schema/state/sqlite/column-spec.js +30 -12
  173. package/dist/schema/state/sqlite/column-spec.js.map +1 -1
  174. package/dist/schema/state/sqlite/column-spec.test.js +23 -14
  175. package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
  176. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +2 -1
  177. package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -1
  178. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +23 -6
  179. package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
  180. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +14 -8
  181. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
  182. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +5 -3
  183. package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
  184. package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
  185. package/dist/schema/state/sqlite/db-schema/dsl/mod.js +2 -1
  186. package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
  187. package/dist/schema/state/sqlite/mod.d.ts +3 -3
  188. package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
  189. package/dist/schema/state/sqlite/mod.js +3 -3
  190. package/dist/schema/state/sqlite/mod.js.map +1 -1
  191. package/dist/schema/state/sqlite/query-builder/api.d.ts +17 -10
  192. package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
  193. package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -1
  194. package/dist/schema/state/sqlite/query-builder/astToSql.js +22 -15
  195. package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
  196. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  197. package/dist/schema/state/sqlite/query-builder/impl.js +6 -3
  198. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  199. package/dist/schema/state/sqlite/query-builder/impl.test.js +252 -88
  200. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  201. package/dist/schema/state/sqlite/schema-helpers.d.ts +2 -2
  202. package/dist/schema/state/sqlite/schema-helpers.d.ts.map +1 -1
  203. package/dist/schema/state/sqlite/schema-helpers.js +22 -12
  204. package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
  205. package/dist/schema/state/sqlite/schema-helpers.test.d.ts +2 -0
  206. package/dist/schema/state/sqlite/schema-helpers.test.d.ts.map +1 -0
  207. package/dist/schema/state/sqlite/schema-helpers.test.js +36 -0
  208. package/dist/schema/state/sqlite/schema-helpers.test.js.map +1 -0
  209. package/dist/schema/state/sqlite/{system-tables.d.ts → system-tables/eventlog-tables.d.ts} +63 -456
  210. package/dist/schema/state/sqlite/system-tables/eventlog-tables.d.ts.map +1 -0
  211. package/dist/schema/state/sqlite/system-tables/eventlog-tables.js +54 -0
  212. package/dist/schema/state/sqlite/system-tables/eventlog-tables.js.map +1 -0
  213. package/dist/schema/state/sqlite/system-tables/mod.d.ts +3 -0
  214. package/dist/schema/state/sqlite/system-tables/mod.d.ts.map +1 -0
  215. package/dist/schema/state/sqlite/system-tables/mod.js +3 -0
  216. package/dist/schema/state/sqlite/system-tables/mod.js.map +1 -0
  217. package/dist/schema/state/sqlite/system-tables/state-tables.d.ts +456 -0
  218. package/dist/schema/state/sqlite/system-tables/state-tables.d.ts.map +1 -0
  219. package/dist/schema/state/sqlite/system-tables/state-tables.js +55 -0
  220. package/dist/schema/state/sqlite/system-tables/state-tables.js.map +1 -0
  221. package/dist/schema/state/sqlite/table-def.d.ts +4 -4
  222. package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
  223. package/dist/schema/state/sqlite/table-def.js +2 -2
  224. package/dist/schema/state/sqlite/table-def.js.map +1 -1
  225. package/dist/schema/state/sqlite/table-def.test.js +80 -0
  226. package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
  227. package/dist/schema/unknown-events.d.ts +47 -0
  228. package/dist/schema/unknown-events.d.ts.map +1 -0
  229. package/dist/schema/unknown-events.js +69 -0
  230. package/dist/schema/unknown-events.js.map +1 -0
  231. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.d.ts +2 -0
  232. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.d.ts.map +1 -0
  233. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +73 -0
  234. package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -0
  235. package/dist/schema-management/migrations.d.ts +32 -2
  236. package/dist/schema-management/migrations.d.ts.map +1 -1
  237. package/dist/schema-management/migrations.js +37 -5
  238. package/dist/schema-management/migrations.js.map +1 -1
  239. package/dist/schema-management/validate-schema.d.ts +3 -3
  240. package/dist/schema-management/validate-schema.d.ts.map +1 -1
  241. package/dist/schema-management/validate-schema.js +2 -2
  242. package/dist/schema-management/validate-schema.js.map +1 -1
  243. package/dist/sql-queries/sql-queries.d.ts.map +1 -1
  244. package/dist/sql-queries/sql-queries.js +11 -1
  245. package/dist/sql-queries/sql-queries.js.map +1 -1
  246. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  247. package/dist/sql-queries/sql-query-builder.js +2 -1
  248. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  249. package/dist/sqlite-types.d.ts +3 -3
  250. package/dist/sqlite-types.d.ts.map +1 -1
  251. package/dist/sync/ClientSessionSyncProcessor.d.ts +11 -13
  252. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  253. package/dist/sync/ClientSessionSyncProcessor.js +45 -42
  254. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  255. package/dist/sync/errors.d.ts +66 -0
  256. package/dist/sync/errors.d.ts.map +1 -0
  257. package/dist/sync/errors.js +36 -0
  258. package/dist/sync/errors.js.map +1 -0
  259. package/dist/sync/index.d.ts +3 -0
  260. package/dist/sync/index.d.ts.map +1 -1
  261. package/dist/sync/index.js +3 -0
  262. package/dist/sync/index.js.map +1 -1
  263. package/dist/sync/mock-sync-backend.d.ts +23 -0
  264. package/dist/sync/mock-sync-backend.d.ts.map +1 -0
  265. package/dist/sync/mock-sync-backend.js +114 -0
  266. package/dist/sync/mock-sync-backend.js.map +1 -0
  267. package/dist/sync/next/compact-events.d.ts.map +1 -1
  268. package/dist/sync/next/compact-events.js +6 -7
  269. package/dist/sync/next/compact-events.js.map +1 -1
  270. package/dist/sync/next/facts.d.ts +5 -5
  271. package/dist/sync/next/facts.d.ts.map +1 -1
  272. package/dist/sync/next/facts.js +1 -2
  273. package/dist/sync/next/facts.js.map +1 -1
  274. package/dist/sync/next/history-dag-common.d.ts +54 -15
  275. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  276. package/dist/sync/next/history-dag-common.js +198 -9
  277. package/dist/sync/next/history-dag-common.js.map +1 -1
  278. package/dist/sync/next/history-dag.d.ts.map +1 -1
  279. package/dist/sync/next/history-dag.js +10 -8
  280. package/dist/sync/next/history-dag.js.map +1 -1
  281. package/dist/sync/next/rebase-events.d.ts +5 -5
  282. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  283. package/dist/sync/next/rebase-events.js +5 -5
  284. package/dist/sync/next/rebase-events.js.map +1 -1
  285. package/dist/sync/next/test/event-fixtures.d.ts +2 -2
  286. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
  287. package/dist/sync/next/test/event-fixtures.js +9 -9
  288. package/dist/sync/next/test/event-fixtures.js.map +1 -1
  289. package/dist/sync/sync-backend-kv.d.ts +7 -0
  290. package/dist/sync/sync-backend-kv.d.ts.map +1 -0
  291. package/dist/sync/sync-backend-kv.js +18 -0
  292. package/dist/sync/sync-backend-kv.js.map +1 -0
  293. package/dist/sync/sync-backend.d.ts +105 -0
  294. package/dist/sync/sync-backend.d.ts.map +1 -0
  295. package/dist/sync/sync-backend.js +61 -0
  296. package/dist/sync/sync-backend.js.map +1 -0
  297. package/dist/sync/sync.d.ts +9 -86
  298. package/dist/sync/sync.d.ts.map +1 -1
  299. package/dist/sync/sync.js +2 -27
  300. package/dist/sync/sync.js.map +1 -1
  301. package/dist/sync/syncstate.d.ts +57 -44
  302. package/dist/sync/syncstate.d.ts.map +1 -1
  303. package/dist/sync/syncstate.js +50 -45
  304. package/dist/sync/syncstate.js.map +1 -1
  305. package/dist/sync/syncstate.test.js +83 -46
  306. package/dist/sync/syncstate.test.js.map +1 -1
  307. package/dist/sync/transport-chunking.d.ts +36 -0
  308. package/dist/sync/transport-chunking.d.ts.map +1 -0
  309. package/dist/sync/transport-chunking.js +56 -0
  310. package/dist/sync/transport-chunking.js.map +1 -0
  311. package/dist/sync/validate-push-payload.d.ts +2 -2
  312. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  313. package/dist/sync/validate-push-payload.js +6 -6
  314. package/dist/sync/validate-push-payload.js.map +1 -1
  315. package/dist/testing/event-factory.d.ts +68 -0
  316. package/dist/testing/event-factory.d.ts.map +1 -0
  317. package/dist/testing/event-factory.js +78 -0
  318. package/dist/testing/event-factory.js.map +1 -0
  319. package/dist/testing/mod.d.ts +2 -0
  320. package/dist/testing/mod.d.ts.map +1 -0
  321. package/dist/testing/mod.js +2 -0
  322. package/dist/testing/mod.js.map +1 -0
  323. package/dist/version.d.ts +16 -6
  324. package/dist/version.d.ts.map +1 -1
  325. package/dist/version.js +16 -6
  326. package/dist/version.js.map +1 -1
  327. package/package.json +7 -8
  328. package/src/ClientSessionLeaderThreadProxy.ts +17 -12
  329. package/src/adapter-types.ts +18 -6
  330. package/src/debug-info.ts +37 -6
  331. package/src/devtools/devtools-messages-client-session.ts +2 -2
  332. package/src/devtools/devtools-messages-common.ts +1 -8
  333. package/src/devtools/devtools-messages-leader.ts +8 -8
  334. package/src/devtools/devtools-sessioninfo.ts +8 -5
  335. package/src/devtools/mod.ts +11 -2
  336. package/src/errors.ts +38 -11
  337. package/src/index.ts +2 -1
  338. package/src/leader-thread/LeaderSyncProcessor.ts +242 -103
  339. package/src/leader-thread/eventlog.ts +33 -34
  340. package/src/leader-thread/leader-worker-devtools.ts +50 -54
  341. package/src/leader-thread/make-leader-thread-layer.test.ts +44 -0
  342. package/src/leader-thread/make-leader-thread-layer.ts +156 -37
  343. package/src/leader-thread/materialize-event.ts +37 -12
  344. package/src/leader-thread/recreate-db.ts +15 -7
  345. package/src/leader-thread/shutdown-channel.ts +16 -2
  346. package/src/leader-thread/types.ts +21 -19
  347. package/src/logging.ts +62 -0
  348. package/src/make-client-session.ts +9 -3
  349. package/src/materializer-helper.ts +27 -10
  350. package/src/rematerialize-from-eventlog.ts +37 -27
  351. package/src/schema/EventDef/define.ts +201 -0
  352. package/src/schema/EventDef/event-def.ts +120 -0
  353. package/src/schema/EventDef/facts.ts +135 -0
  354. package/src/schema/EventDef/materializer.ts +172 -0
  355. package/src/schema/EventDef/mod.ts +4 -0
  356. package/src/schema/EventSequenceNumber/client.ts +257 -0
  357. package/src/schema/EventSequenceNumber/global.ts +19 -0
  358. package/src/schema/EventSequenceNumber/mod.ts +37 -0
  359. package/src/schema/EventSequenceNumber.test.ts +70 -52
  360. package/src/schema/LiveStoreEvent/client.ts +221 -0
  361. package/src/schema/LiveStoreEvent/for-event-def.ts +60 -0
  362. package/src/schema/LiveStoreEvent/global.ts +45 -0
  363. package/src/schema/LiveStoreEvent/input.ts +63 -0
  364. package/src/schema/LiveStoreEvent/mod.ts +4 -0
  365. package/src/schema/events.ts +1 -1
  366. package/src/schema/mod.ts +6 -4
  367. package/src/schema/schema.ts +39 -3
  368. package/src/schema/state/sqlite/client-document-def.test.ts +19 -2
  369. package/src/schema/state/sqlite/client-document-def.ts +120 -8
  370. package/src/schema/state/sqlite/column-annotations.test.ts +1 -1
  371. package/src/schema/state/sqlite/column-annotations.ts +16 -6
  372. package/src/schema/state/sqlite/column-def.test.ts +60 -7
  373. package/src/schema/state/sqlite/column-def.ts +88 -21
  374. package/src/schema/state/sqlite/column-spec.test.ts +29 -16
  375. package/src/schema/state/sqlite/column-spec.ts +36 -11
  376. package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +26 -6
  377. package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +29 -12
  378. package/src/schema/state/sqlite/db-schema/dsl/mod.ts +2 -1
  379. package/src/schema/state/sqlite/mod.ts +4 -3
  380. package/src/schema/state/sqlite/query-builder/api.ts +19 -10
  381. package/src/schema/state/sqlite/query-builder/astToSql.ts +23 -14
  382. package/src/schema/state/sqlite/query-builder/impl.test.ts +305 -92
  383. package/src/schema/state/sqlite/query-builder/impl.ts +8 -3
  384. package/src/schema/state/sqlite/schema-helpers.test.ts +44 -0
  385. package/src/schema/state/sqlite/schema-helpers.ts +28 -20
  386. package/src/schema/state/sqlite/system-tables/eventlog-tables.ts +64 -0
  387. package/src/schema/state/sqlite/system-tables/mod.ts +2 -0
  388. package/src/schema/state/sqlite/system-tables/state-tables.ts +69 -0
  389. package/src/schema/state/sqlite/table-def.test.ts +101 -0
  390. package/src/schema/state/sqlite/table-def.ts +9 -8
  391. package/src/schema/unknown-events.ts +131 -0
  392. package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +86 -0
  393. package/src/schema-management/migrations.ts +41 -8
  394. package/src/schema-management/validate-schema.ts +3 -3
  395. package/src/sql-queries/sql-queries.ts +9 -1
  396. package/src/sql-queries/sql-query-builder.ts +2 -1
  397. package/src/sqlite-types.ts +3 -3
  398. package/src/sync/ClientSessionSyncProcessor.ts +69 -62
  399. package/src/sync/errors.ts +38 -0
  400. package/src/sync/index.ts +3 -0
  401. package/src/sync/mock-sync-backend.ts +184 -0
  402. package/src/sync/next/compact-events.ts +6 -7
  403. package/src/sync/next/facts.ts +7 -9
  404. package/src/sync/next/history-dag-common.ts +277 -26
  405. package/src/sync/next/history-dag.ts +16 -10
  406. package/src/sync/next/rebase-events.ts +11 -11
  407. package/src/sync/next/test/event-fixtures.ts +11 -11
  408. package/src/sync/sync-backend-kv.ts +22 -0
  409. package/src/sync/sync-backend.ts +185 -0
  410. package/src/sync/sync.ts +9 -91
  411. package/src/sync/syncstate.test.ts +96 -52
  412. package/src/sync/syncstate.ts +69 -58
  413. package/src/sync/transport-chunking.ts +90 -0
  414. package/src/sync/validate-push-payload.ts +8 -9
  415. package/src/testing/event-factory.ts +131 -0
  416. package/src/testing/mod.ts +1 -0
  417. package/src/version.ts +16 -6
  418. package/dist/schema/EventDef.d.ts +0 -123
  419. package/dist/schema/EventDef.d.ts.map +0 -1
  420. package/dist/schema/EventDef.js +0 -46
  421. package/dist/schema/EventDef.js.map +0 -1
  422. package/dist/schema/EventSequenceNumber.d.ts +0 -80
  423. package/dist/schema/EventSequenceNumber.d.ts.map +0 -1
  424. package/dist/schema/EventSequenceNumber.js +0 -139
  425. package/dist/schema/EventSequenceNumber.js.map +0 -1
  426. package/dist/schema/LiveStoreEvent.d.ts.map +0 -1
  427. package/dist/schema/LiveStoreEvent.js.map +0 -1
  428. package/dist/schema/state/sqlite/system-tables.d.ts.map +0 -1
  429. package/dist/schema/state/sqlite/system-tables.js +0 -79
  430. package/dist/schema/state/sqlite/system-tables.js.map +0 -1
  431. package/dist/schema-management/migrations.test.d.ts +0 -2
  432. package/dist/schema-management/migrations.test.d.ts.map +0 -1
  433. package/dist/schema-management/migrations.test.js +0 -52
  434. package/dist/schema-management/migrations.test.js.map +0 -1
  435. package/dist/sync/next/graphology.d.ts +0 -8
  436. package/dist/sync/next/graphology.d.ts.map +0 -1
  437. package/dist/sync/next/graphology.js +0 -30
  438. package/dist/sync/next/graphology.js.map +0 -1
  439. package/dist/sync/next/graphology_.d.ts +0 -3
  440. package/dist/sync/next/graphology_.d.ts.map +0 -1
  441. package/dist/sync/next/graphology_.js +0 -3
  442. package/dist/sync/next/graphology_.js.map +0 -1
  443. package/src/schema/EventDef.ts +0 -219
  444. package/src/schema/EventSequenceNumber.ts +0 -199
  445. package/src/schema/LiveStoreEvent.ts +0 -287
  446. package/src/schema/state/sqlite/system-tables.ts +0 -104
  447. package/src/sync/next/ambient.d.ts +0 -3
  448. package/src/sync/next/graphology.ts +0 -41
  449. package/src/sync/next/graphology_.ts +0 -2
@@ -35,7 +35,6 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
35
35
  select: { columns },
36
36
  }) as any
37
37
  },
38
- // biome-ignore lint/complexity/useArrowFunction: prefer function over arrow function for this case
39
38
  where: function () {
40
39
  if (ast._tag === 'InsertQuery') return invalidQueryBuilder('Cannot use where with insert')
41
40
  if (ast._tag === 'RowQuery') return invalidQueryBuilder('Cannot use where with row')
@@ -219,21 +218,27 @@ export const makeQueryBuilder = <TResult, TTableDef extends TableDefBase>(
219
218
  update: (values) => {
220
219
  const filteredValues = Object.fromEntries(Object.entries(values).filter(([, value]) => value !== undefined))
221
220
 
221
+ // Preserve where clauses if coming from a SelectQuery
222
+ const whereClause = ast._tag === 'SelectQuery' ? ast.where : []
223
+
222
224
  return makeQueryBuilder(tableDef, {
223
225
  _tag: 'UpdateQuery',
224
226
  tableDef,
225
227
  values: filteredValues,
226
- where: [],
228
+ where: whereClause,
227
229
  returning: undefined,
228
230
  resultSchema: Schema.Void,
229
231
  }) as any
230
232
  },
231
233
 
232
234
  delete: () => {
235
+ // Preserve where clauses if coming from a SelectQuery
236
+ const whereClause = ast._tag === 'SelectQuery' ? ast.where : []
237
+
233
238
  return makeQueryBuilder(tableDef, {
234
239
  _tag: 'DeleteQuery',
235
240
  tableDef,
236
- where: [],
241
+ where: whereClause,
237
242
  returning: undefined,
238
243
  resultSchema: Schema.Void,
239
244
  }) as any
@@ -0,0 +1,44 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import * as State from '../mod.ts'
4
+ import { getDefaultValuesDecoded, getDefaultValuesEncoded } from './schema-helpers.ts'
5
+
6
+ describe('schema-helpers', () => {
7
+ it('resolves thunk defaults when decoding values', () => {
8
+ let counter = 0
9
+ const table = State.SQLite.table({
10
+ name: 'sessions',
11
+ columns: {
12
+ id: State.SQLite.text({ primaryKey: true }),
13
+ token: State.SQLite.text({ default: () => `token-${++counter}` }),
14
+ },
15
+ })
16
+
17
+ expect(counter).toBe(0)
18
+
19
+ const firstDefaults = getDefaultValuesDecoded(table)
20
+ const secondDefaults = getDefaultValuesDecoded(table)
21
+
22
+ expect(firstDefaults.token).toBe('token-1')
23
+ expect(secondDefaults.token).toBe('token-2')
24
+ })
25
+
26
+ it('resolves thunk defaults when encoding values', () => {
27
+ let counter = 0
28
+ const table = State.SQLite.table({
29
+ name: 'sessions_encoded',
30
+ columns: {
31
+ id: State.SQLite.text({ primaryKey: true }),
32
+ token: State.SQLite.text({ default: () => `encoded-${++counter}` }),
33
+ },
34
+ })
35
+
36
+ expect(counter).toBe(0)
37
+
38
+ const firstDefaults = getDefaultValuesEncoded(table)
39
+ const secondDefaults = getDefaultValuesEncoded(table)
40
+
41
+ expect(firstDefaults.token).toBe('encoded-1')
42
+ expect(secondDefaults.token).toBe('encoded-2')
43
+ })
44
+ })
@@ -2,9 +2,9 @@ import { shouldNeverHappen } from '@livestore/utils'
2
2
  import { pipe, ReadonlyRecord, Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import { SqliteDsl } from './db-schema/mod.ts'
5
- import type { TableDef, TableDefBase } from './table-def.ts'
5
+ import type { TableDefBase } from './table-def.ts'
6
6
 
7
- export const getDefaultValuesEncoded = <TTableDef extends TableDef>(
7
+ export const getDefaultValuesEncoded = <TTableDef extends TableDefBase>(
8
8
  tableDef: TTableDef,
9
9
  fallbackValues?: Record<string, any>,
10
10
  ) =>
@@ -15,15 +15,19 @@ export const getDefaultValuesEncoded = <TTableDef extends TableDef>(
15
15
  if (key === 'id') return false
16
16
  return col!.default._tag === 'None' || SqliteDsl.isSqlDefaultValue(col!.default.value) === false
17
17
  }),
18
- ReadonlyRecord.map((column, columnName) =>
19
- fallbackValues?.[columnName] === undefined
20
- ? column!.default._tag === 'None'
21
- ? column!.nullable === true
22
- ? null
23
- : shouldNeverHappen(`Column ${columnName} has no default value and is not nullable`)
24
- : Schema.encodeSync(column!.schema)(column!.default.value)
25
- : fallbackValues[columnName],
26
- ),
18
+ ReadonlyRecord.map((column, columnName) => {
19
+ if (fallbackValues?.[columnName] !== undefined) return fallbackValues[columnName]
20
+ if (column!.default._tag === 'None') {
21
+ return column!.nullable === true
22
+ ? null
23
+ : shouldNeverHappen(`Column ${columnName} has no default value and is not nullable`)
24
+ }
25
+
26
+ const defaultValue = column!.default.value
27
+ const resolvedDefault = SqliteDsl.resolveColumnDefault(defaultValue)
28
+
29
+ return Schema.encodeSync(column!.schema)(resolvedDefault)
30
+ }),
27
31
  )
28
32
 
29
33
  export const getDefaultValuesDecoded = <TTableDef extends TableDefBase>(
@@ -37,13 +41,17 @@ export const getDefaultValuesDecoded = <TTableDef extends TableDefBase>(
37
41
  if (key === 'id') return false
38
42
  return col!.default._tag === 'None' || SqliteDsl.isSqlDefaultValue(col!.default.value) === false
39
43
  }),
40
- ReadonlyRecord.map((column, columnName) =>
41
- fallbackValues?.[columnName] === undefined
42
- ? column!.default._tag === 'None'
43
- ? column!.nullable === true
44
- ? null
45
- : shouldNeverHappen(`Column ${columnName} has no default value and is not nullable`)
46
- : Schema.validateSync(column!.schema)(column!.default.value)
47
- : fallbackValues[columnName],
48
- ),
44
+ ReadonlyRecord.map((column, columnName) => {
45
+ if (fallbackValues?.[columnName] !== undefined) return fallbackValues[columnName]
46
+ if (column!.default._tag === 'None') {
47
+ return column!.nullable === true
48
+ ? null
49
+ : shouldNeverHappen(`Column ${columnName} has no default value and is not nullable`)
50
+ }
51
+
52
+ const defaultValue = column!.default.value
53
+ const resolvedDefault = SqliteDsl.resolveColumnDefault(defaultValue)
54
+
55
+ return Schema.validateSync(column!.schema)(resolvedDefault)
56
+ }),
49
57
  )
@@ -0,0 +1,64 @@
1
+ import { Schema } from '@livestore/utils/effect'
2
+
3
+ import * as EventSequenceNumber from '../../../EventSequenceNumber/mod.ts'
4
+ import { SqliteDsl } from '../db-schema/mod.ts'
5
+ import { table } from '../table-def.ts'
6
+
7
+ /**
8
+ * EVENTLOG DATABASE SYSTEM TABLES
9
+ *
10
+ * ⚠️ CRITICAL: NEVER modify eventlog schemas without bumping `liveStoreStorageFormatVersion`!
11
+ * Eventlog is the source of truth - schema changes cause permanent data loss.
12
+ *
13
+ * TODO: Implement proper eventlog versioning system to prevent accidental data loss
14
+ */
15
+
16
+ export const EVENTLOG_META_TABLE = 'eventlog'
17
+
18
+ /**
19
+ * Main client-side event log storing all events (global and local/rebased).
20
+ */
21
+ export const eventlogMetaTable = table({
22
+ name: EVENTLOG_META_TABLE,
23
+ columns: {
24
+ // TODO Adjust modeling so a global event never needs a client id component
25
+ seqNumGlobal: SqliteDsl.integer({ primaryKey: true, schema: EventSequenceNumber.Global.Schema }),
26
+ seqNumClient: SqliteDsl.integer({ primaryKey: true, schema: EventSequenceNumber.Client.Schema }),
27
+ seqNumRebaseGeneration: SqliteDsl.integer({ primaryKey: true }),
28
+ parentSeqNumGlobal: SqliteDsl.integer({ schema: EventSequenceNumber.Global.Schema }),
29
+ parentSeqNumClient: SqliteDsl.integer({ schema: EventSequenceNumber.Client.Schema }),
30
+ parentSeqNumRebaseGeneration: SqliteDsl.integer({}),
31
+ /** Event definition name */
32
+ name: SqliteDsl.text({}),
33
+ argsJson: SqliteDsl.text({ schema: Schema.parseJson(Schema.Any) }),
34
+ clientId: SqliteDsl.text({}),
35
+ sessionId: SqliteDsl.text({}),
36
+ schemaHash: SqliteDsl.integer({}),
37
+ syncMetadataJson: SqliteDsl.text({ schema: Schema.parseJson(Schema.Option(Schema.JsonValue)) }),
38
+ },
39
+ indexes: [
40
+ { columns: ['seqNumGlobal'], name: 'idx_eventlog_seqNumGlobal' },
41
+ { columns: ['seqNumGlobal', 'seqNumClient', 'seqNumRebaseGeneration'], name: 'idx_eventlog_seqNum' },
42
+ ],
43
+ })
44
+
45
+ export type EventlogMetaRow = typeof eventlogMetaTable.Type
46
+
47
+ export const SYNC_STATUS_TABLE = '__livestore_sync_status'
48
+
49
+ /**
50
+ * Tracks sync status including the remote head position and backend identity.
51
+ */
52
+ // TODO support sync backend identity (to detect if sync backend changes)
53
+ export const syncStatusTable = table({
54
+ name: SYNC_STATUS_TABLE,
55
+ columns: {
56
+ head: SqliteDsl.integer({ primaryKey: true }),
57
+ // Null means the sync backend is not yet connected and we haven't yet seen a backend ID
58
+ backendId: SqliteDsl.text({ nullable: true }),
59
+ },
60
+ })
61
+
62
+ export type SyncStatusRow = typeof syncStatusTable.Type
63
+
64
+ export const eventlogSystemTables = [eventlogMetaTable, syncStatusTable] as const
@@ -0,0 +1,2 @@
1
+ export * from './eventlog-tables.ts'
2
+ export * from './state-tables.ts'
@@ -0,0 +1,69 @@
1
+ import * as EventSequenceNumber from '../../../EventSequenceNumber/mod.ts'
2
+ import { SqliteDsl } from '../db-schema/mod.ts'
3
+ import { table } from '../table-def.ts'
4
+
5
+ /**
6
+ * STATE DATABASE SYSTEM TABLES
7
+ *
8
+ * ⚠️ SAFE TO CHANGE: State tables are automatically rebuilt from eventlog when schema changes.
9
+ * No need to bump `liveStoreStorageFormatVersion` (uses hash-based migration via SqliteAst.hash()).
10
+ */
11
+
12
+ export const SCHEMA_META_TABLE = '__livestore_schema'
13
+
14
+ /**
15
+ * Tracks schema hashes for user-defined tables to detect schema changes.
16
+ */
17
+ export const schemaMetaTable = table({
18
+ name: SCHEMA_META_TABLE,
19
+ columns: {
20
+ tableName: SqliteDsl.text({ primaryKey: true }),
21
+ schemaHash: SqliteDsl.integer({ nullable: false }),
22
+ /** ISO date format */
23
+ updatedAt: SqliteDsl.text({ nullable: false }),
24
+ },
25
+ })
26
+
27
+ export type SchemaMetaRow = typeof schemaMetaTable.Type
28
+
29
+ export const SCHEMA_EVENT_DEFS_META_TABLE = '__livestore_schema_event_defs'
30
+
31
+ /**
32
+ * Tracks schema hashes for event definitions to detect event schema changes.
33
+ */
34
+ export const schemaEventDefsMetaTable = table({
35
+ name: SCHEMA_EVENT_DEFS_META_TABLE,
36
+ columns: {
37
+ eventName: SqliteDsl.text({ primaryKey: true }),
38
+ schemaHash: SqliteDsl.integer({ nullable: false }),
39
+ /** ISO date format */
40
+ updatedAt: SqliteDsl.text({ nullable: false }),
41
+ },
42
+ })
43
+
44
+ export type SchemaEventDefsMetaRow = typeof schemaEventDefsMetaTable.Type
45
+
46
+ /**
47
+ * Table which stores SQLite changeset blobs which is used for rolling back
48
+ * read-model state during rebasing.
49
+ */
50
+ export const SESSION_CHANGESET_META_TABLE = '__livestore_session_changeset'
51
+
52
+ export const sessionChangesetMetaTable = table({
53
+ name: SESSION_CHANGESET_META_TABLE,
54
+ columns: {
55
+ // TODO bring back primary key
56
+ seqNumGlobal: SqliteDsl.integer({ schema: EventSequenceNumber.Global.Schema }),
57
+ seqNumClient: SqliteDsl.integer({ schema: EventSequenceNumber.Client.Schema }),
58
+ seqNumRebaseGeneration: SqliteDsl.integer({}),
59
+ changeset: SqliteDsl.blob({ nullable: true }),
60
+ debug: SqliteDsl.json({ nullable: true }),
61
+ },
62
+ indexes: [{ columns: ['seqNumGlobal', 'seqNumClient'], name: 'idx_session_changeset_id' }],
63
+ })
64
+
65
+ export type SessionChangesetMetaRow = typeof sessionChangesetMetaTable.Type
66
+
67
+ export const stateSystemTables = [schemaMetaTable, schemaEventDefsMetaTable, sessionChangesetMetaTable] as const
68
+
69
+ export const isStateSystemTable = (tableName: string) => stateSystemTables.some((_) => _.sqliteDef.name === tableName)
@@ -178,6 +178,59 @@ describe('table function overloads', () => {
178
178
  expect(userTable.sqliteDef.columns.age.columnType).toBe('integer')
179
179
  })
180
180
 
181
+ it('should support schemas that transform flat columns into nested types', () => {
182
+ const Flat = Schema.Struct({
183
+ id: Schema.String.pipe(State.SQLite.withPrimaryKey),
184
+ contactFirstName: Schema.String,
185
+ contactLastName: Schema.String,
186
+ contactEmail: Schema.String.pipe(State.SQLite.withUnique),
187
+ })
188
+
189
+ const Nested = Schema.transform(
190
+ Flat,
191
+ Schema.Struct({
192
+ id: Schema.String,
193
+ contact: Schema.Struct({
194
+ firstName: Schema.String,
195
+ lastName: Schema.String,
196
+ email: Schema.String,
197
+ }),
198
+ }),
199
+ {
200
+ decode: ({ id, contactFirstName, contactLastName, contactEmail }) => ({
201
+ id,
202
+ contact: {
203
+ firstName: contactFirstName,
204
+ lastName: contactLastName,
205
+ email: contactEmail,
206
+ },
207
+ }),
208
+ encode: ({ id, contact }) => ({
209
+ id,
210
+ contactFirstName: contact.firstName,
211
+ contactLastName: contact.lastName,
212
+ contactEmail: contact.email,
213
+ }),
214
+ },
215
+ )
216
+
217
+ const contactsTable = State.SQLite.table({
218
+ name: 'contacts',
219
+ schema: Nested,
220
+ })
221
+
222
+ const columns = contactsTable.sqliteDef.columns
223
+
224
+ expect(Object.keys(columns)).toEqual(['id', 'contactFirstName', 'contactLastName', 'contactEmail'])
225
+ expect(columns.id.primaryKey).toBe(true)
226
+ expect(columns.contactEmail.columnType).toBe('text')
227
+ expect(contactsTable.sqliteDef.indexes).toContainEqual({
228
+ name: 'idx_contacts_contactEmail_unique',
229
+ columns: ['contactEmail'],
230
+ isUnique: true,
231
+ })
232
+ })
233
+
181
234
  it('should extract table name from Schema.Class identifier', () => {
182
235
  class TodoItem extends Schema.Class<TodoItem>('TodoItem')({
183
236
  id: Schema.String,
@@ -247,4 +300,52 @@ describe('table function overloads', () => {
247
300
  expect(userTable.sqliteDef.columns.metadata.columnType).toBe('text')
248
301
  expect(userTable.sqliteDef.columns.metadata.nullable).toBe(true)
249
302
  })
303
+
304
+ it('supports discriminated unions with parsed JSON payloads', () => {
305
+ const CircleDataSchema = Schema.Struct({
306
+ radius: Schema.Number,
307
+ })
308
+ const CircleSchema = Schema.Struct({
309
+ kind: Schema.Literal('circle'),
310
+ data: Schema.parseJson(CircleDataSchema),
311
+ })
312
+
313
+ const SquareDataSchema = Schema.Struct({
314
+ sideLength: Schema.Number,
315
+ })
316
+ const SquareSchema = Schema.Struct({
317
+ kind: Schema.Literal('square'),
318
+ data: Schema.parseJson(SquareDataSchema),
319
+ })
320
+
321
+ const ShapeSchema = Schema.Union(CircleSchema, SquareSchema)
322
+
323
+ const shapes = State.SQLite.table({
324
+ name: 'shapes',
325
+ schema: ShapeSchema,
326
+ })
327
+
328
+ expect(shapes.sqliteDef.columns.kind.columnType).toBe('text')
329
+
330
+ const kindSchema = shapes.sqliteDef.columns.kind.schema.toString()
331
+ expect(kindSchema).toContain('"circle" | "square"')
332
+
333
+ expect(() =>
334
+ shapes
335
+ .insert({
336
+ kind: 'square',
337
+ data: { sideLength: 10 },
338
+ })
339
+ .asSql(),
340
+ ).not.toThrow()
341
+
342
+ expect(() =>
343
+ shapes
344
+ .insert({
345
+ kind: 'circle',
346
+ data: { radius: 5 },
347
+ })
348
+ .asSql(),
349
+ ).not.toThrow()
350
+ })
250
351
  })
@@ -1,5 +1,5 @@
1
1
  import { type Nullable, shouldNeverHappen } from '@livestore/utils'
2
- import { Option, type Schema, SchemaAST, type Types } from '@livestore/utils/effect'
2
+ import { Option, Schema, SchemaAST, type Types } from '@livestore/utils/effect'
3
3
 
4
4
  import { getColumnDefForSchema, schemaFieldsToColumns } from './column-def.ts'
5
5
  import { SqliteDsl } from './db-schema/mod.ts'
@@ -221,7 +221,7 @@ export function table<
221
221
  ) as SqliteDsl.Columns
222
222
  additionalIndexes = []
223
223
  } else if ('schema' in args) {
224
- const result = schemaFieldsToColumns(SchemaAST.getPropertySignatures(args.schema.ast))
224
+ const result = schemaFieldsToColumns(Schema.getResolvedPropertySignatures(args.schema))
225
225
  columns = result.columns
226
226
 
227
227
  // We'll set tableName first, then use it for index names
@@ -381,12 +381,13 @@ export declare namespace SchemaToColumns {
381
381
  export type ColumnDefForType<TEncoded, TType> = SqliteDsl.ColumnDefinition<TEncoded, TType>
382
382
 
383
383
  // Create columns type from schema Type and Encoded
384
- export type FromTypes<TType, TEncoded> = TType extends Record<string, any>
385
- ? TEncoded extends Record<string, any>
386
- ? {
387
- [K in keyof TType & keyof TEncoded]: ColumnDefForType<TEncoded[K], TType[K]>
388
- }
389
- : SqliteDsl.Columns
384
+ export type FromTypes<TType, TEncoded> = TEncoded extends Record<string, any>
385
+ ? {
386
+ [K in keyof TEncoded]-?: ColumnDefForType<
387
+ TEncoded[K],
388
+ TType extends Record<string, any> ? (K extends keyof TType ? TType[K] : TEncoded[K]) : TEncoded[K]
389
+ >
390
+ }
390
391
  : SqliteDsl.Columns
391
392
  }
392
393
 
@@ -0,0 +1,131 @@
1
+ import { Effect } from '@livestore/utils/effect'
2
+
3
+ import { UnknownEventError } from '../errors.ts'
4
+ import type { EventDef, Materializer } from './EventDef/mod.ts'
5
+ import type * as LiveStoreEvent from './LiveStoreEvent/mod.ts'
6
+ import type { LiveStoreSchema } from './schema.ts'
7
+
8
+ export type UnknownEventContext = {
9
+ readonly event: Pick<LiveStoreEvent.Client.Encoded, 'name' | 'args' | 'seqNum' | 'clientId' | 'sessionId'>
10
+ readonly reason: 'event-definition-missing' | 'materializer-missing'
11
+ readonly operation: string
12
+ }
13
+
14
+ export namespace UnknownEvents {
15
+ export type HandlingStrategy = 'warn' | 'fail' | 'ignore' | 'callback'
16
+
17
+ export type Callback = (
18
+ context: UnknownEventContext,
19
+ error: UnknownEventError,
20
+ ) => Effect.SyncOrPromiseOrEffect<void, unknown, never>
21
+
22
+ export type HandlingConfig =
23
+ | { readonly strategy: 'warn' }
24
+ | { readonly strategy: 'ignore' }
25
+ | { readonly strategy: 'fail' }
26
+ | { readonly strategy: 'callback'; readonly onUnknownEvent: Callback }
27
+
28
+ export type Reason = UnknownEventContext['reason']
29
+
30
+ export type ResolveContext = Omit<UnknownEventContext, 'reason'>
31
+
32
+ export type Resolved =
33
+ | {
34
+ readonly _tag: 'known'
35
+ readonly eventDef: EventDef.AnyWithoutFn
36
+ readonly materializer: Materializer
37
+ }
38
+ | {
39
+ readonly _tag: 'unknown'
40
+ readonly reason: Reason
41
+ }
42
+ }
43
+
44
+ const DEFAULT_UNKNOWN_EVENT_HANDLING: UnknownEvents.HandlingConfig = { strategy: 'warn' }
45
+
46
+ export const normalizeUnknownEventHandling = (
47
+ input: UnknownEvents.HandlingConfig | undefined,
48
+ ): UnknownEvents.HandlingConfig => input ?? DEFAULT_UNKNOWN_EVENT_HANDLING
49
+
50
+ const handleUnknownEvent = ({
51
+ schema,
52
+ context,
53
+ }: {
54
+ schema: LiveStoreSchema
55
+ context: UnknownEventContext
56
+ }): Effect.Effect<void, UnknownEventError> =>
57
+ Effect.gen(function* () {
58
+ const config = schema.unknownEventHandling
59
+ const error = new UnknownEventError(context)
60
+
61
+ switch (config.strategy) {
62
+ case 'fail': {
63
+ return yield* Effect.fail(error)
64
+ }
65
+ case 'warn': {
66
+ yield* Effect.logWarning('@livestore/common:schema:unknown-event', context)
67
+ return
68
+ }
69
+ case 'ignore': {
70
+ return
71
+ }
72
+ case 'callback': {
73
+ const callback = config.onUnknownEvent
74
+
75
+ yield* Effect.tryAll<void>(() => callback(context, error)).pipe(
76
+ Effect.catchAll((cause) =>
77
+ Effect.logWarning('@livestore/common:schema:unknown-event:callback-error', {
78
+ event: context.event,
79
+ reason: context.reason,
80
+ operation: context.operation,
81
+ cause,
82
+ }),
83
+ ),
84
+ )
85
+ return
86
+ }
87
+ }
88
+ })
89
+
90
+ /**
91
+ * Resolves the runtime event definition + materializer for a given event name.
92
+ *
93
+ * Behaviour is intentionally split across the result and error channels:
94
+ * - For `'fail'` handling, we surface an `UnknownEventError` via the failure channel so
95
+ * callers can convert it into the appropriate domain error (for example `MaterializeError`).
96
+ * - For all other strategies (`warn`, `ignore`, `callback`) we succeed with an
97
+ * `{ _tag: 'unknown' }` value, signalling that the caller should skip the event while
98
+ * continuing normal processing.
99
+ */
100
+ export const resolveEventDef = (
101
+ schema: LiveStoreSchema,
102
+ context: UnknownEvents.ResolveContext,
103
+ ): Effect.Effect<UnknownEvents.Resolved, UnknownEventError> =>
104
+ Effect.gen(function* () {
105
+ const eventName = context.event.name
106
+ const eventDef = schema.eventsDefsMap.get(eventName)
107
+ if (eventDef === undefined) {
108
+ yield* handleUnknownEvent({
109
+ schema,
110
+ context: {
111
+ event: context.event,
112
+ reason: 'event-definition-missing',
113
+ operation: context.operation,
114
+ },
115
+ })
116
+ return { _tag: 'unknown', reason: 'event-definition-missing' }
117
+ }
118
+ const materializer = schema.state.materializers.get(eventName)
119
+ if (materializer === undefined) {
120
+ yield* handleUnknownEvent({
121
+ schema,
122
+ context: {
123
+ event: context.event,
124
+ reason: 'materializer-missing',
125
+ operation: context.operation,
126
+ },
127
+ })
128
+ return { _tag: 'unknown', reason: 'materializer-missing' }
129
+ }
130
+ return { _tag: 'known', eventDef, materializer }
131
+ })
@@ -0,0 +1,86 @@
1
+ import { Effect, Option, Schema } from '@livestore/utils/effect'
2
+ import { describe, expect, it } from 'vitest'
3
+ import { SqliteAst } from '../../schema/state/sqlite/db-schema/mod.ts'
4
+ import type { PreparedStatement, SqliteDb } from '../../sqlite-types.ts'
5
+ import type { PreparedBindValues } from '../../util.ts'
6
+ import { migrateTable } from '../migrations.ts'
7
+
8
+ const makeStubDb = () => {
9
+ const executed: string[] = []
10
+
11
+ const db: SqliteDb = {
12
+ _tag: 'SqliteDb',
13
+ metadata: { dbPointer: 0, persistenceInfo: { fileName: ':memory:' } } as any,
14
+ debug: { head: 0 as any },
15
+ prepare: (queryStr: string): PreparedStatement => ({
16
+ sql: queryStr,
17
+ execute: (_bind: PreparedBindValues | undefined) => {
18
+ executed.push(queryStr)
19
+ },
20
+ select: <T>(_bind: PreparedBindValues | undefined) => [] as unknown as ReadonlyArray<T>,
21
+ finalize: () => {},
22
+ }),
23
+ execute: () => {},
24
+ select: () => [],
25
+ export: () => new Uint8Array(),
26
+ import: () => {},
27
+ close: () => {},
28
+ destroy: () => {},
29
+ session: () => ({ changeset: () => undefined, finish: () => {} }),
30
+ makeChangeset: () => ({ invert: () => ({ invert: () => ({}) as any, apply: () => {} }) as any, apply: () => {} }),
31
+ }
32
+
33
+ return { db, executed }
34
+ }
35
+
36
+ describe('migrateTable - quoting and autoincrement', () => {
37
+ it('creates valid CREATE TABLE with inline INTEGER PRIMARY KEY AUTOINCREMENT and double-quoted identifiers', () => {
38
+ const { db, executed } = makeStubDb()
39
+
40
+ const table = SqliteAst.table(
41
+ 'todos',
42
+ [
43
+ SqliteAst.column({
44
+ name: 'id',
45
+ type: { _tag: 'integer' },
46
+ nullable: false,
47
+ primaryKey: true,
48
+ autoIncrement: true,
49
+ default: Option.none(),
50
+ schema: Schema.Number,
51
+ }),
52
+ SqliteAst.column({
53
+ name: 'text',
54
+ type: { _tag: 'text' },
55
+ nullable: false,
56
+ primaryKey: false,
57
+ autoIncrement: false,
58
+ default: Option.some(''),
59
+ schema: Schema.String,
60
+ }),
61
+ SqliteAst.column({
62
+ name: 'completed',
63
+ type: { _tag: 'integer' },
64
+ nullable: false,
65
+ primaryKey: false,
66
+ autoIncrement: false,
67
+ default: Option.some(0),
68
+ schema: Schema.Number,
69
+ }),
70
+ ],
71
+ [],
72
+ )
73
+
74
+ migrateTable({ db, tableAst: table, behaviour: 'create-if-not-exists', skipMetaTable: true }).pipe(Effect.runSync)
75
+
76
+ const createStmt = executed.find((s) => /create table if not exists/i.test(s))
77
+ expect(createStmt).toBeDefined()
78
+
79
+ // Identifiers must be double-quoted, not single-quoted
80
+ expect(createStmt!).toContain('create table if not exists "todos"')
81
+ expect(createStmt!).toContain('"id" integer primary key autoincrement')
82
+ expect(createStmt!).toContain(" default ''")
83
+ expect(createStmt!).not.toContain("PRIMARY KEY ('id')")
84
+ expect(createStmt!).not.toMatch(/'todos'|'id'|'text'/)
85
+ })
86
+ })