@livestore/common 0.3.0-dev.24 → 0.3.0-dev.26

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 (50) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/adapter-types.d.ts +4 -2
  3. package/dist/adapter-types.d.ts.map +1 -1
  4. package/dist/adapter-types.js +1 -1
  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 +6 -6
  8. package/dist/devtools/devtools-messages-leader.d.ts +24 -24
  9. package/dist/leader-thread/LeaderSyncProcessor.d.ts +2 -1
  10. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  11. package/dist/leader-thread/LeaderSyncProcessor.js +39 -37
  12. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  13. package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
  14. package/dist/leader-thread/make-leader-thread-layer.js +1 -0
  15. package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
  16. package/dist/leader-thread/mutationlog.d.ts +1 -0
  17. package/dist/leader-thread/mutationlog.d.ts.map +1 -1
  18. package/dist/leader-thread/mutationlog.js +1 -0
  19. package/dist/leader-thread/mutationlog.js.map +1 -1
  20. package/dist/schema/MutationEvent.d.ts +17 -1
  21. package/dist/schema/MutationEvent.d.ts.map +1 -1
  22. package/dist/schema/MutationEvent.js +18 -2
  23. package/dist/schema/MutationEvent.js.map +1 -1
  24. package/dist/sync/ClientSessionSyncProcessor.d.ts +2 -0
  25. package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
  26. package/dist/sync/ClientSessionSyncProcessor.js +36 -33
  27. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  28. package/dist/sync/sync.d.ts +10 -0
  29. package/dist/sync/sync.d.ts.map +1 -1
  30. package/dist/sync/sync.js.map +1 -1
  31. package/dist/sync/syncstate.d.ts +38 -16
  32. package/dist/sync/syncstate.d.ts.map +1 -1
  33. package/dist/sync/syncstate.js +110 -40
  34. package/dist/sync/syncstate.js.map +1 -1
  35. package/dist/sync/syncstate.test.js +60 -29
  36. package/dist/sync/syncstate.test.js.map +1 -1
  37. package/dist/version.d.ts +1 -1
  38. package/dist/version.js +1 -1
  39. package/package.json +2 -2
  40. package/src/adapter-types.ts +4 -2
  41. package/src/leader-thread/LeaderSyncProcessor.ts +42 -38
  42. package/src/leader-thread/make-leader-thread-layer.ts +1 -0
  43. package/src/leader-thread/mutationlog.ts +1 -0
  44. package/src/schema/MutationEvent.ts +18 -2
  45. package/src/sync/ClientSessionSyncProcessor.ts +39 -33
  46. package/src/sync/sync.ts +10 -0
  47. package/src/sync/syncstate.test.ts +72 -38
  48. package/src/sync/syncstate.ts +138 -58
  49. package/src/version.ts +1 -1
  50. package/tmp/pack.tgz +0 -0
package/src/sync/sync.ts CHANGED
@@ -19,6 +19,16 @@ export type SyncOptions = {
19
19
  backend?: SyncBackendConstructor<any>
20
20
  /** @default { _tag: 'Skip' } */
21
21
  initialSyncOptions?: InitialSyncOptions
22
+ /**
23
+ * What to do if there is an error during sync.
24
+ *
25
+ * Options:
26
+ * `shutdown` will stop the sync processor and cause the app to crash.
27
+ * `ignore` will log the error and let the app continue running acting as if it was offline.
28
+ *
29
+ * @default 'ignore'
30
+ * */
31
+ onSyncError?: 'shutdown' | 'ignore'
22
32
  }
23
33
 
24
34
  export type SyncBackendConstructor<TSyncMetadata = Schema.JsonValue> = (
@@ -39,22 +39,23 @@ const e_0_2 = new TestEvent({ global: 0, client: 2 }, e_0_1.id, 'a', true)
39
39
  const e_0_3 = new TestEvent({ global: 0, client: 3 }, e_0_2.id, 'a', true)
40
40
  const e_1_0 = new TestEvent({ global: 1, client: 0 }, e_0_0.id, 'a', false)
41
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)
42
43
 
43
44
  const isEqualEvent = MutationEvent.isEqualEncoded
44
45
 
45
- const isLocalEvent = (event: MutationEvent.EncodedWithMeta) => (event as TestEvent).isLocal
46
+ const isClientEvent = (event: MutationEvent.EncodedWithMeta) => (event as TestEvent).isLocal
46
47
 
47
48
  describe('syncstate', () => {
48
- describe('updateSyncState', () => {
49
- const run = ({
49
+ describe('merge', () => {
50
+ const update = ({
50
51
  syncState,
51
52
  payload,
52
- ignoreLocalEvents = false,
53
+ ignoreClientEvents = false,
53
54
  }: {
54
55
  syncState: SyncState.SyncState
55
56
  payload: typeof SyncState.Payload.Type
56
- ignoreLocalEvents?: boolean
57
- }) => SyncState.updateSyncState({ syncState, payload, isLocalEvent, isEqualEvent, ignoreLocalEvents })
57
+ ignoreClientEvents?: boolean
58
+ }) => SyncState.merge({ syncState, payload, isClientEvent, isEqualEvent, ignoreClientEvents })
58
59
 
59
60
  describe.each([{ trimRollbackUntil: false }, { trimRollbackUntil: true }])(
60
61
  'upstream-rebase (trimRollbackUntil: $trimRollbackUntil)',
@@ -68,7 +69,7 @@ describe('syncstate', () => {
68
69
  })
69
70
  const e_0_0_e_1_0 = e_0_0.rebase_(e_1_0.id)
70
71
  const e_0_1_e_1_1 = e_0_1.rebase_(e_0_0_e_1_0.id)
71
- const result = run({
72
+ const result = update({
72
73
  syncState,
73
74
  payload: {
74
75
  _tag: 'upstream-rebase',
@@ -99,7 +100,7 @@ describe('syncstate', () => {
99
100
  localHead: e_1_0.id,
100
101
  })
101
102
  const e_0_1_e_1_0 = e_0_1.rebase_(e_0_0.id)
102
- const result = run({
103
+ const result = update({
103
104
  syncState,
104
105
  payload: {
105
106
  _tag: 'upstream-rebase',
@@ -129,7 +130,7 @@ describe('syncstate', () => {
129
130
  upstreamHead: EventId.ROOT,
130
131
  localHead: e_0_0.id,
131
132
  })
132
- const result = run({
133
+ const result = update({
133
134
  syncState,
134
135
  payload: { _tag: 'upstream-rebase', rollbackUntil: e_0_0.id, newEvents: [e_1_0] },
135
136
  })
@@ -148,7 +149,7 @@ describe('syncstate', () => {
148
149
  upstreamHead: EventId.ROOT,
149
150
  localHead: e_0_0.id,
150
151
  })
151
- const result = run({
152
+ const result = update({
152
153
  syncState,
153
154
  payload: { _tag: 'upstream-rebase', rollbackUntil: e_0_0.id, newEvents: [e_1_0] },
154
155
  })
@@ -162,7 +163,7 @@ describe('syncstate', () => {
162
163
  upstreamHead: EventId.ROOT,
163
164
  localHead: e_0_0.id,
164
165
  })
165
- const result = run({
166
+ const result = update({
166
167
  syncState,
167
168
  payload: { _tag: 'upstream-rebase', rollbackUntil: e_0_0.id, newEvents: [] },
168
169
  })
@@ -184,7 +185,7 @@ describe('syncstate', () => {
184
185
  upstreamHead: EventId.ROOT,
185
186
  localHead: e_0_0.id,
186
187
  })
187
- const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_0] } })
188
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_0] } })
188
189
  expect(result).toMatchObject({ _tag: 'unexpected-error' })
189
190
  })
190
191
 
@@ -195,7 +196,40 @@ describe('syncstate', () => {
195
196
  upstreamHead: EventId.ROOT,
196
197
  localHead: e_0_0.id,
197
198
  })
198
- const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0, e_0_0] } })
199
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0, e_0_0] } })
200
+ expect(result).toMatchObject({ _tag: 'unexpected-error' })
201
+ })
202
+
203
+ it('should throw error if incoming event is < expected upstream head', () => {
204
+ const syncState = new SyncState.SyncState({
205
+ pending: [],
206
+ rollbackTail: [],
207
+ upstreamHead: e_1_0.id,
208
+ localHead: e_1_0.id,
209
+ })
210
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
211
+ expect(result).toMatchObject({ _tag: 'unexpected-error' })
212
+ })
213
+
214
+ it('should throw error if incoming event is = expected upstream head', () => {
215
+ const syncState = new SyncState.SyncState({
216
+ pending: [],
217
+ rollbackTail: [],
218
+ upstreamHead: e_1_0.id,
219
+ localHead: e_1_0.id,
220
+ })
221
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } })
222
+ expect(result).toMatchObject({ _tag: 'unexpected-error' })
223
+ })
224
+
225
+ it('should throw if the parent id of the first incoming event is unknown', () => {
226
+ const syncState = new SyncState.SyncState({
227
+ pending: [],
228
+ rollbackTail: [e_0_0],
229
+ upstreamHead: EventId.ROOT,
230
+ localHead: e_0_0.id,
231
+ })
232
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_2_0] } })
199
233
  expect(result).toMatchObject({ _tag: 'unexpected-error' })
200
234
  })
201
235
 
@@ -206,7 +240,7 @@ describe('syncstate', () => {
206
240
  upstreamHead: EventId.ROOT,
207
241
  localHead: e_0_0.id,
208
242
  })
209
- const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
243
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
210
244
 
211
245
  expectAdvance(result)
212
246
  expectEventArraysEqual(result.newSyncState.pending, [])
@@ -223,7 +257,7 @@ describe('syncstate', () => {
223
257
  upstreamHead: EventId.ROOT,
224
258
  localHead: e_1_0.id,
225
259
  })
226
- const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
260
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
227
261
 
228
262
  expectAdvance(result)
229
263
  expectEventArraysEqual(result.newSyncState.pending, [e_1_0])
@@ -240,7 +274,7 @@ describe('syncstate', () => {
240
274
  upstreamHead: EventId.ROOT,
241
275
  localHead: e_0_0.id,
242
276
  })
243
- const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0, e_0_1] } })
277
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0, e_0_1] } })
244
278
 
245
279
  expectAdvance(result)
246
280
  expectEventArraysEqual(result.newSyncState.pending, [])
@@ -257,7 +291,7 @@ describe('syncstate', () => {
257
291
  upstreamHead: e_0_0.id,
258
292
  localHead: e_0_1.id,
259
293
  })
260
- const result = run({
294
+ const result = update({
261
295
  syncState,
262
296
  payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_2, e_0_3, e_1_0, e_1_1] },
263
297
  })
@@ -277,10 +311,10 @@ describe('syncstate', () => {
277
311
  upstreamHead: EventId.ROOT,
278
312
  localHead: e_0_0.id,
279
313
  })
280
- const result = run({
314
+ const result = update({
281
315
  syncState,
282
316
  payload: { _tag: 'upstream-advance', newEvents: [e_0_0] },
283
- ignoreLocalEvents: true,
317
+ ignoreClientEvents: true,
284
318
  })
285
319
  expectAdvance(result)
286
320
  expectEventArraysEqual(result.newSyncState.pending, [])
@@ -297,10 +331,10 @@ describe('syncstate', () => {
297
331
  upstreamHead: EventId.ROOT,
298
332
  localHead: e_0_0.id,
299
333
  })
300
- const result = run({
334
+ const result = update({
301
335
  syncState,
302
336
  payload: { _tag: 'upstream-advance', newEvents: [e_0_0] },
303
- ignoreLocalEvents: true,
337
+ ignoreClientEvents: true,
304
338
  })
305
339
  expectAdvance(result)
306
340
  expectEventArraysEqual(result.newSyncState.pending, [e_1_0])
@@ -317,10 +351,10 @@ describe('syncstate', () => {
317
351
  upstreamHead: EventId.ROOT,
318
352
  localHead: e_0_1.id,
319
353
  })
320
- const result = run({
354
+ const result = update({
321
355
  syncState,
322
356
  payload: { _tag: 'upstream-advance', newEvents: [e_0_0, e_1_0] },
323
- ignoreLocalEvents: true,
357
+ ignoreClientEvents: true,
324
358
  })
325
359
 
326
360
  expectAdvance(result)
@@ -338,7 +372,7 @@ describe('syncstate', () => {
338
372
  upstreamHead: e_1_0.id,
339
373
  localHead: e_1_0.id,
340
374
  })
341
- const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
375
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
342
376
  expect(result).toMatchObject({ _tag: 'unexpected-error' })
343
377
  })
344
378
  })
@@ -351,7 +385,7 @@ describe('syncstate', () => {
351
385
  upstreamHead: EventId.ROOT,
352
386
  localHead: e_0_0.id,
353
387
  })
354
- const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_1] } })
388
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_1] } })
355
389
 
356
390
  const e_0_0_e_0_2 = e_0_0.rebase_(e_0_1.id)
357
391
 
@@ -372,7 +406,7 @@ describe('syncstate', () => {
372
406
  upstreamHead: EventId.ROOT,
373
407
  localHead: e_0_0_b.id,
374
408
  })
375
- const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
409
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_0_0] } })
376
410
 
377
411
  const e_0_0_e_1_0 = e_0_0_b.rebase_(e_0_0.id)
378
412
 
@@ -393,7 +427,7 @@ describe('syncstate', () => {
393
427
  upstreamHead: EventId.ROOT,
394
428
  localHead: e_1_0_b.id,
395
429
  })
396
- const result = run({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } })
430
+ const result = update({ syncState, payload: { _tag: 'upstream-advance', newEvents: [e_1_0] } })
397
431
  const e_1_0_e_2_0 = e_1_0_b.rebase_(e_1_0.id)
398
432
 
399
433
  expectRebase(result)
@@ -412,7 +446,7 @@ describe('syncstate', () => {
412
446
  upstreamHead: EventId.ROOT,
413
447
  localHead: e_0_0.id,
414
448
  })
415
- const result = run({
449
+ const result = update({
416
450
  syncState,
417
451
  payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_2, e_0_3, e_1_0] },
418
452
  })
@@ -433,7 +467,7 @@ describe('syncstate', () => {
433
467
  upstreamHead: EventId.ROOT,
434
468
  localHead: e_0_0.id,
435
469
  })
436
- const result = run({
470
+ const result = update({
437
471
  syncState,
438
472
  payload: { _tag: 'upstream-advance', newEvents: [e_0_0, e_0_2, e_0_3, e_1_0] },
439
473
  })
@@ -456,7 +490,7 @@ describe('syncstate', () => {
456
490
  upstreamHead: EventId.ROOT,
457
491
  localHead: e_0_1.id,
458
492
  })
459
- const result = run({
493
+ const result = update({
460
494
  syncState,
461
495
  payload: { _tag: 'upstream-advance', newEvents: [e_0_1, e_0_2, e_0_3, e_1_0] },
462
496
  })
@@ -482,7 +516,7 @@ describe('syncstate', () => {
482
516
  upstreamHead: EventId.ROOT,
483
517
  localHead: e_0_0.id,
484
518
  })
485
- const result = run({ syncState, payload: { _tag: 'local-push', newEvents: [e_0_1, e_0_2, e_0_3] } })
519
+ const result = update({ syncState, payload: { _tag: 'local-push', newEvents: [e_0_1, e_0_2, e_0_3] } })
486
520
 
487
521
  expectAdvance(result)
488
522
  expectEventArraysEqual(result.newSyncState.pending, [e_0_0, e_0_1, e_0_2, e_0_3])
@@ -501,7 +535,7 @@ describe('syncstate', () => {
501
535
  upstreamHead: EventId.ROOT,
502
536
  localHead: e_0_1.id,
503
537
  })
504
- const result = run({ syncState, payload: { _tag: 'local-push', newEvents: [e_0_1, e_0_2] } })
538
+ const result = update({ syncState, payload: { _tag: 'local-push', newEvents: [e_0_1, e_0_2] } })
505
539
 
506
540
  expectReject(result)
507
541
  expect(result.expectedMinimumId).toMatchObject(e_0_2.id)
@@ -526,19 +560,19 @@ const expectEventArraysEqual = (
526
560
  }
527
561
 
528
562
  function expectAdvance(
529
- result: typeof SyncState.UpdateResult.Type,
530
- ): asserts result is typeof SyncState.UpdateResultAdvance.Type {
563
+ result: typeof SyncState.MergeResult.Type,
564
+ ): asserts result is typeof SyncState.MergeResultAdvance.Type {
531
565
  expect(result._tag).toBe('advance')
532
566
  }
533
567
 
534
568
  function expectRebase(
535
- result: typeof SyncState.UpdateResult.Type,
536
- ): asserts result is typeof SyncState.UpdateResultRebase.Type {
569
+ result: typeof SyncState.MergeResult.Type,
570
+ ): asserts result is typeof SyncState.MergeResultRebase.Type {
537
571
  expect(result._tag).toBe('rebase')
538
572
  }
539
573
 
540
574
  function expectReject(
541
- result: typeof SyncState.UpdateResult.Type,
542
- ): asserts result is typeof SyncState.UpdateResultReject.Type {
575
+ result: typeof SyncState.MergeResult.Type,
576
+ ): asserts result is typeof SyncState.MergeResultReject.Type {
543
577
  expect(result._tag).toBe('reject')
544
578
  }