@livestore/common 0.3.0-dev.26 → 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 (105) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/adapter-types.d.ts +13 -12
  3. package/dist/adapter-types.d.ts.map +1 -1
  4. package/dist/adapter-types.js +5 -6
  5. package/dist/adapter-types.js.map +1 -1
  6. package/dist/devtools/devtools-messages-client-session.d.ts +21 -21
  7. package/dist/devtools/devtools-messages-common.d.ts +13 -6
  8. package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
  9. package/dist/devtools/devtools-messages-common.js +6 -0
  10. package/dist/devtools/devtools-messages-common.js.map +1 -1
  11. package/dist/devtools/devtools-messages-leader.d.ts +25 -25
  12. package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
  13. package/dist/devtools/devtools-messages-leader.js +1 -2
  14. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  15. package/dist/leader-thread/LeaderSyncProcessor.d.ts +29 -7
  16. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  17. package/dist/leader-thread/LeaderSyncProcessor.js +259 -199
  18. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  19. package/dist/leader-thread/apply-mutation.d.ts +14 -9
  20. package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
  21. package/dist/leader-thread/apply-mutation.js +43 -36
  22. package/dist/leader-thread/apply-mutation.js.map +1 -1
  23. package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
  24. package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
  25. package/dist/leader-thread/leader-worker-devtools.js +4 -5
  26. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  27. package/dist/leader-thread/make-leader-thread-layer.d.ts +15 -3
  28. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  29. package/dist/leader-thread/make-leader-thread-layer.js +29 -34
  30. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  31. package/dist/leader-thread/mod.d.ts +1 -1
  32. package/dist/leader-thread/mod.d.ts.map +1 -1
  33. package/dist/leader-thread/mod.js +1 -1
  34. package/dist/leader-thread/mod.js.map +1 -1
  35. package/dist/leader-thread/mutationlog.d.ts +19 -3
  36. package/dist/leader-thread/mutationlog.d.ts.map +1 -1
  37. package/dist/leader-thread/mutationlog.js +105 -12
  38. package/dist/leader-thread/mutationlog.js.map +1 -1
  39. package/dist/leader-thread/pull-queue-set.d.ts +1 -1
  40. package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
  41. package/dist/leader-thread/pull-queue-set.js +6 -16
  42. package/dist/leader-thread/pull-queue-set.js.map +1 -1
  43. package/dist/leader-thread/recreate-db.d.ts.map +1 -1
  44. package/dist/leader-thread/recreate-db.js +4 -3
  45. package/dist/leader-thread/recreate-db.js.map +1 -1
  46. package/dist/leader-thread/types.d.ts +34 -19
  47. package/dist/leader-thread/types.d.ts.map +1 -1
  48. package/dist/leader-thread/types.js.map +1 -1
  49. package/dist/rehydrate-from-mutationlog.d.ts +5 -4
  50. package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
  51. package/dist/rehydrate-from-mutationlog.js +7 -9
  52. package/dist/rehydrate-from-mutationlog.js.map +1 -1
  53. package/dist/schema/EventId.d.ts +9 -0
  54. package/dist/schema/EventId.d.ts.map +1 -1
  55. package/dist/schema/EventId.js +22 -2
  56. package/dist/schema/EventId.js.map +1 -1
  57. package/dist/schema/MutationEvent.d.ts +78 -25
  58. package/dist/schema/MutationEvent.d.ts.map +1 -1
  59. package/dist/schema/MutationEvent.js +25 -12
  60. package/dist/schema/MutationEvent.js.map +1 -1
  61. package/dist/schema/schema.js +1 -1
  62. package/dist/schema/schema.js.map +1 -1
  63. package/dist/schema/system-tables.d.ts +67 -0
  64. package/dist/schema/system-tables.d.ts.map +1 -1
  65. package/dist/schema/system-tables.js +12 -1
  66. package/dist/schema/system-tables.js.map +1 -1
  67. package/dist/sync/ClientSessionSyncProcessor.d.ts +9 -1
  68. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  69. package/dist/sync/ClientSessionSyncProcessor.js +25 -19
  70. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  71. package/dist/sync/sync.d.ts +6 -5
  72. package/dist/sync/sync.d.ts.map +1 -1
  73. package/dist/sync/sync.js.map +1 -1
  74. package/dist/sync/syncstate.d.ts +47 -71
  75. package/dist/sync/syncstate.d.ts.map +1 -1
  76. package/dist/sync/syncstate.js +136 -139
  77. package/dist/sync/syncstate.js.map +1 -1
  78. package/dist/sync/syncstate.test.js +203 -284
  79. package/dist/sync/syncstate.test.js.map +1 -1
  80. package/dist/version.d.ts +1 -1
  81. package/dist/version.js +1 -1
  82. package/package.json +2 -2
  83. package/src/adapter-types.ts +11 -13
  84. package/src/devtools/devtools-messages-common.ts +9 -0
  85. package/src/devtools/devtools-messages-leader.ts +1 -2
  86. package/src/leader-thread/LeaderSyncProcessor.ts +457 -351
  87. package/src/leader-thread/apply-mutation.ts +81 -71
  88. package/src/leader-thread/leader-worker-devtools.ts +5 -7
  89. package/src/leader-thread/make-leader-thread-layer.ts +60 -53
  90. package/src/leader-thread/mod.ts +1 -1
  91. package/src/leader-thread/mutationlog.ts +166 -13
  92. package/src/leader-thread/recreate-db.ts +4 -3
  93. package/src/leader-thread/types.ts +33 -23
  94. package/src/rehydrate-from-mutationlog.ts +12 -12
  95. package/src/schema/EventId.ts +26 -2
  96. package/src/schema/MutationEvent.ts +32 -16
  97. package/src/schema/schema.ts +1 -1
  98. package/src/schema/system-tables.ts +20 -1
  99. package/src/sync/ClientSessionSyncProcessor.ts +35 -23
  100. package/src/sync/sync.ts +6 -9
  101. package/src/sync/syncstate.test.ts +228 -315
  102. package/src/sync/syncstate.ts +202 -187
  103. package/src/version.ts +1 -1
  104. package/tmp/pack.tgz +0 -0
  105. package/src/leader-thread/pull-queue-set.ts +0 -67
@@ -17,7 +17,6 @@ class TestEvent extends MutationEvent.EncodedWithMeta {
17
17
  parentId: EventId.make(parentId),
18
18
  mutation: 'a',
19
19
  args: payload,
20
-
21
20
  clientId: 'static-local-id',
22
21
  sessionId: 'static-session-id',
23
22
  })
@@ -32,14 +31,13 @@ class TestEvent extends MutationEvent.EncodedWithMeta {
32
31
  // toString = () => this.toJSON()
33
32
  }
34
33
 
35
- const e_r_1 = new TestEvent({ global: -1, client: 1 }, EventId.ROOT, 'a', true)
36
- const e_0_0 = new TestEvent({ global: 0, client: 0 }, EventId.ROOT, 'a', false)
37
- const e_0_1 = new TestEvent({ global: 0, client: 1 }, e_0_0.id, 'a', true)
38
- const e_0_2 = new TestEvent({ global: 0, client: 2 }, e_0_1.id, 'a', true)
39
- const e_0_3 = new TestEvent({ global: 0, client: 3 }, e_0_2.id, 'a', true)
40
- const e_1_0 = new TestEvent({ global: 1, client: 0 }, e_0_0.id, 'a', false)
41
- const e_1_1 = new TestEvent({ global: 1, client: 1 }, e_1_0.id, 'a', true)
42
- const e_2_0 = new TestEvent({ global: 2, client: 0 }, e_1_0.id, 'a', false)
34
+ const e0_1 = new TestEvent({ global: 0, client: 1 }, EventId.ROOT, 'a', true)
35
+ const e1_0 = new TestEvent({ global: 1, client: 0 }, EventId.ROOT, 'a', false)
36
+ const e1_1 = new TestEvent({ global: 1, client: 1 }, e1_0.id, 'a', true)
37
+ const e1_2 = new TestEvent({ global: 1, client: 2 }, e1_1.id, 'a', true)
38
+ const e1_3 = new TestEvent({ global: 1, client: 3 }, e1_2.id, 'a', true)
39
+ const e2_0 = new TestEvent({ global: 2, client: 0 }, e1_0.id, 'a', false)
40
+ const e2_1 = new TestEvent({ global: 2, client: 1 }, e2_0.id, 'a', true)
43
41
 
44
42
  const isEqualEvent = MutationEvent.isEqualEncoded
45
43
 
@@ -47,7 +45,7 @@ const isClientEvent = (event: MutationEvent.EncodedWithMeta) => (event as TestEv
47
45
 
48
46
  describe('syncstate', () => {
49
47
  describe('merge', () => {
50
- const update = ({
48
+ const merge = ({
51
49
  syncState,
52
50
  payload,
53
51
  ignoreClientEvents = false,
@@ -57,322 +55,264 @@ describe('syncstate', () => {
57
55
  ignoreClientEvents?: boolean
58
56
  }) => SyncState.merge({ syncState, payload, isClientEvent, isEqualEvent, ignoreClientEvents })
59
57
 
60
- describe.each([{ trimRollbackUntil: false }, { trimRollbackUntil: true }])(
61
- 'upstream-rebase (trimRollbackUntil: $trimRollbackUntil)',
62
- ({ trimRollbackUntil }) => {
63
- it('should rollback until start', () => {
64
- const syncState = new SyncState.SyncState({
65
- pending: [e_1_0],
66
- rollbackTail: [e_0_0, e_0_1],
67
- upstreamHead: EventId.ROOT,
68
- localHead: e_1_0.id,
69
- })
70
- const e_0_0_e_1_0 = e_0_0.rebase_(e_1_0.id)
71
- const e_0_1_e_1_1 = e_0_1.rebase_(e_0_0_e_1_0.id)
72
- const result = update({
73
- syncState,
74
- payload: {
75
- _tag: 'upstream-rebase',
76
- rollbackUntil: e_0_0.id,
77
- newEvents: [e_0_0_e_1_0, e_0_1_e_1_1],
78
- trimRollbackUntil: trimRollbackUntil ? e_0_1_e_1_1.id : undefined,
79
- },
80
- })
81
- const e_1_0_e_2_0 = e_1_0.rebase_(e_0_0_e_1_0.id)
82
- expectRebase(result)
83
- expectEventArraysEqual(result.newSyncState.pending, [e_1_0_e_2_0])
84
- if (trimRollbackUntil) {
85
- expectEventArraysEqual(result.newSyncState.rollbackTail, [])
86
- } else {
87
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0_e_1_0, e_0_1_e_1_1])
88
- }
89
- expect(result.newSyncState.upstreamHead).toMatchObject(e_0_1_e_1_1.id)
90
- expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_2_0.id)
91
- expectEventArraysEqual(result.newEvents, [e_0_0_e_1_0, e_0_1_e_1_1, e_1_0_e_2_0])
92
- expectEventArraysEqual(result.eventsToRollback, [e_0_0, e_0_1, e_1_0])
93
- })
94
-
95
- it('should rollback only to specified point', () => {
96
- const syncState = new SyncState.SyncState({
97
- pending: [e_1_0],
98
- rollbackTail: [e_0_0, e_0_1],
99
- upstreamHead: EventId.ROOT,
100
- localHead: e_1_0.id,
101
- })
102
- const e_0_1_e_1_0 = e_0_1.rebase_(e_0_0.id)
103
- const result = update({
104
- syncState,
105
- payload: {
106
- _tag: 'upstream-rebase',
107
- rollbackUntil: e_0_1.id,
108
- newEvents: [e_0_1_e_1_0],
109
- trimRollbackUntil: trimRollbackUntil ? e_0_0.id : undefined,
110
- },
111
- })
112
- const e_1_0_e_2_0 = e_1_0.rebase_(e_0_1_e_1_0.id)
113
- expectRebase(result)
114
- expectEventArraysEqual(result.newSyncState.pending, [e_1_0_e_2_0])
115
- if (trimRollbackUntil) {
116
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_1_e_1_0])
117
- } else {
118
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0, e_0_1_e_1_0])
119
- }
120
- expect(result.newSyncState.upstreamHead).toMatchObject(e_0_1_e_1_0.id)
121
- expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_2_0.id)
122
- expectEventArraysEqual(result.newEvents, [e_0_1_e_1_0, e_1_0_e_2_0])
123
- expectEventArraysEqual(result.eventsToRollback, [e_0_1, e_1_0])
124
- })
125
-
126
- it('should work for empty pending', () => {
127
- const syncState = new SyncState.SyncState({
128
- pending: [],
129
- rollbackTail: [e_0_0],
130
- upstreamHead: EventId.ROOT,
131
- localHead: e_0_0.id,
132
- })
133
- const result = update({
134
- syncState,
135
- payload: { _tag: 'upstream-rebase', rollbackUntil: e_0_0.id, newEvents: [e_1_0] },
136
- })
137
- expectRebase(result)
138
- expectEventArraysEqual(result.newSyncState.pending, [])
139
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_1_0])
140
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
141
- expect(result.newSyncState.localHead).toMatchObject(e_1_0.id)
142
- expect(result.newEvents).toStrictEqual([e_1_0])
143
- })
144
-
145
- it('should fail for empty rollback tail', () => {
146
- const syncState = new SyncState.SyncState({
147
- pending: [],
148
- rollbackTail: [],
149
- upstreamHead: EventId.ROOT,
150
- localHead: e_0_0.id,
151
- })
152
- const result = update({
153
- syncState,
154
- payload: { _tag: 'upstream-rebase', rollbackUntil: e_0_0.id, newEvents: [e_1_0] },
155
- })
156
- expect(result).toMatchObject({ _tag: 'unexpected-error' })
58
+ describe('upstream-rebase', () => {
59
+ it('should rollback until start', () => {
60
+ const syncState = new SyncState.SyncState({
61
+ pending: [e2_0],
62
+ upstreamHead: EventId.ROOT,
63
+ localHead: e2_0.id,
64
+ })
65
+ const e1_0_e2_0 = e1_0.rebase_(e2_0.id)
66
+ const e1_1_e2_1 = e1_1.rebase_(e1_0_e2_0.id)
67
+ const result = merge({
68
+ syncState,
69
+ payload: SyncState.PayloadUpstreamRebase.make({
70
+ rollbackEvents: [e1_0, e1_1],
71
+ newEvents: [e1_0_e2_0, e1_1_e2_1],
72
+ }),
73
+ })
74
+ const e2_0_e3_0 = e2_0.rebase_(e1_0_e2_0.id)
75
+ expectRebase(result)
76
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0])
77
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1_e2_1.id)
78
+ expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.id)
79
+ expectEventArraysEqual(result.newEvents, [e1_0_e2_0, e1_1_e2_1, e2_0_e3_0])
80
+ expectEventArraysEqual(result.rollbackEvents, [e1_0, e1_1, e2_0])
81
+ })
82
+
83
+ it('should rollback only to specified point', () => {
84
+ const syncState = new SyncState.SyncState({
85
+ pending: [e2_0],
86
+ upstreamHead: EventId.ROOT,
87
+ localHead: e2_0.id,
88
+ })
89
+ const e1_1_e2_0 = e1_1.rebase_(e1_0.id)
90
+ const result = merge({
91
+ syncState,
92
+ payload: SyncState.PayloadUpstreamRebase.make({
93
+ newEvents: [e1_1_e2_0],
94
+ rollbackEvents: [e1_1],
95
+ }),
157
96
  })
97
+ const e2_0_e3_0 = e2_0.rebase_(e1_1_e2_0.id)
98
+ expectRebase(result)
99
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0])
100
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1_e2_0.id)
101
+ expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.id)
102
+ expectEventArraysEqual(result.newEvents, [e1_1_e2_0, e2_0_e3_0])
103
+ expectEventArraysEqual(result.rollbackEvents, [e1_1, e2_0])
104
+ })
158
105
 
159
- it('should work for empty incoming', () => {
160
- const syncState = new SyncState.SyncState({
161
- pending: [],
162
- rollbackTail: [e_0_0],
163
- upstreamHead: EventId.ROOT,
164
- localHead: e_0_0.id,
165
- })
166
- const result = update({
167
- syncState,
168
- payload: { _tag: 'upstream-rebase', rollbackUntil: e_0_0.id, newEvents: [] },
169
- })
170
- expectRebase(result)
171
- expectEventArraysEqual(result.newSyncState.pending, [])
172
- expectEventArraysEqual(result.newSyncState.rollbackTail, [])
173
- expect(result.newSyncState.upstreamHead).toMatchObject(EventId.ROOT)
174
- expect(result.newSyncState.localHead).toMatchObject(EventId.ROOT)
175
- expect(result.newEvents).toStrictEqual([])
106
+ it('should work for empty pending', () => {
107
+ const syncState = new SyncState.SyncState({
108
+ pending: [],
109
+ upstreamHead: EventId.ROOT,
110
+ localHead: e1_0.id,
176
111
  })
177
- },
178
- )
112
+ const result = merge({
113
+ syncState,
114
+ payload: SyncState.PayloadUpstreamRebase.make({ rollbackEvents: [e1_0], newEvents: [e2_0] }),
115
+ })
116
+ expectRebase(result)
117
+ expectEventArraysEqual(result.newSyncState.pending, [])
118
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id)
119
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.id)
120
+ expect(result.newEvents).toStrictEqual([e2_0])
121
+ })
122
+ })
179
123
 
180
124
  describe('upstream-advance: advance', () => {
181
125
  it('should throw error if newEvents are not sorted in ascending order by eventId (client)', () => {
182
126
  const syncState = new SyncState.SyncState({
183
- pending: [e_0_0],
184
- rollbackTail: [],
127
+ pending: [e1_0],
185
128
  upstreamHead: EventId.ROOT,
186
- localHead: e_0_0.id,
129
+ localHead: e1_0.id,
187
130
  })
188
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_0] } })
131
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_1, e1_0] } })
189
132
  expect(result).toMatchObject({ _tag: 'unexpected-error' })
190
133
  })
191
134
 
192
135
  it('should throw error if newEvents are not sorted in ascending order by eventId (global)', () => {
193
136
  const syncState = new SyncState.SyncState({
194
- pending: [e_0_0],
195
- rollbackTail: [],
137
+ pending: [e1_0],
196
138
  upstreamHead: EventId.ROOT,
197
- localHead: e_0_0.id,
139
+ localHead: e1_0.id,
198
140
  })
199
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0, e_0_0] } })
141
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e2_0, e1_0] } })
200
142
  expect(result).toMatchObject({ _tag: 'unexpected-error' })
201
143
  })
202
144
 
203
145
  it('should throw error if incoming event is < expected upstream head', () => {
204
146
  const syncState = new SyncState.SyncState({
205
147
  pending: [],
206
- rollbackTail: [],
207
- upstreamHead: e_1_0.id,
208
- localHead: e_1_0.id,
148
+ upstreamHead: e2_0.id,
149
+ localHead: e2_0.id,
209
150
  })
210
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
151
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } })
211
152
  expect(result).toMatchObject({ _tag: 'unexpected-error' })
212
153
  })
213
154
 
214
155
  it('should throw error if incoming event is = expected upstream head', () => {
215
156
  const syncState = new SyncState.SyncState({
216
157
  pending: [],
217
- rollbackTail: [],
218
- upstreamHead: e_1_0.id,
219
- localHead: e_1_0.id,
158
+ upstreamHead: e2_0.id,
159
+ localHead: e2_0.id,
220
160
  })
221
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } })
161
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e2_0] } })
222
162
  expect(result).toMatchObject({ _tag: 'unexpected-error' })
223
163
  })
224
164
 
225
- it('should throw if the parent id of the first incoming event is unknown', () => {
165
+ it('should confirm pending event when receiving matching event', () => {
226
166
  const syncState = new SyncState.SyncState({
227
- pending: [],
228
- rollbackTail: [e_0_0],
167
+ pending: [e1_0],
229
168
  upstreamHead: EventId.ROOT,
230
- localHead: e_0_0.id,
169
+ localHead: e1_0.id,
231
170
  })
232
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_2_0] } })
233
- expect(result).toMatchObject({ _tag: 'unexpected-error' })
171
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } })
172
+
173
+ expectAdvance(result)
174
+ expectEventArraysEqual(result.newSyncState.pending, [])
175
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id)
176
+ expect(result.newSyncState.localHead).toMatchObject(e1_0.id)
177
+ expectEventArraysEqual(result.newEvents, [])
178
+ expectEventArraysEqual(result.confirmedEvents, [e1_0])
234
179
  })
235
180
 
236
- it('should acknowledge pending event when receiving matching event', () => {
181
+ it('should confirm partial pending event when receiving matching event', () => {
237
182
  const syncState = new SyncState.SyncState({
238
- pending: [e_0_0],
239
- rollbackTail: [],
183
+ pending: [e1_0, e2_0],
240
184
  upstreamHead: EventId.ROOT,
241
- localHead: e_0_0.id,
185
+ localHead: e2_0.id,
242
186
  })
243
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
187
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } })
244
188
 
245
189
  expectAdvance(result)
246
- expectEventArraysEqual(result.newSyncState.pending, [])
247
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0])
248
- expect(result.newSyncState.upstreamHead).toMatchObject(e_0_0.id)
249
- expect(result.newSyncState.localHead).toMatchObject(e_0_0.id)
250
- expect(result.newEvents).toStrictEqual([])
190
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0])
191
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id)
192
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.id)
193
+ expectEventArraysEqual(result.newEvents, [])
194
+ expectEventArraysEqual(result.confirmedEvents, [e1_0])
251
195
  })
252
196
 
253
- it('should acknowledge partial pending event when receiving matching event', () => {
197
+ it('should confirm pending event and add new event', () => {
254
198
  const syncState = new SyncState.SyncState({
255
- pending: [e_0_0, e_1_0],
256
- rollbackTail: [],
199
+ pending: [e1_0],
257
200
  upstreamHead: EventId.ROOT,
258
- localHead: e_1_0.id,
201
+ localHead: e1_0.id,
259
202
  })
260
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
203
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0, e1_1] } })
261
204
 
262
205
  expectAdvance(result)
263
- expectEventArraysEqual(result.newSyncState.pending, [e_1_0])
264
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0])
265
- expect(result.newSyncState.upstreamHead).toMatchObject(e_0_0.id)
266
- expect(result.newSyncState.localHead).toMatchObject(e_1_0.id)
267
- expect(result.newEvents).toStrictEqual([])
206
+ expectEventArraysEqual(result.newSyncState.pending, [])
207
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1.id)
208
+ expect(result.newSyncState.localHead).toMatchObject(e1_1.id)
209
+ expect(result.newEvents).toStrictEqual([e1_1])
210
+ expectEventArraysEqual(result.confirmedEvents, [e1_0])
268
211
  })
269
212
 
270
- it('should acknowledge pending event and add new event', () => {
213
+ it('should confirm pending event and add multiple new events', () => {
271
214
  const syncState = new SyncState.SyncState({
272
- pending: [e_0_0],
273
- rollbackTail: [],
274
- upstreamHead: EventId.ROOT,
275
- localHead: e_0_0.id,
215
+ pending: [e1_1],
216
+ upstreamHead: e1_0.id,
217
+ localHead: e1_1.id,
218
+ })
219
+ const result = merge({
220
+ syncState,
221
+ payload: { _tag: 'upstream-advance', newEvents: [e1_1, e1_2, e1_3, e2_0, e2_1] },
276
222
  })
277
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0, e_0_1] } })
278
223
 
279
224
  expectAdvance(result)
280
225
  expectEventArraysEqual(result.newSyncState.pending, [])
281
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0, e_0_1])
282
- expect(result.newSyncState.upstreamHead).toMatchObject(e_0_1.id)
283
- expect(result.newSyncState.localHead).toMatchObject(e_0_1.id)
284
- expect(result.newEvents).toStrictEqual([e_0_1])
226
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_1.id)
227
+ expect(result.newSyncState.localHead).toMatchObject(e2_1.id)
228
+ expect(result.newEvents).toStrictEqual([e1_2, e1_3, e2_0, e2_1])
229
+ expectEventArraysEqual(result.confirmedEvents, [e1_1])
285
230
  })
286
231
 
287
- it('should acknowledge pending event and add multiple new events', () => {
232
+ it('should confirm pending global event while keep pending client events', () => {
288
233
  const syncState = new SyncState.SyncState({
289
- pending: [e_0_1],
290
- rollbackTail: [],
291
- upstreamHead: e_0_0.id,
292
- localHead: e_0_1.id,
234
+ pending: [e1_0, e1_1],
235
+ upstreamHead: EventId.ROOT,
236
+ localHead: e1_1.id,
293
237
  })
294
- const result = update({
238
+ const result = merge({
295
239
  syncState,
296
- payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_2, e_0_3, e_1_0, e_1_1] },
240
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
297
241
  })
298
242
 
299
243
  expectAdvance(result)
300
- expectEventArraysEqual(result.newSyncState.pending, [])
301
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_1, e_0_2, e_0_3, e_1_0, e_1_1])
302
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_1.id)
303
- expect(result.newSyncState.localHead).toMatchObject(e_1_1.id)
304
- expect(result.newEvents).toStrictEqual([e_0_2, e_0_3, e_1_0, e_1_1])
244
+ expectEventArraysEqual(result.newSyncState.pending, [e1_1])
245
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id)
246
+ expect(result.newSyncState.localHead).toMatchObject(e1_1.id)
247
+ expectEventArraysEqual(result.newEvents, [])
248
+ expectEventArraysEqual(result.confirmedEvents, [e1_0])
305
249
  })
306
250
 
307
251
  it('should ignore client events (incoming is subset of pending)', () => {
308
252
  const syncState = new SyncState.SyncState({
309
- pending: [e_r_1, e_0_0],
310
- rollbackTail: [],
253
+ pending: [e0_1, e1_0],
311
254
  upstreamHead: EventId.ROOT,
312
- localHead: e_0_0.id,
255
+ localHead: e1_0.id,
313
256
  })
314
- const result = update({
257
+ const result = merge({
315
258
  syncState,
316
- payload: { _tag: 'upstream-advance', newEvents: [e_0_0] },
259
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
317
260
  ignoreClientEvents: true,
318
261
  })
319
262
  expectAdvance(result)
320
263
  expectEventArraysEqual(result.newSyncState.pending, [])
321
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_r_1, e_0_0])
322
- expect(result.newSyncState.upstreamHead).toMatchObject(e_0_0.id)
323
- expect(result.newSyncState.localHead).toMatchObject(e_0_0.id)
324
- expect(result.newEvents).toStrictEqual([])
264
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id)
265
+ expect(result.newSyncState.localHead).toMatchObject(e1_0.id)
266
+ expectEventArraysEqual(result.newEvents, [])
267
+ expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0])
325
268
  })
326
269
 
327
270
  it('should ignore client events (incoming is subset of pending case 2)', () => {
328
271
  const syncState = new SyncState.SyncState({
329
- pending: [e_r_1, e_0_0, e_1_0],
330
- rollbackTail: [],
272
+ pending: [e0_1, e1_0, e2_0],
331
273
  upstreamHead: EventId.ROOT,
332
- localHead: e_0_0.id,
274
+ localHead: e1_0.id,
333
275
  })
334
- const result = update({
276
+ const result = merge({
335
277
  syncState,
336
- payload: { _tag: 'upstream-advance', newEvents: [e_0_0] },
278
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0] },
337
279
  ignoreClientEvents: true,
338
280
  })
339
281
  expectAdvance(result)
340
- expectEventArraysEqual(result.newSyncState.pending, [e_1_0])
341
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_r_1, e_0_0])
342
- expect(result.newSyncState.upstreamHead).toMatchObject(e_0_0.id)
343
- expect(result.newSyncState.localHead).toMatchObject(e_1_0.id)
344
- expect(result.newEvents).toStrictEqual([])
282
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0])
283
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_0.id)
284
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.id)
285
+ expectEventArraysEqual(result.newEvents, [])
286
+ expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0])
345
287
  })
346
288
 
347
289
  it('should ignore client events (incoming goes beyond pending)', () => {
348
290
  const syncState = new SyncState.SyncState({
349
- pending: [e_r_1, e_0_0, e_0_1],
350
- rollbackTail: [],
291
+ pending: [e0_1, e1_0, e1_1],
351
292
  upstreamHead: EventId.ROOT,
352
- localHead: e_0_1.id,
293
+ localHead: e1_1.id,
353
294
  })
354
- const result = update({
295
+ const result = merge({
355
296
  syncState,
356
- payload: { _tag: 'upstream-advance', newEvents: [e_0_0, e_1_0] },
297
+ payload: { _tag: 'upstream-advance', newEvents: [e1_0, e2_0] },
357
298
  ignoreClientEvents: true,
358
299
  })
359
300
 
360
301
  expectAdvance(result)
361
302
  expectEventArraysEqual(result.newSyncState.pending, [])
362
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_r_1, e_0_0, e_0_1, e_1_0])
363
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
364
- expect(result.newSyncState.localHead).toMatchObject(e_1_0.id)
365
- expect(result.newEvents).toStrictEqual([e_1_0])
303
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id)
304
+ expect(result.newSyncState.localHead).toMatchObject(e2_0.id)
305
+ expect(result.newEvents).toStrictEqual([e2_0])
306
+ expectEventArraysEqual(result.confirmedEvents, [e0_1, e1_0, e1_1])
366
307
  })
367
308
 
368
309
  it('should fail if incoming event is ≤ local head', () => {
369
310
  const syncState = new SyncState.SyncState({
370
311
  pending: [],
371
- rollbackTail: [],
372
- upstreamHead: e_1_0.id,
373
- localHead: e_1_0.id,
312
+ upstreamHead: e2_0.id,
313
+ localHead: e2_0.id,
374
314
  })
375
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
315
+ const result = merge({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e1_0] } })
376
316
  expect(result).toMatchObject({ _tag: 'unexpected-error' })
377
317
  })
378
318
  })
@@ -380,165 +320,138 @@ describe('syncstate', () => {
380
320
  describe('upstream-advance: rebase', () => {
381
321
  it('should rebase single client event to end', () => {
382
322
  const syncState = new SyncState.SyncState({
383
- pending: [e_0_0],
384
- rollbackTail: [],
385
- upstreamHead: EventId.ROOT,
386
- localHead: e_0_0.id,
387
- })
388
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_1] } })
389
-
390
- const e_0_0_e_0_2 = e_0_0.rebase_(e_0_1.id)
391
-
392
- expectRebase(result)
393
- expectEventArraysEqual(result.newSyncState.pending, [e_0_0_e_0_2])
394
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_1])
395
- expect(result.newSyncState.upstreamHead).toMatchObject(e_0_1.id)
396
- expect(result.newSyncState.localHead).toMatchObject(e_0_0_e_0_2.id)
397
- expectEventArraysEqual(result.eventsToRollback, [e_0_0])
398
- expectEventArraysEqual(result.newEvents, [e_0_1, e_0_0_e_0_2])
399
- })
400
-
401
- it('should rebase different event with same id (no rollback tail)', () => {
402
- const e_0_0_b = new TestEvent({ global: 0, client: 0 }, EventId.ROOT, '0_0_b', true)
403
- const syncState = new SyncState.SyncState({
404
- pending: [e_0_0_b],
405
- rollbackTail: [],
323
+ pending: [e1_0],
406
324
  upstreamHead: EventId.ROOT,
407
- localHead: e_0_0_b.id,
325
+ localHead: e1_0.id,
408
326
  })
409
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
327
+ const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1] }) })
410
328
 
411
- const e_0_0_e_1_0 = e_0_0_b.rebase_(e_0_0.id)
329
+ const e1_0_e1_2 = e1_0.rebase_(e1_1.id)
412
330
 
413
331
  expectRebase(result)
414
- expectEventArraysEqual(result.newSyncState.pending, [e_0_0_e_1_0])
415
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0])
416
- expectEventArraysEqual(result.newEvents, [e_0_0, e_0_0_e_1_0])
417
- expectEventArraysEqual(result.eventsToRollback, [e_0_0_b])
418
- expect(result.newSyncState.upstreamHead).toMatchObject(e_0_0.id)
419
- expect(result.newSyncState.localHead).toMatchObject(e_0_0_e_1_0.id)
332
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0_e1_2])
333
+ expect(result.newSyncState.upstreamHead).toMatchObject(e1_1.id)
334
+ expect(result.newSyncState.localHead).toMatchObject(e1_0_e1_2.id)
335
+ expectEventArraysEqual(result.rollbackEvents, [e1_0])
336
+ expectEventArraysEqual(result.newEvents, [e1_1, e1_0_e1_2])
420
337
  })
421
338
 
422
339
  it('should rebase different event with same id', () => {
423
- const e_1_0_b = new TestEvent({ global: 1, client: 0 }, e_0_0.id, '1_0_b', false)
340
+ const e2_0_b = new TestEvent({ global: 1, client: 0 }, e1_0.id, '1_0_b', false)
424
341
  const syncState = new SyncState.SyncState({
425
- pending: [e_1_0_b],
426
- rollbackTail: [e_0_0, e_0_1],
342
+ pending: [e2_0_b],
427
343
  upstreamHead: EventId.ROOT,
428
- localHead: e_1_0_b.id,
344
+ localHead: e2_0_b.id,
429
345
  })
430
- const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } })
431
- const e_1_0_e_2_0 = e_1_0_b.rebase_(e_1_0.id)
346
+ const result = merge({ syncState, payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e2_0] }) })
347
+ const e2_0_e3_0 = e2_0_b.rebase_(e2_0.id)
432
348
 
433
349
  expectRebase(result)
434
- expectEventArraysEqual(result.newSyncState.pending, [e_1_0_e_2_0])
435
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0, e_0_1, e_1_0])
436
- expectEventArraysEqual(result.newEvents, [e_1_0, e_1_0_e_2_0])
437
- expectEventArraysEqual(result.eventsToRollback, [e_0_0, e_0_1, e_1_0_b])
438
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
439
- expect(result.newSyncState.localHead).toMatchObject(e_1_0_e_2_0.id)
350
+ expectEventArraysEqual(result.newSyncState.pending, [e2_0_e3_0])
351
+ expectEventArraysEqual(result.newEvents, [e2_0, e2_0_e3_0])
352
+ expectEventArraysEqual(result.rollbackEvents, [e2_0_b])
353
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id)
354
+ expect(result.newSyncState.localHead).toMatchObject(e2_0_e3_0.id)
440
355
  })
441
356
 
442
357
  it('should rebase single client event to end (more incoming events)', () => {
443
358
  const syncState = new SyncState.SyncState({
444
- pending: [e_0_0],
445
- rollbackTail: [],
359
+ pending: [e1_0],
446
360
  upstreamHead: EventId.ROOT,
447
- localHead: e_0_0.id,
361
+ localHead: e1_0.id,
448
362
  })
449
- const result = update({
363
+ const result = merge({
450
364
  syncState,
451
- payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_2, e_0_3, e_1_0] },
365
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1, e1_2, e1_3, e2_0] }),
452
366
  })
453
367
 
454
- const e_0_0_e_2_0 = e_0_0.rebase_(e_1_0.id)
368
+ const e1_0_e3_0 = e1_0.rebase_(e2_0.id)
455
369
 
456
370
  expectRebase(result)
457
- expectEventArraysEqual(result.newSyncState.pending, [e_0_0_e_2_0])
458
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_1, e_0_2, e_0_3, e_1_0])
459
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
460
- expect(result.newSyncState.localHead).toMatchObject(e_0_0_e_2_0.id)
371
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0_e3_0])
372
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id)
373
+ expect(result.newSyncState.localHead).toMatchObject(e1_0_e3_0.id)
461
374
  })
462
375
 
463
376
  it('should only rebase divergent events when first event matches', () => {
464
377
  const syncState = new SyncState.SyncState({
465
- pending: [e_0_0, e_0_1],
466
- rollbackTail: [],
378
+ pending: [e1_0, e1_1],
467
379
  upstreamHead: EventId.ROOT,
468
- localHead: e_0_0.id,
380
+ localHead: e1_0.id,
469
381
  })
470
- const result = update({
382
+ const result = merge({
471
383
  syncState,
472
- payload: { _tag: 'upstream-advance', newEvents: [e_0_0, e_0_2, e_0_3, e_1_0] },
384
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_0, e1_2, e1_3, e2_0] }),
473
385
  })
474
386
 
475
- const e_0_1_e_1_1 = e_0_1.rebase_(e_1_0.id)
387
+ const e1_1_e2_1 = e1_1.rebase_(e2_0.id)
476
388
 
477
389
  expectRebase(result)
478
- expectEventArraysEqual(result.newSyncState.pending, [e_0_1_e_1_1])
479
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_0, e_0_2, e_0_3, e_1_0])
480
- expectEventArraysEqual(result.eventsToRollback, [e_0_1])
481
- expectEventArraysEqual(result.newEvents, [e_0_2, e_0_3, e_1_0, e_0_1_e_1_1])
482
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
483
- expect(result.newSyncState.localHead).toMatchObject(e_0_1_e_1_1.id)
390
+ expectEventArraysEqual(result.newSyncState.pending, [e1_1_e2_1])
391
+ expectEventArraysEqual(result.rollbackEvents, [e1_1])
392
+ expectEventArraysEqual(result.newEvents, [e1_2, e1_3, e2_0, e1_1_e2_1])
393
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id)
394
+ expect(result.newSyncState.localHead).toMatchObject(e1_1_e2_1.id)
484
395
  })
485
396
 
486
397
  it('should rebase all client events when incoming chain starts differently', () => {
487
398
  const syncState = new SyncState.SyncState({
488
- pending: [e_0_0, e_0_1],
489
- rollbackTail: [],
399
+ pending: [e1_0, e1_1],
490
400
  upstreamHead: EventId.ROOT,
491
- localHead: e_0_1.id,
401
+ localHead: e1_1.id,
492
402
  })
493
- const result = update({
403
+ const result = merge({
494
404
  syncState,
495
- payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_2, e_0_3, e_1_0] },
405
+ payload: SyncState.PayloadUpstreamAdvance.make({ newEvents: [e1_1, e1_2, e1_3, e2_0] }),
496
406
  })
497
407
 
498
- const e_0_0_e_1_1 = e_0_0.rebase_(e_1_0.id)
499
- const e_0_1_e_1_2 = e_0_1.rebase_(e_0_0_e_1_1.id)
408
+ const e1_0_e2_1 = e1_0.rebase_(e2_0.id)
409
+ const e1_1_e2_2 = e1_1.rebase_(e1_0_e2_1.id)
500
410
 
501
411
  expectRebase(result)
502
- expectEventArraysEqual(result.newSyncState.pending, [e_0_0_e_1_1, e_0_1_e_1_2])
503
- expectEventArraysEqual(result.newSyncState.rollbackTail, [e_0_1, e_0_2, e_0_3, e_1_0])
504
- 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])
505
- expectEventArraysEqual(result.eventsToRollback, [e_0_0, e_0_1])
506
- expect(result.newSyncState.upstreamHead).toMatchObject(e_1_0.id)
507
- expect(result.newSyncState.localHead).toMatchObject(e_0_1_e_1_2.id)
412
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0_e2_1, e1_1_e2_2])
413
+ expectEventArraysEqual(result.newEvents, [e1_1, e1_2, e1_3, e2_0, e1_0_e2_1, e1_1_e2_2])
414
+ expectEventArraysEqual(result.rollbackEvents, [e1_0, e1_1])
415
+ expect(result.newSyncState.upstreamHead).toMatchObject(e2_0.id)
416
+ expect(result.newSyncState.localHead).toMatchObject(e1_1_e2_2.id)
508
417
  })
509
418
 
510
419
  describe('local-push', () => {
511
420
  describe('advance', () => {
512
421
  it('should advance with new events', () => {
513
422
  const syncState = new SyncState.SyncState({
514
- pending: [e_0_0],
515
- rollbackTail: [],
423
+ pending: [e1_0],
516
424
  upstreamHead: EventId.ROOT,
517
- localHead: e_0_0.id,
425
+ localHead: e1_0.id,
426
+ })
427
+ const result = merge({
428
+ syncState,
429
+ payload: SyncState.PayloadLocalPush.make({ newEvents: [e1_1, e1_2, e1_3] }),
518
430
  })
519
- const result = update({ syncState, payload: { _tag: 'local-push', newEvents: [e_0_1, e_0_2, e_0_3] } })
520
431
 
521
432
  expectAdvance(result)
522
- expectEventArraysEqual(result.newSyncState.pending, [e_0_0, e_0_1, e_0_2, e_0_3])
523
- expectEventArraysEqual(result.newSyncState.rollbackTail, [])
433
+ expectEventArraysEqual(result.newSyncState.pending, [e1_0, e1_1, e1_2, e1_3])
524
434
  expect(result.newSyncState.upstreamHead).toMatchObject(EventId.ROOT)
525
- expect(result.newSyncState.localHead).toMatchObject(e_0_3.id)
526
- expectEventArraysEqual(result.newEvents, [e_0_1, e_0_2, e_0_3])
435
+ expect(result.newSyncState.localHead).toMatchObject(e1_3.id)
436
+ expectEventArraysEqual(result.newEvents, [e1_1, e1_2, e1_3])
437
+ expectEventArraysEqual(result.confirmedEvents, [])
527
438
  })
528
439
  })
529
440
 
530
441
  describe('reject', () => {
531
442
  it('should reject when new events are greater than pending events', () => {
532
443
  const syncState = new SyncState.SyncState({
533
- pending: [e_0_0, e_0_1],
534
- rollbackTail: [],
444
+ pending: [e1_0, e1_1],
535
445
  upstreamHead: EventId.ROOT,
536
- localHead: e_0_1.id,
446
+ localHead: e1_1.id,
447
+ })
448
+ const result = merge({
449
+ syncState,
450
+ payload: SyncState.PayloadLocalPush.make({ newEvents: [e1_1, e1_2] }),
537
451
  })
538
- const result = update({ syncState, payload: { _tag: 'local-push', newEvents: [e_0_1, e_0_2] } })
539
452
 
540
453
  expectReject(result)
541
- expect(result.expectedMinimumId).toMatchObject(e_0_2.id)
454
+ expect(result.expectedMinimumId).toMatchObject(e1_2.id)
542
455
  })
543
456
  })
544
457
  })
@@ -568,7 +481,7 @@ function expectAdvance(
568
481
  function expectRebase(
569
482
  result: typeof SyncState.MergeResult.Type,
570
483
  ): asserts result is typeof SyncState.MergeResultRebase.Type {
571
- expect(result._tag).toBe('rebase')
484
+ expect(result._tag, `Expected rebase, got ${result}`).toBe('rebase')
572
485
  }
573
486
 
574
487
  function expectReject(