@livestore/common 0.0.0-snapshot-2b8a9de3ec1a701aca891ebc2c98eb328274ae9e → 0.0.0-snapshot-2ef046b02334f52613d31dbe06af53487685edc0

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