@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
@@ -56,9 +56,9 @@ describe('makeColumnSpec', () => {
56
56
  )
57
57
 
58
58
  const result = makeColumnSpec(table)
59
- expect(result).toMatchInlineSnapshot(`"'order' integer not null , 'group' text "`)
60
- expect(result).toContain("'order'")
61
- expect(result).toContain("'group'")
59
+ expect(result).toMatchInlineSnapshot(`""order" integer not null , "group" text "`)
60
+ expect(result).toContain('"order"')
61
+ expect(result).toContain('"group"')
62
62
  })
63
63
 
64
64
  it('should handle basic columns with primary keys', () => {
@@ -69,8 +69,7 @@ describe('makeColumnSpec', () => {
69
69
  )
70
70
 
71
71
  const result = makeColumnSpec(table)
72
- expect(result).toMatchInlineSnapshot(`"'id' text not null , 'name' text , PRIMARY KEY ('id')"`)
73
- expect(result).toContain("PRIMARY KEY ('id')")
72
+ expect(result).toMatchInlineSnapshot(`""id" text primary key , "name" text "`)
74
73
  })
75
74
 
76
75
  it('should handle multi-column primary keys', () => {
@@ -85,9 +84,9 @@ describe('makeColumnSpec', () => {
85
84
 
86
85
  const result = makeColumnSpec(table)
87
86
  expect(result).toMatchInlineSnapshot(
88
- `"'tenant_id' text not null , 'user_id' text not null , PRIMARY KEY ('tenant_id', 'user_id')"`,
87
+ `""tenant_id" text not null , "user_id" text not null , PRIMARY KEY ("tenant_id", "user_id")"`,
89
88
  )
90
- expect(result).toContain("PRIMARY KEY ('tenant_id', 'user_id')")
89
+ expect(result).toContain('PRIMARY KEY ("tenant_id", "user_id")')
91
90
  })
92
91
 
93
92
  it('should handle auto-increment columns', () => {
@@ -101,9 +100,9 @@ describe('makeColumnSpec', () => {
101
100
  )
102
101
 
103
102
  const result = makeColumnSpec(table)
104
- expect(result).toMatchInlineSnapshot(`"'id' integer not null autoincrement , 'title' text , PRIMARY KEY ('id')"`)
103
+ expect(result).toMatchInlineSnapshot(`""id" integer primary key autoincrement , "title" text "`)
105
104
  expect(result).toContain('autoincrement')
106
- expect(result).toContain("PRIMARY KEY ('id')")
105
+ expect(result).not.toContain("PRIMARY KEY ('id')")
107
106
  })
108
107
 
109
108
  it('should handle columns with default values', () => {
@@ -121,7 +120,7 @@ describe('makeColumnSpec', () => {
121
120
 
122
121
  const result = makeColumnSpec(table)
123
122
  expect(result).toMatchInlineSnapshot(
124
- `"'id' integer not null , 'name' text not null , 'price' real default 0, 'active' integer default true, 'description' text default 'No description', PRIMARY KEY ('id')"`,
123
+ `""id" integer primary key , "name" text not null , "price" real default 0, "active" integer default true, "description" text default 'No description'"`,
125
124
  )
126
125
  expect(result).toContain('default 0')
127
126
  expect(result).toContain('default true')
@@ -141,12 +140,28 @@ describe('makeColumnSpec', () => {
141
140
 
142
141
  const result = makeColumnSpec(table)
143
142
  expect(result).toMatchInlineSnapshot(
144
- `"'id' integer not null , 'created_at' text default CURRENT_TIMESTAMP, 'random_value' real default RANDOM(), PRIMARY KEY ('id')"`,
143
+ `""id" integer primary key , "created_at" text default CURRENT_TIMESTAMP, "random_value" real default RANDOM()"`,
145
144
  )
146
145
  expect(result).toContain('default CURRENT_TIMESTAMP')
147
146
  expect(result).toContain('default RANDOM()')
148
147
  })
149
148
 
149
+ it('should omit default clause for thunk defaults', () => {
150
+ const table = SqliteAst.table(
151
+ 'thunks',
152
+ [
153
+ createColumn('id', 'integer', { nullable: false, primaryKey: true }),
154
+ createColumn('token', 'text', { defaultValue: () => 'dynamic-token' }),
155
+ ],
156
+ [],
157
+ )
158
+
159
+ const result = makeColumnSpec(table)
160
+ expect(result).toMatchInlineSnapshot(`""id" integer primary key , "token" text "`)
161
+ expect(result).not.toContain('dynamic-token')
162
+ expect(result).not.toMatch(/token" text\s+default/i)
163
+ })
164
+
150
165
  it('should handle null default values', () => {
151
166
  const table = SqliteAst.table(
152
167
  'nullable_defaults',
@@ -158,9 +173,7 @@ describe('makeColumnSpec', () => {
158
173
  )
159
174
 
160
175
  const result = makeColumnSpec(table)
161
- expect(result).toMatchInlineSnapshot(
162
- `"'id' integer not null , 'optional_text' text default null, PRIMARY KEY ('id')"`,
163
- )
176
+ expect(result).toMatchInlineSnapshot(`""id" integer primary key , "optional_text" text default null"`)
164
177
  expect(result).toContain('default null')
165
178
  })
166
179
 
@@ -190,7 +203,7 @@ describe('makeColumnSpec', () => {
190
203
 
191
204
  const result = makeColumnSpec(table)
192
205
  expect(result).toMatchInlineSnapshot(
193
- `"'id' integer not null autoincrement , 'name' text not null default 'Unnamed', 'created_at' text not null default CURRENT_TIMESTAMP, 'status' text default 'pending', PRIMARY KEY ('id')"`,
206
+ `""id" integer primary key autoincrement , "name" text not null default 'Unnamed', "created_at" text not null default CURRENT_TIMESTAMP, "status" text default 'pending'"`,
194
207
  )
195
208
  })
196
209
 
@@ -213,7 +226,7 @@ describe('makeColumnSpec', () => {
213
226
  const result = makeColumnSpec(table)
214
227
  // The makeColumnSpec function only generates column specifications, not indexes
215
228
  expect(result).toMatchInlineSnapshot(
216
- `"'id' integer not null autoincrement , 'email' text not null , 'username' text not null , 'created_at' text default CURRENT_TIMESTAMP, PRIMARY KEY ('id')"`,
229
+ `""id" integer primary key autoincrement , "email" text not null , "username" text not null , "created_at" text default CURRENT_TIMESTAMP"`,
217
230
  )
218
231
  // Verify the table has the indexes (even though they're not in the column spec)
219
232
  expect(table.indexes).toHaveLength(3)
@@ -10,33 +10,58 @@ import { type SqliteAst, SqliteDsl } from './db-schema/mod.ts'
10
10
  * ```
11
11
  */
12
12
  export const makeColumnSpec = (tableAst: SqliteAst.Table) => {
13
- const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => `'${_.name}'`)
14
- const columnDefStrs = tableAst.columns.map(toSqliteColumnSpec)
13
+ const pkColumns = tableAst.columns.filter((_) => _.primaryKey)
14
+ const hasSinglePk = pkColumns.length === 1
15
+ const pkColumn = hasSinglePk ? pkColumns[0] : undefined
15
16
 
16
- if (primaryKeys.length > 0) {
17
- columnDefStrs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`)
17
+ // Build column definitions, handling the special SQLite rule that AUTOINCREMENT
18
+ // is only valid on a single column declared as INTEGER PRIMARY KEY (column-level).
19
+ const columnDefStrs = tableAst.columns.map((column) =>
20
+ toSqliteColumnSpec(column, {
21
+ inlinePrimaryKey: hasSinglePk && column === pkColumn && column.primaryKey === true,
22
+ }),
23
+ )
24
+
25
+ // For composite primary keys, add a table-level PRIMARY KEY clause.
26
+ if (pkColumns.length > 1) {
27
+ const quotedPkCols = pkColumns.map((_) => `"${_.name}"`)
28
+ columnDefStrs.push(`PRIMARY KEY (${quotedPkCols.join(', ')})`)
18
29
  }
19
30
 
20
31
  return columnDefStrs.join(', ')
21
32
  }
22
33
 
23
34
  /** NOTE primary keys are applied on a table level not on a column level to account for multi-column primary keys */
24
- const toSqliteColumnSpec = (column: SqliteAst.Column) => {
35
+ const toSqliteColumnSpec = (column: SqliteAst.Column, opts: { inlinePrimaryKey: boolean }) => {
25
36
  const columnTypeStr = column.type._tag
26
- const nullableStr = column.nullable === false ? 'not null' : ''
27
- const autoIncrementStr = column.autoIncrement ? 'autoincrement' : ''
37
+ // When PRIMARY KEY is declared inline, NOT NULL is implied and should not be emitted,
38
+ // and AUTOINCREMENT must immediately follow PRIMARY KEY within the same constraint.
39
+ const nullableStr = opts.inlinePrimaryKey ? '' : column.nullable === false ? 'not null' : ''
40
+
41
+ // Only include AUTOINCREMENT when it's valid: single-column INTEGER PRIMARY KEY
42
+ const includeAutoIncrement = opts.inlinePrimaryKey && column.type._tag === 'integer' && column.autoIncrement === true
43
+
44
+ const pkStr = opts.inlinePrimaryKey ? 'primary key' : ''
45
+ const autoIncrementStr = includeAutoIncrement ? 'autoincrement' : ''
46
+
28
47
  const defaultValueStr = (() => {
29
48
  if (column.default._tag === 'None') return ''
30
49
 
31
- if (column.default.value === null) return 'default null'
32
- if (SqliteDsl.isSqlDefaultValue(column.default.value)) return `default ${column.default.value.sql}`
50
+ const defaultValue = column.default.value
51
+ if (SqliteDsl.isDefaultThunk(defaultValue)) return ''
52
+
53
+ const resolvedDefault = SqliteDsl.resolveColumnDefault(defaultValue)
54
+
55
+ if (resolvedDefault === null) return 'default null'
56
+ if (SqliteDsl.isSqlDefaultValue(resolvedDefault)) return `default ${resolvedDefault.sql}`
33
57
 
34
58
  const encodeValue = Schema.encodeSync(column.schema)
35
- const encodedDefaultValue = encodeValue(column.default.value)
59
+ const encodedDefaultValue = encodeValue(resolvedDefault)
36
60
 
37
61
  if (columnTypeStr === 'text') return `default '${encodedDefaultValue}'`
38
62
  return `default ${encodedDefaultValue}`
39
63
  })()
40
64
 
41
- return `'${column.name}' ${columnTypeStr} ${nullableStr} ${autoIncrementStr} ${defaultValueStr}`
65
+ // Ensure order: PRIMARY KEY [AUTOINCREMENT] [NOT NULL] ...
66
+ return `"${column.name}" ${columnTypeStr} ${pkStr} ${autoIncrementStr} ${nullableStr} ${defaultValueStr}`
42
67
  }
@@ -1,4 +1,5 @@
1
- import { type Option, Schema } from '@livestore/utils/effect'
1
+ import { omitUndefineds } from '@livestore/utils'
2
+ import { type Option, Schema, SchemaAST } from '@livestore/utils/effect'
2
3
 
3
4
  import { hashCode } from '../hash.ts'
4
5
 
@@ -45,9 +46,7 @@ export const index = (
45
46
  ): Index => ({
46
47
  _tag: 'index',
47
48
  columns,
48
- name,
49
- unique,
50
- primaryKey,
49
+ ...omitUndefineds({ name, unique, primaryKey }),
51
50
  })
52
51
 
53
52
  export type ForeignKey = {
@@ -85,7 +84,19 @@ export type DbSchema = {
85
84
  export const dbSchema = (tables: Table[]): DbSchema => ({ _tag: 'dbSchema', tables })
86
85
 
87
86
  /**
88
- * NOTE we're only including SQLite-relevant information in the hash (which excludes the schema mapping)
87
+ * Helper to detect if a column is a JSON column (has parseJson transformation)
88
+ */
89
+ const isJsonColumn = (column: Column): boolean => {
90
+ if (column.type._tag !== 'text') return false
91
+
92
+ // Check if the schema AST is a parseJson transformation
93
+ const ast = column.schema.ast
94
+ return ast._tag === 'Transformation' && ast.annotations.schemaId === SchemaAST.ParseJsonSchemaId
95
+ }
96
+
97
+ /**
98
+ * NOTE we're now including JSON schema information for JSON columns
99
+ * to detect client document schema changes
89
100
  */
90
101
  export const hash = (obj: Table | Column | Index | ForeignKey | DbSchema): number =>
91
102
  hashCode(JSON.stringify(trimInfoForHasing(obj)))
@@ -101,7 +112,7 @@ const trimInfoForHasing = (obj: Table | Column | Index | ForeignKey | DbSchema):
101
112
  }
102
113
  }
103
114
  case 'column': {
104
- return {
115
+ const baseInfo: Record<string, any> = {
105
116
  _tag: 'column',
106
117
  name: obj.name,
107
118
  type: obj.type._tag,
@@ -110,6 +121,15 @@ const trimInfoForHasing = (obj: Table | Column | Index | ForeignKey | DbSchema):
110
121
  autoIncrement: obj.autoIncrement,
111
122
  default: obj.default,
112
123
  }
124
+
125
+ // NEW: Include schema hash for JSON columns
126
+ // This ensures that changes to the JSON schema are detected
127
+ if (isJsonColumn(obj) && obj.schema) {
128
+ // Use Effect's Schema.hash for consistent hashing
129
+ baseInfo.jsonSchemaHash = Schema.hash(obj.schema)
130
+ }
131
+
132
+ return baseInfo
113
133
  }
114
134
  case 'index': {
115
135
  return {
@@ -1,10 +1,27 @@
1
1
  import { casesHandled } from '@livestore/utils'
2
2
  import { Option, Schema } from '@livestore/utils/effect'
3
3
 
4
+ export type SqlDefaultValue = {
5
+ readonly sql: string
6
+ }
7
+
8
+ export const isSqlDefaultValue = (value: unknown): value is SqlDefaultValue => {
9
+ return typeof value === 'object' && value !== null && 'sql' in value && typeof (value as any).sql === 'string'
10
+ }
11
+
12
+ export type ColumnDefaultThunk<T> = () => T
13
+
14
+ export const isDefaultThunk = (value: unknown): value is ColumnDefaultThunk<unknown> => typeof value === 'function'
15
+
16
+ export type ColumnDefaultValue<T> = T | null | ColumnDefaultThunk<T | null> | SqlDefaultValue
17
+
18
+ export const resolveColumnDefault = <T>(value: ColumnDefaultValue<T>): T | null | SqlDefaultValue =>
19
+ isDefaultThunk(value) ? (value as ColumnDefaultThunk<T | null>)() : value
20
+
4
21
  export type ColumnDefinition<TEncoded, TDecoded> = {
5
22
  readonly columnType: FieldColumnType
6
23
  readonly schema: Schema.Schema<TDecoded, TEncoded>
7
- readonly default: Option.Option<TEncoded>
24
+ readonly default: Option.Option<ColumnDefaultValue<TDecoded>>
8
25
  /** @default false */
9
26
  readonly nullable: boolean
10
27
  /** @default false */
@@ -27,9 +44,17 @@ export const isColumnDefinition = (value: unknown): value is ColumnDefinition.An
27
44
  )
28
45
  }
29
46
 
47
+ type MaybeNull<T, TNullable extends boolean> = T | (TNullable extends true ? null : never)
48
+
49
+ type ColumnDefaultArg<T, TNullable extends boolean> =
50
+ | MaybeNull<T, TNullable>
51
+ | ColumnDefaultThunk<MaybeNull<T, TNullable>>
52
+ | SqlDefaultValue
53
+ | NoDefault
54
+
30
55
  export type ColumnDefinitionInput = {
31
56
  readonly schema?: Schema.Schema<unknown>
32
- readonly default?: unknown | NoDefault
57
+ readonly default?: ColumnDefaultArg<unknown, boolean>
33
58
  readonly nullable?: boolean
34
59
  readonly primaryKey?: boolean
35
60
  readonly autoIncrement?: boolean
@@ -38,14 +63,6 @@ export type ColumnDefinitionInput = {
38
63
  export const NoDefault = Symbol.for('NoDefault')
39
64
  export type NoDefault = typeof NoDefault
40
65
 
41
- export type SqlDefaultValue = {
42
- readonly sql: string
43
- }
44
-
45
- export const isSqlDefaultValue = (value: unknown): value is SqlDefaultValue => {
46
- return typeof value === 'object' && value !== null && 'sql' in value && typeof value.sql === 'string'
47
- }
48
-
49
66
  export type ColDefFn<TColumnType extends FieldColumnType> = {
50
67
  (): {
51
68
  columnType: TColumnType
@@ -59,7 +76,7 @@ export type ColDefFn<TColumnType extends FieldColumnType> = {
59
76
  TEncoded extends DefaultEncodedForColumnType<TColumnType>,
60
77
  TDecoded = DefaultEncodedForColumnType<TColumnType>,
61
78
  const TNullable extends boolean = false,
62
- const TDefault extends TDecoded | SqlDefaultValue | NoDefault | (TNullable extends true ? null : never) = NoDefault,
79
+ const TDefault extends ColumnDefaultArg<NoInfer<TDecoded>, TNullable> = NoDefault,
63
80
  const TPrimaryKey extends boolean = false,
64
81
  const TAutoIncrement extends boolean = false,
65
82
  >(args: {
@@ -132,7 +149,7 @@ export type SpecializedColDefFn<
132
149
  <
133
150
  TDecoded = TBaseDecoded,
134
151
  const TNullable extends boolean = false,
135
- const TDefault extends TDecoded | NoDefault | (TNullable extends true ? null : never) = NoDefault,
152
+ const TDefault extends ColumnDefaultArg<NoInfer<TDecoded>, TNullable> = NoDefault,
136
153
  const TPrimaryKey extends boolean = false,
137
154
  const TAutoIncrement extends boolean = false,
138
155
  >(
@@ -1,4 +1,5 @@
1
1
  import type { Nullable } from '@livestore/utils'
2
+ import { omitUndefineds } from '@livestore/utils'
2
3
  import type { Option, Types } from '@livestore/utils/effect'
3
4
  import { Schema } from '@livestore/utils/effect'
4
5
 
@@ -46,7 +47,7 @@ export const table = <TTableName extends string, TColumns extends Columns, TInde
46
47
  indexes: indexesToAst(indexes ?? []),
47
48
  }
48
49
 
49
- return { name, columns, indexes, ast }
50
+ return { name, columns, ...omitUndefineds({ indexes }), ast }
50
51
  }
51
52
 
52
53
  export type AnyIfConstained<In, Out> = '__constrained' extends keyof In ? any : Out
@@ -1,19 +1,20 @@
1
1
  import { shouldNeverHappen } from '@livestore/utils'
2
2
 
3
3
  import type { MigrationOptions } from '../../../adapter-types.ts'
4
- import type { Materializer } from '../../EventDef.ts'
4
+ import type { Materializer } from '../../EventDef/mod.ts'
5
5
  import type { InternalState } from '../../schema.ts'
6
6
  import { ClientDocumentTableDefSymbol, tableIsClientDocumentTable } from './client-document-def.ts'
7
7
  import { SqliteAst } from './db-schema/mod.ts'
8
- import { stateSystemTables } from './system-tables.ts'
8
+ import { stateSystemTables } from './system-tables/state-tables.ts'
9
9
  import type { TableDef, TableDefBase } from './table-def.ts'
10
10
 
11
- export * from '../../EventDef.ts'
11
+ export * from '../../EventDef/mod.ts'
12
12
  export {
13
13
  type ClientDocumentTableDef,
14
14
  ClientDocumentTableDefSymbol,
15
15
  type ClientDocumentTableOptions,
16
16
  clientDocument,
17
+ createOptimisticEventSchema,
17
18
  tableIsClientDocumentTable,
18
19
  } from './client-document-def.ts'
19
20
  export * from './column-annotations.ts'
@@ -3,7 +3,7 @@ import { type Option, Predicate, type Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import type { SessionIdSymbol } from '../../../../adapter-types.ts'
5
5
  import type { SqlValue } from '../../../../util.ts'
6
- import type { ClientDocumentTableDef } from '../client-document-def.ts'
6
+ import type { ClientDocumentTableDef, ClientDocumentTableDefSymbol } from '../client-document-def.ts'
7
7
  import type { SqliteDsl } from '../db-schema/mod.ts'
8
8
  import type { TableDefBase } from '../table-def.ts'
9
9
 
@@ -347,22 +347,26 @@ export namespace QueryBuilder {
347
347
  >
348
348
 
349
349
  /**
350
- * Example: If the row already exists, it will be ignored.
350
+ * Upsert: insert a row, or handle conflicts on existing rows.
351
+ * Equivalent to SQLite's `INSERT ... ON CONFLICT` clause.
352
+ *
353
+ * Actions:
354
+ * - `'ignore'`: Skip the insert if a row with the same key exists
355
+ * - `'replace'`: Delete the existing row and insert the new one
356
+ * - `'update'`: Update specific columns on the existing row
357
+ *
351
358
  * ```ts
359
+ * // Ignore: skip if row exists
352
360
  * db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' }).onConflict('id', 'ignore')
353
- * ```
354
361
  *
355
- * Example: If the row already exists, it will be replaced.
356
- * ```ts
362
+ * // Replace: delete existing row and insert new one
357
363
  * db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' }).onConflict('id', 'replace')
358
- * ```
359
364
  *
360
- * Example: If the row already exists, it will be updated.
361
- * ```ts
365
+ * // Update: merge specific columns into existing row
362
366
  * db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' }).onConflict('id', 'update', { text: 'Buy soy milk' })
363
367
  * ```
364
368
  *
365
- * NOTE This API doesn't yet support composite primary keys.
369
+ * NOTE: Composite primary keys are not yet supported.
366
370
  */
367
371
  readonly onConflict: {
368
372
  <TTarget extends SingleOrReadonlyArray<keyof TTableDef['sqliteDef']['columns']>>(
@@ -437,7 +441,12 @@ export namespace QueryBuilder {
437
441
 
438
442
  export namespace RowQuery {
439
443
  export type GetOrCreateOptions<TTableDef extends ClientDocumentTableDef.TraitAny> = {
440
- default: Partial<TTableDef['Value']>
444
+ /**
445
+ * Default value to use instead of the default value from the table definition
446
+ */
447
+ default: TTableDef[ClientDocumentTableDefSymbol]['options']['partialSet'] extends false
448
+ ? TTableDef['Value']
449
+ : Partial<TTableDef['Value']>
441
450
  }
442
451
 
443
452
  // TODO get rid of this
@@ -7,6 +7,8 @@ import type { State } from '../../../mod.ts'
7
7
  import type { QueryBuilderAst } from './api.ts'
8
8
 
9
9
  // Helper functions for SQL generation
10
+ const quoteIdentifier = (identifier: string): string => `"${identifier.replace(/"/g, '""')}"`
11
+
10
12
  const formatWhereClause = (
11
13
  whereConditions: ReadonlyArray<QueryBuilderAst.Where>,
12
14
  tableDef: State.SQLite.TableDefBase,
@@ -16,13 +18,15 @@ const formatWhereClause = (
16
18
 
17
19
  const whereClause = whereConditions
18
20
  .map(({ col, op, value }) => {
21
+ const quotedCol = quoteIdentifier(col)
22
+
19
23
  // Handle NULL values
20
24
  if (value === null) {
21
25
  if (op !== '=' && op !== '!=') {
22
26
  throw new Error(`Unsupported operator for NULL value: ${op}`)
23
27
  }
24
28
  const opStmt = op === '=' ? 'IS' : 'IS NOT'
25
- return `${col} ${opStmt} NULL`
29
+ return `${quotedCol} ${opStmt} NULL`
26
30
  }
27
31
 
28
32
  // Get column definition and encode value
@@ -48,11 +52,11 @@ const formatWhereClause = (
48
52
  const encodedValues = value.map((v) => Schema.encodeSync(colDef.schema)(v)) as SqlValue[]
49
53
  bindValues.push(...encodedValues)
50
54
  const placeholders = encodedValues.map(() => '?').join(', ')
51
- return `${col} ${op} (${placeholders})`
55
+ return `${quotedCol} ${op} (${placeholders})`
52
56
  } else {
53
57
  const encodedValue = Schema.encodeSync(colDef.schema)(value)
54
58
  bindValues.push(encodedValue as SqlValue)
55
- return `${col} ${op} ?`
59
+ return `${quotedCol} ${op} ?`
56
60
  }
57
61
  })
58
62
  .join(' AND ')
@@ -62,7 +66,7 @@ const formatWhereClause = (
62
66
 
63
67
  const formatReturningClause = (returning?: string[]): string => {
64
68
  if (!returning || returning.length === 0) return ''
65
- return ` RETURNING ${returning.join(', ')}`
69
+ return ` RETURNING ${returning.map(quoteIdentifier).join(', ')}`
66
70
  }
67
71
 
68
72
  export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: SqlValue[]; usedTables: Set<string> } => {
@@ -72,6 +76,7 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
72
76
  // INSERT query
73
77
  if (ast._tag === 'InsertQuery') {
74
78
  const columns = Object.keys(ast.values)
79
+ const quotedColumns = columns.map(quoteIdentifier)
75
80
  const placeholders = columns.map(() => '?').join(', ')
76
81
  const encodedValues = Schema.encodeSync(ast.tableDef.insertSchema)(ast.values)
77
82
 
@@ -91,7 +96,8 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
91
96
  // For REPLACE, the conflict target is implied and no further clause is needed
92
97
  } else {
93
98
  // Build the ON CONFLICT clause for IGNORE or UPDATE
94
- conflictClause = ` ON CONFLICT (${ast.onConflict.targets.join(', ')}) `
99
+ const conflictTargets = ast.onConflict.targets.map(quoteIdentifier).join(', ')
100
+ conflictClause = ` ON CONFLICT (${conflictTargets}) `
95
101
  if (ast.onConflict.action._tag === 'ignore') {
96
102
  conflictClause += 'DO NOTHING'
97
103
  } else {
@@ -105,8 +111,9 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
105
111
  const updates = updateCols
106
112
  .map((col) => {
107
113
  const value = updateValues[col]
114
+ const quotedCol = quoteIdentifier(col)
108
115
  // If the value is undefined, use excluded.col
109
- return value === undefined ? `${col} = excluded.${col}` : `${col} = ?`
116
+ return value === undefined ? `${quotedCol} = excluded.${quotedCol}` : `${quotedCol} = ?`
110
117
  })
111
118
  .join(', ')
112
119
 
@@ -129,7 +136,7 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
129
136
  }
130
137
 
131
138
  // Construct the main query part
132
- let query = `${insertVerb} INTO '${ast.tableDef.sqliteDef.name}' (${columns.join(', ')}) VALUES (${placeholders})`
139
+ let query = `${insertVerb} INTO '${ast.tableDef.sqliteDef.name}' (${quotedColumns.join(', ')}) VALUES (${placeholders})`
133
140
 
134
141
  // Append the conflict clause if it was generated (i.e., not for REPLACE)
135
142
  query += conflictClause
@@ -157,7 +164,9 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
157
164
  bindValues.push(encodedValues[col] as SqlValue)
158
165
  })
159
166
 
160
- let query = `UPDATE '${ast.tableDef.sqliteDef.name}' SET ${setColumns.map((col) => `${col} = ?`).join(', ')}`
167
+ let query = `UPDATE '${ast.tableDef.sqliteDef.name}' SET ${setColumns
168
+ .map((col) => `${quoteIdentifier(col)} = ?`)
169
+ .join(', ')}`
161
170
 
162
171
  const whereClause = formatWhereClause(ast.where, ast.tableDef, bindValues)
163
172
  if (whereClause) query += ` ${whereClause}`
@@ -201,31 +210,31 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
201
210
  const encodedId = ast.id === SessionIdSymbol ? ast.id : Schema.encodeSync(idColDef.schema)(ast.id)
202
211
 
203
212
  return {
204
- query: `SELECT * FROM '${ast.tableDef.sqliteDef.name}' WHERE id = ?`,
213
+ query: `SELECT * FROM '${ast.tableDef.sqliteDef.name}' WHERE ${quoteIdentifier('id')} = ?`,
205
214
  bindValues: [encodedId as SqlValue],
206
215
  usedTables,
207
216
  }
208
217
  }
209
218
 
210
219
  // SELECT query
211
- const columnsStmt = ast.select.columns.length === 0 ? '*' : ast.select.columns.join(', ')
220
+ const columnsStmt = ast.select.columns.length === 0 ? '*' : ast.select.columns.map(quoteIdentifier).join(', ')
212
221
  const selectStmt = `SELECT ${columnsStmt}`
213
222
  const fromStmt = `FROM '${ast.tableDef.sqliteDef.name}'`
214
223
  const whereStmt = formatWhereClause(ast.where, ast.tableDef, bindValues)
215
224
 
216
225
  const orderByStmt =
217
226
  ast.orderBy.length > 0
218
- ? `ORDER BY ${ast.orderBy.map(({ col, direction }) => `${col} ${direction}`).join(', ')}`
227
+ ? `ORDER BY ${ast.orderBy.map(({ col, direction }) => `${quoteIdentifier(col)} ${direction}`).join(', ')}`
219
228
  : ''
220
229
 
221
230
  const limitStmt = ast.limit._tag === 'Some' ? `LIMIT ?` : ''
222
231
  const offsetStmt = ast.offset._tag === 'Some' ? `OFFSET ?` : ''
223
232
 
224
- // Push offset and limit values in the correct order matching the query string
225
- if (ast.offset._tag === 'Some') bindValues.push(ast.offset.value)
233
+ // Push limit and offset values in the correct order matching the query string
226
234
  if (ast.limit._tag === 'Some') bindValues.push(ast.limit.value)
235
+ if (ast.offset._tag === 'Some') bindValues.push(ast.offset.value)
227
236
 
228
- const query = [selectStmt, fromStmt, whereStmt, orderByStmt, offsetStmt, limitStmt]
237
+ const query = [selectStmt, fromStmt, whereStmt, orderByStmt, limitStmt, offsetStmt]
229
238
  .map((clause) => clause.trim())
230
239
  .filter((clause) => clause.length > 0)
231
240
  .join(' ')