@livestore/common 0.3.0-dev.2 → 0.3.0-dev.21

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 (332) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/__tests__/fixture.d.ts +21 -21
  3. package/dist/adapter-types.d.ts +97 -53
  4. package/dist/adapter-types.d.ts.map +1 -1
  5. package/dist/adapter-types.js +17 -0
  6. package/dist/adapter-types.js.map +1 -1
  7. package/dist/bounded-collections.d.ts +1 -1
  8. package/dist/bounded-collections.d.ts.map +1 -1
  9. package/dist/debug-info.d.ts +1 -1
  10. package/dist/debug-info.d.ts.map +1 -1
  11. package/dist/derived-mutations.d.ts +5 -5
  12. package/dist/derived-mutations.d.ts.map +1 -1
  13. package/dist/derived-mutations.js +3 -3
  14. package/dist/derived-mutations.js.map +1 -1
  15. package/dist/derived-mutations.test.js.map +1 -1
  16. package/dist/devtools/devtools-messages-client-session.d.ts +389 -0
  17. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -0
  18. package/dist/devtools/devtools-messages-client-session.js +96 -0
  19. package/dist/devtools/devtools-messages-client-session.js.map +1 -0
  20. package/dist/devtools/devtools-messages-common.d.ts +61 -0
  21. package/dist/devtools/devtools-messages-common.d.ts.map +1 -0
  22. package/dist/devtools/devtools-messages-common.js +54 -0
  23. package/dist/devtools/devtools-messages-common.js.map +1 -0
  24. package/dist/devtools/devtools-messages-leader.d.ts +393 -0
  25. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -0
  26. package/dist/devtools/devtools-messages-leader.js +148 -0
  27. package/dist/devtools/devtools-messages-leader.js.map +1 -0
  28. package/dist/devtools/devtools-messages.d.ts +3 -592
  29. package/dist/devtools/devtools-messages.d.ts.map +1 -1
  30. package/dist/devtools/devtools-messages.js +3 -171
  31. package/dist/devtools/devtools-messages.js.map +1 -1
  32. package/dist/devtools/devtools-sessioninfo.d.ts +28 -0
  33. package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -0
  34. package/dist/devtools/devtools-sessioninfo.js +34 -0
  35. package/dist/devtools/devtools-sessioninfo.js.map +1 -0
  36. package/dist/devtools/devtools-sessions-channel.d.ts +28 -0
  37. package/dist/devtools/devtools-sessions-channel.d.ts.map +1 -0
  38. package/dist/devtools/devtools-sessions-channel.js +34 -0
  39. package/dist/devtools/devtools-sessions-channel.js.map +1 -0
  40. package/dist/devtools/index.d.ts +35 -38
  41. package/dist/devtools/index.d.ts.map +1 -1
  42. package/dist/devtools/index.js +20 -45
  43. package/dist/devtools/index.js.map +1 -1
  44. package/dist/devtools/mod.d.ts +39 -0
  45. package/dist/devtools/mod.d.ts.map +1 -0
  46. package/dist/devtools/mod.js +27 -0
  47. package/dist/devtools/mod.js.map +1 -0
  48. package/dist/index.d.ts +2 -6
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +2 -2
  51. package/dist/index.js.map +1 -1
  52. package/dist/init-singleton-tables.d.ts +2 -2
  53. package/dist/init-singleton-tables.d.ts.map +1 -1
  54. package/dist/init-singleton-tables.js.map +1 -1
  55. package/dist/leader-thread/LeaderSyncProcessor.d.ts +39 -0
  56. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -0
  57. package/dist/leader-thread/LeaderSyncProcessor.js +527 -0
  58. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -0
  59. package/dist/leader-thread/apply-mutation.d.ts +5 -2
  60. package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
  61. package/dist/leader-thread/apply-mutation.js +55 -35
  62. package/dist/leader-thread/apply-mutation.js.map +1 -1
  63. package/dist/leader-thread/connection.d.ts +34 -6
  64. package/dist/leader-thread/connection.d.ts.map +1 -1
  65. package/dist/leader-thread/connection.js +22 -7
  66. package/dist/leader-thread/connection.js.map +1 -1
  67. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
  68. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  69. package/dist/leader-thread/leader-worker-devtools.js +147 -124
  70. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  71. package/dist/leader-thread/make-leader-thread-layer.d.ts +12 -11
  72. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  73. package/dist/leader-thread/make-leader-thread-layer.js +55 -18
  74. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  75. package/dist/leader-thread/mutationlog.d.ts +6 -19
  76. package/dist/leader-thread/mutationlog.d.ts.map +1 -1
  77. package/dist/leader-thread/mutationlog.js +12 -9
  78. package/dist/leader-thread/mutationlog.js.map +1 -1
  79. package/dist/leader-thread/pull-queue-set.d.ts +3 -3
  80. package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
  81. package/dist/leader-thread/pull-queue-set.js +9 -0
  82. package/dist/leader-thread/pull-queue-set.js.map +1 -1
  83. package/dist/leader-thread/recreate-db.d.ts +4 -2
  84. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  85. package/dist/leader-thread/recreate-db.js +32 -21
  86. package/dist/leader-thread/recreate-db.js.map +1 -1
  87. package/dist/leader-thread/shutdown-channel.d.ts +2 -5
  88. package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
  89. package/dist/leader-thread/shutdown-channel.js +2 -4
  90. package/dist/leader-thread/shutdown-channel.js.map +1 -1
  91. package/dist/leader-thread/types.d.ts +58 -26
  92. package/dist/leader-thread/types.d.ts.map +1 -1
  93. package/dist/leader-thread/types.js +1 -3
  94. package/dist/leader-thread/types.js.map +1 -1
  95. package/dist/mutation.d.ts +9 -2
  96. package/dist/mutation.d.ts.map +1 -1
  97. package/dist/mutation.js +5 -5
  98. package/dist/mutation.js.map +1 -1
  99. package/dist/otel.d.ts +2 -0
  100. package/dist/otel.d.ts.map +1 -1
  101. package/dist/otel.js +5 -0
  102. package/dist/otel.js.map +1 -1
  103. package/dist/query-builder/api.d.ts +3 -3
  104. package/dist/query-builder/api.d.ts.map +1 -1
  105. package/dist/query-builder/impl.d.ts +4 -4
  106. package/dist/query-builder/impl.d.ts.map +1 -1
  107. package/dist/query-builder/impl.js.map +1 -1
  108. package/dist/query-builder/impl.test.js +16 -1
  109. package/dist/query-builder/impl.test.js.map +1 -1
  110. package/dist/query-info.d.ts +3 -3
  111. package/dist/query-info.d.ts.map +1 -1
  112. package/dist/rehydrate-from-mutationlog.d.ts +5 -5
  113. package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
  114. package/dist/rehydrate-from-mutationlog.js +23 -27
  115. package/dist/rehydrate-from-mutationlog.js.map +1 -1
  116. package/dist/schema/EventId.d.ts +27 -16
  117. package/dist/schema/EventId.d.ts.map +1 -1
  118. package/dist/schema/EventId.js +36 -11
  119. package/dist/schema/EventId.js.map +1 -1
  120. package/dist/schema/EventId.test.d.ts +2 -0
  121. package/dist/schema/EventId.test.d.ts.map +1 -0
  122. package/dist/schema/EventId.test.js +11 -0
  123. package/dist/schema/EventId.test.js.map +1 -0
  124. package/dist/schema/MutationEvent.d.ts +76 -82
  125. package/dist/schema/MutationEvent.d.ts.map +1 -1
  126. package/dist/schema/MutationEvent.js +53 -20
  127. package/dist/schema/MutationEvent.js.map +1 -1
  128. package/dist/schema/db-schema/ast/sqlite.d.ts +69 -0
  129. package/dist/schema/db-schema/ast/sqlite.d.ts.map +1 -0
  130. package/dist/schema/db-schema/ast/sqlite.js +71 -0
  131. package/dist/schema/db-schema/ast/sqlite.js.map +1 -0
  132. package/dist/schema/db-schema/ast/validate.d.ts +3 -0
  133. package/dist/schema/db-schema/ast/validate.d.ts.map +1 -0
  134. package/dist/schema/db-schema/ast/validate.js +12 -0
  135. package/dist/schema/db-schema/ast/validate.js.map +1 -0
  136. package/dist/schema/db-schema/dsl/field-defs.d.ts +90 -0
  137. package/dist/schema/db-schema/dsl/field-defs.d.ts.map +1 -0
  138. package/dist/schema/db-schema/dsl/field-defs.js +87 -0
  139. package/dist/schema/db-schema/dsl/field-defs.js.map +1 -0
  140. package/dist/schema/db-schema/dsl/field-defs.test.d.ts +2 -0
  141. package/dist/schema/db-schema/dsl/field-defs.test.d.ts.map +1 -0
  142. package/dist/schema/db-schema/dsl/field-defs.test.js +29 -0
  143. package/dist/schema/db-schema/dsl/field-defs.test.js.map +1 -0
  144. package/dist/schema/db-schema/dsl/mod.d.ts +88 -0
  145. package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -0
  146. package/dist/schema/db-schema/dsl/mod.js +35 -0
  147. package/dist/schema/db-schema/dsl/mod.js.map +1 -0
  148. package/dist/schema/db-schema/hash.d.ts +2 -0
  149. package/dist/schema/db-schema/hash.d.ts.map +1 -0
  150. package/dist/schema/db-schema/hash.js +14 -0
  151. package/dist/schema/db-schema/hash.js.map +1 -0
  152. package/dist/schema/db-schema/mod.d.ts +3 -0
  153. package/dist/schema/db-schema/mod.d.ts.map +1 -0
  154. package/dist/schema/db-schema/mod.js +3 -0
  155. package/dist/schema/db-schema/mod.js.map +1 -0
  156. package/dist/schema/mod.d.ts +1 -0
  157. package/dist/schema/mod.d.ts.map +1 -1
  158. package/dist/schema/mod.js +1 -0
  159. package/dist/schema/mod.js.map +1 -1
  160. package/dist/schema/mutations.d.ts +8 -9
  161. package/dist/schema/mutations.d.ts.map +1 -1
  162. package/dist/schema/mutations.js +2 -2
  163. package/dist/schema/mutations.js.map +1 -1
  164. package/dist/schema/schema-helpers.d.ts.map +1 -1
  165. package/dist/schema/schema-helpers.js +1 -1
  166. package/dist/schema/schema-helpers.js.map +1 -1
  167. package/dist/schema/schema.d.ts +5 -2
  168. package/dist/schema/schema.d.ts.map +1 -1
  169. package/dist/schema/schema.js +20 -9
  170. package/dist/schema/schema.js.map +1 -1
  171. package/dist/schema/system-tables.d.ts +65 -47
  172. package/dist/schema/system-tables.d.ts.map +1 -1
  173. package/dist/schema/system-tables.js +24 -13
  174. package/dist/schema/system-tables.js.map +1 -1
  175. package/dist/schema/table-def.d.ts +18 -24
  176. package/dist/schema/table-def.d.ts.map +1 -1
  177. package/dist/schema/table-def.js +3 -4
  178. package/dist/schema/table-def.js.map +1 -1
  179. package/dist/schema-management/common.d.ts +3 -3
  180. package/dist/schema-management/common.d.ts.map +1 -1
  181. package/dist/schema-management/common.js.map +1 -1
  182. package/dist/schema-management/migrations.d.ts +6 -6
  183. package/dist/schema-management/migrations.d.ts.map +1 -1
  184. package/dist/schema-management/migrations.js +13 -8
  185. package/dist/schema-management/migrations.js.map +1 -1
  186. package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -1
  187. package/dist/schema-management/validate-mutation-defs.js +2 -2
  188. package/dist/schema-management/validate-mutation-defs.js.map +1 -1
  189. package/dist/sql-queries/misc.d.ts.map +1 -1
  190. package/dist/sql-queries/sql-queries.d.ts +1 -1
  191. package/dist/sql-queries/sql-queries.d.ts.map +1 -1
  192. package/dist/sql-queries/sql-queries.js.map +1 -1
  193. package/dist/sql-queries/sql-query-builder.d.ts +1 -1
  194. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  195. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  196. package/dist/sql-queries/types.d.ts +2 -1
  197. package/dist/sql-queries/types.d.ts.map +1 -1
  198. package/dist/sql-queries/types.js.map +1 -1
  199. package/dist/sync/{client-session-sync-processor.d.ts → ClientSessionSyncProcessor.d.ts} +25 -14
  200. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -0
  201. package/dist/sync/ClientSessionSyncProcessor.js +199 -0
  202. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -0
  203. package/dist/sync/index.d.ts +1 -1
  204. package/dist/sync/index.d.ts.map +1 -1
  205. package/dist/sync/index.js +1 -1
  206. package/dist/sync/index.js.map +1 -1
  207. package/dist/sync/next/compact-events.d.ts.map +1 -1
  208. package/dist/sync/next/facts.d.ts.map +1 -1
  209. package/dist/sync/next/facts.js +1 -1
  210. package/dist/sync/next/facts.js.map +1 -1
  211. package/dist/sync/next/history-dag-common.d.ts +3 -4
  212. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  213. package/dist/sync/next/history-dag-common.js +3 -1
  214. package/dist/sync/next/history-dag-common.js.map +1 -1
  215. package/dist/sync/next/history-dag.d.ts.map +1 -1
  216. package/dist/sync/next/history-dag.js +1 -1
  217. package/dist/sync/next/history-dag.js.map +1 -1
  218. package/dist/sync/next/rebase-events.d.ts +6 -4
  219. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  220. package/dist/sync/next/rebase-events.js +6 -3
  221. package/dist/sync/next/rebase-events.js.map +1 -1
  222. package/dist/sync/next/test/compact-events.calculator.test.js +12 -12
  223. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  224. package/dist/sync/next/test/compact-events.test.js +43 -43
  225. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  226. package/dist/sync/next/test/mutation-fixtures.d.ts +4 -4
  227. package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -1
  228. package/dist/sync/next/test/mutation-fixtures.js +12 -16
  229. package/dist/sync/next/test/mutation-fixtures.js.map +1 -1
  230. package/dist/sync/sync.d.ts +31 -16
  231. package/dist/sync/sync.d.ts.map +1 -1
  232. package/dist/sync/sync.js +7 -3
  233. package/dist/sync/sync.js.map +1 -1
  234. package/dist/sync/syncstate.d.ts +177 -44
  235. package/dist/sync/syncstate.d.ts.map +1 -1
  236. package/dist/sync/syncstate.js +188 -56
  237. package/dist/sync/syncstate.js.map +1 -1
  238. package/dist/sync/syncstate.test.js +162 -92
  239. package/dist/sync/syncstate.test.js.map +1 -1
  240. package/dist/sync/validate-push-payload.d.ts +2 -2
  241. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  242. package/dist/sync/validate-push-payload.js +2 -2
  243. package/dist/sync/validate-push-payload.js.map +1 -1
  244. package/dist/util.d.ts +2 -2
  245. package/dist/util.d.ts.map +1 -1
  246. package/dist/version.d.ts +1 -1
  247. package/dist/version.d.ts.map +1 -1
  248. package/dist/version.js +1 -1
  249. package/dist/version.js.map +1 -1
  250. package/package.json +6 -6
  251. package/src/adapter-types.ts +80 -56
  252. package/src/derived-mutations.test.ts +1 -1
  253. package/src/derived-mutations.ts +13 -9
  254. package/src/devtools/devtools-messages-client-session.ts +141 -0
  255. package/src/devtools/devtools-messages-common.ts +106 -0
  256. package/src/devtools/devtools-messages-leader.ts +192 -0
  257. package/src/devtools/devtools-messages.ts +3 -243
  258. package/src/devtools/devtools-sessioninfo.ts +99 -0
  259. package/src/devtools/mod.ts +36 -0
  260. package/src/index.ts +2 -8
  261. package/src/init-singleton-tables.ts +2 -2
  262. package/src/leader-thread/LeaderSyncProcessor.ts +833 -0
  263. package/src/leader-thread/apply-mutation.ts +87 -43
  264. package/src/leader-thread/connection.ts +54 -9
  265. package/src/leader-thread/leader-worker-devtools.ts +199 -174
  266. package/src/leader-thread/make-leader-thread-layer.ts +89 -35
  267. package/src/leader-thread/mutationlog.ts +20 -14
  268. package/src/leader-thread/pull-queue-set.ts +10 -1
  269. package/src/leader-thread/recreate-db.ts +38 -25
  270. package/src/leader-thread/shutdown-channel.ts +2 -4
  271. package/src/leader-thread/types.ts +68 -34
  272. package/src/mutation.ts +17 -7
  273. package/src/otel.ts +8 -0
  274. package/src/query-builder/api.ts +4 -4
  275. package/src/query-builder/impl.test.ts +22 -1
  276. package/src/query-builder/impl.ts +2 -2
  277. package/src/query-info.ts +3 -3
  278. package/src/rehydrate-from-mutationlog.ts +28 -34
  279. package/src/schema/EventId.test.ts +12 -0
  280. package/src/schema/EventId.ts +49 -15
  281. package/src/schema/MutationEvent.ts +78 -31
  282. package/src/schema/db-schema/ast/sqlite.ts +142 -0
  283. package/src/schema/db-schema/ast/validate.ts +13 -0
  284. package/src/schema/db-schema/dsl/__snapshots__/field-defs.test.ts.snap +206 -0
  285. package/src/schema/db-schema/dsl/field-defs.test.ts +35 -0
  286. package/src/schema/db-schema/dsl/field-defs.ts +242 -0
  287. package/src/schema/db-schema/dsl/mod.ts +195 -0
  288. package/src/schema/db-schema/hash.ts +14 -0
  289. package/src/schema/db-schema/mod.ts +2 -0
  290. package/src/schema/mod.ts +1 -0
  291. package/src/schema/mutations.ts +10 -20
  292. package/src/schema/schema-helpers.ts +1 -1
  293. package/src/schema/schema.ts +22 -10
  294. package/src/schema/system-tables.ts +24 -13
  295. package/src/schema/table-def.ts +17 -17
  296. package/src/schema-management/common.ts +3 -3
  297. package/src/schema-management/migrations.ts +19 -15
  298. package/src/schema-management/validate-mutation-defs.ts +2 -2
  299. package/src/sql-queries/sql-queries.ts +1 -1
  300. package/src/sql-queries/sql-query-builder.ts +1 -2
  301. package/src/sql-queries/types.ts +3 -1
  302. package/src/sync/ClientSessionSyncProcessor.ts +313 -0
  303. package/src/sync/index.ts +1 -1
  304. package/src/sync/next/facts.ts +1 -1
  305. package/src/sync/next/history-dag-common.ts +5 -1
  306. package/src/sync/next/history-dag.ts +1 -1
  307. package/src/sync/next/rebase-events.ts +13 -7
  308. package/src/sync/next/test/compact-events.calculator.test.ts +12 -12
  309. package/src/sync/next/test/compact-events.test.ts +43 -43
  310. package/src/sync/next/test/mutation-fixtures.ts +16 -19
  311. package/src/sync/sync.ts +26 -10
  312. package/src/sync/syncstate.test.ts +178 -98
  313. package/src/sync/syncstate.ts +170 -83
  314. package/src/sync/validate-push-payload.ts +7 -4
  315. package/src/version.ts +1 -1
  316. package/tmp/pack.tgz +0 -0
  317. package/tsconfig.json +1 -1
  318. package/dist/devtools/devtools-bridge.d.ts +0 -12
  319. package/dist/devtools/devtools-bridge.d.ts.map +0 -1
  320. package/dist/devtools/devtools-bridge.js +0 -2
  321. package/dist/devtools/devtools-bridge.js.map +0 -1
  322. package/dist/leader-thread/leader-sync-processor.d.ts +0 -47
  323. package/dist/leader-thread/leader-sync-processor.d.ts.map +0 -1
  324. package/dist/leader-thread/leader-sync-processor.js +0 -422
  325. package/dist/leader-thread/leader-sync-processor.js.map +0 -1
  326. package/dist/sync/client-session-sync-processor.d.ts.map +0 -1
  327. package/dist/sync/client-session-sync-processor.js +0 -131
  328. package/dist/sync/client-session-sync-processor.js.map +0 -1
  329. package/src/devtools/devtools-bridge.ts +0 -13
  330. package/src/devtools/index.ts +0 -48
  331. package/src/leader-thread/leader-sync-processor.ts +0 -666
  332. package/src/sync/client-session-sync-processor.ts +0 -207
@@ -1,22 +1,29 @@
1
- import { memoizeByRef, shouldNeverHappen } from '@livestore/utils'
1
+ import { LS_DEV, memoizeByRef, shouldNeverHappen } from '@livestore/utils'
2
2
  import type { Scope } from '@livestore/utils/effect'
3
3
  import { Effect, Option, Schema } from '@livestore/utils/effect'
4
4
 
5
- import type { SqliteError, SynchronousDatabase, UnexpectedError } from '../index.js'
5
+ import type { PreparedBindValues, SqliteDb, SqliteError, UnexpectedError } from '../index.js'
6
+ import { getExecArgsFromMutation } from '../mutation.js'
6
7
  import {
7
- getExecArgsFromMutation,
8
+ EventId,
9
+ getMutationDef,
10
+ type LiveStoreSchema,
8
11
  MUTATION_LOG_META_TABLE,
12
+ type MutationEvent,
9
13
  mutationLogMetaTable,
10
14
  SESSION_CHANGESET_META_TABLE,
11
15
  sessionChangesetMetaTable,
12
- } from '../index.js'
13
- import type { LiveStoreSchema, MutationEvent } from '../schema/mod.js'
16
+ } from '../schema/mod.js'
14
17
  import { insertRow } from '../sql-queries/index.js'
15
18
  import { execSql, execSqlPrepared } from './connection.js'
16
19
  import { LeaderThreadCtx } from './types.js'
17
20
 
18
21
  export type ApplyMutation = (
19
22
  mutationEventEncoded: MutationEvent.AnyEncoded,
23
+ options?: {
24
+ /** Needed for rehydrateFromMutationLog */
25
+ skipMutationLog?: boolean
26
+ },
20
27
  ) => Effect.Effect<void, SqliteError | UnexpectedError>
21
28
 
22
29
  export const makeApplyMutation: Effect.Effect<ApplyMutation, never, Scope.Scope | LeaderThreadCtx> = Effect.gen(
@@ -28,18 +35,30 @@ export const makeApplyMutation: Effect.Effect<ApplyMutation, never, Scope.Scope
28
35
  // TODO Running `Schema.hash` can be a bottleneck for larger schemas. There is an opportunity to run this
29
36
  // at build time and lookup the pre-computed hash at runtime.
30
37
  // Also see https://github.com/Effect-TS/effect/issues/2719
31
- [...leaderThreadCtx.schema.mutations.entries()].map(([k, v]) => [k, Schema.hash(v.schema)] as const),
38
+ [...leaderThreadCtx.schema.mutations.map.entries()].map(([k, v]) => [k, Schema.hash(v.schema)] as const),
32
39
  )
33
40
 
34
- return (mutationEventEncoded) =>
41
+ return (mutationEventEncoded, options) =>
35
42
  Effect.gen(function* () {
36
- const { mutationEventSchema, schema, db, dbLog } = leaderThreadCtx
37
- const mutationEventDecoded = Schema.decodeUnknownSync(mutationEventSchema)(mutationEventEncoded)
38
-
39
- const mutationName = mutationEventDecoded.mutation
40
- const mutationDef = schema.mutations.get(mutationName) ?? shouldNeverHappen(`Unknown mutation: ${mutationName}`)
41
-
42
- const execArgsArr = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
43
+ const { schema, dbReadModel: db, dbMutationLog } = leaderThreadCtx
44
+ const skipMutationLog = options?.skipMutationLog ?? false
45
+
46
+ const mutationName = mutationEventEncoded.mutation
47
+ const mutationDef = getMutationDef(schema, mutationName)
48
+
49
+ const execArgsArr = getExecArgsFromMutation({
50
+ mutationDef,
51
+ mutationEvent: { decoded: undefined, encoded: mutationEventEncoded },
52
+ })
53
+
54
+ // NOTE we might want to bring this back if we want to debug no-op mutations
55
+ // const makeExecuteOptions = (statementSql: string, bindValues: any) => ({
56
+ // onRowsChanged: (rowsChanged: number) => {
57
+ // if (rowsChanged === 0) {
58
+ // console.warn(`Mutation "${mutationDef.name}" did not affect any rows:`, statementSql, bindValues)
59
+ // }
60
+ // },
61
+ // })
43
62
 
44
63
  // console.group('[@livestore/common:leader-thread:applyMutation]', { mutationName })
45
64
 
@@ -53,31 +72,35 @@ export const makeApplyMutation: Effect.Effect<ApplyMutation, never, Scope.Scope
53
72
 
54
73
  const changeset = session.changeset()
55
74
  session.finish()
56
- // NOTE for no-op mutations (e.g. if the state didn't change) the changeset will be empty
57
- // TODO possibly write a null value instead of omitting the row
58
- if (changeset !== undefined && changeset.length > 0) {
59
- // TODO use prepared statements
60
- yield* execSql(
61
- db,
62
- ...insertRow({
63
- tableName: SESSION_CHANGESET_META_TABLE,
64
- columns: sessionChangesetMetaTable.sqliteDef.columns,
65
- values: {
66
- idGlobal: mutationEventEncoded.id.global,
67
- idLocal: mutationEventEncoded.id.local,
68
- changeset,
69
- debug: execArgsArr,
70
- },
71
- }),
72
- )
73
- }
75
+
76
+ // TODO use prepared statements
77
+ yield* execSql(
78
+ db,
79
+ ...insertRow({
80
+ tableName: SESSION_CHANGESET_META_TABLE,
81
+ columns: sessionChangesetMetaTable.sqliteDef.columns,
82
+ values: {
83
+ idGlobal: mutationEventEncoded.id.global,
84
+ idClient: mutationEventEncoded.id.client,
85
+ // NOTE the changeset will be empty (i.e. null) for no-op mutations
86
+ changeset: changeset ?? null,
87
+ debug: execArgsArr,
88
+ },
89
+ }),
90
+ )
74
91
 
75
92
  // console.groupEnd()
76
93
 
77
94
  // write to mutation_log
78
- const excludeFromMutationLog = shouldExcludeMutationFromLog(mutationName, mutationEventDecoded)
79
- if (excludeFromMutationLog === false) {
80
- yield* insertIntoMutationLog(mutationEventEncoded, dbLog, mutationDefSchemaHashMap)
95
+ const excludeFromMutationLog = shouldExcludeMutationFromLog(mutationName, mutationEventEncoded)
96
+ if (skipMutationLog === false && excludeFromMutationLog === false) {
97
+ yield* insertIntoMutationLog(
98
+ mutationEventEncoded,
99
+ dbMutationLog,
100
+ mutationDefSchemaHashMap,
101
+ mutationEventEncoded.clientId,
102
+ mutationEventEncoded.sessionId,
103
+ )
81
104
  } else {
82
105
  // console.debug('[@livestore/common:leader-thread] skipping mutation log write', mutation, statementSql, bindValues)
83
106
  }
@@ -86,7 +109,7 @@ export const makeApplyMutation: Effect.Effect<ApplyMutation, never, Scope.Scope
86
109
  attributes: {
87
110
  mutationName: mutationEventEncoded.mutation,
88
111
  mutationId: mutationEventEncoded.id,
89
- 'span.label': mutationEventEncoded.mutation,
112
+ 'span.label': `(${mutationEventEncoded.id.global},${mutationEventEncoded.id.client}) ${mutationEventEncoded.mutation}`,
90
113
  },
91
114
  }),
92
115
  // Effect.logDuration('@livestore/common:leader-thread:applyMutation'),
@@ -96,27 +119,45 @@ export const makeApplyMutation: Effect.Effect<ApplyMutation, never, Scope.Scope
96
119
 
97
120
  const insertIntoMutationLog = (
98
121
  mutationEventEncoded: MutationEvent.AnyEncoded,
99
- dbLog: SynchronousDatabase,
122
+ dbMutationLog: SqliteDb,
100
123
  mutationDefSchemaHashMap: Map<string, number>,
124
+ clientId: string,
125
+ sessionId: string | undefined,
101
126
  ) =>
102
127
  Effect.gen(function* () {
103
128
  const mutationName = mutationEventEncoded.mutation
104
129
  const mutationDefSchemaHash =
105
130
  mutationDefSchemaHashMap.get(mutationName) ?? shouldNeverHappen(`Unknown mutation: ${mutationName}`)
106
131
 
132
+ if (LS_DEV && mutationEventEncoded.parentId.global !== EventId.ROOT.global) {
133
+ const parentMutationExists =
134
+ dbMutationLog.select<{ count: number }>(
135
+ `SELECT COUNT(*) as count FROM ${MUTATION_LOG_META_TABLE} WHERE idGlobal = ? AND idClient = ?`,
136
+ [mutationEventEncoded.parentId.global, mutationEventEncoded.parentId.client] as any as PreparedBindValues,
137
+ )[0]!.count === 1
138
+
139
+ if (parentMutationExists === false) {
140
+ shouldNeverHappen(
141
+ `Parent mutation ${mutationEventEncoded.parentId.global},${mutationEventEncoded.parentId.client} does not exist`,
142
+ )
143
+ }
144
+ }
145
+
107
146
  // TODO use prepared statements
108
147
  yield* execSql(
109
- dbLog,
148
+ dbMutationLog,
110
149
  ...insertRow({
111
150
  tableName: MUTATION_LOG_META_TABLE,
112
151
  columns: mutationLogMetaTable.sqliteDef.columns,
113
152
  values: {
114
153
  idGlobal: mutationEventEncoded.id.global,
115
- idLocal: mutationEventEncoded.id.local,
154
+ idClient: mutationEventEncoded.id.client,
116
155
  parentIdGlobal: mutationEventEncoded.parentId.global,
117
- parentIdLocal: mutationEventEncoded.parentId.local,
156
+ parentIdClient: mutationEventEncoded.parentId.client,
118
157
  mutation: mutationEventEncoded.mutation,
119
158
  argsJson: mutationEventEncoded.args ?? {},
159
+ clientId,
160
+ sessionId: sessionId ?? null,
120
161
  schemaHash: mutationDefSchemaHash,
121
162
  syncMetadataJson: Option.none(),
122
163
  },
@@ -132,11 +173,14 @@ const makeShouldExcludeMutationFromLog = memoizeByRef((schema: LiveStoreSchema)
132
173
  ? (migrationOptions.excludeMutations ?? new Set(['livestore.RawSql']))
133
174
  : new Set(['livestore.RawSql'])
134
175
 
135
- return (mutationName: string, mutationEventDecoded: MutationEvent.Any): boolean => {
176
+ return (mutationName: string, mutationEventEncoded: MutationEvent.AnyEncoded): boolean => {
136
177
  if (mutationLogExclude.has(mutationName)) return true
137
178
 
138
- const mutationDef = schema.mutations.get(mutationName) ?? shouldNeverHappen(`Unknown mutation: ${mutationName}`)
139
- const execArgsArr = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
179
+ const mutationDef = getMutationDef(schema, mutationName)
180
+ const execArgsArr = getExecArgsFromMutation({
181
+ mutationDef,
182
+ mutationEvent: { decoded: undefined, encoded: mutationEventEncoded },
183
+ })
140
184
 
141
185
  return execArgsArr.some((_) => _.statementSql.includes('__livestore'))
142
186
  }
@@ -1,7 +1,7 @@
1
1
  // import type { WaSqlite } from '@livestore/sqlite-wasm'
2
2
  import { Effect } from '@livestore/utils/effect'
3
3
 
4
- import type { SynchronousDatabase } from '../adapter-types.js'
4
+ import type { SqliteDb } from '../adapter-types.js'
5
5
  import { SqliteError } from '../adapter-types.js'
6
6
  import type { BindValues } from '../sql-queries/index.js'
7
7
  import type { PreparedBindValues } from '../util.js'
@@ -12,21 +12,66 @@ namespace WaSqlite {
12
12
  export type SQLiteError = any
13
13
  }
14
14
 
15
- export const configureConnection = (syncDb: SynchronousDatabase, { fkEnabled }: { fkEnabled: boolean }) =>
15
+ type ConnectionOptions = {
16
+ /**
17
+ * The database connection locking mode.
18
+ *
19
+ * @remarks
20
+ *
21
+ * This **option is ignored** when used on an **in-memory database** as they can only operate in exclusive locking mode.
22
+ * In-memory databases can’t share state between connections (unless using a
23
+ * {@link https://www.sqlite.org/sharedcache.html#shared_cache_and_in_memory_databases|shared cache}),
24
+ * making concurrent access impossible. This is functionally equivalent to exclusive locking.
25
+ *
26
+ * @defaultValue
27
+ * The default is `"NORMAL"` unless it was unless overridden at compile-time using `SQLITE_DEFAULT_LOCKING_MODE`.
28
+ *
29
+ * @see {@link https://www.sqlite.org/pragma.html#pragma_locking_mode|`locking_mode` pragma}
30
+ */
31
+ lockingMode?: 'NORMAL' | 'EXCLUSIVE'
32
+
33
+ /**
34
+ * Whether to enforce foreign key constraints.
35
+ *
36
+ * @privateRemarks
37
+ *
38
+ * We require a value for this option to minimize future problems, as the default value might change in future
39
+ * versions of SQLite.
40
+ *
41
+ * @see {@link https://www.sqlite.org/pragma.html#pragma_foreign_keys|`foreign_keys` pragma}
42
+ */
43
+ foreignKeys: boolean
44
+ }
45
+
46
+ export const configureConnection = (sqliteDb: SqliteDb, { foreignKeys, lockingMode }: ConnectionOptions) =>
16
47
  execSql(
17
- syncDb,
48
+ sqliteDb,
49
+ // We use the WAL journal mode is significantly faster in most scenarios than the traditional rollback journal mode.
50
+ // It specifically significantly improves write performance. However, when using the WAL journal mode, transactions
51
+ // that involve changes against multiple ATTACHed databases are atomic for each database but are not atomic
52
+ // across all databases as a set. Additionally, it is not possible to change the page size after entering WAL mode,
53
+ // whether on an empty database or by using VACUUM or the backup API. To change the page size, we must switch to the
54
+ // rollback journal mode.
55
+ //
56
+ // When connected to an in-memory database, the WAL journal mode option is ignored because an in-memory database can
57
+ // only be in either the MEMORY or OFF options. By default, an in-memory database is in the MEMORY option, which
58
+ // means that it stores the rollback journal in volatile RAM. This saves disk I/O but at the expense of safety and
59
+ // integrity. If the thread using SQLite crashes in the middle of a transaction, then the database file will very
60
+ // likely go corrupt.
18
61
  sql`
62
+ -- disable WAL until we have it working properly
63
+ -- PRAGMA journal_mode=WAL;
19
64
  PRAGMA page_size=8192;
20
- PRAGMA journal_mode=MEMORY;
21
- ${fkEnabled ? sql`PRAGMA foreign_keys='ON';` : sql`PRAGMA foreign_keys='OFF';`}
65
+ PRAGMA foreign_keys=${foreignKeys ? 'ON' : 'OFF'};
66
+ ${lockingMode === undefined ? '' : sql`PRAGMA locking_mode=${lockingMode};`}
22
67
  `,
23
68
  {},
24
69
  )
25
70
 
26
- export const execSql = (syncDb: SynchronousDatabase, sql: string, bind: BindValues) => {
71
+ export const execSql = (sqliteDb: SqliteDb, sql: string, bind: BindValues) => {
27
72
  const bindValues = prepareBindValues(bind, sql)
28
73
  return Effect.try({
29
- try: () => syncDb.execute(sql, bindValues),
74
+ try: () => sqliteDb.execute(sql, bindValues),
30
75
  catch: (cause) =>
31
76
  new SqliteError({ cause, query: { bindValues, sql }, code: (cause as WaSqlite.SQLiteError).code }),
32
77
  }).pipe(
@@ -48,9 +93,9 @@ export const execSql = (syncDb: SynchronousDatabase, sql: string, bind: BindValu
48
93
  // }
49
94
 
50
95
  // TODO actually use prepared statements
51
- export const execSqlPrepared = (syncDb: SynchronousDatabase, sql: string, bindValues: PreparedBindValues) => {
96
+ export const execSqlPrepared = (sqliteDb: SqliteDb, sql: string, bindValues: PreparedBindValues) => {
52
97
  return Effect.try({
53
- try: () => syncDb.execute(sql, bindValues),
98
+ try: () => sqliteDb.execute(sql, bindValues),
54
99
  catch: (cause) =>
55
100
  new SqliteError({ cause, query: { bindValues, sql }, code: (cause as WaSqlite.SQLiteError).code }),
56
101
  }).pipe(