@livestore/common 0.3.0-dev.27 → 0.3.0-dev.28

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 (33) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/devtools/devtools-messages-client-session.d.ts +21 -21
  3. package/dist/devtools/devtools-messages-common.d.ts +6 -6
  4. package/dist/devtools/devtools-messages-leader.d.ts +24 -24
  5. package/dist/leader-thread/LeaderSyncProcessor.d.ts +16 -3
  6. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  7. package/dist/leader-thread/LeaderSyncProcessor.js +65 -27
  8. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  9. package/dist/leader-thread/make-leader-thread-layer.d.ts +15 -3
  10. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  11. package/dist/leader-thread/make-leader-thread-layer.js +8 -1
  12. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  13. package/dist/schema/EventId.d.ts.map +1 -1
  14. package/dist/schema/EventId.js +5 -0
  15. package/dist/schema/EventId.js.map +1 -1
  16. package/dist/schema/MutationEvent.js +1 -1
  17. package/dist/schema/MutationEvent.js.map +1 -1
  18. package/dist/sync/syncstate.d.ts.map +1 -1
  19. package/dist/sync/syncstate.js +21 -15
  20. package/dist/sync/syncstate.js.map +1 -1
  21. package/dist/sync/syncstate.test.js +160 -170
  22. package/dist/sync/syncstate.test.js.map +1 -1
  23. package/dist/version.d.ts +1 -1
  24. package/dist/version.js +1 -1
  25. package/package.json +2 -2
  26. package/src/leader-thread/LeaderSyncProcessor.ts +105 -34
  27. package/src/leader-thread/make-leader-thread-layer.ts +34 -12
  28. package/src/schema/EventId.ts +6 -0
  29. package/src/schema/MutationEvent.ts +1 -1
  30. package/src/sync/syncstate.test.ts +160 -171
  31. package/src/sync/syncstate.ts +29 -19
  32. package/src/version.ts +1 -1
  33. package/tmp/pack.tgz +0 -0
@@ -22,14 +22,13 @@ class TestEvent extends MutationEvent.EncodedWithMeta {
22
22
  return this.rebase(parentId, this.isLocal);
23
23
  };
24
24
  }
25
- const e_0_1 = new TestEvent({ global: 0, client: 1 }, EventId.ROOT, 'a', true);
26
- const e_1_0 = new TestEvent({ global: 1, client: 0 }, EventId.ROOT, 'a', false);
27
- const e_1_1 = new TestEvent({ global: 1, client: 1 }, e_1_0.id, 'a', true);
28
- const e_1_2 = new TestEvent({ global: 1, client: 2 }, e_1_1.id, 'a', true);
29
- const e_1_3 = new TestEvent({ global: 1, client: 3 }, e_1_2.id, 'a', true);
30
- const e_2_0 = new TestEvent({ global: 2, client: 0 }, e_1_0.id, 'a', false);
31
- const e_2_1 = new TestEvent({ global: 2, client: 1 }, e_2_0.id, 'a', true);
32
- const e_3_0 = new TestEvent({ global: 3, client: 0 }, e_2_0.id, 'a', false);
25
+ const e0_1 = new TestEvent({ global: 0, client: 1 }, EventId.ROOT, 'a', true);
26
+ const e1_0 = new TestEvent({ global: 1, client: 0 }, EventId.ROOT, 'a', false);
27
+ const e1_1 = new TestEvent({ global: 1, client: 1 }, e1_0.id, 'a', true);
28
+ const e1_2 = new TestEvent({ global: 1, client: 2 }, e1_1.id, 'a', true);
29
+ const e1_3 = new TestEvent({ global: 1, client: 3 }, e1_2.id, 'a', true);
30
+ const e2_0 = new TestEvent({ global: 2, client: 0 }, e1_0.id, 'a', false);
31
+ const e2_1 = new TestEvent({ global: 2, client: 1 }, e2_0.id, 'a', true);
33
32
  const isEqualEvent = MutationEvent.isEqualEncoded;
34
33
  const isClientEvent = (event) => event.isLocal;
35
34
  describe('syncstate', () => {
@@ -38,370 +37,361 @@ describe('syncstate', () => {
38
37
  describe('upstream-rebase', () => {
39
38
  it('should rollback until start', () => {
40
39
  const syncState = new SyncState.SyncState({
41
- pending: [e_2_0],
40
+ pending: [e2_0],
42
41
  upstreamHead: EventId.ROOT,
43
- localHead: e_2_0.id,
42
+ localHead: e2_0.id,
44
43
  });
45
- const e_1_0_e_2_0 = e_1_0.rebase_(e_2_0.id);
46
- const e_1_1_e_2_1 = e_1_1.rebase_(e_1_0_e_2_0.id);
44
+ const e1_0_e2_0 = e1_0.rebase_(e2_0.id);
45
+ const e1_1_e2_1 = e1_1.rebase_(e1_0_e2_0.id);
47
46
  const result = merge({
48
47
  syncState,
49
48
  payload: SyncState.PayloadUpstreamRebase.make({
50
- rollbackEvents: [e_1_0, e_1_1],
51
- newEvents: [e_1_0_e_2_0, e_1_1_e_2_1],
49
+ rollbackEvents: [e1_0, e1_1],
50
+ newEvents: [e1_0_e2_0, e1_1_e2_1],
52
51
  }),
53
52
  });
54
- const e_2_0_e_3_0 = e_2_0.rebase_(e_1_0_e_2_0.id);
53
+ const e2_0_e3_0 = e2_0.rebase_(e1_0_e2_0.id);
55
54
  expectRebase(result);
56
- expectEventArraysEqual(result.newSyncState.pending, [e_2_0_e_3_0]);
57
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_1_e_2_1.id);
58
- expect(result.newSyncState.localHead).toMatchObject(e_2_0_e_3_0.id);
59
- expectEventArraysEqual(result.newEvents, [e_1_0_e_2_0, e_1_1_e_2_1, e_2_0_e_3_0]);
60
- expectEventArraysEqual(result.rollbackEvents, [e_1_0, e_1_1, e_2_0]);
55
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0]);
56
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1_e2_1.id);
57
+ expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.id);
58
+ expectEventArraysEqual(result.newEvents, [e1_0_e2_0, e1_1_e2_1, e2_0_e3_0]);
59
+ expectEventArraysEqual(result.rollbackEvents, [e1_0, e1_1, e2_0]);
61
60
  });
62
61
  it('should rollback only to specified point', () => {
63
62
  const syncState = new SyncState.SyncState({
64
- pending: [e_2_0],
63
+ pending: [e2_0],
65
64
  upstreamHead: EventId.ROOT,
66
- localHead: e_2_0.id,
65
+ localHead: e2_0.id,
67
66
  });
68
- const e_1_1_e_2_0 = e_1_1.rebase_(e_1_0.id);
67
+ const e1_1_e2_0 = e1_1.rebase_(e1_0.id);
69
68
  const result = merge({
70
69
  syncState,
71
70
  payload: SyncState.PayloadUpstreamRebase.make({
72
- newEvents: [e_1_1_e_2_0],
73
- rollbackEvents: [e_1_1],
71
+ newEvents: [e1_1_e2_0],
72
+ rollbackEvents: [e1_1],
74
73
  }),
75
74
  });
76
- const e_2_0_e_3_0 = e_2_0.rebase_(e_1_1_e_2_0.id);
75
+ const e2_0_e3_0 = e2_0.rebase_(e1_1_e2_0.id);
77
76
  expectRebase(result);
78
- expectEventArraysEqual(result.newSyncState.pending, [e_2_0_e_3_0]);
79
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_1_e_2_0.id);
80
- expect(result.newSyncState.localHead).toMatchObject(e_2_0_e_3_0.id);
81
- expectEventArraysEqual(result.newEvents, [e_1_1_e_2_0, e_2_0_e_3_0]);
82
- expectEventArraysEqual(result.rollbackEvents, [e_1_1, e_2_0]);
77
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0]);
78
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1_e2_0.id);
79
+ expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.id);
80
+ expectEventArraysEqual(result.newEvents, [e1_1_e2_0, e2_0_e3_0]);
81
+ expectEventArraysEqual(result.rollbackEvents, [e1_1, e2_0]);
83
82
  });
84
83
  it('should work for empty pending', () => {
85
84
  const syncState = new SyncState.SyncState({
86
85
  pending: [],
87
86
  upstreamHead: EventId.ROOT,
88
- localHead: e_1_0.id,
87
+ localHead: e1_0.id,
89
88
  });
90
89
  const result = merge({
91
90
  syncState,
92
- payload: SyncState.PayloadUpstreamRebase.make({ rollbackEvents: [e_1_0], newEvents: [e_2_0] }),
91
+ payload: SyncState.PayloadUpstreamRebase.make({ rollbackEvents: [e1_0], newEvents: [e2_0] }),
93
92
  });
94
93
  expectRebase(result);
95
94
  expectEventArraysEqual(result.newSyncState.pending, []);
96
- expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
97
- expect(result.newSyncState.localHead).toMatchObject(e_2_0.id);
98
- expect(result.newEvents).toStrictEqual([e_2_0]);
95
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
96
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.id);
97
+ expect(result.newEvents).toStrictEqual([e2_0]);
99
98
  });
100
99
  });
101
100
  describe('upstream-advance: advance', () => {
102
101
  it('should throw error if newEvents are not sorted in ascending order by eventId (client)', () => {
103
102
  const syncState = new SyncState.SyncState({
104
- pending: [e_1_0],
103
+ pending: [e1_0],
105
104
  upstreamHead: EventId.ROOT,
106
- localHead: e_1_0.id,
105
+ localHead: e1_0.id,
107
106
  });
108
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_1, e_1_0] } });
107
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_1, e1_0] } });
109
108
  expect(result).toMatchObject({ _tag: 'unexpected-error' });
110
109
  });
111
110
  it('should throw error if newEvents are not sorted in ascending order by eventId (global)', () => {
112
111
  const syncState = new SyncState.SyncState({
113
- pending: [e_1_0],
112
+ pending: [e1_0],
114
113
  upstreamHead: EventId.ROOT,
115
- localHead: e_1_0.id,
114
+ localHead: e1_0.id,
116
115
  });
117
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_2_0, e_1_0] } });
116
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e2_0, e1_0] } });
118
117
  expect(result).toMatchObject({ _tag: 'unexpected-error' });
119
118
  });
120
119
  it('should throw error if incoming event is < expected upstream head', () => {
121
120
  const syncState = new SyncState.SyncState({
122
121
  pending: [],
123
- upstreamHead: e_2_0.id,
124
- localHead: e_2_0.id,
122
+ upstreamHead: e2_0.id,
123
+ localHead: e2_0.id,
125
124
  });
126
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } });
125
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } });
127
126
  expect(result).toMatchObject({ _tag: 'unexpected-error' });
128
127
  });
129
128
  it('should throw error if incoming event is = expected upstream head', () => {
130
129
  const syncState = new SyncState.SyncState({
131
130
  pending: [],
132
- upstreamHead: e_2_0.id,
133
- localHead: e_2_0.id,
131
+ upstreamHead: e2_0.id,
132
+ localHead: e2_0.id,
134
133
  });
135
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_2_0] } });
136
- expect(result).toMatchObject({ _tag: 'unexpected-error' });
137
- });
138
- it('should throw if the parent id of the first incoming event is unknown', () => {
139
- const syncState = new SyncState.SyncState({
140
- pending: [],
141
- upstreamHead: EventId.ROOT,
142
- localHead: e_1_0.id,
143
- });
144
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_3_0] } });
134
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e2_0] } });
145
135
  expect(result).toMatchObject({ _tag: 'unexpected-error' });
146
136
  });
147
137
  it('should confirm pending event when receiving matching event', () => {
148
138
  const syncState = new SyncState.SyncState({
149
- pending: [e_1_0],
139
+ pending: [e1_0],
150
140
  upstreamHead: EventId.ROOT,
151
- localHead: e_1_0.id,
141
+ localHead: e1_0.id,
152
142
  });
153
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } });
143
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } });
154
144
  expectAdvance(result);
155
145
  expectEventArraysEqual(result.newSyncState.pending, []);
156
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id);
157
- expect(result.newSyncState.localHead).toMatchObject(e_1_0.id);
146
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id);
147
+ expect(result.newSyncState.localHead).toMatchObject(e1_0.id);
158
148
  expectEventArraysEqual(result.newEvents, []);
159
- expectEventArraysEqual(result.confirmedEvents, [e_1_0]);
149
+ expectEventArraysEqual(result.confirmedEvents, [e1_0]);
160
150
  });
161
151
  it('should confirm partial pending event when receiving matching event', () => {
162
152
  const syncState = new SyncState.SyncState({
163
- pending: [e_1_0, e_2_0],
153
+ pending: [e1_0, e2_0],
164
154
  upstreamHead: EventId.ROOT,
165
- localHead: e_2_0.id,
155
+ localHead: e2_0.id,
166
156
  });
167
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } });
157
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } });
168
158
  expectAdvance(result);
169
- expectEventArraysEqual(result.newSyncState.pending, [e_2_0]);
170
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id);
171
- expect(result.newSyncState.localHead).toMatchObject(e_2_0.id);
159
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0]);
160
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id);
161
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.id);
172
162
  expectEventArraysEqual(result.newEvents, []);
173
- expectEventArraysEqual(result.confirmedEvents, [e_1_0]);
163
+ expectEventArraysEqual(result.confirmedEvents, [e1_0]);
174
164
  });
175
165
  it('should confirm pending event and add new event', () => {
176
166
  const syncState = new SyncState.SyncState({
177
- pending: [e_1_0],
167
+ pending: [e1_0],
178
168
  upstreamHead: EventId.ROOT,
179
- localHead: e_1_0.id,
169
+ localHead: e1_0.id,
180
170
  });
181
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0, e_1_1] } });
171
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0, e1_1] } });
182
172
  expectAdvance(result);
183
173
  expectEventArraysEqual(result.newSyncState.pending, []);
184
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_1.id);
185
- expect(result.newSyncState.localHead).toMatchObject(e_1_1.id);
186
- expect(result.newEvents).toStrictEqual([e_1_1]);
187
- expectEventArraysEqual(result.confirmedEvents, [e_1_0]);
174
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1.id);
175
+ expect(result.newSyncState.localHead).toMatchObject(e1_1.id);
176
+ expect(result.newEvents).toStrictEqual([e1_1]);
177
+ expectEventArraysEqual(result.confirmedEvents, [e1_0]);
188
178
  });
189
179
  it('should confirm pending event and add multiple new events', () => {
190
180
  const syncState = new SyncState.SyncState({
191
- pending: [e_1_1],
192
- upstreamHead: e_1_0.id,
193
- localHead: e_1_1.id,
181
+ pending: [e1_1],
182
+ upstreamHead: e1_0.id,
183
+ localHead: e1_1.id,
194
184
  });
195
185
  const result = merge({
196
186
  syncState,
197
- payload: { _tag: 'upstream-advance', newEvents: [e_1_1, e_1_2, e_1_3, e_2_0, e_2_1] },
187
+ payload: { _tag: 'upstream-advance', newEvents: [e1_1, e1_2, e1_3, e2_0, e2_1] },
198
188
  });
199
189
  expectAdvance(result);
200
190
  expectEventArraysEqual(result.newSyncState.pending, []);
201
- expect(result.newSyncState.upstreamHead).toMatchObject(e_2_1.id);
202
- expect(result.newSyncState.localHead).toMatchObject(e_2_1.id);
203
- expect(result.newEvents).toStrictEqual([e_1_2, e_1_3, e_2_0, e_2_1]);
204
- expectEventArraysEqual(result.confirmedEvents, [e_1_1]);
191
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_1.id);
192
+ expect(result.newSyncState.localHead).toMatchObject(e2_1.id);
193
+ expect(result.newEvents).toStrictEqual([e1_2, e1_3, e2_0, e2_1]);
194
+ expectEventArraysEqual(result.confirmedEvents, [e1_1]);
205
195
  });
206
196
  it('should confirm pending global event while keep pending client events', () => {
207
197
  const syncState = new SyncState.SyncState({
208
- pending: [e_1_0, e_1_1],
198
+ pending: [e1_0, e1_1],
209
199
  upstreamHead: EventId.ROOT,
210
- localHead: e_1_1.id,
200
+ localHead: e1_1.id,
211
201
  });
212
202
  const result = merge({
213
203
  syncState,
214
- payload: { _tag: 'upstream-advance', newEvents: [e_1_0] },
204
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
215
205
  });
216
206
  expectAdvance(result);
217
- expectEventArraysEqual(result.newSyncState.pending, [e_1_1]);
218
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id);
219
- expect(result.newSyncState.localHead).toMatchObject(e_1_1.id);
207
+ expectEventArraysEqual(result.newSyncState.pending, [e1_1]);
208
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id);
209
+ expect(result.newSyncState.localHead).toMatchObject(e1_1.id);
220
210
  expectEventArraysEqual(result.newEvents, []);
221
- expectEventArraysEqual(result.confirmedEvents, [e_1_0]);
211
+ expectEventArraysEqual(result.confirmedEvents, [e1_0]);
222
212
  });
223
213
  it('should ignore client events (incoming is subset of pending)', () => {
224
214
  const syncState = new SyncState.SyncState({
225
- pending: [e_0_1, e_1_0],
215
+ pending: [e0_1, e1_0],
226
216
  upstreamHead: EventId.ROOT,
227
- localHead: e_1_0.id,
217
+ localHead: e1_0.id,
228
218
  });
229
219
  const result = merge({
230
220
  syncState,
231
- payload: { _tag: 'upstream-advance', newEvents: [e_1_0] },
221
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
232
222
  ignoreClientEvents: true,
233
223
  });
234
224
  expectAdvance(result);
235
225
  expectEventArraysEqual(result.newSyncState.pending, []);
236
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id);
237
- expect(result.newSyncState.localHead).toMatchObject(e_1_0.id);
226
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id);
227
+ expect(result.newSyncState.localHead).toMatchObject(e1_0.id);
238
228
  expectEventArraysEqual(result.newEvents, []);
239
- expectEventArraysEqual(result.confirmedEvents, [e_0_1, e_1_0]);
229
+ expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0]);
240
230
  });
241
231
  it('should ignore client events (incoming is subset of pending case 2)', () => {
242
232
  const syncState = new SyncState.SyncState({
243
- pending: [e_0_1, e_1_0, e_2_0],
233
+ pending: [e0_1, e1_0, e2_0],
244
234
  upstreamHead: EventId.ROOT,
245
- localHead: e_1_0.id,
235
+ localHead: e1_0.id,
246
236
  });
247
237
  const result = merge({
248
238
  syncState,
249
- payload: { _tag: 'upstream-advance', newEvents: [e_1_0] },
239
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
250
240
  ignoreClientEvents: true,
251
241
  });
252
242
  expectAdvance(result);
253
- expectEventArraysEqual(result.newSyncState.pending, [e_2_0]);
254
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id);
255
- expect(result.newSyncState.localHead).toMatchObject(e_2_0.id);
243
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0]);
244
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id);
245
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.id);
256
246
  expectEventArraysEqual(result.newEvents, []);
257
- expectEventArraysEqual(result.confirmedEvents, [e_0_1, e_1_0]);
247
+ expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0]);
258
248
  });
259
249
  it('should ignore client events (incoming goes beyond pending)', () => {
260
250
  const syncState = new SyncState.SyncState({
261
- pending: [e_0_1, e_1_0, e_1_1],
251
+ pending: [e0_1, e1_0, e1_1],
262
252
  upstreamHead: EventId.ROOT,
263
- localHead: e_1_1.id,
253
+ localHead: e1_1.id,
264
254
  });
265
255
  const result = merge({
266
256
  syncState,
267
- payload: { _tag: 'upstream-advance', newEvents: [e_1_0, e_2_0] },
257
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0, e2_0] },
268
258
  ignoreClientEvents: true,
269
259
  });
270
260
  expectAdvance(result);
271
261
  expectEventArraysEqual(result.newSyncState.pending, []);
272
- expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
273
- expect(result.newSyncState.localHead).toMatchObject(e_2_0.id);
274
- expect(result.newEvents).toStrictEqual([e_2_0]);
275
- expectEventArraysEqual(result.confirmedEvents, [e_0_1, e_1_0, e_1_1]);
262
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
263
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.id);
264
+ expect(result.newEvents).toStrictEqual([e2_0]);
265
+ expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0, e1_1]);
276
266
  });
277
267
  it('should fail if incoming event is ≤ local head', () => {
278
268
  const syncState = new SyncState.SyncState({
279
269
  pending: [],
280
- upstreamHead: e_2_0.id,
281
- localHead: e_2_0.id,
270
+ upstreamHead: e2_0.id,
271
+ localHead: e2_0.id,
282
272
  });
283
- const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } });
273
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } });
284
274
  expect(result).toMatchObject({ _tag: 'unexpected-error' });
285
275
  });
286
276
  });
287
277
  describe('upstream-advance: rebase', () => {
288
278
  it('should rebase single client event to end', () => {
289
279
  const syncState = new SyncState.SyncState({
290
- pending: [e_1_0],
280
+ pending: [e1_0],
291
281
  upstreamHead: EventId.ROOT,
292
- localHead: e_1_0.id,
282
+ localHead: e1_0.id,
293
283
  });
294
- const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e_1_1] }) });
295
- const e_1_0_e_1_2 = e_1_0.rebase_(e_1_1.id);
284
+ const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1] }) });
285
+ const e1_0_e1_2 = e1_0.rebase_(e1_1.id);
296
286
  expectRebase(result);
297
- expectEventArraysEqual(result.newSyncState.pending, [e_1_0_e_1_2]);
298
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_1.id);
299
- expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_1_2.id);
300
- expectEventArraysEqual(result.rollbackEvents, [e_1_0]);
301
- expectEventArraysEqual(result.newEvents, [e_1_1, e_1_0_e_1_2]);
287
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0_e1_2]);
288
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1.id);
289
+ expect(result.newSyncState.localHead).toMatchObject(e1_0_e1_2.id);
290
+ expectEventArraysEqual(result.rollbackEvents, [e1_0]);
291
+ expectEventArraysEqual(result.newEvents, [e1_1, e1_0_e1_2]);
302
292
  });
303
293
  it('should rebase different event with same id', () => {
304
- const e_2_0_b = new TestEvent({ global: 1, client: 0 }, e_1_0.id, '1_0_b', false);
294
+ const e2_0_b = new TestEvent({ global: 1, client: 0 }, e1_0.id, '1_0_b', false);
305
295
  const syncState = new SyncState.SyncState({
306
- pending: [e_2_0_b],
296
+ pending: [e2_0_b],
307
297
  upstreamHead: EventId.ROOT,
308
- localHead: e_2_0_b.id,
298
+ localHead: e2_0_b.id,
309
299
  });
310
- const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e_2_0] }) });
311
- const e_2_0_e_3_0 = e_2_0_b.rebase_(e_2_0.id);
300
+ const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e2_0] }) });
301
+ const e2_0_e3_0 = e2_0_b.rebase_(e2_0.id);
312
302
  expectRebase(result);
313
- expectEventArraysEqual(result.newSyncState.pending, [e_2_0_e_3_0]);
314
- expectEventArraysEqual(result.newEvents, [e_2_0, e_2_0_e_3_0]);
315
- expectEventArraysEqual(result.rollbackEvents, [e_2_0_b]);
316
- expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
317
- expect(result.newSyncState.localHead).toMatchObject(e_2_0_e_3_0.id);
303
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0]);
304
+ expectEventArraysEqual(result.newEvents, [e2_0, e2_0_e3_0]);
305
+ expectEventArraysEqual(result.rollbackEvents, [e2_0_b]);
306
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
307
+ expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.id);
318
308
  });
319
309
  it('should rebase single client event to end (more incoming events)', () => {
320
310
  const syncState = new SyncState.SyncState({
321
- pending: [e_1_0],
311
+ pending: [e1_0],
322
312
  upstreamHead: EventId.ROOT,
323
- localHead: e_1_0.id,
313
+ localHead: e1_0.id,
324
314
  });
325
315
  const result = merge({
326
316
  syncState,
327
- payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e_1_1, e_1_2, e_1_3, e_2_0] }),
317
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1, e1_2, e1_3, e2_0] }),
328
318
  });
329
- const e_1_0_e_3_0 = e_1_0.rebase_(e_2_0.id);
319
+ const e1_0_e3_0 = e1_0.rebase_(e2_0.id);
330
320
  expectRebase(result);
331
- expectEventArraysEqual(result.newSyncState.pending, [e_1_0_e_3_0]);
332
- expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
333
- expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_3_0.id);
321
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0_e3_0]);
322
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
323
+ expect(result.newSyncState.localHead).toMatchObject(e1_0_e3_0.id);
334
324
  });
335
325
  it('should only rebase divergent events when first event matches', () => {
336
326
  const syncState = new SyncState.SyncState({
337
- pending: [e_1_0, e_1_1],
327
+ pending: [e1_0, e1_1],
338
328
  upstreamHead: EventId.ROOT,
339
- localHead: e_1_0.id,
329
+ localHead: e1_0.id,
340
330
  });
341
331
  const result = merge({
342
332
  syncState,
343
- payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e_1_0, e_1_2, e_1_3, e_2_0] }),
333
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_0, e1_2, e1_3, e2_0] }),
344
334
  });
345
- const e_1_1_e_2_1 = e_1_1.rebase_(e_2_0.id);
335
+ const e1_1_e2_1 = e1_1.rebase_(e2_0.id);
346
336
  expectRebase(result);
347
- expectEventArraysEqual(result.newSyncState.pending, [e_1_1_e_2_1]);
348
- expectEventArraysEqual(result.rollbackEvents, [e_1_1]);
349
- expectEventArraysEqual(result.newEvents, [e_1_2, e_1_3, e_2_0, e_1_1_e_2_1]);
350
- expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
351
- expect(result.newSyncState.localHead).toMatchObject(e_1_1_e_2_1.id);
337
+ expectEventArraysEqual(result.newSyncState.pending, [e1_1_e2_1]);
338
+ expectEventArraysEqual(result.rollbackEvents, [e1_1]);
339
+ expectEventArraysEqual(result.newEvents, [e1_2, e1_3, e2_0, e1_1_e2_1]);
340
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
341
+ expect(result.newSyncState.localHead).toMatchObject(e1_1_e2_1.id);
352
342
  });
353
343
  it('should rebase all client events when incoming chain starts differently', () => {
354
344
  const syncState = new SyncState.SyncState({
355
- pending: [e_1_0, e_1_1],
345
+ pending: [e1_0, e1_1],
356
346
  upstreamHead: EventId.ROOT,
357
- localHead: e_1_1.id,
347
+ localHead: e1_1.id,
358
348
  });
359
349
  const result = merge({
360
350
  syncState,
361
- payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e_1_1, e_1_2, e_1_3, e_2_0] }),
351
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1, e1_2, e1_3, e2_0] }),
362
352
  });
363
- const e_1_0_e_2_1 = e_1_0.rebase_(e_2_0.id);
364
- const e_1_1_e_2_2 = e_1_1.rebase_(e_1_0_e_2_1.id);
353
+ const e1_0_e2_1 = e1_0.rebase_(e2_0.id);
354
+ const e1_1_e2_2 = e1_1.rebase_(e1_0_e2_1.id);
365
355
  expectRebase(result);
366
- expectEventArraysEqual(result.newSyncState.pending, [e_1_0_e_2_1, e_1_1_e_2_2]);
367
- expectEventArraysEqual(result.newEvents, [e_1_1, e_1_2, e_1_3, e_2_0, e_1_0_e_2_1, e_1_1_e_2_2]);
368
- expectEventArraysEqual(result.rollbackEvents, [e_1_0, e_1_1]);
369
- expect(result.newSyncState.upstreamHead).toMatchObject(e_2_0.id);
370
- expect(result.newSyncState.localHead).toMatchObject(e_1_1_e_2_2.id);
356
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0_e2_1, e1_1_e2_2]);
357
+ expectEventArraysEqual(result.newEvents, [e1_1, e1_2, e1_3, e2_0, e1_0_e2_1, e1_1_e2_2]);
358
+ expectEventArraysEqual(result.rollbackEvents, [e1_0, e1_1]);
359
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id);
360
+ expect(result.newSyncState.localHead).toMatchObject(e1_1_e2_2.id);
371
361
  });
372
362
  describe('local-push', () => {
373
363
  describe('advance', () => {
374
364
  it('should advance with new events', () => {
375
365
  const syncState = new SyncState.SyncState({
376
- pending: [e_1_0],
366
+ pending: [e1_0],
377
367
  upstreamHead: EventId.ROOT,
378
- localHead: e_1_0.id,
368
+ localHead: e1_0.id,
379
369
  });
380
370
  const result = merge({
381
371
  syncState,
382
- payload: SyncState.PayloadLocalPush.make({ newEvents: [e_1_1, e_1_2, e_1_3] }),
372
+ payload: SyncState.PayloadLocalPush.make({ newEvents: [e1_1, e1_2, e1_3] }),
383
373
  });
384
374
  expectAdvance(result);
385
- expectEventArraysEqual(result.newSyncState.pending, [e_1_0, e_1_1, e_1_2, e_1_3]);
375
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0, e1_1, e1_2, e1_3]);
386
376
  expect(result.newSyncState.upstreamHead).toMatchObject(EventId.ROOT);
387
- expect(result.newSyncState.localHead).toMatchObject(e_1_3.id);
388
- expectEventArraysEqual(result.newEvents, [e_1_1, e_1_2, e_1_3]);
377
+ expect(result.newSyncState.localHead).toMatchObject(e1_3.id);
378
+ expectEventArraysEqual(result.newEvents, [e1_1, e1_2, e1_3]);
389
379
  expectEventArraysEqual(result.confirmedEvents, []);
390
380
  });
391
381
  });
392
382
  describe('reject', () => {
393
383
  it('should reject when new events are greater than pending events', () => {
394
384
  const syncState = new SyncState.SyncState({
395
- pending: [e_1_0, e_1_1],
385
+ pending: [e1_0, e1_1],
396
386
  upstreamHead: EventId.ROOT,
397
- localHead: e_1_1.id,
387
+ localHead: e1_1.id,
398
388
  });
399
389
  const result = merge({
400
390
  syncState,
401
- payload: SyncState.PayloadLocalPush.make({ newEvents: [e_1_1, e_1_2] }),
391
+ payload: SyncState.PayloadLocalPush.make({ newEvents: [e1_1, e1_2] }),
402
392
  });
403
393
  expectReject(result);
404
- expect(result.expectedMinimumId).toMatchObject(e_1_2.id);
394
+ expect(result.expectedMinimumId).toMatchObject(e1_2.id);
405
395
  });
406
396
  });
407
397
  });