@@ -4,7 +4,7 @@ import { Option, type Runtime, type Scope } from '@livestore/utils/effect'
4
4
import { BucketQueue , Effect , FiberHandle , Queue , Schema , Stream , Subscribable } from '@livestore/utils/effect'
5
5
import type * as otel from '@opentelemetry/api'
6
6
7
- import type { ClientSession , UnexpectedError } from '../adapter-types.js'
7
+ import { type ClientSession , SyncError , type UnexpectedError } from '../adapter-types.js'
8
8
import * as EventSequenceNumber from '../schema/EventSequenceNumber.js'
9
9
import * as LiveStoreEvent from '../schema/LiveStoreEvent.js'
10
10
import { getEventDef , type LiveStoreSchema , SystemTables } from '../schema/mod.js'
@@ -21,6 +21,10 @@ import * as SyncState from './syncstate.js'
21
21
* - We might need to make the rebase behaviour configurable e.g. to let users manually trigger a rebase
22
22
*
23
23
* Longer term we should evalutate whether we can unify the ClientSessionSyncProcessor with the LeaderSyncProcessor.
24
+ *
25
+ * The session and leader sync processor are different in the following ways:
26
+ * - The leader sync processor pulls regular LiveStore events, while the session sync processor pulls SyncState.PayloadUpstream items
27
+ * - The session sync processor has no downstream nodes.
24
28
*/
25
29
export const makeClientSessionSyncProcessor = ( {
26
30
schema,
@@ -37,7 +41,7 @@ export const makeClientSessionSyncProcessor = ({
37
41
clientSession : ClientSession
38
42
runtime : Runtime . Runtime < Scope . Scope >
39
43
materializeEvent : (
40
- eventDecoded : LiveStoreEvent . PartialAnyDecoded ,
44
+ eventDecoded : LiveStoreEvent . AnyDecoded ,
41
45
options : { withChangeset : boolean ; materializerHashLeader : Option . Option < number > } ,
42
46
) => Effect . Effect < {
43
47
writeTables : Set < string >
@@ -82,7 +86,10 @@ export const makeClientSessionSyncProcessor = ({
82
86
let baseEventSequenceNumber = syncStateRef . current . localHead
83
87
const encodedEventDefs = batch . map ( ( { name, args } ) => {
84
88
const eventDef = getEventDef ( schema , name )
85
- const nextNumPair = EventSequenceNumber . nextPair ( baseEventSequenceNumber , eventDef . eventDef . options . clientOnly )
89
+ const nextNumPair = EventSequenceNumber . nextPair ( {
90
+ seqNum : baseEventSequenceNumber ,
91
+ isClient : eventDef . eventDef . options . clientOnly ,
92
+ } )
86
93
baseEventSequenceNumber = nextNumPair . seqNum
87
94
return new LiveStoreEvent . EncodedWithMeta (
88
95
Schema . encodeUnknownSync ( eventSchema ) ( {
@@ -106,7 +113,7 @@ export const makeClientSessionSyncProcessor = ({
106
113
)
107
114
108
115
if ( mergeResult . _tag === 'unexpected-error' ) {
109
- return yield * Effect . die ( new Error ( `Unexpected error in client-session-sync-processor: ${ mergeResult . cause } ` ) )
116
+ return yield * Effect . die ( new Error ( `Unexpected error in client-session-sync-processor: ${ mergeResult . message } ` ) )
110
117
}
111
118
112
119
if ( TRACE_VERBOSE ) yield * Effect . annotateCurrentSpan ( { mergeResult : JSON . stringify ( mergeResult ) } )
@@ -183,18 +190,11 @@ export const makeClientSessionSyncProcessor = ({
183
190
184
191
yield * FiberHandle . run ( leaderPushingFiberHandle , backgroundLeaderPushing )
185
192
186
- const getMergeCounter = ( ) =>
187
- clientSession . sqliteDb . select < { mergeCounter : number } > (
188
- sql `SELECT mergeCounter FROM ${ SystemTables . LEADER_MERGE_COUNTER_TABLE } WHERE id = 0` ,
189
- ) [ 0 ] ?. mergeCounter ?? 0
190
-
191
193
// NOTE We need to lazily call `.pull` as we want the cursor to be updated
192
194
yield * Stream . suspend ( ( ) =>
193
- clientSession . leaderThread . events . pull ( {
194
- cursor : { mergeCounter : getMergeCounter ( ) , eventNum : syncStateRef . current . localHead } ,
195
- } ) ,
195
+ clientSession . leaderThread . events . pull ( { cursor : syncStateRef . current . upstreamHead } ) ,
196
196
) . pipe (
197
- Stream . tap ( ( { payload, mergeCounter : leaderMergeCounter } ) =>
197
+ Stream . tap ( ( { payload } ) =>
198
198
Effect . gen ( function * ( ) {
199
199
// yield* Effect.logDebug('ClientSessionSyncProcessor:pull', payload)
200
200
@@ -210,13 +210,13 @@ export const makeClientSessionSyncProcessor = ({
210
210
} )
211
211
212
212
if ( mergeResult . _tag === 'unexpected-error' ) {
213
- return yield * Effect . fail ( mergeResult . cause )
213
+ return yield * new SyncError ( { cause : mergeResult . message } )
214
214
} else if ( mergeResult . _tag === 'reject' ) {
215
215
return shouldNeverHappen ( 'Unexpected reject in client-session-sync-processor' , mergeResult )
216
216
}
217
217
218
218
syncStateRef . current = mergeResult . newSyncState
219
- syncStateUpdateQueue . offer ( mergeResult . newSyncState ) . pipe ( Effect . runSync )
219
+ yield * syncStateUpdateQueue . offer ( mergeResult . newSyncState )
220
220
221
221
if ( mergeResult . _tag === 'rebase' ) {
222
222
span . addEvent ( 'merge:pull:rebase' , {
@@ -225,7 +225,7 @@ export const makeClientSessionSyncProcessor = ({
225
225
newEventsCount : mergeResult . newEvents . length ,
226
226
rollbackCount : mergeResult . rollbackEvents . length ,
227
227
res : TRACE_VERBOSE ? JSON . stringify ( mergeResult ) : undefined ,
228
- leaderMergeCounter ,
228
+ rebaseGeneration : mergeResult . newSyncState . localHead . rebaseGeneration ,
229
229
} )
230
230
231
231
debugInfo . rebaseCount ++
@@ -242,7 +242,6 @@ export const makeClientSessionSyncProcessor = ({
242
242
'merge:pull:rebase: rollback' ,
243
243
mergeResult . rollbackEvents . length ,
244
244
...mergeResult . rollbackEvents . slice ( 0 , 10 ) . map ( ( _ ) => _ . toJSON ( ) ) ,
245
- { leaderMergeCounter } ,
246
245
) . pipe ( Effect . provide ( runtime ) , Effect . runSync )
247
246
}
248
247
@@ -262,7 +261,6 @@ export const makeClientSessionSyncProcessor = ({
262
261
payload : TRACE_VERBOSE ? JSON . stringify ( payload ) : undefined ,
263
262
newEventsCount : mergeResult . newEvents . length ,
264
263
res : TRACE_VERBOSE ? JSON . stringify ( mergeResult ) : undefined ,
265
- leaderMergeCounter,
266
264
} )
267
265
268
266
debugInfo . advanceCount ++
0 commit comments