@livestore/common 0.3.0-dev.11 → 0.3.0-dev.13

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 (280) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/__tests__/fixture.d.ts +21 -21
  3. package/dist/adapter-types.d.ts +41 -18
  4. package/dist/adapter-types.d.ts.map +1 -1
  5. package/dist/adapter-types.js +12 -0
  6. package/dist/adapter-types.js.map +1 -1
  7. package/dist/db-schema/ast/sqlite.d.ts +69 -0
  8. package/dist/db-schema/ast/sqlite.d.ts.map +1 -0
  9. package/dist/db-schema/ast/sqlite.js +71 -0
  10. package/dist/db-schema/ast/sqlite.js.map +1 -0
  11. package/dist/db-schema/ast/validate.d.ts +3 -0
  12. package/dist/db-schema/ast/validate.d.ts.map +1 -0
  13. package/dist/db-schema/ast/validate.js +12 -0
  14. package/dist/db-schema/ast/validate.js.map +1 -0
  15. package/dist/db-schema/dsl/field-defs.d.ts +90 -0
  16. package/dist/db-schema/dsl/field-defs.d.ts.map +1 -0
  17. package/dist/db-schema/dsl/field-defs.js +87 -0
  18. package/dist/db-schema/dsl/field-defs.js.map +1 -0
  19. package/dist/db-schema/dsl/field-defs.test.d.ts +2 -0
  20. package/dist/db-schema/dsl/field-defs.test.d.ts.map +1 -0
  21. package/dist/db-schema/dsl/field-defs.test.js +29 -0
  22. package/dist/db-schema/dsl/field-defs.test.js.map +1 -0
  23. package/dist/db-schema/dsl/index.d.ts +88 -0
  24. package/dist/db-schema/dsl/index.d.ts.map +1 -0
  25. package/dist/db-schema/dsl/index.js +35 -0
  26. package/dist/db-schema/dsl/index.js.map +1 -0
  27. package/dist/db-schema/dsl/mod.d.ts +90 -0
  28. package/dist/db-schema/dsl/mod.d.ts.map +1 -0
  29. package/dist/db-schema/dsl/mod.js +35 -0
  30. package/dist/db-schema/dsl/mod.js.map +1 -0
  31. package/dist/db-schema/dsl/sqlite/field-defs.d.ts +90 -0
  32. package/dist/db-schema/dsl/sqlite/field-defs.d.ts.map +1 -0
  33. package/dist/db-schema/dsl/sqlite/field-defs.js +86 -0
  34. package/dist/db-schema/dsl/sqlite/field-defs.js.map +1 -0
  35. package/dist/db-schema/dsl/sqlite/field-defs.test.d.ts +2 -0
  36. package/dist/db-schema/dsl/sqlite/field-defs.test.d.ts.map +1 -0
  37. package/dist/db-schema/dsl/sqlite/field-defs.test.js +29 -0
  38. package/dist/db-schema/dsl/sqlite/field-defs.test.js.map +1 -0
  39. package/dist/db-schema/dsl/sqlite/index.d.ts +88 -0
  40. package/dist/db-schema/dsl/sqlite/index.d.ts.map +1 -0
  41. package/dist/db-schema/dsl/sqlite/index.js +35 -0
  42. package/dist/db-schema/dsl/sqlite/index.js.map +1 -0
  43. package/dist/db-schema/hash.d.ts +2 -0
  44. package/dist/db-schema/hash.d.ts.map +1 -0
  45. package/dist/db-schema/hash.js +14 -0
  46. package/dist/db-schema/hash.js.map +1 -0
  47. package/dist/db-schema/index.d.ts +4 -0
  48. package/dist/db-schema/index.d.ts.map +1 -0
  49. package/dist/db-schema/index.js +6 -0
  50. package/dist/db-schema/index.js.map +1 -0
  51. package/dist/db-schema/mod.d.ts +3 -0
  52. package/dist/db-schema/mod.d.ts.map +1 -0
  53. package/dist/db-schema/mod.js +3 -0
  54. package/dist/db-schema/mod.js.map +1 -0
  55. package/dist/derived-mutations.d.ts +1 -1
  56. package/dist/derived-mutations.d.ts.map +1 -1
  57. package/dist/derived-mutations.js +3 -3
  58. package/dist/derived-mutations.js.map +1 -1
  59. package/dist/devtools/devtools-bridge.d.ts +10 -7
  60. package/dist/devtools/devtools-bridge.d.ts.map +1 -1
  61. package/dist/devtools/devtools-messages-client-session.d.ts +101 -28
  62. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
  63. package/dist/devtools/devtools-messages-client-session.js +19 -3
  64. package/dist/devtools/devtools-messages-client-session.js.map +1 -1
  65. package/dist/devtools/devtools-messages-common.d.ts +24 -32
  66. package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
  67. package/dist/devtools/devtools-messages-common.js +19 -10
  68. package/dist/devtools/devtools-messages-common.js.map +1 -1
  69. package/dist/devtools/devtools-messages-leader.d.ts +220 -56
  70. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  71. package/dist/devtools/devtools-messages-leader.js +57 -9
  72. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  73. package/dist/devtools/devtools-messages.d.ts +2 -2
  74. package/dist/devtools/devtools-messages.d.ts.map +1 -1
  75. package/dist/devtools/devtools-messages.js +2 -2
  76. package/dist/devtools/devtools-messages.js.map +1 -1
  77. package/dist/index.d.ts +1 -1
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +1 -1
  80. package/dist/index.js.map +1 -1
  81. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  82. package/dist/leader-thread/LeaderSyncProcessor.js +50 -35
  83. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  84. package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
  85. package/dist/leader-thread/apply-mutation.js +8 -6
  86. package/dist/leader-thread/apply-mutation.js.map +1 -1
  87. package/dist/leader-thread/connection.d.ts +31 -3
  88. package/dist/leader-thread/connection.d.ts.map +1 -1
  89. package/dist/leader-thread/connection.js +18 -3
  90. package/dist/leader-thread/connection.js.map +1 -1
  91. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  92. package/dist/leader-thread/leader-worker-devtools.js +56 -31
  93. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  94. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  95. package/dist/leader-thread/make-leader-thread-layer.js +23 -6
  96. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  97. package/dist/leader-thread/mutationlog.d.ts +1 -1
  98. package/dist/leader-thread/mutationlog.d.ts.map +1 -1
  99. package/dist/leader-thread/mutationlog.js +7 -5
  100. package/dist/leader-thread/mutationlog.js.map +1 -1
  101. package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
  102. package/dist/leader-thread/recreate-db.d.ts +4 -2
  103. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  104. package/dist/leader-thread/recreate-db.js +13 -8
  105. package/dist/leader-thread/recreate-db.js.map +1 -1
  106. package/dist/leader-thread/types.d.ts +22 -15
  107. package/dist/leader-thread/types.d.ts.map +1 -1
  108. package/dist/leader-thread/types.js +1 -3
  109. package/dist/leader-thread/types.js.map +1 -1
  110. package/dist/query-builder/api.d.ts +3 -3
  111. package/dist/query-builder/api.d.ts.map +1 -1
  112. package/dist/query-builder/impl.js.map +1 -1
  113. package/dist/query-builder/impl.test.js +16 -1
  114. package/dist/query-builder/impl.test.js.map +1 -1
  115. package/dist/query-info.d.ts +3 -3
  116. package/dist/query-info.d.ts.map +1 -1
  117. package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
  118. package/dist/rehydrate-from-mutationlog.js +8 -6
  119. package/dist/rehydrate-from-mutationlog.js.map +1 -1
  120. package/dist/schema/EventId.d.ts +10 -9
  121. package/dist/schema/EventId.d.ts.map +1 -1
  122. package/dist/schema/EventId.js +14 -11
  123. package/dist/schema/EventId.js.map +1 -1
  124. package/dist/schema/EventId.test.js +3 -3
  125. package/dist/schema/EventId.test.js.map +1 -1
  126. package/dist/schema/MutationEvent.d.ts +37 -12
  127. package/dist/schema/MutationEvent.d.ts.map +1 -1
  128. package/dist/schema/MutationEvent.js +20 -4
  129. package/dist/schema/MutationEvent.js.map +1 -1
  130. package/dist/schema/db-schema/ast/sqlite.d.ts +69 -0
  131. package/dist/schema/db-schema/ast/sqlite.d.ts.map +1 -0
  132. package/dist/schema/db-schema/ast/sqlite.js +71 -0
  133. package/dist/schema/db-schema/ast/sqlite.js.map +1 -0
  134. package/dist/schema/db-schema/ast/validate.d.ts +3 -0
  135. package/dist/schema/db-schema/ast/validate.d.ts.map +1 -0
  136. package/dist/schema/db-schema/ast/validate.js +12 -0
  137. package/dist/schema/db-schema/ast/validate.js.map +1 -0
  138. package/dist/schema/db-schema/dsl/field-defs.d.ts +90 -0
  139. package/dist/schema/db-schema/dsl/field-defs.d.ts.map +1 -0
  140. package/dist/schema/db-schema/dsl/field-defs.js +87 -0
  141. package/dist/schema/db-schema/dsl/field-defs.js.map +1 -0
  142. package/dist/schema/db-schema/dsl/field-defs.test.d.ts +2 -0
  143. package/dist/schema/db-schema/dsl/field-defs.test.d.ts.map +1 -0
  144. package/dist/schema/db-schema/dsl/field-defs.test.js +29 -0
  145. package/dist/schema/db-schema/dsl/field-defs.test.js.map +1 -0
  146. package/dist/schema/db-schema/dsl/mod.d.ts +88 -0
  147. package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -0
  148. package/dist/schema/db-schema/dsl/mod.js +35 -0
  149. package/dist/schema/db-schema/dsl/mod.js.map +1 -0
  150. package/dist/schema/db-schema/hash.d.ts +2 -0
  151. package/dist/schema/db-schema/hash.d.ts.map +1 -0
  152. package/dist/schema/db-schema/hash.js +14 -0
  153. package/dist/schema/db-schema/hash.js.map +1 -0
  154. package/dist/schema/db-schema/mod.d.ts +3 -0
  155. package/dist/schema/db-schema/mod.d.ts.map +1 -0
  156. package/dist/schema/db-schema/mod.js +3 -0
  157. package/dist/schema/db-schema/mod.js.map +1 -0
  158. package/dist/schema/mod.d.ts +1 -0
  159. package/dist/schema/mod.d.ts.map +1 -1
  160. package/dist/schema/mod.js +1 -0
  161. package/dist/schema/mod.js.map +1 -1
  162. package/dist/schema/mutations.d.ts +4 -8
  163. package/dist/schema/mutations.d.ts.map +1 -1
  164. package/dist/schema/mutations.js +2 -2
  165. package/dist/schema/mutations.js.map +1 -1
  166. package/dist/schema/schema-helpers.js +1 -1
  167. package/dist/schema/schema-helpers.js.map +1 -1
  168. package/dist/schema/schema.d.ts +1 -1
  169. package/dist/schema/schema.d.ts.map +1 -1
  170. package/dist/schema/schema.js +1 -1
  171. package/dist/schema/schema.js.map +1 -1
  172. package/dist/schema/system-tables.d.ts +47 -29
  173. package/dist/schema/system-tables.d.ts.map +1 -1
  174. package/dist/schema/system-tables.js +10 -7
  175. package/dist/schema/system-tables.js.map +1 -1
  176. package/dist/schema/table-def.d.ts +18 -14
  177. package/dist/schema/table-def.d.ts.map +1 -1
  178. package/dist/schema/table-def.js +3 -4
  179. package/dist/schema/table-def.js.map +1 -1
  180. package/dist/schema-management/migrations.d.ts +3 -3
  181. package/dist/schema-management/migrations.d.ts.map +1 -1
  182. package/dist/schema-management/migrations.js +7 -2
  183. package/dist/schema-management/migrations.js.map +1 -1
  184. package/dist/sql-queries/sql-queries.d.ts +1 -1
  185. package/dist/sql-queries/sql-queries.d.ts.map +1 -1
  186. package/dist/sql-queries/sql-queries.js.map +1 -1
  187. package/dist/sql-queries/sql-query-builder.d.ts +1 -1
  188. package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
  189. package/dist/sql-queries/sql-query-builder.js.map +1 -1
  190. package/dist/sql-queries/types.d.ts +2 -1
  191. package/dist/sql-queries/types.d.ts.map +1 -1
  192. package/dist/sql-queries/types.js.map +1 -1
  193. package/dist/sync/ClientSessionSyncProcessor.d.ts +3 -5
  194. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  195. package/dist/sync/ClientSessionSyncProcessor.js +38 -12
  196. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  197. package/dist/sync/next/facts.js +1 -1
  198. package/dist/sync/next/facts.js.map +1 -1
  199. package/dist/sync/next/history-dag-common.d.ts +2 -0
  200. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  201. package/dist/sync/next/history-dag-common.js +3 -1
  202. package/dist/sync/next/history-dag-common.js.map +1 -1
  203. package/dist/sync/next/history-dag.d.ts.map +1 -1
  204. package/dist/sync/next/history-dag.js +1 -1
  205. package/dist/sync/next/history-dag.js.map +1 -1
  206. package/dist/sync/next/rebase-events.d.ts +3 -1
  207. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  208. package/dist/sync/next/rebase-events.js +5 -3
  209. package/dist/sync/next/rebase-events.js.map +1 -1
  210. package/dist/sync/next/test/compact-events.calculator.test.js +12 -12
  211. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  212. package/dist/sync/next/test/compact-events.test.js +43 -43
  213. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  214. package/dist/sync/next/test/mutation-fixtures.d.ts +11 -11
  215. package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -1
  216. package/dist/sync/next/test/mutation-fixtures.js +12 -10
  217. package/dist/sync/next/test/mutation-fixtures.js.map +1 -1
  218. package/dist/sync/sync.d.ts +2 -2
  219. package/dist/sync/syncstate.d.ts +9 -9
  220. package/dist/sync/syncstate.js +6 -6
  221. package/dist/sync/syncstate.js.map +1 -1
  222. package/dist/sync/syncstate.test.js +18 -16
  223. package/dist/sync/syncstate.test.js.map +1 -1
  224. package/dist/version.d.ts +1 -1
  225. package/dist/version.js +1 -1
  226. package/package.json +2 -3
  227. package/src/adapter-types.ts +35 -17
  228. package/src/derived-mutations.ts +4 -4
  229. package/src/devtools/devtools-bridge.ts +10 -7
  230. package/src/devtools/devtools-messages-client-session.ts +26 -10
  231. package/src/devtools/devtools-messages-common.ts +37 -8
  232. package/src/devtools/devtools-messages-leader.ts +78 -16
  233. package/src/devtools/devtools-messages.ts +2 -2
  234. package/src/index.ts +1 -1
  235. package/src/leader-thread/LeaderSyncProcessor.ts +59 -38
  236. package/src/leader-thread/apply-mutation.ts +15 -5
  237. package/src/leader-thread/connection.ts +48 -3
  238. package/src/leader-thread/leader-worker-devtools.ts +85 -35
  239. package/src/leader-thread/make-leader-thread-layer.ts +29 -9
  240. package/src/leader-thread/mutationlog.ts +8 -6
  241. package/src/leader-thread/recreate-db.ts +19 -10
  242. package/src/leader-thread/types.ts +22 -15
  243. package/src/query-builder/api.ts +4 -4
  244. package/src/query-builder/impl.test.ts +22 -1
  245. package/src/query-builder/impl.ts +2 -2
  246. package/src/query-info.ts +3 -3
  247. package/src/rehydrate-from-mutationlog.ts +8 -6
  248. package/src/schema/EventId.test.ts +3 -3
  249. package/src/schema/EventId.ts +20 -16
  250. package/src/schema/MutationEvent.ts +31 -6
  251. package/src/schema/db-schema/ast/sqlite.ts +142 -0
  252. package/src/schema/db-schema/ast/validate.ts +13 -0
  253. package/src/schema/db-schema/dsl/__snapshots__/field-defs.test.ts.snap +206 -0
  254. package/src/schema/db-schema/dsl/field-defs.test.ts +35 -0
  255. package/src/schema/db-schema/dsl/field-defs.ts +242 -0
  256. package/src/schema/db-schema/dsl/mod.ts +195 -0
  257. package/src/schema/db-schema/hash.ts +14 -0
  258. package/src/schema/db-schema/mod.ts +2 -0
  259. package/src/schema/mod.ts +1 -0
  260. package/src/schema/mutations.ts +6 -19
  261. package/src/schema/schema-helpers.ts +1 -1
  262. package/src/schema/schema.ts +2 -2
  263. package/src/schema/system-tables.ts +10 -7
  264. package/src/schema/table-def.ts +17 -16
  265. package/src/schema-management/migrations.ts +10 -6
  266. package/src/sql-queries/sql-queries.ts +1 -1
  267. package/src/sql-queries/sql-query-builder.ts +1 -2
  268. package/src/sql-queries/types.ts +3 -1
  269. package/src/sync/ClientSessionSyncProcessor.ts +44 -14
  270. package/src/sync/next/facts.ts +1 -1
  271. package/src/sync/next/history-dag-common.ts +5 -1
  272. package/src/sync/next/history-dag.ts +1 -1
  273. package/src/sync/next/rebase-events.ts +8 -2
  274. package/src/sync/next/test/compact-events.calculator.test.ts +12 -12
  275. package/src/sync/next/test/compact-events.test.ts +43 -43
  276. package/src/sync/next/test/mutation-fixtures.ts +16 -12
  277. package/src/sync/syncstate.test.ts +19 -17
  278. package/src/sync/syncstate.ts +6 -6
  279. package/src/version.ts +1 -1
  280. package/tsconfig.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import type { HttpClient, Scope } from '@livestore/utils/effect'
2
2
  import { Deferred, Effect, Layer, Queue, SubscriptionRef } from '@livestore/utils/effect'
3
3
 
4
- import type { BootStatus, MakeSqliteDb, SqliteError } from '../adapter-types.js'
4
+ import type { BootStatus, MakeSqliteDb, MigrationsReport, SqliteError } from '../adapter-types.js'
5
5
  import { UnexpectedError } from '../adapter-types.js'
6
6
  import type * as Devtools from '../devtools/index.js'
7
7
  import type { LiveStoreSchema } from '../schema/mod.js'
@@ -67,15 +67,15 @@ export const makeLeaderThreadLayer = ({
67
67
  initialBlockingSyncContext,
68
68
  })
69
69
 
70
- const extraIncomingMessagesQueue = yield* Queue.unbounded<Devtools.MessageToAppLeader>().pipe(
70
+ const extraIncomingMessagesQueue = yield* Queue.unbounded<Devtools.Leader.MessageToApp>().pipe(
71
71
  Effect.acquireRelease(Queue.shutdown),
72
72
  )
73
73
 
74
74
  const devtoolsContext = devtoolsOptions.enabled
75
75
  ? {
76
76
  enabled: true as const,
77
- syncBackendPullLatch: yield* Effect.makeLatch(true),
78
- syncBackendPushLatch: yield* Effect.makeLatch(true),
77
+ syncBackendLatch: yield* Effect.makeLatch(true),
78
+ syncBackendLatchState: yield* SubscriptionRef.make<{ latchClosed: boolean }>({ latchClosed: false }),
79
79
  }
80
80
  : { enabled: false as const }
81
81
 
@@ -95,6 +95,8 @@ export const makeLeaderThreadLayer = ({
95
95
  connectedClientSessionPullQueues: yield* makePullQueueSet,
96
96
  extraIncomingMessagesQueue,
97
97
  devtools: devtoolsContext,
98
+ // State will be set during `bootLeaderThread`
99
+ initialState: {} as any as LeaderThreadCtx['Type']['initialState'],
98
100
  } satisfies typeof LeaderThreadCtx.Service
99
101
 
100
102
  // @ts-expect-error For debugging purposes
@@ -102,7 +104,11 @@ export const makeLeaderThreadLayer = ({
102
104
 
103
105
  const layer = Layer.succeed(LeaderThreadCtx, ctx)
104
106
 
105
- yield* bootLeaderThread({ dbMissing, initialBlockingSyncContext, devtoolsOptions }).pipe(Effect.provide(layer))
107
+ ctx.initialState = yield* bootLeaderThread({
108
+ dbMissing,
109
+ initialBlockingSyncContext,
110
+ devtoolsOptions,
111
+ }).pipe(Effect.provide(layer))
106
112
 
107
113
  return layer
108
114
  }).pipe(
@@ -172,7 +178,7 @@ const bootLeaderThread = ({
172
178
  initialBlockingSyncContext: InitialBlockingSyncContext
173
179
  devtoolsOptions: DevtoolsOptions
174
180
  }): Effect.Effect<
175
- void,
181
+ LeaderThreadCtx['Type']['initialState'],
176
182
  UnexpectedError | SqliteError | IsOfflineError | InvalidPullError,
177
183
  LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient
178
184
  > =>
@@ -206,19 +212,33 @@ const bootLeaderThread = ({
206
212
 
207
213
  // We're already starting pulling from the sync backend concurrently but wait until the db is ready before
208
214
  // processing any incoming mutations
209
- yield* syncProcessor.boot({ dbReady })
215
+ const { initialLeaderHead } = yield* syncProcessor.boot({ dbReady })
210
216
 
217
+ let migrationsReport: MigrationsReport
211
218
  if (dbMissing) {
212
- yield* recreateDb
219
+ const recreateResult = yield* recreateDb
220
+ migrationsReport = recreateResult.migrationsReport
221
+ } else {
222
+ migrationsReport = { migrations: [] }
213
223
  }
214
224
 
215
225
  yield* Deferred.succeed(dbReady, void 0)
216
226
 
217
227
  if (initialBlockingSyncContext.blockingDeferred !== undefined) {
218
- yield* initialBlockingSyncContext.blockingDeferred
228
+ // Provides a syncing status right away before the first pull response comes in
229
+ yield* Queue.offer(bootStatusQueue, {
230
+ stage: 'syncing',
231
+ progress: { done: 0, total: -1 },
232
+ })
233
+
234
+ yield* initialBlockingSyncContext.blockingDeferred.pipe(
235
+ Effect.withSpan('@livestore/common:leader-thread:initial-sync-blocking'),
236
+ )
219
237
  }
220
238
 
221
239
  yield* Queue.offer(bootStatusQueue, { stage: 'done' })
222
240
 
223
241
  yield* bootDevtools(devtoolsOptions).pipe(Effect.tapCauseLogPretty, Effect.forkScoped)
242
+
243
+ return { migrationsReport, leaderHead: initialLeaderHead }
224
244
  })
@@ -23,18 +23,20 @@ export const getMutationEventsSince = (
23
23
  .map((_) => ({
24
24
  mutation: _.mutation,
25
25
  args: _.argsJson,
26
- id: { global: _.idGlobal, local: _.idLocal },
27
- parentId: { global: _.parentIdGlobal, local: _.parentIdLocal },
26
+ id: { global: _.idGlobal, client: _.idClient },
27
+ parentId: { global: _.parentIdGlobal, client: _.parentIdClient },
28
+ clientId: _.clientId,
29
+ sessionId: _.sessionId ?? undefined,
28
30
  }))
29
31
  .filter((_) => EventId.compare(_.id, since) > 0)
30
32
  })
31
33
 
32
- export const getLocalHeadFromDb = (dbMutationLog: SqliteDb): EventId.EventId => {
33
- const res = dbMutationLog.select<{ idGlobal: EventId.GlobalEventId; idLocal: EventId.LocalEventId }>(
34
- sql`select idGlobal, idLocal from ${MUTATION_LOG_META_TABLE} order by idGlobal DESC, idLocal DESC limit 1`,
34
+ export const getClientHeadFromDb = (dbMutationLog: SqliteDb): EventId.EventId => {
35
+ const res = dbMutationLog.select<{ idGlobal: EventId.GlobalEventId; idClient: EventId.ClientEventId }>(
36
+ sql`select idGlobal, idClient from ${MUTATION_LOG_META_TABLE} order by idGlobal DESC, idClient DESC limit 1`,
35
37
  )[0]
36
38
 
37
- return res ? { global: res.idGlobal, local: res.idLocal } : EventId.ROOT
39
+ return res ? { global: res.idGlobal, client: res.idClient } : EventId.ROOT
38
40
  }
39
41
 
40
42
  export const getBackendHeadFromDb = (dbMutationLog: SqliteDb): EventId.GlobalEventId =>
@@ -2,19 +2,20 @@ import { casesHandled } from '@livestore/utils'
2
2
  import type { HttpClient } from '@livestore/utils/effect'
3
3
  import { Effect, Queue } from '@livestore/utils/effect'
4
4
 
5
- import type { InvalidPullError, IsOfflineError, MigrationHooks, SqliteError } from '../index.js'
5
+ import type { InvalidPullError, IsOfflineError, MigrationHooks, MigrationsReport, SqliteError } from '../index.js'
6
6
  import { initializeSingletonTables, migrateDb, rehydrateFromMutationLog, UnexpectedError } from '../index.js'
7
7
  import { configureConnection } from './connection.js'
8
8
  import { LeaderThreadCtx } from './types.js'
9
9
 
10
10
  export const recreateDb: Effect.Effect<
11
- void,
11
+ { migrationsReport: MigrationsReport },
12
12
  UnexpectedError | SqliteError | IsOfflineError | InvalidPullError,
13
13
  LeaderThreadCtx | HttpClient.HttpClient
14
14
  > = Effect.gen(function* () {
15
15
  const { dbReadModel, dbMutationLog, schema, bootStatusQueue } = yield* LeaderThreadCtx
16
16
 
17
17
  const migrationOptions = schema.migrationOptions
18
+ let migrationsReport: MigrationsReport
18
19
 
19
20
  yield* Effect.addFinalizer(
20
21
  Effect.fn('recreateDb:finalizer')(function* (ex) {
@@ -27,13 +28,13 @@ export const recreateDb: Effect.Effect<
27
28
  // TODO bring back this optimization
28
29
  // const tmpDb = yield* makeSqliteDb({ _tag: 'in-memory' })
29
30
  const tmpDb = dbReadModel
30
- yield* configureConnection(tmpDb, { fkEnabled: true })
31
+ yield* configureConnection(tmpDb, { foreignKeys: true })
31
32
 
32
33
  const initDb = (hooks: Partial<MigrationHooks> | undefined) =>
33
34
  Effect.gen(function* () {
34
35
  yield* Effect.tryAll(() => hooks?.init?.(tmpDb)).pipe(UnexpectedError.mapToUnexpectedError)
35
36
 
36
- yield* migrateDb({
37
+ const migrationsReport = yield* migrateDb({
37
38
  db: tmpDb,
38
39
  schema,
39
40
  onProgress: ({ done, total }) =>
@@ -44,16 +45,18 @@ export const recreateDb: Effect.Effect<
44
45
 
45
46
  yield* Effect.tryAll(() => hooks?.pre?.(tmpDb)).pipe(UnexpectedError.mapToUnexpectedError)
46
47
 
47
- return tmpDb
48
+ return { migrationsReport, tmpDb }
48
49
  })
49
50
 
50
51
  switch (migrationOptions.strategy) {
51
52
  case 'from-mutation-log': {
52
53
  const hooks = migrationOptions.hooks
53
- const tmpDb = yield* initDb(hooks)
54
+ const initResult = yield* initDb(hooks)
55
+
56
+ migrationsReport = initResult.migrationsReport
54
57
 
55
58
  yield* rehydrateFromMutationLog({
56
- db: tmpDb,
59
+ db: initResult.tmpDb,
57
60
  logDb: dbMutationLog,
58
61
  schema,
59
62
  migrationOptions,
@@ -61,23 +64,27 @@ export const recreateDb: Effect.Effect<
61
64
  Queue.offer(bootStatusQueue, { stage: 'rehydrating', progress: { done, total } }),
62
65
  })
63
66
 
64
- yield* Effect.tryAll(() => hooks?.post?.(tmpDb)).pipe(UnexpectedError.mapToUnexpectedError)
67
+ yield* Effect.tryAll(() => hooks?.post?.(initResult.tmpDb)).pipe(UnexpectedError.mapToUnexpectedError)
65
68
 
66
69
  break
67
70
  }
68
71
  case 'hard-reset': {
69
72
  const hooks = migrationOptions.hooks
70
- const tmpInMemoryDb = yield* initDb(hooks)
73
+ const initResult = yield* initDb(hooks)
74
+
75
+ migrationsReport = initResult.migrationsReport
71
76
 
72
77
  // The database is migrated but empty now, so nothing else to do
73
78
 
74
- yield* Effect.tryAll(() => hooks?.post?.(tmpInMemoryDb)).pipe(UnexpectedError.mapToUnexpectedError)
79
+ yield* Effect.tryAll(() => hooks?.post?.(initResult.tmpDb)).pipe(UnexpectedError.mapToUnexpectedError)
75
80
 
76
81
  break
77
82
  }
78
83
  case 'manual': {
79
84
  const oldDbData = dbReadModel.export()
80
85
 
86
+ migrationsReport = { migrations: [] }
87
+
81
88
  const newDbData = yield* Effect.tryAll(() => migrationOptions.migrate(oldDbData)).pipe(
82
89
  UnexpectedError.mapToUnexpectedError,
83
90
  )
@@ -106,6 +113,8 @@ export const recreateDb: Effect.Effect<
106
113
 
107
114
  // TODO bring back
108
115
  // tmpDb.close()
116
+
117
+ return { migrationsReport }
109
118
  }).pipe(
110
119
  Effect.scoped, // NOTE we're closing the scope here so finalizers are called when the effect is done
111
120
  Effect.withSpan('@livestore/common:leader-thread:recreateDb'),
@@ -1,7 +1,6 @@
1
1
  import type {
2
2
  Deferred,
3
3
  Effect,
4
- Fiber,
5
4
  HttpClient,
6
5
  Option,
7
6
  Queue,
@@ -17,6 +16,7 @@ import type {
17
16
  Devtools,
18
17
  InvalidPushError,
19
18
  MakeSqliteDb,
19
+ MigrationsReport,
20
20
  PersistenceInfo,
21
21
  SqliteDb,
22
22
  SyncBackend,
@@ -28,18 +28,11 @@ import type { ShutdownChannel } from './shutdown-channel.js'
28
28
 
29
29
  export type ShutdownState = 'running' | 'shutting-down'
30
30
 
31
- export class OuterWorkerCtx extends Context.Tag('OuterWorkerCtx')<
32
- OuterWorkerCtx,
33
- {
34
- innerFiber: Fiber.RuntimeFiber<any, any>
35
- }
36
- >() {}
37
-
38
31
  export const InitialSyncOptionsSkip = Schema.TaggedStruct('Skip', {})
39
32
  export type InitialSyncOptionsSkip = typeof InitialSyncOptionsSkip.Type
40
33
 
41
34
  export const InitialSyncOptionsBlocking = Schema.TaggedStruct('Blocking', {
42
- timeout: Schema.DurationFromMillis,
35
+ timeout: Schema.Union(Schema.DurationFromMillis, Schema.Number),
43
36
  })
44
37
 
45
38
  export type InitialSyncOptionsBlocking = typeof InitialSyncOptionsBlocking.Type
@@ -67,7 +60,7 @@ export type DevtoolsOptions =
67
60
  enabled: true
68
61
  makeBootContext: Effect.Effect<
69
62
  {
70
- devtoolsWebChannel: WebChannel.WebChannel<Devtools.MessageToAppLeader, Devtools.MessageFromAppLeader>
63
+ devtoolsWebChannel: WebChannel.WebChannel<Devtools.Leader.MessageToApp, Devtools.Leader.MessageFromApp>
71
64
  persistenceInfo: PersistenceInfoPair
72
65
  },
73
66
  UnexpectedError,
@@ -78,8 +71,10 @@ export type DevtoolsOptions =
78
71
  export type DevtoolsContext =
79
72
  | {
80
73
  enabled: true
81
- syncBackendPullLatch: Effect.Latch
82
- syncBackendPushLatch: Effect.Latch
74
+ // syncBackendPullLatch: Effect.Latch
75
+ // syncBackendPushLatch: Effect.Latch
76
+ syncBackendLatch: Effect.Latch
77
+ syncBackendLatchState: SubscriptionRef.SubscriptionRef<{ latchClosed: boolean }>
83
78
  }
84
79
  | {
85
80
  enabled: false
@@ -103,12 +98,16 @@ export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
103
98
  syncBackend: SyncBackend | undefined
104
99
  syncProcessor: LeaderSyncProcessor
105
100
  connectedClientSessionPullQueues: PullQueueSet
101
+ initialState: {
102
+ leaderHead: EventId.EventId
103
+ migrationsReport: MigrationsReport
104
+ }
106
105
  /**
107
106
  * e.g. used for `store._dev` APIs
108
107
  *
109
108
  * This is currently separated from `.devtools` as it also needs to work when devtools are disabled
110
109
  */
111
- extraIncomingMessagesQueue: Queue.Queue<Devtools.MessageToAppLeader>
110
+ extraIncomingMessagesQueue: Queue.Queue<Devtools.Leader.MessageToApp>
112
111
  }
113
112
  >() {}
114
113
 
@@ -135,10 +134,18 @@ export interface LeaderSyncProcessor {
135
134
  },
136
135
  ) => Effect.Effect<void, InvalidPushError>
137
136
 
138
- pushPartial: (mutationEvent: MutationEvent.PartialAnyEncoded) => Effect.Effect<void, UnexpectedError, LeaderThreadCtx>
137
+ pushPartial: (args: {
138
+ mutationEvent: MutationEvent.PartialAnyEncoded
139
+ clientId: string
140
+ sessionId: string | undefined
141
+ }) => Effect.Effect<void, UnexpectedError, LeaderThreadCtx>
139
142
  boot: (args: {
140
143
  dbReady: Deferred.Deferred<void>
141
- }) => Effect.Effect<void, UnexpectedError, LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient>
144
+ }) => Effect.Effect<
145
+ { initialLeaderHead: EventId.EventId },
146
+ UnexpectedError,
147
+ LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient
148
+ >
142
149
  syncState: Subscribable.Subscribable<SyncState.SyncState>
143
150
  }
144
151
 
@@ -3,8 +3,8 @@ import { type Option, Predicate, type Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import type { SessionIdSymbol } from '../adapter-types.js'
5
5
  import type { QueryInfo } from '../query-info.js'
6
+ import type { SqliteDsl } from '../schema/db-schema/mod.js'
6
7
  import type { DbSchema } from '../schema/mod.js'
7
- import type { SqliteDsl } from '../schema/table-def.js'
8
8
  import type { SqlValue } from '../util.js'
9
9
 
10
10
  export type QueryBuilderAst = QueryBuilderAst.SelectQuery | QueryBuilderAst.CountQuery | QueryBuilderAst.RowQuery
@@ -35,7 +35,7 @@ export namespace QueryBuilderAst {
35
35
  export type RowQuery = {
36
36
  readonly _tag: 'RowQuery'
37
37
  readonly tableDef: DbSchema.TableDefBase
38
- readonly id: string | SessionIdSymbol
38
+ readonly id: string | SessionIdSymbol | number
39
39
  readonly insertValues: Record<string, unknown>
40
40
  }
41
41
 
@@ -252,10 +252,10 @@ export namespace QueryBuilder {
252
252
  ? (_: 'Error: Need to enable deriveMutations to use row()') => any
253
253
  : TTableDef['options']['requiredInsertColumnNames'] extends never
254
254
  ? (
255
- id: string | SessionIdSymbol,
255
+ id: string | SessionIdSymbol | number,
256
256
  ) => QueryBuilder<RowQuery.Result<TTableDef>, TTableDef, QueryBuilder.ApiFeature, QueryInfo.Row>
257
257
  : <TOptions extends RowQuery.RequiredColumnsOptions<TTableDef>>(
258
- id: string | SessionIdSymbol,
258
+ id: string | SessionIdSymbol | number,
259
259
  opts: TOptions,
260
260
  ) => QueryBuilder<RowQuery.Result<TTableDef>, TTableDef, QueryBuilder.ApiFeature, QueryInfo.Row>
261
261
  }
@@ -18,13 +18,23 @@ const todos = DbSchema.table(
18
18
  { deriveMutations: true },
19
19
  )
20
20
 
21
+ const todosWithIntId = DbSchema.table(
22
+ 'todos_with_int_id',
23
+ {
24
+ id: DbSchema.integer({ primaryKey: true }),
25
+ text: DbSchema.text({ default: '', nullable: false }),
26
+ status: DbSchema.text({ schema: Schema.Literal('active', 'completed') }),
27
+ },
28
+ { deriveMutations: true },
29
+ )
30
+
21
31
  const comments = DbSchema.table('comments', {
22
32
  id: DbSchema.text({ primaryKey: true }),
23
33
  text: DbSchema.text({ default: '', nullable: false }),
24
34
  todoId: DbSchema.text({}),
25
35
  })
26
36
 
27
- const db = { todos: todos.query, comments: comments.query }
37
+ const db = { todos: todos.query, todosWithIntId: todosWithIntId.query, comments: comments.query }
28
38
 
29
39
  describe('query builder', () => {
30
40
  describe('result schema', () => {
@@ -204,6 +214,17 @@ describe('query builder', () => {
204
214
  }
205
215
  `)
206
216
  })
217
+
218
+ it('should handle row queries with numbers', () => {
219
+ expect(db.todosWithIntId.row(123, { insertValues: { status: 'active' } }).asSql()).toMatchInlineSnapshot(`
220
+ {
221
+ "bindValues": [
222
+ 123,
223
+ ],
224
+ "query": "SELECT * FROM 'todos_with_int_id' WHERE id = ?",
225
+ }
226
+ `)
227
+ })
207
228
  })
208
229
  })
209
230
 
@@ -128,12 +128,12 @@ export const makeQueryBuilder = <TResult, TTableDef extends DbSchema.TableDefBas
128
128
  // eslint-disable-next-line prefer-rest-params
129
129
  const params = [...arguments]
130
130
 
131
- let id: string
131
+ let id: string | number
132
132
 
133
133
  if (tableDef.options.isSingleton) {
134
134
  id = tableDef.sqliteDef.columns.id!.default.pipe(Option.getOrThrow)
135
135
  } else {
136
- id = params[0] as string
136
+ id = params[0] as string | number
137
137
  if (id === undefined) {
138
138
  invalidQueryBuilder(`Id missing for row query on non-singleton table ${tableDef.sqliteDef.name}`)
139
139
  }
package/src/query-info.ts CHANGED
@@ -24,20 +24,20 @@ export namespace QueryInfo {
24
24
  export type Row = {
25
25
  _tag: 'Row'
26
26
  table: DbSchema.TableDefBase
27
- id: string | SessionIdSymbol
27
+ id: string | SessionIdSymbol | number
28
28
  }
29
29
 
30
30
  export type Col = {
31
31
  _tag: 'Col'
32
32
  table: DbSchema.TableDefBase
33
- id: string | SessionIdSymbol
33
+ id: string | SessionIdSymbol | number
34
34
  column: string
35
35
  }
36
36
 
37
37
  export type ColJsonValue = {
38
38
  _tag: 'ColJsonValue'
39
39
  table: DbSchema.TableDefBase
40
- id: string | SessionIdSymbol
40
+ id: string | SessionIdSymbol | number
41
41
  column: string
42
42
  /**
43
43
  * example: `$.tabs[3].items[2]` (`$` referring to the column value)
@@ -60,10 +60,12 @@ This likely means the schema has changed in an incompatible way.
60
60
  )
61
61
 
62
62
  const mutationEventEncoded = {
63
- id: { global: row.idGlobal, local: row.idLocal },
64
- parentId: { global: row.parentIdGlobal, local: row.parentIdLocal },
63
+ id: { global: row.idGlobal, client: row.idClient },
64
+ parentId: { global: row.parentIdGlobal, client: row.parentIdClient },
65
65
  mutation: row.mutation,
66
66
  args,
67
+ clientId: row.clientId,
68
+ sessionId: row.sessionId ?? undefined,
67
69
  } satisfies MutationEvent.AnyEncoded
68
70
 
69
71
  yield* applyMutation(mutationEventEncoded, { skipMutationLog: true })
@@ -73,8 +75,8 @@ This likely means the schema has changed in an incompatible way.
73
75
 
74
76
  const stmt = logDb.prepare(sql`\
75
77
  SELECT * FROM ${MUTATION_LOG_META_TABLE}
76
- WHERE idGlobal > $idGlobal OR (idGlobal = $idGlobal AND idLocal > $idLocal)
77
- ORDER BY idGlobal ASC, idLocal ASC
78
+ WHERE idGlobal > $idGlobal OR (idGlobal = $idGlobal AND idClient > $idClient)
79
+ ORDER BY idGlobal ASC, idClient ASC
78
80
  LIMIT ${CHUNK_SIZE}
79
81
  `)
80
82
 
@@ -88,14 +90,14 @@ LIMIT ${CHUNK_SIZE}
88
90
 
89
91
  const lastId = Chunk.isChunk(item)
90
92
  ? Chunk.last(item).pipe(
91
- Option.map((_) => ({ global: _.idGlobal, local: _.idLocal })),
93
+ Option.map((_) => ({ global: _.idGlobal, client: _.idClient })),
92
94
  Option.getOrElse(() => EventId.ROOT),
93
95
  )
94
96
  : EventId.ROOT
95
97
  const nextItem = Chunk.fromIterable(
96
98
  stmt.select<MutationLogMetaRow>({
97
99
  $idGlobal: lastId?.global,
98
- $idLocal: lastId?.local,
100
+ $idClient: lastId?.client,
99
101
  } as any as PreparedBindValues),
100
102
  )
101
103
  const prevItem = Chunk.isChunk(item) ? item : Chunk.empty()
@@ -5,8 +5,8 @@ import { EventId } from './mod.js'
5
5
 
6
6
  Vitest.describe('EventId', () => {
7
7
  Vitest.test('nextPair', () => {
8
- const e_0_0 = EventId.make({ global: 0, local: 0 })
9
- expect(EventId.nextPair(e_0_0, false).id).toStrictEqual({ global: 1, local: 0 })
10
- expect(EventId.nextPair(e_0_0, true).id).toStrictEqual({ global: 0, local: 1 })
8
+ const e_0_0 = EventId.make({ global: 0, client: 0 })
9
+ expect(EventId.nextPair(e_0_0, false).id).toStrictEqual({ global: 1, client: 0 })
10
+ expect(EventId.nextPair(e_0_0, true).id).toStrictEqual({ global: 0, client: 1 })
11
11
  })
12
12
  })
@@ -1,26 +1,26 @@
1
1
  import { Brand, Schema } from '@livestore/utils/effect'
2
2
 
3
- export type LocalEventId = Brand.Branded<number, 'LocalEventId'>
4
- export const localEventId = Brand.nominal<LocalEventId>()
5
- export const LocalEventId = Schema.fromBrand(localEventId)(Schema.Int)
3
+ export type ClientEventId = Brand.Branded<number, 'ClientEventId'>
4
+ export const localEventId = Brand.nominal<ClientEventId>()
5
+ export const ClientEventId = Schema.fromBrand(localEventId)(Schema.Int)
6
6
 
7
7
  export type GlobalEventId = Brand.Branded<number, 'GlobalEventId'>
8
8
  export const globalEventId = Brand.nominal<GlobalEventId>()
9
9
  export const GlobalEventId = Schema.fromBrand(globalEventId)(Schema.Int)
10
10
 
11
- export const localDefault = 0 as any as LocalEventId
11
+ export const clientDefault = 0 as any as ClientEventId
12
12
 
13
13
  /**
14
14
  * LiveStore event id value consisting of a globally unique event sequence number
15
- * and a local sequence number.
15
+ * and a client sequence number.
16
16
  *
17
- * The local sequence number is only used for localOnly mutations and starts from 0 for each global sequence number.
17
+ * The client sequence number is only used for clientOnly mutations and starts from 0 for each global sequence number.
18
18
  */
19
- export type EventId = { global: GlobalEventId; local: LocalEventId }
19
+ export type EventId = { global: GlobalEventId; client: ClientEventId }
20
20
 
21
21
  export const EventId = Schema.Struct({
22
22
  global: GlobalEventId,
23
- local: LocalEventId,
23
+ client: ClientEventId,
24
24
  }).annotations({ title: 'LiveStore.EventId' })
25
25
 
26
26
  /**
@@ -30,17 +30,21 @@ export const compare = (a: EventId, b: EventId) => {
30
30
  if (a.global !== b.global) {
31
31
  return a.global - b.global
32
32
  }
33
- return a.local - b.local
33
+ return a.client - b.client
34
34
  }
35
35
 
36
- export const isEqual = (a: EventId, b: EventId) => a.global === b.global && a.local === b.local
36
+ export const isEqual = (a: EventId, b: EventId) => a.global === b.global && a.client === b.client
37
37
 
38
38
  export type EventIdPair = { id: EventId; parentId: EventId }
39
39
 
40
- export const ROOT = { global: -1 as any as GlobalEventId, local: localDefault } satisfies EventId
40
+ export const ROOT = { global: -1 as any as GlobalEventId, client: clientDefault } satisfies EventId
41
41
 
42
42
  export const isGreaterThan = (a: EventId, b: EventId) => {
43
- return a.global > b.global || (a.global === b.global && a.local > b.local)
43
+ return a.global > b.global || (a.global === b.global && a.client > b.client)
44
+ }
45
+
46
+ export const isGreaterThanOrEqual = (a: EventId, b: EventId) => {
47
+ return a.global > b.global || (a.global === b.global && a.client >= b.client)
44
48
  }
45
49
 
46
50
  export const make = (id: EventId | typeof EventId.Encoded): EventId => {
@@ -49,12 +53,12 @@ export const make = (id: EventId | typeof EventId.Encoded): EventId => {
49
53
 
50
54
  export const nextPair = (id: EventId, isLocal: boolean): EventIdPair => {
51
55
  if (isLocal) {
52
- return { id: { global: id.global, local: (id.local + 1) as any as LocalEventId }, parentId: id }
56
+ return { id: { global: id.global, client: (id.client + 1) as any as ClientEventId }, parentId: id }
53
57
  }
54
58
 
55
59
  return {
56
- id: { global: (id.global + 1) as any as GlobalEventId, local: localDefault },
57
- // NOTE we always point to `local: 0` for non-localOnly mutations
58
- parentId: { global: id.global, local: localDefault },
60
+ id: { global: (id.global + 1) as any as GlobalEventId, client: clientDefault },
61
+ // NOTE we always point to `client: 0` for non-clientOnly mutations
62
+ parentId: { global: id.global, client: clientDefault },
59
63
  }
60
64
  }