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

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 (90) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/adapter-types.d.ts +22 -13
  3. package/dist/adapter-types.d.ts.map +1 -1
  4. package/dist/adapter-types.js.map +1 -1
  5. package/dist/devtools/devtool-message-leader.d.ts +2 -0
  6. package/dist/devtools/devtool-message-leader.d.ts.map +1 -0
  7. package/dist/devtools/devtool-message-leader.js +2 -0
  8. package/dist/devtools/devtool-message-leader.js.map +1 -0
  9. package/dist/devtools/devtools-messages-client-session.d.ts +297 -0
  10. package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -0
  11. package/dist/devtools/devtools-messages-client-session.js +61 -0
  12. package/dist/devtools/devtools-messages-client-session.js.map +1 -0
  13. package/dist/devtools/devtools-messages-common.d.ts +65 -0
  14. package/dist/devtools/devtools-messages-common.d.ts.map +1 -0
  15. package/dist/devtools/devtools-messages-common.js +35 -0
  16. package/dist/devtools/devtools-messages-common.js.map +1 -0
  17. package/dist/devtools/devtools-messages-leader.d.ts +261 -0
  18. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -0
  19. package/dist/devtools/devtools-messages-leader.js +85 -0
  20. package/dist/devtools/devtools-messages-leader.js.map +1 -0
  21. package/dist/devtools/devtools-messages.d.ts +3 -580
  22. package/dist/devtools/devtools-messages.d.ts.map +1 -1
  23. package/dist/devtools/devtools-messages.js +3 -174
  24. package/dist/devtools/devtools-messages.js.map +1 -1
  25. package/dist/init-singleton-tables.d.ts +2 -2
  26. package/dist/init-singleton-tables.d.ts.map +1 -1
  27. package/dist/init-singleton-tables.js.map +1 -1
  28. package/dist/leader-thread/LeaderSyncProcessor.d.ts +4 -4
  29. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  30. package/dist/leader-thread/LeaderSyncProcessor.js +50 -35
  31. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  32. package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
  33. package/dist/leader-thread/apply-mutation.js +4 -4
  34. package/dist/leader-thread/apply-mutation.js.map +1 -1
  35. package/dist/leader-thread/connection.d.ts +4 -4
  36. package/dist/leader-thread/connection.d.ts.map +1 -1
  37. package/dist/leader-thread/connection.js +5 -5
  38. package/dist/leader-thread/connection.js.map +1 -1
  39. package/dist/leader-thread/leader-worker-devtools.js +17 -17
  40. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  41. package/dist/leader-thread/make-leader-thread-layer.d.ts +6 -6
  42. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  43. package/dist/leader-thread/make-leader-thread-layer.js +23 -10
  44. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  45. package/dist/leader-thread/mutationlog.d.ts +4 -4
  46. package/dist/leader-thread/mutationlog.d.ts.map +1 -1
  47. package/dist/leader-thread/mutationlog.js +6 -6
  48. package/dist/leader-thread/mutationlog.js.map +1 -1
  49. package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
  50. package/dist/leader-thread/recreate-db.js +19 -19
  51. package/dist/leader-thread/recreate-db.js.map +1 -1
  52. package/dist/leader-thread/types.d.ts +20 -8
  53. package/dist/leader-thread/types.d.ts.map +1 -1
  54. package/dist/leader-thread/types.js.map +1 -1
  55. package/dist/rehydrate-from-mutationlog.d.ts +3 -3
  56. package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
  57. package/dist/rehydrate-from-mutationlog.js.map +1 -1
  58. package/dist/schema-management/common.d.ts +3 -3
  59. package/dist/schema-management/common.d.ts.map +1 -1
  60. package/dist/schema-management/common.js.map +1 -1
  61. package/dist/schema-management/migrations.d.ts +4 -4
  62. package/dist/schema-management/migrations.d.ts.map +1 -1
  63. package/dist/schema-management/migrations.js.map +1 -1
  64. package/dist/sync/ClientSessionSyncProcessor.d.ts +5 -7
  65. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  66. package/dist/sync/ClientSessionSyncProcessor.js +13 -6
  67. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  68. package/dist/sync/next/test/mutation-fixtures.d.ts +7 -7
  69. package/dist/version.d.ts +1 -1
  70. package/dist/version.js +1 -1
  71. package/package.json +3 -3
  72. package/src/adapter-types.ts +18 -17
  73. package/src/devtools/devtools-messages-client-session.ts +109 -0
  74. package/src/devtools/devtools-messages-common.ts +52 -0
  75. package/src/devtools/devtools-messages-leader.ts +115 -0
  76. package/src/devtools/devtools-messages.ts +3 -246
  77. package/src/init-singleton-tables.ts +2 -2
  78. package/src/leader-thread/LeaderSyncProcessor.ts +78 -45
  79. package/src/leader-thread/apply-mutation.ts +5 -5
  80. package/src/leader-thread/connection.ts +7 -7
  81. package/src/leader-thread/leader-worker-devtools.ts +25 -18
  82. package/src/leader-thread/make-leader-thread-layer.ts +38 -17
  83. package/src/leader-thread/mutationlog.ts +9 -9
  84. package/src/leader-thread/recreate-db.ts +19 -19
  85. package/src/leader-thread/types.ts +24 -10
  86. package/src/rehydrate-from-mutationlog.ts +3 -3
  87. package/src/schema-management/common.ts +3 -3
  88. package/src/schema-management/migrations.ts +4 -4
  89. package/src/sync/ClientSessionSyncProcessor.ts +18 -13
  90. package/src/version.ts +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, MakeSynchronousDatabase, SqliteError, SynchronousDatabase } from '../adapter-types.js'
4
+ import type { BootStatus, MakeSqliteDb, 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'
@@ -15,27 +15,33 @@ import { makeLeaderSyncProcessor } from './LeaderSyncProcessor.js'
15
15
  import { makePullQueueSet } from './pull-queue-set.js'
16
16
  import { recreateDb } from './recreate-db.js'
17
17
  import type { ShutdownChannel } from './shutdown-channel.js'
18
- import type { DevtoolsOptions, InitialBlockingSyncContext, InitialSyncOptions, ShutdownState } from './types.js'
18
+ import type {
19
+ DevtoolsOptions,
20
+ InitialBlockingSyncContext,
21
+ InitialSyncOptions,
22
+ LeaderSqliteDb,
23
+ ShutdownState,
24
+ } from './types.js'
19
25
  import { LeaderThreadCtx } from './types.js'
20
26
 
21
27
  export const makeLeaderThreadLayer = ({
22
28
  schema,
23
29
  storeId,
24
30
  clientId,
25
- makeSyncDb,
31
+ makeSqliteDb,
26
32
  syncOptions,
27
- db,
28
- dbLog,
33
+ dbReadModel,
34
+ dbMutationLog,
29
35
  devtoolsOptions,
30
36
  shutdownChannel,
31
37
  }: {
32
38
  storeId: string
33
39
  clientId: string
34
40
  schema: LiveStoreSchema
35
- makeSyncDb: MakeSynchronousDatabase
41
+ makeSqliteDb: MakeSqliteDb
36
42
  syncOptions: SyncOptions | undefined
37
- db: SynchronousDatabase
38
- dbLog: SynchronousDatabase
43
+ dbReadModel: LeaderSqliteDb
44
+ dbMutationLog: LeaderSqliteDb
39
45
  devtoolsOptions: DevtoolsOptions
40
46
  shutdownChannel: ShutdownChannel
41
47
  }): Layer.Layer<LeaderThreadCtx, UnexpectedError, Scope.Scope | HttpClient.HttpClient> =>
@@ -44,7 +50,8 @@ export const makeLeaderThreadLayer = ({
44
50
 
45
51
  // TODO do more validation here than just checking the count of tables
46
52
  // Either happens on initial boot or if schema changes
47
- const dbMissing = db.select<{ count: number }>(sql`select count(*) as count from sqlite_master`)[0]!.count === 0
53
+ const dbMissing =
54
+ dbReadModel.select<{ count: number }>(sql`select count(*) as count from sqlite_master`)[0]!.count === 0
48
55
 
49
56
  const syncBackend = syncOptions === undefined ? undefined : yield* syncOptions.makeBackend({ storeId, clientId })
50
57
 
@@ -53,20 +60,33 @@ export const makeLeaderThreadLayer = ({
53
60
  bootStatusQueue,
54
61
  })
55
62
 
56
- const syncProcessor = yield* makeLeaderSyncProcessor({ schema, dbMissing, dbLog, initialBlockingSyncContext })
63
+ const syncProcessor = yield* makeLeaderSyncProcessor({
64
+ schema,
65
+ dbMissing,
66
+ dbMutationLog,
67
+ initialBlockingSyncContext,
68
+ })
57
69
 
58
70
  const extraIncomingMessagesQueue = yield* Queue.unbounded<Devtools.MessageToAppLeader>().pipe(
59
71
  Effect.acquireRelease(Queue.shutdown),
60
72
  )
61
73
 
74
+ const devtoolsContext = devtoolsOptions.enabled
75
+ ? {
76
+ enabled: true as const,
77
+ syncBackendPullLatch: yield* Effect.makeLatch(true),
78
+ syncBackendPushLatch: yield* Effect.makeLatch(true),
79
+ }
80
+ : { enabled: false as const }
81
+
62
82
  const ctx = {
63
83
  schema,
64
84
  bootStatusQueue,
65
85
  storeId,
66
86
  clientId,
67
- db,
68
- dbLog,
69
- makeSyncDb,
87
+ dbReadModel,
88
+ dbMutationLog,
89
+ makeSqliteDb,
70
90
  mutationEventSchema: MutationEvent.makeMutationEventSchema(schema),
71
91
  shutdownStateSubRef: yield* SubscriptionRef.make<ShutdownState>('running'),
72
92
  shutdownChannel,
@@ -74,6 +94,7 @@ export const makeLeaderThreadLayer = ({
74
94
  syncProcessor,
75
95
  connectedClientSessionPullQueues: yield* makePullQueueSet,
76
96
  extraIncomingMessagesQueue,
97
+ devtools: devtoolsContext,
77
98
  } satisfies typeof LeaderThreadCtx.Service
78
99
 
79
100
  // @ts-expect-error For debugging purposes
@@ -156,17 +177,17 @@ const bootLeaderThread = ({
156
177
  LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient
157
178
  > =>
158
179
  Effect.gen(function* () {
159
- const { dbLog, bootStatusQueue, syncProcessor } = yield* LeaderThreadCtx
180
+ const { dbMutationLog, bootStatusQueue, syncProcessor } = yield* LeaderThreadCtx
160
181
 
161
182
  yield* migrateTable({
162
- db: dbLog,
183
+ db: dbMutationLog,
163
184
  behaviour: 'create-if-not-exists',
164
185
  tableAst: mutationLogMetaTable.sqliteDef.ast,
165
186
  skipMetaTable: true,
166
187
  })
167
188
 
168
189
  yield* migrateTable({
169
- db: dbLog,
190
+ db: dbMutationLog,
170
191
  behaviour: 'create-if-not-exists',
171
192
  tableAst: syncStatusTable.sqliteDef.ast,
172
193
  skipMetaTable: true,
@@ -174,7 +195,7 @@ const bootLeaderThread = ({
174
195
 
175
196
  // Create sync status row if it doesn't exist
176
197
  yield* execSql(
177
- dbLog,
198
+ dbMutationLog,
178
199
  sql`INSERT INTO ${SYNC_STATUS_TABLE} (head)
179
200
  SELECT ${EventId.ROOT.global}
180
201
  WHERE NOT EXISTS (SELECT 1 FROM ${SYNC_STATUS_TABLE})`,
@@ -1,6 +1,6 @@
1
1
  import { Effect, Schema } from '@livestore/utils/effect'
2
2
 
3
- import type { SynchronousDatabase } from '../adapter-types.js'
3
+ import type { SqliteDb } from '../adapter-types.js'
4
4
  import * as EventId from '../schema/EventId.js'
5
5
  import type * as MutationEvent from '../schema/MutationEvent.js'
6
6
  import { MUTATION_LOG_META_TABLE, mutationLogMetaTable, SYNC_STATUS_TABLE } from '../schema/system-tables.js'
@@ -11,10 +11,10 @@ export const getMutationEventsSince = (
11
11
  since: EventId.EventId,
12
12
  ): Effect.Effect<ReadonlyArray<MutationEvent.AnyEncoded>, never, LeaderThreadCtx> =>
13
13
  Effect.gen(function* () {
14
- const { dbLog } = yield* LeaderThreadCtx
14
+ const { dbMutationLog } = yield* LeaderThreadCtx
15
15
 
16
16
  const query = mutationLogMetaTable.query.where('idGlobal', '>=', since.global).asSql()
17
- const pendingMutationEventsRaw = dbLog.select(query.query, prepareBindValues(query.bindValues, query.query))
17
+ const pendingMutationEventsRaw = dbMutationLog.select(query.query, prepareBindValues(query.bindValues, query.query))
18
18
  const pendingMutationEvents = Schema.decodeUnknownSync(mutationLogMetaTable.schema.pipe(Schema.Array))(
19
19
  pendingMutationEventsRaw,
20
20
  )
@@ -29,18 +29,18 @@ export const getMutationEventsSince = (
29
29
  .filter((_) => EventId.compare(_.id, since) > 0)
30
30
  })
31
31
 
32
- export const getLocalHeadFromDb = (dbLog: SynchronousDatabase): EventId.EventId => {
33
- const res = dbLog.select<{ idGlobal: EventId.GlobalEventId; idLocal: EventId.LocalEventId }>(
32
+ export const getLocalHeadFromDb = (dbMutationLog: SqliteDb): EventId.EventId => {
33
+ const res = dbMutationLog.select<{ idGlobal: EventId.GlobalEventId; idLocal: EventId.LocalEventId }>(
34
34
  sql`select idGlobal, idLocal from ${MUTATION_LOG_META_TABLE} order by idGlobal DESC, idLocal DESC limit 1`,
35
35
  )[0]
36
36
 
37
37
  return res ? { global: res.idGlobal, local: res.idLocal } : EventId.ROOT
38
38
  }
39
39
 
40
- export const getBackendHeadFromDb = (dbLog: SynchronousDatabase): EventId.GlobalEventId =>
41
- dbLog.select<{ head: EventId.GlobalEventId }>(sql`select head from ${SYNC_STATUS_TABLE}`)[0]?.head ??
40
+ export const getBackendHeadFromDb = (dbMutationLog: SqliteDb): EventId.GlobalEventId =>
41
+ dbMutationLog.select<{ head: EventId.GlobalEventId }>(sql`select head from ${SYNC_STATUS_TABLE}`)[0]?.head ??
42
42
  EventId.ROOT.global
43
43
 
44
44
  // TODO use prepared statements
45
- export const updateBackendHead = (dbLog: SynchronousDatabase, head: EventId.EventId) =>
46
- dbLog.execute(sql`UPDATE ${SYNC_STATUS_TABLE} SET head = ${head.global}`)
45
+ export const updateBackendHead = (dbMutationLog: SqliteDb, head: EventId.EventId) =>
46
+ dbMutationLog.execute(sql`UPDATE ${SYNC_STATUS_TABLE} SET head = ${head.global}`)
@@ -12,56 +12,56 @@ export const recreateDb: Effect.Effect<
12
12
  UnexpectedError | SqliteError | IsOfflineError | InvalidPullError,
13
13
  LeaderThreadCtx | HttpClient.HttpClient
14
14
  > = Effect.gen(function* () {
15
- const { db, dbLog, makeSyncDb, schema, bootStatusQueue } = yield* LeaderThreadCtx
15
+ const { dbReadModel, dbMutationLog, schema, bootStatusQueue } = yield* LeaderThreadCtx
16
16
 
17
17
  const migrationOptions = schema.migrationOptions
18
18
 
19
19
  yield* Effect.addFinalizer(
20
20
  Effect.fn('recreateDb:finalizer')(function* (ex) {
21
- if (ex._tag === 'Failure') db.destroy()
21
+ if (ex._tag === 'Failure') dbReadModel.destroy()
22
22
  }),
23
23
  )
24
24
 
25
25
  // NOTE to speed up the operations below, we're creating a temporary in-memory database
26
26
  // and later we'll overwrite the persisted database with the new data
27
27
  // TODO bring back this optimization
28
- // const tmpSyncDb = yield* makeSyncDb({ _tag: 'in-memory' })
29
- const tmpSyncDb = db
30
- yield* configureConnection(tmpSyncDb, { fkEnabled: true })
28
+ // const tmpDb = yield* makeSqliteDb({ _tag: 'in-memory' })
29
+ const tmpDb = dbReadModel
30
+ yield* configureConnection(tmpDb, { fkEnabled: true })
31
31
 
32
32
  const initDb = (hooks: Partial<MigrationHooks> | undefined) =>
33
33
  Effect.gen(function* () {
34
- yield* Effect.tryAll(() => hooks?.init?.(tmpSyncDb)).pipe(UnexpectedError.mapToUnexpectedError)
34
+ yield* Effect.tryAll(() => hooks?.init?.(tmpDb)).pipe(UnexpectedError.mapToUnexpectedError)
35
35
 
36
36
  yield* migrateDb({
37
- db: tmpSyncDb,
37
+ db: tmpDb,
38
38
  schema,
39
39
  onProgress: ({ done, total }) =>
40
40
  Queue.offer(bootStatusQueue, { stage: 'migrating', progress: { done, total } }),
41
41
  })
42
42
 
43
- initializeSingletonTables(schema, tmpSyncDb)
43
+ initializeSingletonTables(schema, tmpDb)
44
44
 
45
- yield* Effect.tryAll(() => hooks?.pre?.(tmpSyncDb)).pipe(UnexpectedError.mapToUnexpectedError)
45
+ yield* Effect.tryAll(() => hooks?.pre?.(tmpDb)).pipe(UnexpectedError.mapToUnexpectedError)
46
46
 
47
- return tmpSyncDb
47
+ return tmpDb
48
48
  })
49
49
 
50
50
  switch (migrationOptions.strategy) {
51
51
  case 'from-mutation-log': {
52
52
  const hooks = migrationOptions.hooks
53
- const tmpSyncDb = yield* initDb(hooks)
53
+ const tmpDb = yield* initDb(hooks)
54
54
 
55
55
  yield* rehydrateFromMutationLog({
56
- db: tmpSyncDb,
57
- logDb: dbLog,
56
+ db: tmpDb,
57
+ logDb: dbMutationLog,
58
58
  schema,
59
59
  migrationOptions,
60
60
  onProgress: ({ done, total }) =>
61
61
  Queue.offer(bootStatusQueue, { stage: 'rehydrating', progress: { done, total } }),
62
62
  })
63
63
 
64
- yield* Effect.tryAll(() => hooks?.post?.(tmpSyncDb)).pipe(UnexpectedError.mapToUnexpectedError)
64
+ yield* Effect.tryAll(() => hooks?.post?.(tmpDb)).pipe(UnexpectedError.mapToUnexpectedError)
65
65
 
66
66
  break
67
67
  }
@@ -76,13 +76,13 @@ export const recreateDb: Effect.Effect<
76
76
  break
77
77
  }
78
78
  case 'manual': {
79
- const oldDbData = db.export()
79
+ const oldDbData = dbReadModel.export()
80
80
 
81
81
  const newDbData = yield* Effect.tryAll(() => migrationOptions.migrate(oldDbData)).pipe(
82
82
  UnexpectedError.mapToUnexpectedError,
83
83
  )
84
84
 
85
- tmpSyncDb.import(newDbData)
85
+ tmpDb.import(newDbData)
86
86
 
87
87
  // TODO validate schema
88
88
 
@@ -95,17 +95,17 @@ export const recreateDb: Effect.Effect<
95
95
 
96
96
  // TODO bring back
97
97
  // Import the temporary in-memory database into the persistent database
98
- // yield* Effect.sync(() => db.import(tmpSyncDb)).pipe(
98
+ // yield* Effect.sync(() => db.import(tmpDb)).pipe(
99
99
  // Effect.withSpan('@livestore/common:leader-thread:recreateDb:import'),
100
100
  // )
101
101
 
102
102
  // TODO maybe bring back re-using this initial snapshot to avoid calling `.export()` again
103
103
  // We've disabled this for now as it made the code too complex, as we often run syncing right after
104
104
  // so the snapshot is no longer up to date
105
- // const snapshotFromTmpDb = tmpSyncDb.export()
105
+ // const snapshotFromTmpDb = tmpDb.export()
106
106
 
107
107
  // TODO bring back
108
- // tmpSyncDb.close()
108
+ // tmpDb.close()
109
109
  }).pipe(
110
110
  Effect.scoped, // NOTE we're closing the scope here so finalizers are called when the effect is done
111
111
  Effect.withSpan('@livestore/common:leader-thread:recreateDb'),
@@ -16,10 +16,10 @@ import type {
16
16
  BootStatus,
17
17
  Devtools,
18
18
  InvalidPushError,
19
- MakeSynchronousDatabase,
19
+ MakeSqliteDb,
20
20
  PersistenceInfo,
21
+ SqliteDb,
21
22
  SyncBackend,
22
- SynchronousDatabase,
23
23
  UnexpectedError,
24
24
  } from '../index.js'
25
25
  import type { EventId, LiveStoreSchema, MutationEvent } from '../schema/mod.js'
@@ -56,8 +56,8 @@ export type InitialSyncInfo = Option.Option<{
56
56
  // | { _tag: 'Recreate'; snapshotRef: Ref.Ref<Uint8Array | undefined>; syncInfo: InitialSyncInfo }
57
57
  // | { _tag: 'Reuse'; syncInfo: InitialSyncInfo }
58
58
 
59
- export type LeaderDatabase = SynchronousDatabase<{ dbPointer: number; persistenceInfo: PersistenceInfo }>
60
- export type PersistenceInfoPair = { db: PersistenceInfo; mutationLog: PersistenceInfo }
59
+ export type LeaderSqliteDb = SqliteDb<{ dbPointer: number; persistenceInfo: PersistenceInfo }>
60
+ export type PersistenceInfoPair = { readModel: PersistenceInfo; mutationLog: PersistenceInfo }
61
61
 
62
62
  export type DevtoolsOptions =
63
63
  | {
@@ -65,7 +65,7 @@ export type DevtoolsOptions =
65
65
  }
66
66
  | {
67
67
  enabled: true
68
- makeContext: Effect.Effect<
68
+ makeBootContext: Effect.Effect<
69
69
  {
70
70
  devtoolsWebChannel: WebChannel.WebChannel<Devtools.MessageToAppLeader, Devtools.MessageFromAppLeader>
71
71
  persistenceInfo: PersistenceInfoPair
@@ -75,25 +75,39 @@ export type DevtoolsOptions =
75
75
  >
76
76
  }
77
77
 
78
+ export type DevtoolsContext =
79
+ | {
80
+ enabled: true
81
+ syncBackendPullLatch: Effect.Latch
82
+ syncBackendPushLatch: Effect.Latch
83
+ }
84
+ | {
85
+ enabled: false
86
+ }
87
+
78
88
  export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
79
89
  LeaderThreadCtx,
80
90
  {
81
91
  schema: LiveStoreSchema
82
92
  storeId: string
83
93
  clientId: string
84
- makeSyncDb: MakeSynchronousDatabase
85
- db: LeaderDatabase
86
- dbLog: LeaderDatabase
94
+ makeSqliteDb: MakeSqliteDb
95
+ dbReadModel: LeaderSqliteDb
96
+ dbMutationLog: LeaderSqliteDb
87
97
  bootStatusQueue: Queue.Queue<BootStatus>
88
98
  // TODO we should find a more elegant way to handle cases which need this ref for their implementation
89
99
  shutdownStateSubRef: SubscriptionRef.SubscriptionRef<ShutdownState>
90
100
  shutdownChannel: ShutdownChannel
91
101
  mutationEventSchema: MutationEvent.ForMutationDefRecord<any>
92
- // devtools: DevtoolsContext
102
+ devtools: DevtoolsContext
93
103
  syncBackend: SyncBackend | undefined
94
104
  syncProcessor: LeaderSyncProcessor
95
105
  connectedClientSessionPullQueues: PullQueueSet
96
- /** e.g. used for `store.__dev` APIs */
106
+ /**
107
+ * e.g. used for `store._dev` APIs
108
+ *
109
+ * This is currently separated from `.devtools` as it also needs to work when devtools are disabled
110
+ */
97
111
  extraIncomingMessagesQueue: Queue.Queue<Devtools.MessageToAppLeader>
98
112
  }
99
113
  >() {}
@@ -1,7 +1,7 @@
1
1
  import { memoizeByRef, shouldNeverHappen } from '@livestore/utils'
2
2
  import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
3
3
 
4
- import { type MigrationOptionsFromMutationLog, type SynchronousDatabase, UnexpectedError } from './adapter-types.js'
4
+ import { type MigrationOptionsFromMutationLog, type SqliteDb, UnexpectedError } from './adapter-types.js'
5
5
  import { makeApplyMutation } from './leader-thread/apply-mutation.js'
6
6
  import type { LiveStoreSchema, MutationDef, MutationEvent, MutationLogMetaRow } from './schema/mod.js'
7
7
  import { EventId, MUTATION_LOG_META_TABLE } from './schema/mod.js'
@@ -16,8 +16,8 @@ export const rehydrateFromMutationLog = ({
16
16
  migrationOptions,
17
17
  onProgress,
18
18
  }: {
19
- logDb: SynchronousDatabase
20
- db: SynchronousDatabase
19
+ logDb: SqliteDb
20
+ db: SqliteDb
21
21
  schema: LiveStoreSchema
22
22
  migrationOptions: MigrationOptionsFromMutationLog
23
23
  onProgress: (_: { done: number; total: number }) => Effect.Effect<void>
@@ -1,4 +1,4 @@
1
- import type { SynchronousDatabase } from '../adapter-types.js'
1
+ import type { SqliteDb } from '../adapter-types.js'
2
2
  import type { ParamsObject } from '../util.js'
3
3
  import { prepareBindValues } from '../util.js'
4
4
 
@@ -6,7 +6,7 @@ import { prepareBindValues } from '../util.js'
6
6
  // will require proper scope-aware cleanup etc (for testing and apps with multiple LiveStore instances)
7
7
  // const cachedStmts = new Map<string, PreparedStatement>()
8
8
 
9
- export const dbExecute = (db: SynchronousDatabase, queryStr: string, bindValues?: ParamsObject) => {
9
+ export const dbExecute = (db: SqliteDb, queryStr: string, bindValues?: ParamsObject) => {
10
10
  // let stmt = cachedStmts.get(queryStr)
11
11
  // if (!stmt) {
12
12
  const stmt = db.prepare(queryStr)
@@ -20,7 +20,7 @@ export const dbExecute = (db: SynchronousDatabase, queryStr: string, bindValues?
20
20
  stmt.finalize()
21
21
  }
22
22
 
23
- export const dbSelect = <T>(db: SynchronousDatabase, queryStr: string, bindValues?: ParamsObject) => {
23
+ export const dbSelect = <T>(db: SqliteDb, queryStr: string, bindValues?: ParamsObject) => {
24
24
  // let stmt = cachedStmts.get(queryStr)
25
25
  // if (!stmt) {
26
26
  const stmt = db.prepare(queryStr)
@@ -2,7 +2,7 @@ import { SqliteAst, SqliteDsl } from '@livestore/db-schema'
2
2
  import { memoizeByStringifyArgs } from '@livestore/utils'
3
3
  import { Effect, Schema as EffectSchema } from '@livestore/utils/effect'
4
4
 
5
- import type { SynchronousDatabase } from '../adapter-types.js'
5
+ import type { SqliteDb } from '../adapter-types.js'
6
6
  import type { LiveStoreSchema } from '../schema/mod.js'
7
7
  import type { SchemaMetaRow, SchemaMutationsMetaRow } from '../schema/system-tables.js'
8
8
  import {
@@ -19,7 +19,7 @@ import { validateSchema } from './validate-mutation-defs.js'
19
19
 
20
20
  const getMemoizedTimestamp = memoizeByStringifyArgs(() => new Date().toISOString())
21
21
 
22
- export const makeSchemaManager = (db: SynchronousDatabase): Effect.Effect<SchemaManager> =>
22
+ export const makeSchemaManager = (db: SqliteDb): Effect.Effect<SchemaManager> =>
23
23
  Effect.gen(function* () {
24
24
  yield* migrateTable({
25
25
  db,
@@ -51,7 +51,7 @@ export const migrateDb = ({
51
51
  schema,
52
52
  onProgress,
53
53
  }: {
54
- db: SynchronousDatabase
54
+ db: SqliteDb
55
55
  schema: LiveStoreSchema
56
56
  onProgress?: (opts: { done: number; total: number }) => Effect.Effect<void>
57
57
  }) =>
@@ -116,7 +116,7 @@ export const migrateTable = ({
116
116
  behaviour,
117
117
  skipMetaTable = false,
118
118
  }: {
119
- db: SynchronousDatabase
119
+ db: SqliteDb
120
120
  tableAst: SqliteAst.Table
121
121
  schemaHash?: number
122
122
  behaviour: 'drop-and-recreate' | 'create-if-not-exists'
@@ -1,9 +1,9 @@
1
1
  import { LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils'
2
- import type { Scope } from '@livestore/utils/effect'
2
+ import type { Runtime, Scope } from '@livestore/utils/effect'
3
3
  import { Effect, Schema, Stream } from '@livestore/utils/effect'
4
4
  import * as otel from '@opentelemetry/api'
5
5
 
6
- import type { ClientSessionLeaderThreadProxy, UnexpectedError } from '../adapter-types.js'
6
+ import type { ClientSession, UnexpectedError } from '../adapter-types.js'
7
7
  import * as EventId from '../schema/EventId.js'
8
8
  import { type LiveStoreSchema } from '../schema/mod.js'
9
9
  import * as MutationEvent from '../schema/MutationEvent.js'
@@ -20,18 +20,16 @@ import { SyncState, updateSyncState } from './syncstate.js'
20
20
  */
21
21
  export const makeClientSessionSyncProcessor = ({
22
22
  schema,
23
- initialLeaderHead,
24
- pushToLeader,
25
- pullFromLeader,
23
+ clientSession,
24
+ runtime,
26
25
  applyMutation,
27
26
  rollback,
28
27
  refreshTables,
29
28
  span,
30
29
  }: {
31
30
  schema: LiveStoreSchema
32
- initialLeaderHead: EventId.EventId
33
- pushToLeader: (batch: ReadonlyArray<MutationEvent.AnyEncoded>) => void
34
- pullFromLeader: ClientSessionLeaderThreadProxy['mutations']['pull']
31
+ clientSession: ClientSession
32
+ runtime: Runtime.Runtime<Scope.Scope>
35
33
  applyMutation: (
36
34
  mutationEventDecoded: MutationEvent.PartialAnyDecoded,
37
35
  options: { otelContext: otel.Context; withChangeset: boolean },
@@ -47,8 +45,8 @@ export const makeClientSessionSyncProcessor = ({
47
45
 
48
46
  const syncStateRef = {
49
47
  current: new SyncState({
50
- localHead: initialLeaderHead,
51
- upstreamHead: initialLeaderHead,
48
+ localHead: clientSession.leaderThread.mutations.initialMutationEventId,
49
+ upstreamHead: clientSession.leaderThread.mutations.initialMutationEventId,
52
50
  pending: [],
53
51
  // TODO init rollbackTail from leader to be ready for backend rebasing
54
52
  rollbackTail: [],
@@ -103,7 +101,9 @@ export const makeClientSessionSyncProcessor = ({
103
101
  }
104
102
 
105
103
  // console.debug('pushToLeader', encodedMutationEvents.length, ...encodedMutationEvents.map((_) => _.toJSON()))
106
- pushToLeader(encodedMutationEvents)
104
+ clientSession.leaderThread.mutations
105
+ .push(encodedMutationEvents)
106
+ .pipe(Effect.tapCauseLogPretty, Effect.provide(runtime), Effect.runFork)
107
107
 
108
108
  return { writeTables }
109
109
  }
@@ -111,10 +111,13 @@ export const makeClientSessionSyncProcessor = ({
111
111
  const otelContext = otel.trace.setSpan(otel.context.active(), span)
112
112
 
113
113
  const boot: ClientSessionSyncProcessor['boot'] = Effect.gen(function* () {
114
- yield* pullFromLeader.pipe(
114
+ yield* clientSession.leaderThread.mutations.pull.pipe(
115
115
  Stream.tap(({ payload, remaining }) =>
116
116
  Effect.gen(function* () {
117
117
  // console.log('pulled payload from leader', { payload, remaining })
118
+ if (clientSession.devtools.enabled) {
119
+ yield* clientSession.devtools.pullLatch.await
120
+ }
118
121
 
119
122
  const updateResult = updateSyncState({
120
123
  syncState: syncStateRef.current,
@@ -155,7 +158,9 @@ export const makeClientSessionSyncProcessor = ({
155
158
  }
156
159
  }
157
160
 
158
- pushToLeader(updateResult.newSyncState.pending)
161
+ clientSession.leaderThread.mutations
162
+ .push(updateResult.newSyncState.pending)
163
+ .pipe(Effect.tapCauseLogPretty, Effect.provide(runtime), Effect.runFork)
159
164
  } else {
160
165
  span.addEvent('pull:advance', {
161
166
  payloadTag: payload._tag,
package/src/version.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // import packageJson from '../package.json' with { type: 'json' }
3
3
  // export const liveStoreVersion = packageJson.version
4
4
 
5
- export const liveStoreVersion = '0.3.0-dev.10' as const
5
+ export const liveStoreVersion = '0.3.0-dev.11' as const
6
6
 
7
7
  /**
8
8
  * This version number is incremented whenever the internal storage format changes in a breaking way.