@livestore/common 0.3.0-dev.0 → 0.3.0-dev.10
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/adapter-types.d.ts +26 -23
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js.map +1 -1
- package/dist/derived-mutations.d.ts +4 -4
- package/dist/derived-mutations.d.ts.map +1 -1
- package/dist/derived-mutations.test.js.map +1 -1
- package/dist/devtools/devtools-bridge.d.ts +2 -1
- package/dist/devtools/devtools-bridge.d.ts.map +1 -1
- package/dist/devtools/devtools-messages.d.ts +98 -110
- package/dist/devtools/devtools-messages.d.ts.map +1 -1
- package/dist/devtools/devtools-messages.js +9 -6
- package/dist/devtools/devtools-messages.js.map +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +37 -0
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -0
- package/dist/leader-thread/LeaderSyncProcessor.js +417 -0
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -0
- package/dist/leader-thread/apply-mutation.d.ts +5 -2
- package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
- package/dist/leader-thread/apply-mutation.js +38 -26
- package/dist/leader-thread/apply-mutation.js.map +1 -1
- package/dist/leader-thread/leader-sync-processor.d.ts +2 -2
- package/dist/leader-thread/leader-sync-processor.d.ts.map +1 -1
- package/dist/leader-thread/leader-sync-processor.js +20 -12
- package/dist/leader-thread/leader-sync-processor.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +22 -66
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +8 -7
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +11 -5
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/mutationlog.d.ts +4 -17
- package/dist/leader-thread/mutationlog.d.ts.map +1 -1
- package/dist/leader-thread/mutationlog.js +2 -1
- 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.map +1 -1
- package/dist/leader-thread/recreate-db.js +9 -3
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/types.d.ts +17 -9
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/mutation.d.ts +9 -2
- package/dist/mutation.d.ts.map +1 -1
- package/dist/mutation.js +5 -5
- package/dist/mutation.js.map +1 -1
- package/dist/query-builder/impl.d.ts +1 -1
- package/dist/rehydrate-from-mutationlog.d.ts +2 -2
- package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
- package/dist/rehydrate-from-mutationlog.js +13 -19
- package/dist/rehydrate-from-mutationlog.js.map +1 -1
- package/dist/schema/EventId.d.ts +16 -14
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +15 -7
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/EventId.test.d.ts +2 -0
- package/dist/schema/EventId.test.d.ts.map +1 -0
- package/dist/schema/EventId.test.js +11 -0
- package/dist/schema/EventId.test.js.map +1 -0
- package/dist/schema/MutationEvent.d.ts +49 -80
- package/dist/schema/MutationEvent.d.ts.map +1 -1
- package/dist/schema/MutationEvent.js +32 -15
- package/dist/schema/MutationEvent.js.map +1 -1
- package/dist/schema/MutationEvent.test.d.ts +2 -0
- package/dist/schema/MutationEvent.test.d.ts.map +1 -0
- package/dist/schema/MutationEvent.test.js +2 -0
- package/dist/schema/MutationEvent.test.js.map +1 -0
- package/dist/schema/system-tables.d.ts +26 -26
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +19 -11
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/schema-management/migrations.js +6 -6
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +45 -0
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -0
- package/dist/sync/ClientSessionSyncProcessor.js +134 -0
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -0
- package/dist/sync/client-session-sync-processor.d.ts +4 -4
- package/dist/sync/client-session-sync-processor.d.ts.map +1 -1
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +1 -1
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +1 -4
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +1 -1
- package/dist/sync/next/history-dag-common.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +3 -3
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +3 -2
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.js +3 -9
- package/dist/sync/next/test/mutation-fixtures.js.map +1 -1
- package/dist/sync/sync.d.ts +21 -11
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/syncstate.d.ts +45 -23
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +56 -12
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +125 -69
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/sync/validate-push-payload.d.ts +2 -2
- package/dist/sync/validate-push-payload.d.ts.map +1 -1
- package/dist/sync/validate-push-payload.js +2 -2
- package/dist/sync/validate-push-payload.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +6 -5
- package/src/adapter-types.ts +22 -24
- package/src/derived-mutations.test.ts +1 -1
- package/src/derived-mutations.ts +9 -5
- package/src/devtools/devtools-bridge.ts +2 -1
- package/src/devtools/devtools-messages.ts +9 -6
- package/src/index.ts +0 -6
- package/src/leader-thread/{leader-sync-processor.ts → LeaderSyncProcessor.ts} +235 -230
- package/src/leader-thread/apply-mutation.ts +49 -31
- package/src/leader-thread/leader-worker-devtools.ts +30 -109
- package/src/leader-thread/make-leader-thread-layer.ts +24 -13
- package/src/leader-thread/mutationlog.ts +9 -5
- package/src/leader-thread/recreate-db.ts +9 -5
- package/src/leader-thread/types.ts +18 -11
- package/src/mutation.ts +17 -7
- package/src/rehydrate-from-mutationlog.ts +15 -23
- package/src/schema/EventId.test.ts +12 -0
- package/src/schema/EventId.ts +23 -9
- package/src/schema/MutationEvent.ts +46 -24
- package/src/schema/system-tables.ts +19 -11
- package/src/schema-management/migrations.ts +6 -6
- package/src/sync/{client-session-sync-processor.ts → ClientSessionSyncProcessor.ts} +11 -9
- package/src/sync/index.ts +1 -1
- package/src/sync/next/history-dag-common.ts +1 -1
- package/src/sync/next/rebase-events.ts +7 -7
- package/src/sync/next/test/mutation-fixtures.ts +3 -10
- package/src/sync/sync.ts +19 -6
- package/src/sync/syncstate.test.ts +127 -67
- package/src/sync/syncstate.ts +21 -19
- package/src/sync/validate-push-payload.ts +7 -4
- package/src/version.ts +1 -1
@@ -7,14 +7,14 @@ import * as SyncState from './syncstate.js'
|
|
7
7
|
|
8
8
|
class TestEvent extends MutationEvent.EncodedWithMeta {
|
9
9
|
constructor(
|
10
|
-
|
11
|
-
|
10
|
+
id: EventId.EventId | typeof EventId.EventId.Encoded,
|
11
|
+
parentId: EventId.EventId,
|
12
12
|
public readonly payload: string,
|
13
13
|
public readonly isLocal: boolean,
|
14
14
|
) {
|
15
15
|
super({
|
16
|
-
id,
|
17
|
-
parentId,
|
16
|
+
id: EventId.make(id),
|
17
|
+
parentId: EventId.make(parentId),
|
18
18
|
mutation: 'a',
|
19
19
|
args: payload,
|
20
20
|
meta: {},
|
@@ -58,12 +58,12 @@ describe('syncstate', () => {
|
|
58
58
|
'upstream-rebase (trimRollbackUntil: $trimRollbackUntil)',
|
59
59
|
({ trimRollbackUntil }) => {
|
60
60
|
it('should rollback until start', () => {
|
61
|
-
const syncState = {
|
61
|
+
const syncState = new SyncState.SyncState({
|
62
62
|
pending: [e_1_0],
|
63
63
|
rollbackTail: [e_0_0, e_0_1],
|
64
64
|
upstreamHead: EventId.ROOT,
|
65
65
|
localHead: e_1_0.id,
|
66
|
-
}
|
66
|
+
})
|
67
67
|
const e_0_0_e_1_0 = e_0_0.rebase_(e_1_0.id)
|
68
68
|
const e_0_1_e_1_1 = e_0_1.rebase_(e_0_0_e_1_0.id)
|
69
69
|
const result = run({
|
@@ -83,19 +83,19 @@ describe('syncstate', () => {
|
|
83
83
|
} else {
|
84
84
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0_e_1_0, e_0_1_e_1_1])
|
85
85
|
}
|
86
|
-
expect(result.newSyncState.upstreamHead).
|
86
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_1_e_1_1.id)
|
87
87
|
expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_2_0.id)
|
88
88
|
expectEventArraysEqual(result.newEvents, [e_0_0_e_1_0, e_0_1_e_1_1])
|
89
89
|
expectEventArraysEqual(result.eventsToRollback, [e_0_0, e_0_1, e_1_0])
|
90
90
|
})
|
91
91
|
|
92
92
|
it('should rollback only to specified point', () => {
|
93
|
-
const syncState = {
|
93
|
+
const syncState = new SyncState.SyncState({
|
94
94
|
pending: [e_1_0],
|
95
95
|
rollbackTail: [e_0_0, e_0_1],
|
96
96
|
upstreamHead: EventId.ROOT,
|
97
97
|
localHead: e_1_0.id,
|
98
|
-
}
|
98
|
+
})
|
99
99
|
const e_0_1_e_1_0 = e_0_1.rebase_(e_0_0.id)
|
100
100
|
const result = run({
|
101
101
|
syncState,
|
@@ -114,14 +114,19 @@ describe('syncstate', () => {
|
|
114
114
|
} else {
|
115
115
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0, e_0_1_e_1_0])
|
116
116
|
}
|
117
|
-
expect(result.newSyncState.upstreamHead).
|
117
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_1_e_1_0.id)
|
118
118
|
expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_2_0.id)
|
119
119
|
expectEventArraysEqual(result.newEvents, [e_0_1_e_1_0])
|
120
120
|
expectEventArraysEqual(result.eventsToRollback, [e_0_1, e_1_0])
|
121
121
|
})
|
122
122
|
|
123
123
|
it('should work for empty pending', () => {
|
124
|
-
const syncState =
|
124
|
+
const syncState = new SyncState.SyncState({
|
125
|
+
pending: [],
|
126
|
+
rollbackTail: [e_0_0],
|
127
|
+
upstreamHead: EventId.ROOT,
|
128
|
+
localHead: e_0_0.id,
|
129
|
+
})
|
125
130
|
const result = run({
|
126
131
|
syncState,
|
127
132
|
payload: { _tag: 'upstream-rebase', rollbackUntil: e_0_0.id, newEvents: [e_1_0] },
|
@@ -129,13 +134,18 @@ describe('syncstate', () => {
|
|
129
134
|
expectRebase(result)
|
130
135
|
expectEventArraysEqual(result.newSyncState.pending, [])
|
131
136
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_1_0])
|
132
|
-
expect(result.newSyncState.upstreamHead).
|
137
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
|
133
138
|
expect(result.newSyncState.localHead).toMatchObject(e_1_0.id)
|
134
|
-
expect(result.newEvents).
|
139
|
+
expect(result.newEvents).toStrictEqual([e_1_0])
|
135
140
|
})
|
136
141
|
|
137
142
|
it('should fail for empty rollback tail', () => {
|
138
|
-
const syncState =
|
143
|
+
const syncState = new SyncState.SyncState({
|
144
|
+
pending: [],
|
145
|
+
rollbackTail: [],
|
146
|
+
upstreamHead: EventId.ROOT,
|
147
|
+
localHead: e_0_0.id,
|
148
|
+
})
|
139
149
|
expect(() =>
|
140
150
|
run({
|
141
151
|
syncState,
|
@@ -145,7 +155,12 @@ describe('syncstate', () => {
|
|
145
155
|
})
|
146
156
|
|
147
157
|
it('should work for empty incoming', () => {
|
148
|
-
const syncState =
|
158
|
+
const syncState = new SyncState.SyncState({
|
159
|
+
pending: [],
|
160
|
+
rollbackTail: [e_0_0],
|
161
|
+
upstreamHead: EventId.ROOT,
|
162
|
+
localHead: e_0_0.id,
|
163
|
+
})
|
149
164
|
const result = run({
|
150
165
|
syncState,
|
151
166
|
payload: { _tag: 'upstream-rebase', rollbackUntil: e_0_0.id, newEvents: [] },
|
@@ -153,67 +168,92 @@ describe('syncstate', () => {
|
|
153
168
|
expectRebase(result)
|
154
169
|
expectEventArraysEqual(result.newSyncState.pending, [])
|
155
170
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [])
|
156
|
-
expect(result.newSyncState.upstreamHead).
|
171
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(EventId.ROOT)
|
157
172
|
expect(result.newSyncState.localHead).toMatchObject(EventId.ROOT)
|
158
|
-
expect(result.newEvents).
|
173
|
+
expect(result.newEvents).toStrictEqual([])
|
159
174
|
})
|
160
175
|
},
|
161
176
|
)
|
162
177
|
|
163
178
|
describe('upstream-advance: advance', () => {
|
164
179
|
it('should throw error if newEvents are not sorted in ascending order by eventId (local)', () => {
|
165
|
-
const syncState =
|
180
|
+
const syncState = new SyncState.SyncState({
|
181
|
+
pending: [e_0_0],
|
182
|
+
rollbackTail: [],
|
183
|
+
upstreamHead: EventId.ROOT,
|
184
|
+
localHead: e_0_0.id,
|
185
|
+
})
|
166
186
|
expect(() => run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_0] } })).toThrow()
|
167
187
|
})
|
168
188
|
|
169
189
|
it('should throw error if newEvents are not sorted in ascending order by eventId (global)', () => {
|
170
|
-
const syncState =
|
190
|
+
const syncState = new SyncState.SyncState({
|
191
|
+
pending: [e_0_0],
|
192
|
+
rollbackTail: [],
|
193
|
+
upstreamHead: EventId.ROOT,
|
194
|
+
localHead: e_0_0.id,
|
195
|
+
})
|
171
196
|
expect(() => run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0, e_0_0] } })).toThrow()
|
172
197
|
})
|
173
198
|
|
174
199
|
it('should acknowledge pending event when receiving matching event', () => {
|
175
|
-
const syncState =
|
200
|
+
const syncState = new SyncState.SyncState({
|
201
|
+
pending: [e_0_0],
|
202
|
+
rollbackTail: [],
|
203
|
+
upstreamHead: EventId.ROOT,
|
204
|
+
localHead: e_0_0.id,
|
205
|
+
})
|
176
206
|
const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
|
177
207
|
|
178
208
|
expectAdvance(result)
|
179
209
|
expectEventArraysEqual(result.newSyncState.pending, [])
|
180
210
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0])
|
181
|
-
expect(result.newSyncState.upstreamHead).
|
211
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_0.id)
|
182
212
|
expect(result.newSyncState.localHead).toMatchObject(e_0_0.id)
|
183
|
-
expect(result.newEvents).
|
213
|
+
expect(result.newEvents).toStrictEqual([])
|
184
214
|
})
|
185
215
|
|
186
216
|
it('should acknowledge partial pending event when receiving matching event', () => {
|
187
|
-
const syncState = {
|
217
|
+
const syncState = new SyncState.SyncState({
|
188
218
|
pending: [e_0_0, e_1_0],
|
189
219
|
rollbackTail: [],
|
190
220
|
upstreamHead: EventId.ROOT,
|
191
221
|
localHead: e_1_0.id,
|
192
|
-
}
|
222
|
+
})
|
193
223
|
const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
|
194
224
|
|
195
225
|
expectAdvance(result)
|
196
226
|
expectEventArraysEqual(result.newSyncState.pending, [e_1_0])
|
197
227
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0])
|
198
|
-
expect(result.newSyncState.upstreamHead).
|
228
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_0.id)
|
199
229
|
expect(result.newSyncState.localHead).toMatchObject(e_1_0.id)
|
200
|
-
expect(result.newEvents).
|
230
|
+
expect(result.newEvents).toStrictEqual([])
|
201
231
|
})
|
202
232
|
|
203
233
|
it('should acknowledge pending event and add new event', () => {
|
204
|
-
const syncState =
|
234
|
+
const syncState = new SyncState.SyncState({
|
235
|
+
pending: [e_0_0],
|
236
|
+
rollbackTail: [],
|
237
|
+
upstreamHead: EventId.ROOT,
|
238
|
+
localHead: e_0_0.id,
|
239
|
+
})
|
205
240
|
const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0, e_0_1] } })
|
206
241
|
|
207
242
|
expectAdvance(result)
|
208
243
|
expectEventArraysEqual(result.newSyncState.pending, [])
|
209
244
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0, e_0_1])
|
210
|
-
expect(result.newSyncState.upstreamHead).
|
245
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_1.id)
|
211
246
|
expect(result.newSyncState.localHead).toMatchObject(e_0_1.id)
|
212
|
-
expect(result.newEvents).
|
247
|
+
expect(result.newEvents).toStrictEqual([e_0_1])
|
213
248
|
})
|
214
249
|
|
215
250
|
it('should acknowledge pending event and add multiple new events', () => {
|
216
|
-
const syncState =
|
251
|
+
const syncState = new SyncState.SyncState({
|
252
|
+
pending: [e_0_1],
|
253
|
+
rollbackTail: [],
|
254
|
+
upstreamHead: e_0_0.id,
|
255
|
+
localHead: e_0_1.id,
|
256
|
+
})
|
217
257
|
const result = run({
|
218
258
|
syncState,
|
219
259
|
payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_2, e_0_3, e_1_0, e_1_1] },
|
@@ -222,18 +262,18 @@ describe('syncstate', () => {
|
|
222
262
|
expectAdvance(result)
|
223
263
|
expectEventArraysEqual(result.newSyncState.pending, [])
|
224
264
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_1, e_0_2, e_0_3, e_1_0, e_1_1])
|
225
|
-
expect(result.newSyncState.upstreamHead).
|
265
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_1.id)
|
226
266
|
expect(result.newSyncState.localHead).toMatchObject(e_1_1.id)
|
227
|
-
expect(result.newEvents).
|
267
|
+
expect(result.newEvents).toStrictEqual([e_0_2, e_0_3, e_1_0, e_1_1])
|
228
268
|
})
|
229
269
|
|
230
270
|
it('should ignore local events (incoming is subset of pending)', () => {
|
231
|
-
const syncState = {
|
271
|
+
const syncState = new SyncState.SyncState({
|
232
272
|
pending: [e_r_1, e_0_0],
|
233
273
|
rollbackTail: [],
|
234
274
|
upstreamHead: EventId.ROOT,
|
235
275
|
localHead: e_0_0.id,
|
236
|
-
}
|
276
|
+
})
|
237
277
|
const result = run({
|
238
278
|
syncState,
|
239
279
|
payload: { _tag: 'upstream-advance', newEvents: [e_0_0] },
|
@@ -242,18 +282,18 @@ describe('syncstate', () => {
|
|
242
282
|
expectAdvance(result)
|
243
283
|
expectEventArraysEqual(result.newSyncState.pending, [])
|
244
284
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_r_1, e_0_0])
|
245
|
-
expect(result.newSyncState.upstreamHead).
|
285
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_0.id)
|
246
286
|
expect(result.newSyncState.localHead).toMatchObject(e_0_0.id)
|
247
|
-
expect(result.newEvents).
|
287
|
+
expect(result.newEvents).toStrictEqual([])
|
248
288
|
})
|
249
289
|
|
250
290
|
it('should ignore local events (incoming is subset of pending case 2)', () => {
|
251
|
-
const syncState = {
|
291
|
+
const syncState = new SyncState.SyncState({
|
252
292
|
pending: [e_r_1, e_0_0, e_1_0],
|
253
293
|
rollbackTail: [],
|
254
294
|
upstreamHead: EventId.ROOT,
|
255
295
|
localHead: e_0_0.id,
|
256
|
-
}
|
296
|
+
})
|
257
297
|
const result = run({
|
258
298
|
syncState,
|
259
299
|
payload: { _tag: 'upstream-advance', newEvents: [e_0_0] },
|
@@ -262,18 +302,18 @@ describe('syncstate', () => {
|
|
262
302
|
expectAdvance(result)
|
263
303
|
expectEventArraysEqual(result.newSyncState.pending, [e_1_0])
|
264
304
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_r_1, e_0_0])
|
265
|
-
expect(result.newSyncState.upstreamHead).
|
305
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_0.id)
|
266
306
|
expect(result.newSyncState.localHead).toMatchObject(e_1_0.id)
|
267
|
-
expect(result.newEvents).
|
307
|
+
expect(result.newEvents).toStrictEqual([])
|
268
308
|
})
|
269
309
|
|
270
310
|
it('should ignore local events (incoming goes beyond pending)', () => {
|
271
|
-
const syncState = {
|
311
|
+
const syncState = new SyncState.SyncState({
|
272
312
|
pending: [e_r_1, e_0_0, e_0_1],
|
273
313
|
rollbackTail: [],
|
274
314
|
upstreamHead: EventId.ROOT,
|
275
315
|
localHead: e_0_1.id,
|
276
|
-
}
|
316
|
+
})
|
277
317
|
const result = run({
|
278
318
|
syncState,
|
279
319
|
payload: { _tag: 'upstream-advance', newEvents: [e_0_0, e_1_0] },
|
@@ -283,15 +323,20 @@ describe('syncstate', () => {
|
|
283
323
|
expectAdvance(result)
|
284
324
|
expectEventArraysEqual(result.newSyncState.pending, [])
|
285
325
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_r_1, e_0_0, e_0_1, e_1_0])
|
286
|
-
expect(result.newSyncState.upstreamHead).
|
326
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
|
287
327
|
expect(result.newSyncState.localHead).toMatchObject(e_1_0.id)
|
288
|
-
expect(result.newEvents).
|
328
|
+
expect(result.newEvents).toStrictEqual([e_1_0])
|
289
329
|
})
|
290
330
|
})
|
291
331
|
|
292
332
|
describe('upstream-advance: rebase', () => {
|
293
333
|
it('should rebase single local event to end', () => {
|
294
|
-
const syncState =
|
334
|
+
const syncState = new SyncState.SyncState({
|
335
|
+
pending: [e_0_0],
|
336
|
+
rollbackTail: [],
|
337
|
+
upstreamHead: EventId.ROOT,
|
338
|
+
localHead: e_0_0.id,
|
339
|
+
})
|
295
340
|
const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_1] } })
|
296
341
|
|
297
342
|
const e_0_0_e_0_2 = e_0_0.rebase_(e_0_1.id)
|
@@ -299,7 +344,7 @@ describe('syncstate', () => {
|
|
299
344
|
expectRebase(result)
|
300
345
|
expectEventArraysEqual(result.newSyncState.pending, [e_0_0_e_0_2])
|
301
346
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_1])
|
302
|
-
expect(result.newSyncState.upstreamHead).
|
347
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_1.id)
|
303
348
|
expect(result.newSyncState.localHead).toMatchObject(e_0_0_e_0_2.id)
|
304
349
|
expectEventArraysEqual(result.eventsToRollback, [e_0_0])
|
305
350
|
expectEventArraysEqual(result.newEvents, [e_0_1, e_0_0_e_0_2])
|
@@ -307,7 +352,12 @@ describe('syncstate', () => {
|
|
307
352
|
|
308
353
|
it('should rebase different event with same id (no rollback tail)', () => {
|
309
354
|
const e_0_0_b = new TestEvent({ global: 0, local: 0 }, EventId.ROOT, '0_0_b', true)
|
310
|
-
const syncState =
|
355
|
+
const syncState = new SyncState.SyncState({
|
356
|
+
pending: [e_0_0_b],
|
357
|
+
rollbackTail: [],
|
358
|
+
upstreamHead: EventId.ROOT,
|
359
|
+
localHead: e_0_0_b.id,
|
360
|
+
})
|
311
361
|
const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
|
312
362
|
|
313
363
|
const e_0_0_e_1_0 = e_0_0_b.rebase_(e_0_0.id)
|
@@ -317,18 +367,18 @@ describe('syncstate', () => {
|
|
317
367
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0])
|
318
368
|
expectEventArraysEqual(result.newEvents, [e_0_0, e_0_0_e_1_0])
|
319
369
|
expectEventArraysEqual(result.eventsToRollback, [e_0_0_b])
|
320
|
-
expect(result.newSyncState.upstreamHead).
|
370
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_0_0.id)
|
321
371
|
expect(result.newSyncState.localHead).toMatchObject(e_0_0_e_1_0.id)
|
322
372
|
})
|
323
373
|
|
324
374
|
it('should rebase different event with same id', () => {
|
325
375
|
const e_1_0_b = new TestEvent({ global: 1, local: 0 }, e_0_0.id, '1_0_b', false)
|
326
|
-
const syncState = {
|
376
|
+
const syncState = new SyncState.SyncState({
|
327
377
|
pending: [e_1_0_b],
|
328
378
|
rollbackTail: [e_0_0, e_0_1],
|
329
379
|
upstreamHead: EventId.ROOT,
|
330
380
|
localHead: e_1_0_b.id,
|
331
|
-
}
|
381
|
+
})
|
332
382
|
const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } })
|
333
383
|
const e_1_0_e_2_0 = e_1_0_b.rebase_(e_1_0.id)
|
334
384
|
|
@@ -337,12 +387,17 @@ describe('syncstate', () => {
|
|
337
387
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0, e_0_1, e_1_0])
|
338
388
|
expectEventArraysEqual(result.newEvents, [e_1_0, e_1_0_e_2_0])
|
339
389
|
expectEventArraysEqual(result.eventsToRollback, [e_0_0, e_0_1, e_1_0_b])
|
340
|
-
expect(result.newSyncState.upstreamHead).
|
390
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
|
341
391
|
expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_2_0.id)
|
342
392
|
})
|
343
393
|
|
344
394
|
it('should rebase single local event to end (more incoming events)', () => {
|
345
|
-
const syncState =
|
395
|
+
const syncState = new SyncState.SyncState({
|
396
|
+
pending: [e_0_0],
|
397
|
+
rollbackTail: [],
|
398
|
+
upstreamHead: EventId.ROOT,
|
399
|
+
localHead: e_0_0.id,
|
400
|
+
})
|
346
401
|
const result = run({
|
347
402
|
syncState,
|
348
403
|
payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_2, e_0_3, e_1_0] },
|
@@ -353,17 +408,17 @@ describe('syncstate', () => {
|
|
353
408
|
expectRebase(result)
|
354
409
|
expectEventArraysEqual(result.newSyncState.pending, [e_0_0_e_2_0])
|
355
410
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_1, e_0_2, e_0_3, e_1_0])
|
356
|
-
expect(result.newSyncState.upstreamHead).
|
411
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
|
357
412
|
expect(result.newSyncState.localHead).toMatchObject(e_0_0_e_2_0.id)
|
358
413
|
})
|
359
414
|
|
360
415
|
it('should only rebase divergent events when first event matches', () => {
|
361
|
-
const syncState = {
|
416
|
+
const syncState = new SyncState.SyncState({
|
362
417
|
pending: [e_0_0, e_0_1],
|
363
418
|
rollbackTail: [],
|
364
419
|
upstreamHead: EventId.ROOT,
|
365
420
|
localHead: e_0_0.id,
|
366
|
-
}
|
421
|
+
})
|
367
422
|
const result = run({
|
368
423
|
syncState,
|
369
424
|
payload: { _tag: 'upstream-advance', newEvents: [e_0_0, e_0_2, e_0_3, e_1_0] },
|
@@ -376,17 +431,17 @@ describe('syncstate', () => {
|
|
376
431
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0, e_0_2, e_0_3, e_1_0])
|
377
432
|
expectEventArraysEqual(result.eventsToRollback, [e_0_1])
|
378
433
|
expectEventArraysEqual(result.newEvents, [e_0_2, e_0_3, e_1_0, e_0_1_e_1_1])
|
379
|
-
expect(result.newSyncState.upstreamHead).
|
434
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
|
380
435
|
expect(result.newSyncState.localHead).toMatchObject(e_0_1_e_1_1.id)
|
381
436
|
})
|
382
437
|
|
383
438
|
it('should rebase all local events when incoming chain starts differently', () => {
|
384
|
-
const syncState = {
|
439
|
+
const syncState = new SyncState.SyncState({
|
385
440
|
pending: [e_0_0, e_0_1],
|
386
441
|
rollbackTail: [],
|
387
442
|
upstreamHead: EventId.ROOT,
|
388
443
|
localHead: e_0_1.id,
|
389
|
-
}
|
444
|
+
})
|
390
445
|
const result = run({
|
391
446
|
syncState,
|
392
447
|
payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_2, e_0_3, e_1_0] },
|
@@ -400,20 +455,25 @@ describe('syncstate', () => {
|
|
400
455
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_1, e_0_2, e_0_3, e_1_0])
|
401
456
|
expectEventArraysEqual(result.newEvents, [e_0_1, e_0_2, e_0_3, e_1_0, e_0_0_e_1_1, e_0_1_e_1_2])
|
402
457
|
expectEventArraysEqual(result.eventsToRollback, [e_0_0, e_0_1])
|
403
|
-
expect(result.newSyncState.upstreamHead).
|
458
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
|
404
459
|
expect(result.newSyncState.localHead).toMatchObject(e_0_1_e_1_2.id)
|
405
460
|
})
|
406
461
|
|
407
462
|
describe('local-push', () => {
|
408
463
|
describe('advance', () => {
|
409
464
|
it('should advance with new events', () => {
|
410
|
-
const syncState =
|
465
|
+
const syncState = new SyncState.SyncState({
|
466
|
+
pending: [e_0_0],
|
467
|
+
rollbackTail: [],
|
468
|
+
upstreamHead: EventId.ROOT,
|
469
|
+
localHead: e_0_0.id,
|
470
|
+
})
|
411
471
|
const result = run({ syncState, payload: { _tag: 'local-push', newEvents: [e_0_1, e_0_2, e_0_3] } })
|
412
472
|
|
413
473
|
expectAdvance(result)
|
414
474
|
expectEventArraysEqual(result.newSyncState.pending, [e_0_0, e_0_1, e_0_2, e_0_3])
|
415
475
|
expectEventArraysEqual(result.newSyncState.rollbackTail, [])
|
416
|
-
expect(result.newSyncState.upstreamHead).
|
476
|
+
expect(result.newSyncState.upstreamHead).toMatchObject(EventId.ROOT)
|
417
477
|
expect(result.newSyncState.localHead).toMatchObject(e_0_3.id)
|
418
478
|
expectEventArraysEqual(result.newEvents, [e_0_1, e_0_2, e_0_3])
|
419
479
|
})
|
@@ -421,12 +481,12 @@ describe('syncstate', () => {
|
|
421
481
|
|
422
482
|
describe('reject', () => {
|
423
483
|
it('should reject when new events are greater than pending events', () => {
|
424
|
-
const syncState = {
|
484
|
+
const syncState = new SyncState.SyncState({
|
425
485
|
pending: [e_0_0, e_0_1],
|
426
486
|
rollbackTail: [],
|
427
487
|
upstreamHead: EventId.ROOT,
|
428
488
|
localHead: e_0_1.id,
|
429
|
-
}
|
489
|
+
})
|
430
490
|
const result = run({ syncState, payload: { _tag: 'local-push', newEvents: [e_0_1, e_0_2] } })
|
431
491
|
|
432
492
|
expectReject(result)
|
@@ -444,10 +504,10 @@ const expectEventArraysEqual = (
|
|
444
504
|
) => {
|
445
505
|
expect(actual.length).toBe(expected.length)
|
446
506
|
actual.forEach((event, i) => {
|
447
|
-
expect(event.id).
|
448
|
-
expect(event.parentId).
|
449
|
-
expect(event.mutation).
|
450
|
-
expect(event.args).
|
507
|
+
expect(event.id).toStrictEqual(expected[i]!.id)
|
508
|
+
expect(event.parentId).toStrictEqual(expected[i]!.parentId)
|
509
|
+
expect(event.mutation).toStrictEqual(expected[i]!.mutation)
|
510
|
+
expect(event.args).toStrictEqual(expected[i]!.args)
|
451
511
|
})
|
452
512
|
}
|
453
513
|
|
package/src/sync/syncstate.ts
CHANGED
@@ -39,19 +39,21 @@ import * as MutationEvent from '../schema/MutationEvent.js'
|
|
39
39
|
* The `updateSyncState` function processes updates to the sync state based on incoming payloads,
|
40
40
|
* handling cases such as upstream rebase, advance, local push, and rollback tail trimming.
|
41
41
|
*/
|
42
|
-
export
|
43
|
-
pending: ReadonlyArray<MutationEvent.EncodedWithMeta>
|
44
|
-
rollbackTail: ReadonlyArray<MutationEvent.EncodedWithMeta>
|
45
|
-
upstreamHead: EventId.EventId
|
46
|
-
localHead: EventId.EventId
|
47
|
-
}
|
48
|
-
|
49
|
-
export const SyncState = Schema.Struct({
|
42
|
+
export class SyncState extends Schema.Class<SyncState>('SyncState')({
|
50
43
|
pending: Schema.Array(MutationEvent.EncodedWithMeta),
|
51
44
|
rollbackTail: Schema.Array(MutationEvent.EncodedWithMeta),
|
52
45
|
upstreamHead: EventId.EventId,
|
53
46
|
localHead: EventId.EventId,
|
54
|
-
})
|
47
|
+
}) {
|
48
|
+
toJSON = (): any => {
|
49
|
+
return {
|
50
|
+
pending: this.pending.map((e) => e.toJSON()),
|
51
|
+
rollbackTail: this.rollbackTail.map((e) => e.toJSON()),
|
52
|
+
upstreamHead: `(${this.upstreamHead.global},${this.upstreamHead.local})`,
|
53
|
+
localHead: `(${this.localHead.global},${this.localHead.local})`,
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
55
57
|
|
56
58
|
export class PayloadUpstreamRebase extends Schema.TaggedStruct('upstream-rebase', {
|
57
59
|
/** Rollback until this event in the rollback tail (inclusive). Starting from the end of the rollback tail. */
|
@@ -153,12 +155,12 @@ export const updateSyncState = ({
|
|
153
155
|
|
154
156
|
return {
|
155
157
|
_tag: 'rebase',
|
156
|
-
newSyncState: {
|
158
|
+
newSyncState: new SyncState({
|
157
159
|
pending: rebasedPending,
|
158
160
|
rollbackTail: trimRollbackTail([...syncState.rollbackTail.slice(0, rollbackIndex), ...payload.newEvents]),
|
159
161
|
upstreamHead: newUpstreamHead,
|
160
162
|
localHead: rebasedPending.at(-1)?.id ?? newUpstreamHead,
|
161
|
-
},
|
163
|
+
}),
|
162
164
|
previousSyncState: syncState,
|
163
165
|
newEvents: payload.newEvents,
|
164
166
|
eventsToRollback,
|
@@ -169,12 +171,12 @@ export const updateSyncState = ({
|
|
169
171
|
if (payload.newEvents.length === 0) {
|
170
172
|
return {
|
171
173
|
_tag: 'advance',
|
172
|
-
newSyncState: {
|
174
|
+
newSyncState: new SyncState({
|
173
175
|
pending: syncState.pending,
|
174
176
|
rollbackTail: trimRollbackTail(syncState.rollbackTail),
|
175
177
|
upstreamHead: syncState.upstreamHead,
|
176
178
|
localHead: syncState.localHead,
|
177
|
-
},
|
179
|
+
}),
|
178
180
|
previousSyncState: syncState,
|
179
181
|
newEvents: [],
|
180
182
|
}
|
@@ -235,12 +237,12 @@ export const updateSyncState = ({
|
|
235
237
|
|
236
238
|
return {
|
237
239
|
_tag: 'advance',
|
238
|
-
newSyncState: {
|
240
|
+
newSyncState: new SyncState({
|
239
241
|
pending: pendingRemaining,
|
240
242
|
rollbackTail: trimRollbackTail([...syncState.rollbackTail, ...pendingAndNewEvents]),
|
241
243
|
upstreamHead: newUpstreamHead,
|
242
244
|
localHead: pendingRemaining.at(-1)?.id ?? newUpstreamHead,
|
243
|
-
},
|
245
|
+
}),
|
244
246
|
previousSyncState: syncState,
|
245
247
|
newEvents,
|
246
248
|
}
|
@@ -262,12 +264,12 @@ export const updateSyncState = ({
|
|
262
264
|
|
263
265
|
return {
|
264
266
|
_tag: 'rebase',
|
265
|
-
newSyncState: {
|
267
|
+
newSyncState: new SyncState({
|
266
268
|
pending: rebasedPending,
|
267
269
|
rollbackTail: trimRollbackTail([...syncState.rollbackTail, ...payload.newEvents]),
|
268
270
|
upstreamHead: newUpstreamHead,
|
269
271
|
localHead: rebasedPending.at(-1)!.id,
|
270
|
-
},
|
272
|
+
}),
|
271
273
|
previousSyncState: syncState,
|
272
274
|
newEvents: [...payload.newEvents.slice(divergentNewEventsIndex), ...rebasedPending],
|
273
275
|
eventsToRollback: [...syncState.rollbackTail, ...divergentPending],
|
@@ -289,12 +291,12 @@ export const updateSyncState = ({
|
|
289
291
|
} else {
|
290
292
|
return {
|
291
293
|
_tag: 'advance',
|
292
|
-
newSyncState: {
|
294
|
+
newSyncState: new SyncState({
|
293
295
|
pending: [...syncState.pending, ...payload.newEvents],
|
294
296
|
rollbackTail: syncState.rollbackTail,
|
295
297
|
upstreamHead: syncState.upstreamHead,
|
296
298
|
localHead: payload.newEvents.at(-1)!.id,
|
297
|
-
},
|
299
|
+
}),
|
298
300
|
previousSyncState: syncState,
|
299
301
|
newEvents: payload.newEvents,
|
300
302
|
}
|
@@ -1,17 +1,20 @@
|
|
1
1
|
import { Effect } from '@livestore/utils/effect'
|
2
2
|
|
3
|
-
import type { MutationEvent } from '../schema/mod.js'
|
3
|
+
import type { EventId, MutationEvent } from '../schema/mod.js'
|
4
4
|
import { InvalidPushError } from './sync.js'
|
5
5
|
|
6
6
|
// TODO proper batch validation
|
7
|
-
export const validatePushPayload = (
|
7
|
+
export const validatePushPayload = (
|
8
|
+
batch: ReadonlyArray<MutationEvent.AnyEncodedGlobal>,
|
9
|
+
currentEventId: EventId.GlobalEventId,
|
10
|
+
) =>
|
8
11
|
Effect.gen(function* () {
|
9
|
-
if (batch[0]!.id
|
12
|
+
if (batch[0]!.id <= currentEventId) {
|
10
13
|
return yield* InvalidPushError.make({
|
11
14
|
reason: {
|
12
15
|
_tag: 'ServerAhead',
|
13
16
|
minimumExpectedId: currentEventId + 1,
|
14
|
-
providedId: batch[0]!.id
|
17
|
+
providedId: batch[0]!.id,
|
15
18
|
},
|
16
19
|
})
|
17
20
|
}
|
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.
|
5
|
+
export const liveStoreVersion = '0.3.0-dev.10' as const
|
6
6
|
|
7
7
|
/**
|
8
8
|
* This version number is incremented whenever the internal storage format changes in a breaking way.
|