@livestore/common 0.0.0-snapshot-aed277ba0960f72b8d464508961ab4aec1881230 → 0.0.0-snapshot-7bcbc24bb8873481e482d982636957f0c1f791f6
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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/fixture.d.ts +6 -6
- package/dist/adapter-types.d.ts +39 -16
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +12 -0
- package/dist/adapter-types.js.map +1 -1
- package/dist/derived-mutations.js +3 -3
- package/dist/derived-mutations.js.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +23 -23
- package/dist/devtools/devtools-messages-common.d.ts +19 -6
- package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-common.js +14 -0
- package/dist/devtools/devtools-messages-common.js.map +1 -1
- package/dist/devtools/devtools-messages-leader.d.ts +94 -75
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +18 -17
- package/dist/devtools/devtools-messages-leader.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +50 -35
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
- package/dist/leader-thread/apply-mutation.js +8 -6
- package/dist/leader-thread/apply-mutation.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +26 -18
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +23 -6
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/mutationlog.d.ts +1 -1
- package/dist/leader-thread/mutationlog.d.ts.map +1 -1
- package/dist/leader-thread/mutationlog.js +7 -5
- package/dist/leader-thread/mutationlog.js.map +1 -1
- package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts +4 -2
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +12 -7
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/types.d.ts +19 -7
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js +1 -1
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
- package/dist/rehydrate-from-mutationlog.js +8 -6
- package/dist/rehydrate-from-mutationlog.js.map +1 -1
- package/dist/schema/EventId.d.ts +10 -9
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +14 -11
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/EventId.test.js +3 -3
- package/dist/schema/EventId.test.js.map +1 -1
- package/dist/schema/MutationEvent.d.ts +37 -12
- package/dist/schema/MutationEvent.d.ts.map +1 -1
- package/dist/schema/MutationEvent.js +20 -4
- package/dist/schema/MutationEvent.js.map +1 -1
- package/dist/schema/mutations.d.ts +4 -8
- package/dist/schema/mutations.d.ts.map +1 -1
- package/dist/schema/mutations.js +2 -2
- package/dist/schema/mutations.js.map +1 -1
- package/dist/schema/system-tables.d.ts +38 -20
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +9 -6
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/schema/table-def.d.ts +7 -7
- package/dist/schema/table-def.d.ts.map +1 -1
- package/dist/schema/table-def.js +2 -2
- package/dist/schema/table-def.js.map +1 -1
- package/dist/schema-management/migrations.d.ts +2 -2
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +6 -1
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +20 -5
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/next/facts.js +1 -1
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +2 -0
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +3 -1
- package/dist/sync/next/history-dag-common.js.map +1 -1
- package/dist/sync/next/history-dag.d.ts.map +1 -1
- package/dist/sync/next/history-dag.js +1 -1
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +3 -1
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +5 -3
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/compact-events.calculator.test.js +12 -12
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
- package/dist/sync/next/test/compact-events.test.js +30 -30
- package/dist/sync/next/test/compact-events.test.js.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts +1 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.js +9 -7
- package/dist/sync/next/test/mutation-fixtures.js.map +1 -1
- package/dist/sync/sync.d.ts +2 -2
- package/dist/sync/syncstate.d.ts +9 -9
- package/dist/sync/syncstate.js +6 -6
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +18 -16
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/src/adapter-types.ts +33 -15
- package/src/derived-mutations.ts +3 -3
- package/src/devtools/devtools-messages-common.ts +34 -0
- package/src/devtools/devtools-messages-leader.ts +28 -18
- package/src/index.ts +1 -1
- package/src/leader-thread/LeaderSyncProcessor.ts +59 -38
- package/src/leader-thread/apply-mutation.ts +15 -5
- package/src/leader-thread/leader-worker-devtools.ts +33 -19
- package/src/leader-thread/make-leader-thread-layer.ts +28 -8
- package/src/leader-thread/mutationlog.ts +8 -6
- package/src/leader-thread/recreate-db.ts +18 -9
- package/src/leader-thread/types.ts +20 -5
- package/src/rehydrate-from-mutationlog.ts +8 -6
- package/src/schema/EventId.test.ts +3 -3
- package/src/schema/EventId.ts +20 -16
- package/src/schema/MutationEvent.ts +31 -6
- package/src/schema/mutations.ts +6 -19
- package/src/schema/system-tables.ts +9 -6
- package/src/schema/table-def.ts +8 -8
- package/src/schema-management/migrations.ts +9 -5
- package/src/sync/ClientSessionSyncProcessor.ts +25 -6
- package/src/sync/next/facts.ts +1 -1
- package/src/sync/next/history-dag-common.ts +5 -1
- package/src/sync/next/history-dag.ts +1 -1
- package/src/sync/next/rebase-events.ts +8 -2
- package/src/sync/next/test/compact-events.calculator.test.ts +12 -12
- package/src/sync/next/test/compact-events.test.ts +30 -30
- package/src/sync/next/test/mutation-fixtures.ts +10 -6
- package/src/sync/syncstate.test.ts +19 -17
- package/src/sync/syncstate.ts +6 -6
- package/src/version.ts +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isNotUndefined, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils'
|
|
1
|
+
import { isNotUndefined, LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils'
|
|
2
2
|
import type { HttpClient, Scope, Tracer } from '@livestore/utils/effect'
|
|
3
3
|
import {
|
|
4
4
|
BucketQueue,
|
|
@@ -32,7 +32,7 @@ import * as SyncState from '../sync/syncstate.js'
|
|
|
32
32
|
import { sql } from '../util.js'
|
|
33
33
|
import { makeApplyMutation } from './apply-mutation.js'
|
|
34
34
|
import { execSql } from './connection.js'
|
|
35
|
-
import { getBackendHeadFromDb,
|
|
35
|
+
import { getBackendHeadFromDb, getClientHeadFromDb, getMutationEventsSince, updateBackendHead } from './mutationlog.js'
|
|
36
36
|
import type { InitialBlockingSyncContext, InitialSyncInfo, LeaderSyncProcessor } from './types.js'
|
|
37
37
|
import { LeaderThreadCtx } from './types.js'
|
|
38
38
|
|
|
@@ -83,7 +83,7 @@ export const makeLeaderSyncProcessor = ({
|
|
|
83
83
|
|
|
84
84
|
const isLocalEvent = (mutationEventEncoded: MutationEvent.EncodedWithMeta) => {
|
|
85
85
|
const mutationDef = schema.mutations.get(mutationEventEncoded.mutation)!
|
|
86
|
-
return mutationDef.options.
|
|
86
|
+
return mutationDef.options.clientOnly
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// This context depends on data from `boot`, we should find a better implementation to avoid this ref indirection.
|
|
@@ -93,8 +93,7 @@ export const makeLeaderSyncProcessor = ({
|
|
|
93
93
|
| {
|
|
94
94
|
otelSpan: otel.Span | undefined
|
|
95
95
|
span: Tracer.Span
|
|
96
|
-
|
|
97
|
-
devtoolsPushLatch: Effect.Latch | undefined
|
|
96
|
+
devtoolsLatch: Effect.Latch | undefined
|
|
98
97
|
},
|
|
99
98
|
}
|
|
100
99
|
|
|
@@ -107,10 +106,6 @@ export const makeLeaderSyncProcessor = ({
|
|
|
107
106
|
// TODO validate batch
|
|
108
107
|
if (newEvents.length === 0) return
|
|
109
108
|
|
|
110
|
-
if (ctxRef.current?.devtoolsPushLatch !== undefined) {
|
|
111
|
-
yield* ctxRef.current.devtoolsPushLatch.await
|
|
112
|
-
}
|
|
113
|
-
|
|
114
109
|
const waitForProcessing = options?.waitForProcessing ?? false
|
|
115
110
|
|
|
116
111
|
if (waitForProcessing) {
|
|
@@ -137,18 +132,24 @@ export const makeLeaderSyncProcessor = ({
|
|
|
137
132
|
}),
|
|
138
133
|
)
|
|
139
134
|
|
|
140
|
-
const pushPartial: LeaderSyncProcessor['pushPartial'] = (
|
|
135
|
+
const pushPartial: LeaderSyncProcessor['pushPartial'] = ({
|
|
136
|
+
mutationEvent: partialMutationEvent,
|
|
137
|
+
clientId,
|
|
138
|
+
sessionId,
|
|
139
|
+
}) =>
|
|
141
140
|
Effect.gen(function* () {
|
|
142
141
|
const syncState = yield* syncStateSref
|
|
143
142
|
if (syncState === undefined) return shouldNeverHappen('Not initialized')
|
|
144
143
|
|
|
145
144
|
const mutationDef =
|
|
146
|
-
schema.mutations.get(
|
|
147
|
-
shouldNeverHappen(`Unknown mutation: ${
|
|
145
|
+
schema.mutations.get(partialMutationEvent.mutation) ??
|
|
146
|
+
shouldNeverHappen(`Unknown mutation: ${partialMutationEvent.mutation}`)
|
|
148
147
|
|
|
149
148
|
const mutationEventEncoded = new MutationEvent.EncodedWithMeta({
|
|
150
|
-
...
|
|
151
|
-
|
|
149
|
+
...partialMutationEvent,
|
|
150
|
+
clientId,
|
|
151
|
+
sessionId,
|
|
152
|
+
...EventId.nextPair(syncState.localHead, mutationDef.options.clientOnly),
|
|
152
153
|
})
|
|
153
154
|
|
|
154
155
|
yield* push([mutationEventEncoded])
|
|
@@ -164,12 +165,11 @@ export const makeLeaderSyncProcessor = ({
|
|
|
164
165
|
ctxRef.current = {
|
|
165
166
|
otelSpan,
|
|
166
167
|
span,
|
|
167
|
-
|
|
168
|
-
devtoolsPushLatch: devtools.enabled ? devtools.syncBackendPushLatch : undefined,
|
|
168
|
+
devtoolsLatch: devtools.enabled ? devtools.syncBackendLatch : undefined,
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
const initialBackendHead = dbMissing ? EventId.ROOT.global : getBackendHeadFromDb(dbMutationLog)
|
|
172
|
-
const initialLocalHead = dbMissing ? EventId.ROOT :
|
|
172
|
+
const initialLocalHead = dbMissing ? EventId.ROOT : getClientHeadFromDb(dbMutationLog)
|
|
173
173
|
|
|
174
174
|
if (initialBackendHead > initialLocalHead.global) {
|
|
175
175
|
return shouldNeverHappen(
|
|
@@ -179,14 +179,14 @@ export const makeLeaderSyncProcessor = ({
|
|
|
179
179
|
|
|
180
180
|
const pendingMutationEvents = yield* getMutationEventsSince({
|
|
181
181
|
global: initialBackendHead,
|
|
182
|
-
|
|
182
|
+
client: EventId.clientDefault,
|
|
183
183
|
}).pipe(Effect.map(ReadonlyArray.map((_) => new MutationEvent.EncodedWithMeta(_))))
|
|
184
184
|
|
|
185
185
|
const initialSyncState = new SyncState.SyncState({
|
|
186
186
|
pending: pendingMutationEvents,
|
|
187
187
|
// On the leader we don't need a rollback tail beyond `pending` items
|
|
188
188
|
rollbackTail: [],
|
|
189
|
-
upstreamHead: { global: initialBackendHead,
|
|
189
|
+
upstreamHead: { global: initialBackendHead, client: EventId.clientDefault },
|
|
190
190
|
localHead: initialLocalHead,
|
|
191
191
|
})
|
|
192
192
|
|
|
@@ -196,10 +196,10 @@ export const makeLeaderSyncProcessor = ({
|
|
|
196
196
|
// Rehydrate sync queue
|
|
197
197
|
if (pendingMutationEvents.length > 0) {
|
|
198
198
|
const filteredBatch = pendingMutationEvents
|
|
199
|
-
// Don't sync
|
|
199
|
+
// Don't sync clientOnly mutations
|
|
200
200
|
.filter((mutationEventEncoded) => {
|
|
201
201
|
const mutationDef = schema.mutations.get(mutationEventEncoded.mutation)!
|
|
202
|
-
return mutationDef.options.
|
|
202
|
+
return mutationDef.options.clientOnly === false
|
|
203
203
|
})
|
|
204
204
|
|
|
205
205
|
yield* BucketQueue.offerAll(syncBackendQueue, filteredBatch)
|
|
@@ -220,7 +220,12 @@ export const makeLeaderSyncProcessor = ({
|
|
|
220
220
|
|
|
221
221
|
yield* FiberHandle.run(
|
|
222
222
|
backendPushingFiberHandle,
|
|
223
|
-
backgroundBackendPushing({
|
|
223
|
+
backgroundBackendPushing({
|
|
224
|
+
dbReady,
|
|
225
|
+
syncBackendQueue,
|
|
226
|
+
otelSpan,
|
|
227
|
+
devtoolsLatch: ctxRef.current?.devtoolsLatch,
|
|
228
|
+
}).pipe(Effect.tapCauseLogPretty),
|
|
224
229
|
)
|
|
225
230
|
|
|
226
231
|
yield* backgroundBackendPulling({
|
|
@@ -239,7 +244,12 @@ export const makeLeaderSyncProcessor = ({
|
|
|
239
244
|
// Restart pushing fiber
|
|
240
245
|
yield* FiberHandle.run(
|
|
241
246
|
backendPushingFiberHandle,
|
|
242
|
-
backgroundBackendPushing({
|
|
247
|
+
backgroundBackendPushing({
|
|
248
|
+
dbReady,
|
|
249
|
+
syncBackendQueue,
|
|
250
|
+
otelSpan,
|
|
251
|
+
devtoolsLatch: ctxRef.current?.devtoolsLatch,
|
|
252
|
+
}).pipe(Effect.tapCauseLogPretty),
|
|
243
253
|
)
|
|
244
254
|
}),
|
|
245
255
|
syncStateSref,
|
|
@@ -247,8 +257,10 @@ export const makeLeaderSyncProcessor = ({
|
|
|
247
257
|
pullLatch,
|
|
248
258
|
otelSpan,
|
|
249
259
|
initialBlockingSyncContext,
|
|
250
|
-
|
|
260
|
+
devtoolsLatch: ctxRef.current?.devtoolsLatch,
|
|
251
261
|
}).pipe(Effect.tapCauseLogPretty, Effect.forkScoped)
|
|
262
|
+
|
|
263
|
+
return { initialLeaderHead: initialLocalHead }
|
|
252
264
|
}).pipe(Effect.withSpanScoped('@livestore/common:leader-thread:syncing'))
|
|
253
265
|
|
|
254
266
|
return {
|
|
@@ -357,10 +369,10 @@ const backgroundApplyLocalPushes = ({
|
|
|
357
369
|
updateResult: TRACE_VERBOSE ? JSON.stringify(updateResult) : undefined,
|
|
358
370
|
})
|
|
359
371
|
|
|
360
|
-
// Don't sync
|
|
372
|
+
// Don't sync clientOnly mutations
|
|
361
373
|
const filteredBatch = updateResult.newEvents.filter((mutationEventEncoded) => {
|
|
362
374
|
const mutationDef = schema.mutations.get(mutationEventEncoded.mutation)!
|
|
363
|
-
return mutationDef.options.
|
|
375
|
+
return mutationDef.options.clientOnly === false
|
|
364
376
|
})
|
|
365
377
|
|
|
366
378
|
yield* BucketQueue.offerAll(syncBackendQueue, filteredBatch)
|
|
@@ -431,7 +443,7 @@ const backgroundBackendPulling = ({
|
|
|
431
443
|
syncStateSref,
|
|
432
444
|
localPushesLatch,
|
|
433
445
|
pullLatch,
|
|
434
|
-
|
|
446
|
+
devtoolsLatch,
|
|
435
447
|
initialBlockingSyncContext,
|
|
436
448
|
}: {
|
|
437
449
|
dbReady: Deferred.Deferred<void>
|
|
@@ -444,7 +456,7 @@ const backgroundBackendPulling = ({
|
|
|
444
456
|
syncStateSref: SubscriptionRef.SubscriptionRef<SyncState.SyncState | undefined>
|
|
445
457
|
localPushesLatch: Effect.Latch
|
|
446
458
|
pullLatch: Effect.Latch
|
|
447
|
-
|
|
459
|
+
devtoolsLatch: Effect.Latch | undefined
|
|
448
460
|
initialBlockingSyncContext: InitialBlockingSyncContext
|
|
449
461
|
}) =>
|
|
450
462
|
Effect.gen(function* () {
|
|
@@ -466,8 +478,8 @@ const backgroundBackendPulling = ({
|
|
|
466
478
|
Effect.gen(function* () {
|
|
467
479
|
if (newEvents.length === 0) return
|
|
468
480
|
|
|
469
|
-
if (
|
|
470
|
-
yield*
|
|
481
|
+
if (devtoolsLatch !== undefined) {
|
|
482
|
+
yield* devtoolsLatch.await
|
|
471
483
|
}
|
|
472
484
|
|
|
473
485
|
// Prevent more local pushes from being processed until this pull is finished
|
|
@@ -507,7 +519,7 @@ const backgroundBackendPulling = ({
|
|
|
507
519
|
|
|
508
520
|
const filteredRebasedPending = updateResult.newSyncState.pending.filter((mutationEvent) => {
|
|
509
521
|
const mutationDef = schema.mutations.get(mutationEvent.mutation)!
|
|
510
|
-
return mutationDef.options.
|
|
522
|
+
return mutationDef.options.clientOnly === false
|
|
511
523
|
})
|
|
512
524
|
yield* restartBackendPushing(filteredRebasedPending)
|
|
513
525
|
|
|
@@ -592,9 +604,9 @@ const rollback = ({
|
|
|
592
604
|
Effect.gen(function* () {
|
|
593
605
|
const rollbackEvents = db
|
|
594
606
|
.select<SessionChangesetMetaRow>(
|
|
595
|
-
sql`SELECT * FROM ${SESSION_CHANGESET_META_TABLE} WHERE (idGlobal,
|
|
607
|
+
sql`SELECT * FROM ${SESSION_CHANGESET_META_TABLE} WHERE (idGlobal, idClient) IN (${eventIdsToRollback.map((id) => `(${id.global}, ${id.client})`).join(', ')})`,
|
|
596
608
|
)
|
|
597
|
-
.map((_) => ({ id: { global: _.idGlobal,
|
|
609
|
+
.map((_) => ({ id: { global: _.idGlobal, client: _.idClient }, changeset: _.changeset, debug: _.debug }))
|
|
598
610
|
.toSorted((a, b) => EventId.compare(a.id, b.id))
|
|
599
611
|
|
|
600
612
|
// Apply changesets in reverse order
|
|
@@ -607,12 +619,12 @@ const rollback = ({
|
|
|
607
619
|
|
|
608
620
|
// Delete the changeset rows
|
|
609
621
|
db.execute(
|
|
610
|
-
sql`DELETE FROM ${SESSION_CHANGESET_META_TABLE} WHERE (idGlobal,
|
|
622
|
+
sql`DELETE FROM ${SESSION_CHANGESET_META_TABLE} WHERE (idGlobal, idClient) IN (${eventIdsToRollback.map((id) => `(${id.global}, ${id.client})`).join(', ')})`,
|
|
611
623
|
)
|
|
612
624
|
|
|
613
625
|
// Delete the mutation log rows
|
|
614
626
|
dbMutationLog.execute(
|
|
615
|
-
sql`DELETE FROM ${MUTATION_LOG_META_TABLE} WHERE (idGlobal,
|
|
627
|
+
sql`DELETE FROM ${MUTATION_LOG_META_TABLE} WHERE (idGlobal, idClient) IN (${eventIdsToRollback.map((id) => `(${id.global}, ${id.client})`).join(', ')})`,
|
|
616
628
|
)
|
|
617
629
|
}).pipe(
|
|
618
630
|
Effect.withSpan('@livestore/common:leader-thread:syncing:rollback', {
|
|
@@ -632,12 +644,12 @@ const getCursorInfo = (remoteHead: EventId.GlobalEventId) =>
|
|
|
632
644
|
|
|
633
645
|
const syncMetadataOption = yield* Effect.sync(() =>
|
|
634
646
|
dbMutationLog.select<{ syncMetadataJson: string }>(
|
|
635
|
-
sql`SELECT syncMetadataJson FROM ${MUTATION_LOG_META_TABLE} WHERE idGlobal = ${remoteHead} ORDER BY
|
|
647
|
+
sql`SELECT syncMetadataJson FROM ${MUTATION_LOG_META_TABLE} WHERE idGlobal = ${remoteHead} ORDER BY idClient ASC LIMIT 1`,
|
|
636
648
|
),
|
|
637
649
|
).pipe(Effect.andThen(Schema.decode(MutationlogQuerySchema)), Effect.map(Option.flatten), Effect.orDie)
|
|
638
650
|
|
|
639
651
|
return Option.some({
|
|
640
|
-
cursor: { global: remoteHead,
|
|
652
|
+
cursor: { global: remoteHead, client: EventId.clientDefault },
|
|
641
653
|
metadata: syncMetadataOption,
|
|
642
654
|
}) satisfies InitialSyncInfo
|
|
643
655
|
}).pipe(Effect.withSpan('@livestore/common:leader-thread:syncing:getCursorInfo', { attributes: { remoteHead } }))
|
|
@@ -646,10 +658,12 @@ const backgroundBackendPushing = ({
|
|
|
646
658
|
dbReady,
|
|
647
659
|
syncBackendQueue,
|
|
648
660
|
otelSpan,
|
|
661
|
+
devtoolsLatch,
|
|
649
662
|
}: {
|
|
650
663
|
dbReady: Deferred.Deferred<void>
|
|
651
664
|
syncBackendQueue: BucketQueue.BucketQueue<MutationEvent.EncodedWithMeta>
|
|
652
665
|
otelSpan: otel.Span | undefined
|
|
666
|
+
devtoolsLatch: Effect.Latch | undefined
|
|
653
667
|
}) =>
|
|
654
668
|
Effect.gen(function* () {
|
|
655
669
|
const { syncBackend, dbMutationLog } = yield* LeaderThreadCtx
|
|
@@ -665,6 +679,10 @@ const backgroundBackendPushing = ({
|
|
|
665
679
|
|
|
666
680
|
yield* SubscriptionRef.waitUntil(syncBackend.isConnected, (isConnected) => isConnected === true)
|
|
667
681
|
|
|
682
|
+
if (devtoolsLatch !== undefined) {
|
|
683
|
+
yield* devtoolsLatch.await
|
|
684
|
+
}
|
|
685
|
+
|
|
668
686
|
otelSpan?.addEvent('backend-push', {
|
|
669
687
|
batchSize: queueItems.length,
|
|
670
688
|
batch: TRACE_VERBOSE ? JSON.stringify(queueItems) : undefined,
|
|
@@ -674,6 +692,9 @@ const backgroundBackendPushing = ({
|
|
|
674
692
|
const pushResult = yield* syncBackend.push(queueItems.map((_) => _.toGlobal())).pipe(Effect.either)
|
|
675
693
|
|
|
676
694
|
if (pushResult._tag === 'Left') {
|
|
695
|
+
if (LS_DEV) {
|
|
696
|
+
yield* Effect.logDebug('backend-push-error', { error: pushResult.left.toString() })
|
|
697
|
+
}
|
|
677
698
|
otelSpan?.addEvent('backend-push-error', { error: pushResult.left.toString() })
|
|
678
699
|
// wait for interrupt caused by background pulling which will then restart pushing
|
|
679
700
|
return yield* Effect.never
|
|
@@ -689,7 +710,7 @@ const backgroundBackendPushing = ({
|
|
|
689
710
|
...updateRows({
|
|
690
711
|
tableName: MUTATION_LOG_META_TABLE,
|
|
691
712
|
columns: mutationLogMetaTable.sqliteDef.columns,
|
|
692
|
-
where: { idGlobal: mutationEventEncoded.id.global,
|
|
713
|
+
where: { idGlobal: mutationEventEncoded.id.global, idClient: mutationEventEncoded.id.client },
|
|
693
714
|
updateValues: { syncMetadataJson: metadata[i]! },
|
|
694
715
|
}),
|
|
695
716
|
)
|
|
@@ -79,7 +79,7 @@ export const makeApplyMutation: Effect.Effect<ApplyMutation, never, Scope.Scope
|
|
|
79
79
|
columns: sessionChangesetMetaTable.sqliteDef.columns,
|
|
80
80
|
values: {
|
|
81
81
|
idGlobal: mutationEventEncoded.id.global,
|
|
82
|
-
|
|
82
|
+
idClient: mutationEventEncoded.id.client,
|
|
83
83
|
// NOTE the changeset will be empty (i.e. null) for no-op mutations
|
|
84
84
|
changeset: changeset ?? null,
|
|
85
85
|
debug: execArgsArr,
|
|
@@ -92,7 +92,13 @@ export const makeApplyMutation: Effect.Effect<ApplyMutation, never, Scope.Scope
|
|
|
92
92
|
// write to mutation_log
|
|
93
93
|
const excludeFromMutationLog = shouldExcludeMutationFromLog(mutationName, mutationEventEncoded)
|
|
94
94
|
if (skipMutationLog === false && excludeFromMutationLog === false) {
|
|
95
|
-
yield* insertIntoMutationLog(
|
|
95
|
+
yield* insertIntoMutationLog(
|
|
96
|
+
mutationEventEncoded,
|
|
97
|
+
dbMutationLog,
|
|
98
|
+
mutationDefSchemaHashMap,
|
|
99
|
+
mutationEventEncoded.clientId,
|
|
100
|
+
mutationEventEncoded.sessionId,
|
|
101
|
+
)
|
|
96
102
|
} else {
|
|
97
103
|
// console.debug('[@livestore/common:leader-thread] skipping mutation log write', mutation, statementSql, bindValues)
|
|
98
104
|
}
|
|
@@ -101,7 +107,7 @@ export const makeApplyMutation: Effect.Effect<ApplyMutation, never, Scope.Scope
|
|
|
101
107
|
attributes: {
|
|
102
108
|
mutationName: mutationEventEncoded.mutation,
|
|
103
109
|
mutationId: mutationEventEncoded.id,
|
|
104
|
-
'span.label': `(${mutationEventEncoded.id.global},${mutationEventEncoded.id.
|
|
110
|
+
'span.label': `(${mutationEventEncoded.id.global},${mutationEventEncoded.id.client}) ${mutationEventEncoded.mutation}`,
|
|
105
111
|
},
|
|
106
112
|
}),
|
|
107
113
|
// Effect.logDuration('@livestore/common:leader-thread:applyMutation'),
|
|
@@ -113,6 +119,8 @@ const insertIntoMutationLog = (
|
|
|
113
119
|
mutationEventEncoded: MutationEvent.AnyEncoded,
|
|
114
120
|
dbMutationLog: SqliteDb,
|
|
115
121
|
mutationDefSchemaHashMap: Map<string, number>,
|
|
122
|
+
clientId: string,
|
|
123
|
+
sessionId: string | undefined,
|
|
116
124
|
) =>
|
|
117
125
|
Effect.gen(function* () {
|
|
118
126
|
const mutationName = mutationEventEncoded.mutation
|
|
@@ -127,11 +135,13 @@ const insertIntoMutationLog = (
|
|
|
127
135
|
columns: mutationLogMetaTable.sqliteDef.columns,
|
|
128
136
|
values: {
|
|
129
137
|
idGlobal: mutationEventEncoded.id.global,
|
|
130
|
-
|
|
138
|
+
idClient: mutationEventEncoded.id.client,
|
|
131
139
|
parentIdGlobal: mutationEventEncoded.parentId.global,
|
|
132
|
-
|
|
140
|
+
parentIdClient: mutationEventEncoded.parentId.client,
|
|
133
141
|
mutation: mutationEventEncoded.mutation,
|
|
134
142
|
argsJson: mutationEventEncoded.args ?? {},
|
|
143
|
+
clientId,
|
|
144
|
+
sessionId: sessionId ?? null,
|
|
135
145
|
schemaHash: mutationDefSchemaHash,
|
|
136
146
|
syncMetadataJson: Option.none(),
|
|
137
147
|
},
|
|
@@ -38,18 +38,7 @@ export const bootDevtools = (options: DevtoolsOptions) =>
|
|
|
38
38
|
const pullQueue = yield* connectedClientSessionPullQueues.makeQueue(localHead)
|
|
39
39
|
|
|
40
40
|
yield* Stream.fromQueue(pullQueue).pipe(
|
|
41
|
-
Stream.tap((msg) =>
|
|
42
|
-
Effect.gen(function* () {
|
|
43
|
-
if (msg.payload._tag === 'upstream-advance') {
|
|
44
|
-
for (const mutationEventEncoded of msg.payload.newEvents) {
|
|
45
|
-
// TODO refactor with push semantics
|
|
46
|
-
yield* sendMessage(Devtools.Leader.MutationBroadcast.make({ mutationEventEncoded, liveStoreVersion }))
|
|
47
|
-
}
|
|
48
|
-
} else {
|
|
49
|
-
yield* Effect.logWarning('TODO implement rebases in devtools')
|
|
50
|
-
}
|
|
51
|
-
}),
|
|
52
|
-
),
|
|
41
|
+
Stream.tap((msg) => sendMessage(Devtools.Leader.SyncPull.make({ payload: msg.payload, liveStoreVersion }))),
|
|
53
42
|
Stream.runDrain,
|
|
54
43
|
Effect.forkScoped,
|
|
55
44
|
)
|
|
@@ -80,6 +69,7 @@ const listenToDevtools = ({
|
|
|
80
69
|
shutdownChannel,
|
|
81
70
|
syncProcessor,
|
|
82
71
|
clientId,
|
|
72
|
+
devtools,
|
|
83
73
|
} = yield* LeaderThreadCtx
|
|
84
74
|
|
|
85
75
|
type RequestId = string
|
|
@@ -158,7 +148,7 @@ const listenToDevtools = ({
|
|
|
158
148
|
|
|
159
149
|
return
|
|
160
150
|
}
|
|
161
|
-
case 'LSD.Leader.
|
|
151
|
+
case 'LSD.Leader.ResetAllData.Request': {
|
|
162
152
|
const { mode } = decodedEvent
|
|
163
153
|
|
|
164
154
|
yield* SubscriptionRef.set(shutdownStateSubRef, 'shutting-down')
|
|
@@ -169,7 +159,7 @@ const listenToDevtools = ({
|
|
|
169
159
|
dbMutationLog.destroy()
|
|
170
160
|
}
|
|
171
161
|
|
|
172
|
-
yield* sendMessage(Devtools.Leader.
|
|
162
|
+
yield* sendMessage(Devtools.Leader.ResetAllData.Response.make({ ...reqPayload }))
|
|
173
163
|
|
|
174
164
|
yield* shutdownChannel.send(IntentionalShutdownCause.make({ reason: 'devtools-reset' })) ?? Effect.void
|
|
175
165
|
|
|
@@ -203,7 +193,11 @@ const listenToDevtools = ({
|
|
|
203
193
|
return
|
|
204
194
|
}
|
|
205
195
|
case 'LSD.Leader.RunMutationReq': {
|
|
206
|
-
yield* syncProcessor.pushPartial(
|
|
196
|
+
yield* syncProcessor.pushPartial({
|
|
197
|
+
mutationEvent: decodedEvent.mutationEventEncoded,
|
|
198
|
+
clientId: `devtools-${clientId}`,
|
|
199
|
+
sessionId: undefined,
|
|
200
|
+
})
|
|
207
201
|
|
|
208
202
|
yield* sendMessage(Devtools.Leader.RunMutationRes.make({ ...reqPayload }))
|
|
209
203
|
|
|
@@ -257,11 +251,14 @@ const listenToDevtools = ({
|
|
|
257
251
|
// This is probably the same "flaky databrowser loading" bug as we're seeing in the playwright tests
|
|
258
252
|
yield* Effect.sleep(1000)
|
|
259
253
|
|
|
260
|
-
yield*
|
|
261
|
-
|
|
254
|
+
yield* Stream.zipLatest(
|
|
255
|
+
syncBackend.isConnected.changes,
|
|
256
|
+
devtools.enabled ? devtools.syncBackendLatchState.changes : Stream.make({ latchClosed: false }),
|
|
257
|
+
).pipe(
|
|
258
|
+
Stream.tap(([isConnected, { latchClosed }]) =>
|
|
262
259
|
sendMessage(
|
|
263
260
|
Devtools.Leader.NetworkStatusRes.make({
|
|
264
|
-
networkStatus: { isConnected, timestampMs: Date.now() },
|
|
261
|
+
networkStatus: { isConnected, timestampMs: Date.now(), latchClosed },
|
|
265
262
|
...reqPayload,
|
|
266
263
|
}),
|
|
267
264
|
),
|
|
@@ -310,8 +307,25 @@ const listenToDevtools = ({
|
|
|
310
307
|
|
|
311
308
|
return
|
|
312
309
|
}
|
|
310
|
+
case 'LSD.Leader.SetSyncLatch.Request': {
|
|
311
|
+
const { closeLatch } = decodedEvent
|
|
312
|
+
|
|
313
|
+
if (devtools.enabled === false) return
|
|
314
|
+
|
|
315
|
+
if (closeLatch === true) {
|
|
316
|
+
yield* devtools.syncBackendLatch.close
|
|
317
|
+
} else {
|
|
318
|
+
yield* devtools.syncBackendLatch.open
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
yield* SubscriptionRef.set(devtools.syncBackendLatchState, { latchClosed: closeLatch })
|
|
322
|
+
|
|
323
|
+
yield* sendMessage(Devtools.Leader.SetSyncLatch.Response.make({ ...reqPayload }))
|
|
324
|
+
|
|
325
|
+
return
|
|
326
|
+
}
|
|
313
327
|
default: {
|
|
314
|
-
yield* Effect.logWarning(`TODO implement
|
|
328
|
+
yield* Effect.logWarning(`TODO implement devtools message`, decodedEvent)
|
|
315
329
|
}
|
|
316
330
|
}
|
|
317
331
|
}).pipe(Effect.withSpan(`@livestore/common:leader-thread:onDevtoolsMessage:${decodedEvent._tag}`)),
|
|
@@ -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'
|
|
@@ -74,8 +74,8 @@ export const makeLeaderThreadLayer = ({
|
|
|
74
74
|
const devtoolsContext = devtoolsOptions.enabled
|
|
75
75
|
? {
|
|
76
76
|
enabled: true as const,
|
|
77
|
-
|
|
78
|
-
|
|
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({
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
27
|
-
parentId: { global: _.parentIdGlobal,
|
|
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
|
|
33
|
-
const res = dbMutationLog.select<{ idGlobal: EventId.GlobalEventId;
|
|
34
|
-
sql`select idGlobal,
|
|
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,
|
|
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
|
-
|
|
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) {
|
|
@@ -33,7 +34,7 @@ export const recreateDb: Effect.Effect<
|
|
|
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
|
|
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
|
|
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?.(
|
|
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'),
|