@livestore/common 0.3.0-dev.47 → 0.3.0-dev.49

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 (154) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/adapter-types.d.ts +8 -6
  3. package/dist/adapter-types.d.ts.map +1 -1
  4. package/dist/adapter-types.js +2 -2
  5. package/dist/adapter-types.js.map +1 -1
  6. package/dist/devtools/devtools-messages-client-session.d.ts +25 -25
  7. package/dist/devtools/devtools-messages-client-session.js +3 -3
  8. package/dist/devtools/devtools-messages-client-session.js.map +1 -1
  9. package/dist/devtools/devtools-messages-common.d.ts +6 -6
  10. package/dist/devtools/devtools-messages-leader.d.ts +30 -30
  11. package/dist/devtools/devtools-messages-leader.js +3 -3
  12. package/dist/devtools/devtools-messages-leader.js.map +1 -1
  13. package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
  14. package/dist/leader-thread/LeaderSyncProcessor.js +27 -25
  15. package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
  16. package/dist/leader-thread/eventlog.d.ts +10 -10
  17. package/dist/leader-thread/eventlog.d.ts.map +1 -1
  18. package/dist/leader-thread/eventlog.js +24 -24
  19. package/dist/leader-thread/eventlog.js.map +1 -1
  20. package/dist/leader-thread/leader-worker-devtools.js +1 -1
  21. package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
  22. package/dist/leader-thread/materialize-event.d.ts +3 -3
  23. package/dist/leader-thread/materialize-event.d.ts.map +1 -1
  24. package/dist/leader-thread/materialize-event.js +19 -15
  25. package/dist/leader-thread/materialize-event.js.map +1 -1
  26. package/dist/leader-thread/types.d.ts +4 -4
  27. package/dist/leader-thread/types.d.ts.map +1 -1
  28. package/dist/make-client-session.d.ts +1 -1
  29. package/dist/make-client-session.d.ts.map +1 -1
  30. package/dist/make-client-session.js +2 -1
  31. package/dist/make-client-session.js.map +1 -1
  32. package/dist/materializer-helper.d.ts.map +1 -1
  33. package/dist/materializer-helper.js +4 -2
  34. package/dist/materializer-helper.js.map +1 -1
  35. package/dist/rematerialize-from-eventlog.js +9 -9
  36. package/dist/rematerialize-from-eventlog.js.map +1 -1
  37. package/dist/schema/EventId.d.ts +28 -28
  38. package/dist/schema/EventId.d.ts.map +1 -1
  39. package/dist/schema/EventId.js +9 -9
  40. package/dist/schema/EventId.js.map +1 -1
  41. package/dist/schema/EventId.test.js +5 -5
  42. package/dist/schema/EventId.test.js.map +1 -1
  43. package/dist/schema/EventNumber.d.ts +57 -0
  44. package/dist/schema/EventNumber.d.ts.map +1 -0
  45. package/dist/schema/EventNumber.js +82 -0
  46. package/dist/schema/EventNumber.js.map +1 -0
  47. package/dist/schema/EventNumber.test.d.ts +2 -0
  48. package/dist/schema/EventNumber.test.d.ts.map +1 -0
  49. package/dist/schema/EventNumber.test.js +11 -0
  50. package/dist/schema/EventNumber.test.js.map +1 -0
  51. package/dist/schema/EventSequenceNumber.d.ts +57 -0
  52. package/dist/schema/EventSequenceNumber.d.ts.map +1 -0
  53. package/dist/schema/EventSequenceNumber.js +82 -0
  54. package/dist/schema/EventSequenceNumber.js.map +1 -0
  55. package/dist/schema/EventSequenceNumber.test.d.ts +2 -0
  56. package/dist/schema/EventSequenceNumber.test.d.ts.map +1 -0
  57. package/dist/schema/EventSequenceNumber.test.js +11 -0
  58. package/dist/schema/EventSequenceNumber.test.js.map +1 -0
  59. package/dist/schema/LiveStoreEvent.d.ts +81 -79
  60. package/dist/schema/LiveStoreEvent.d.ts.map +1 -1
  61. package/dist/schema/LiveStoreEvent.js +31 -32
  62. package/dist/schema/LiveStoreEvent.js.map +1 -1
  63. package/dist/schema/mod.d.ts +1 -1
  64. package/dist/schema/mod.d.ts.map +1 -1
  65. package/dist/schema/mod.js +1 -1
  66. package/dist/schema/mod.js.map +1 -1
  67. package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
  68. package/dist/schema/state/sqlite/query-builder/impl.js +2 -2
  69. package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
  70. package/dist/schema/state/sqlite/query-builder/impl.test.d.ts +3 -3
  71. package/dist/schema/state/sqlite/query-builder/impl.test.js +9 -0
  72. package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
  73. package/dist/schema/state/sqlite/system-tables.d.ts +52 -52
  74. package/dist/schema/state/sqlite/system-tables.d.ts.map +1 -1
  75. package/dist/schema/state/sqlite/system-tables.js +11 -10
  76. package/dist/schema/state/sqlite/system-tables.js.map +1 -1
  77. package/dist/sync/ClientSessionSyncProcessor.js +6 -6
  78. package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
  79. package/dist/sync/next/compact-events.js +38 -35
  80. package/dist/sync/next/compact-events.js.map +1 -1
  81. package/dist/sync/next/facts.d.ts +4 -4
  82. package/dist/sync/next/facts.d.ts.map +1 -1
  83. package/dist/sync/next/facts.js +8 -8
  84. package/dist/sync/next/facts.js.map +1 -1
  85. package/dist/sync/next/history-dag-common.d.ts +4 -4
  86. package/dist/sync/next/history-dag-common.d.ts.map +1 -1
  87. package/dist/sync/next/history-dag-common.js +7 -4
  88. package/dist/sync/next/history-dag-common.js.map +1 -1
  89. package/dist/sync/next/history-dag.d.ts +0 -2
  90. package/dist/sync/next/history-dag.d.ts.map +1 -1
  91. package/dist/sync/next/history-dag.js +15 -13
  92. package/dist/sync/next/history-dag.js.map +1 -1
  93. package/dist/sync/next/rebase-events.d.ts.map +1 -1
  94. package/dist/sync/next/rebase-events.js +10 -4
  95. package/dist/sync/next/rebase-events.js.map +1 -1
  96. package/dist/sync/next/test/compact-events.calculator.test.js +13 -13
  97. package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
  98. package/dist/sync/next/test/compact-events.test.js +31 -31
  99. package/dist/sync/next/test/compact-events.test.js.map +1 -1
  100. package/dist/sync/next/test/event-fixtures.d.ts +10 -0
  101. package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
  102. package/dist/sync/next/test/event-fixtures.js +19 -13
  103. package/dist/sync/next/test/event-fixtures.js.map +1 -1
  104. package/dist/sync/sync.d.ts +11 -11
  105. package/dist/sync/sync.d.ts.map +1 -1
  106. package/dist/sync/sync.js +5 -5
  107. package/dist/sync/sync.js.map +1 -1
  108. package/dist/sync/syncstate.d.ts +18 -18
  109. package/dist/sync/syncstate.d.ts.map +1 -1
  110. package/dist/sync/syncstate.js +46 -47
  111. package/dist/sync/syncstate.js.map +1 -1
  112. package/dist/sync/syncstate.test.js +110 -110
  113. package/dist/sync/syncstate.test.js.map +1 -1
  114. package/dist/sync/validate-push-payload.d.ts +2 -2
  115. package/dist/sync/validate-push-payload.d.ts.map +1 -1
  116. package/dist/sync/validate-push-payload.js +4 -4
  117. package/dist/sync/validate-push-payload.js.map +1 -1
  118. package/dist/version.d.ts +2 -2
  119. package/dist/version.js +2 -2
  120. package/package.json +4 -4
  121. package/src/adapter-types.ts +6 -4
  122. package/src/devtools/devtools-messages-client-session.ts +3 -3
  123. package/src/devtools/devtools-messages-leader.ts +3 -3
  124. package/src/leader-thread/LeaderSyncProcessor.ts +36 -29
  125. package/src/leader-thread/eventlog.ts +36 -31
  126. package/src/leader-thread/leader-worker-devtools.ts +1 -1
  127. package/src/leader-thread/materialize-event.ts +21 -17
  128. package/src/leader-thread/types.ts +4 -4
  129. package/src/make-client-session.ts +2 -0
  130. package/src/materializer-helper.ts +5 -2
  131. package/src/rematerialize-from-eventlog.ts +10 -10
  132. package/src/schema/EventSequenceNumber.test.ts +12 -0
  133. package/src/schema/EventSequenceNumber.ts +121 -0
  134. package/src/schema/LiveStoreEvent.ts +66 -65
  135. package/src/schema/mod.ts +1 -1
  136. package/src/schema/state/sqlite/query-builder/impl.test.ts +9 -0
  137. package/src/schema/state/sqlite/query-builder/impl.ts +3 -2
  138. package/src/schema/state/sqlite/system-tables.ts +11 -10
  139. package/src/sync/ClientSessionSyncProcessor.ts +6 -6
  140. package/src/sync/next/compact-events.ts +38 -35
  141. package/src/sync/next/facts.ts +12 -9
  142. package/src/sync/next/history-dag-common.ts +9 -6
  143. package/src/sync/next/history-dag.ts +15 -16
  144. package/src/sync/next/rebase-events.ts +10 -4
  145. package/src/sync/next/test/compact-events.calculator.test.ts +13 -13
  146. package/src/sync/next/test/compact-events.test.ts +31 -31
  147. package/src/sync/next/test/event-fixtures.ts +20 -13
  148. package/src/sync/sync.ts +7 -7
  149. package/src/sync/syncstate.test.ts +112 -112
  150. package/src/sync/syncstate.ts +58 -48
  151. package/src/sync/validate-push-payload.ts +5 -5
  152. package/src/version.ts +2 -2
  153. package/src/schema/EventId.test.ts +0 -12
  154. package/src/schema/EventId.ts +0 -106
@@ -2,7 +2,7 @@ import { casesHandled, LS_DEV, shouldNeverHappen } from '@livestore/utils'
2
2
  import { Match, ReadonlyArray, Schema } from '@livestore/utils/effect'
3
3
 
4
4
  import { UnexpectedError } from '../adapter-types.js'
5
- import * as EventId from '../schema/EventId.js'
5
+ import * as EventSequenceNumber from '../schema/EventSequenceNumber.js'
6
6
  import * as LiveStoreEvent from '../schema/LiveStoreEvent.js'
7
7
 
8
8
  /**
@@ -45,14 +45,14 @@ import * as LiveStoreEvent from '../schema/LiveStoreEvent.js'
45
45
  export class SyncState extends Schema.Class<SyncState>('SyncState')({
46
46
  pending: Schema.Array(LiveStoreEvent.EncodedWithMeta),
47
47
  /** What this node expects the next upstream node to have as its own local head */
48
- upstreamHead: EventId.EventId,
48
+ upstreamHead: EventSequenceNumber.EventSequenceNumber,
49
49
  /** Equivalent to `pending.at(-1)?.id` if there are pending events */
50
- localHead: EventId.EventId,
50
+ localHead: EventSequenceNumber.EventSequenceNumber,
51
51
  }) {
52
52
  toJSON = (): any => ({
53
53
  pending: this.pending.map((e) => e.toJSON()),
54
- upstreamHead: EventId.toString(this.upstreamHead),
55
- localHead: EventId.toString(this.localHead),
54
+ upstreamHead: EventSequenceNumber.toString(this.upstreamHead),
55
+ localHead: EventSequenceNumber.toString(this.localHead),
56
56
  })
57
57
  }
58
58
 
@@ -148,13 +148,13 @@ export class MergeResultRebase extends Schema.Class<MergeResultRebase>('MergeRes
148
148
  export class MergeResultReject extends Schema.Class<MergeResultReject>('MergeResultReject')({
149
149
  _tag: Schema.Literal('reject'),
150
150
  /** The minimum id that the new events must have */
151
- expectedMinimumId: EventId.EventId,
151
+ expectedMinimumId: EventSequenceNumber.EventSequenceNumber,
152
152
  mergeContext: MergeContext,
153
153
  }) {
154
154
  toJSON = (): any => {
155
155
  return {
156
156
  _tag: this._tag,
157
- expectedMinimumId: EventId.toString(this.expectedMinimumId),
157
+ expectedMinimumId: EventSequenceNumber.toString(this.expectedMinimumId),
158
158
  mergeContext: this.mergeContext.toJSON(),
159
159
  }
160
160
  }
@@ -185,7 +185,7 @@ const unexpectedError = (cause: unknown): MergeResultUnexpectedError => {
185
185
 
186
186
  // TODO Idea: call merge recursively through hierarchy levels
187
187
  /*
188
- Idea: have a map that maps from `globalEventId` to Array<ClientEvents>
188
+ Idea: have a map that maps from `globalEventSequenceNumber` to Array<ClientEvents>
189
189
  The same applies to even further hierarchy levels
190
190
 
191
191
  TODO: possibly even keep the client events in a separate table in the client leader
@@ -214,12 +214,12 @@ export const merge = ({
214
214
  const rollbackEvents = [...payload.rollbackEvents, ...syncState.pending]
215
215
 
216
216
  // Get the last new event's ID as the new upstream head
217
- const newUpstreamHead = payload.newEvents.at(-1)?.id ?? syncState.upstreamHead
217
+ const newUpstreamHead = payload.newEvents.at(-1)?.seqNum ?? syncState.upstreamHead
218
218
 
219
219
  // Rebase pending events on top of the new events
220
220
  const rebasedPending = rebaseEvents({
221
221
  events: syncState.pending,
222
- baseEventId: newUpstreamHead,
222
+ baseEventSequenceNumber: newUpstreamHead,
223
223
  isClientEvent,
224
224
  })
225
225
 
@@ -229,7 +229,7 @@ export const merge = ({
229
229
  newSyncState: new SyncState({
230
230
  pending: rebasedPending,
231
231
  upstreamHead: newUpstreamHead,
232
- localHead: rebasedPending.at(-1)?.id ?? newUpstreamHead,
232
+ localHead: rebasedPending.at(-1)?.seqNum ?? newUpstreamHead,
233
233
  }),
234
234
  newEvents: [...payload.newEvents, ...rebasedPending],
235
235
  rollbackEvents,
@@ -256,26 +256,26 @@ export const merge = ({
256
256
  )
257
257
  }
258
258
 
259
- // Validate that newEvents are sorted in ascending order by eventId
259
+ // Validate that newEvents are sorted in ascending order by eventNum
260
260
  for (let i = 1; i < payload.newEvents.length; i++) {
261
- if (EventId.isGreaterThan(payload.newEvents[i - 1]!.id, payload.newEvents[i]!.id)) {
261
+ if (EventSequenceNumber.isGreaterThan(payload.newEvents[i - 1]!.seqNum, payload.newEvents[i]!.seqNum)) {
262
262
  return unexpectedError(
263
- `Events must be sorted in ascending order by eventId. Received: [${payload.newEvents.map((e) => EventId.toString(e.id)).join(', ')}]`,
263
+ `Events must be sorted in ascending order by event number. Received: [${payload.newEvents.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`,
264
264
  )
265
265
  }
266
266
  }
267
267
 
268
268
  // Validate that incoming events are larger than upstream head
269
269
  if (
270
- EventId.isGreaterThan(syncState.upstreamHead, payload.newEvents[0]!.id) ||
271
- EventId.isEqual(syncState.upstreamHead, payload.newEvents[0]!.id)
270
+ EventSequenceNumber.isGreaterThan(syncState.upstreamHead, payload.newEvents[0]!.seqNum) ||
271
+ EventSequenceNumber.isEqual(syncState.upstreamHead, payload.newEvents[0]!.seqNum)
272
272
  ) {
273
273
  return unexpectedError(
274
- `Incoming events must be greater than upstream head. Expected greater than: ${EventId.toString(syncState.upstreamHead)}. Received: [${payload.newEvents.map((e) => EventId.toString(e.id)).join(', ')}]`,
274
+ `Incoming events must be greater than upstream head. Expected greater than: ${EventSequenceNumber.toString(syncState.upstreamHead)}. Received: [${payload.newEvents.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`,
275
275
  )
276
276
  }
277
277
 
278
- const newUpstreamHead = payload.newEvents.at(-1)!.id
278
+ const newUpstreamHead = payload.newEvents.at(-1)!.seqNum
279
279
 
280
280
  const divergentPendingIndex = findDivergencePoint({
281
281
  existingEvents: syncState.pending,
@@ -287,8 +287,12 @@ export const merge = ({
287
287
 
288
288
  // No divergent pending events, thus we can just advance (some of) the pending events
289
289
  if (divergentPendingIndex === -1) {
290
- const pendingEventIds = new Set(syncState.pending.map((e) => `${e.id.global},${e.id.client}`))
291
- const newEvents = payload.newEvents.filter((e) => !pendingEventIds.has(`${e.id.global},${e.id.client}`))
290
+ const pendingEventSequenceNumbers = new Set(
291
+ syncState.pending.map((e) => `${e.seqNum.global},${e.seqNum.client}`),
292
+ )
293
+ const newEvents = payload.newEvents.filter(
294
+ (e) => !pendingEventSequenceNumbers.has(`${e.seqNum.global},${e.seqNum.client}`),
295
+ )
292
296
 
293
297
  // In the case where the incoming events are a subset of the pending events,
294
298
  // we need to split the pending events into two groups:
@@ -318,7 +322,8 @@ export const merge = ({
318
322
  newSyncState: new SyncState({
319
323
  pending: pendingRemaining,
320
324
  upstreamHead: newUpstreamHead,
321
- localHead: pendingRemaining.at(-1)?.id ?? EventId.max(syncState.localHead, newUpstreamHead),
325
+ localHead:
326
+ pendingRemaining.at(-1)?.seqNum ?? EventSequenceNumber.max(syncState.localHead, newUpstreamHead),
322
327
  }),
323
328
  newEvents,
324
329
  confirmedEvents: pendingMatching,
@@ -329,7 +334,7 @@ export const merge = ({
329
334
  const divergentPending = syncState.pending.slice(divergentPendingIndex)
330
335
  const rebasedPending = rebaseEvents({
331
336
  events: divergentPending,
332
- baseEventId: newUpstreamHead,
337
+ baseEventSequenceNumber: newUpstreamHead,
333
338
  isClientEvent,
334
339
  })
335
340
 
@@ -347,7 +352,7 @@ export const merge = ({
347
352
  newSyncState: new SyncState({
348
353
  pending: rebasedPending,
349
354
  upstreamHead: newUpstreamHead,
350
- localHead: rebasedPending.at(-1)!.id,
355
+ localHead: rebasedPending.at(-1)!.seqNum,
351
356
  }),
352
357
  newEvents: [...payload.newEvents.slice(divergentNewEventsIndex), ...rebasedPending],
353
358
  rollbackEvents: divergentPending,
@@ -373,10 +378,11 @@ export const merge = ({
373
378
  }
374
379
 
375
380
  const newEventsFirst = payload.newEvents.at(0)!
376
- const invalidEventId = EventId.isGreaterThan(newEventsFirst.id, syncState.localHead) === false
381
+ const invalidEventSequenceNumber =
382
+ EventSequenceNumber.isGreaterThan(newEventsFirst.seqNum, syncState.localHead) === false
377
383
 
378
- if (invalidEventId) {
379
- const expectedMinimumId = EventId.nextPair(syncState.localHead, true).id
384
+ if (invalidEventSequenceNumber) {
385
+ const expectedMinimumId = EventSequenceNumber.nextPair(syncState.localHead, true).seqNum
380
386
  return validateMergeResult(
381
387
  MergeResultReject.make({
382
388
  _tag: 'reject',
@@ -391,7 +397,7 @@ export const merge = ({
391
397
  newSyncState: new SyncState({
392
398
  pending: [...syncState.pending, ...payload.newEvents],
393
399
  upstreamHead: syncState.upstreamHead,
394
- localHead: payload.newEvents.at(-1)!.id,
400
+ localHead: payload.newEvents.at(-1)!.seqNum,
395
401
  }),
396
402
  newEvents: payload.newEvents,
397
403
  confirmedEvents: [],
@@ -436,9 +442,11 @@ export const findDivergencePoint = ({
436
442
 
437
443
  if (divergencePointWithoutClientEvents === -1) return -1
438
444
 
439
- const divergencePointEventId = existingEvents[divergencePointWithoutClientEvents]!.id
445
+ const divergencePointEventSequenceNumber = existingEvents[divergencePointWithoutClientEvents]!.seqNum
440
446
  // Now find the divergence point in the original array
441
- return existingEvents.findIndex((event) => EventId.isEqual(event.id, divergencePointEventId))
447
+ return existingEvents.findIndex((event) =>
448
+ EventSequenceNumber.isEqual(event.seqNum, divergencePointEventSequenceNumber),
449
+ )
442
450
  }
443
451
 
444
452
  return existingEvents.findIndex((existingEvent, index) => {
@@ -450,18 +458,18 @@ export const findDivergencePoint = ({
450
458
 
451
459
  const rebaseEvents = ({
452
460
  events,
453
- baseEventId,
461
+ baseEventSequenceNumber,
454
462
  isClientEvent,
455
463
  }: {
456
464
  events: ReadonlyArray<LiveStoreEvent.EncodedWithMeta>
457
- baseEventId: EventId.EventId
465
+ baseEventSequenceNumber: EventSequenceNumber.EventSequenceNumber
458
466
  isClientEvent: (event: LiveStoreEvent.EncodedWithMeta) => boolean
459
467
  }): ReadonlyArray<LiveStoreEvent.EncodedWithMeta> => {
460
- let prevEventId = baseEventId
468
+ let prevEventSequenceNumber = baseEventSequenceNumber
461
469
  return events.map((event) => {
462
470
  const isLocal = isClientEvent(event)
463
- const newEvent = event.rebase(prevEventId, isLocal)
464
- prevEventId = newEvent.id
471
+ const newEvent = event.rebase(prevEventSequenceNumber, isLocal)
472
+ prevEventSequenceNumber = newEvent.seqNum
465
473
  return newEvent
466
474
  })
467
475
  }
@@ -477,9 +485,9 @@ const _flattenMergeResults = (_updateResults: ReadonlyArray<MergeResult>) => {}
477
485
 
478
486
  const validatePayload = (payload: typeof Payload.Type) => {
479
487
  for (let i = 1; i < payload.newEvents.length; i++) {
480
- if (EventId.isGreaterThanOrEqual(payload.newEvents[i - 1]!.id, payload.newEvents[i]!.id)) {
488
+ if (EventSequenceNumber.isGreaterThanOrEqual(payload.newEvents[i - 1]!.seqNum, payload.newEvents[i]!.seqNum)) {
481
489
  return unexpectedError(
482
- `Events must be ordered in monotonically ascending order by eventId. Received: [${payload.newEvents.map((e) => EventId.toString(e.id)).join(', ')}]`,
490
+ `Events must be ordered in monotonically ascending order by eventNum. Received: [${payload.newEvents.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`,
483
491
  )
484
492
  }
485
493
  }
@@ -491,9 +499,9 @@ const validateSyncState = (syncState: SyncState) => {
491
499
  const nextEvent = syncState.pending[i + 1]
492
500
  if (nextEvent === undefined) break // Reached end of chain
493
501
 
494
- if (EventId.isGreaterThanOrEqual(event.id, nextEvent.id)) {
502
+ if (EventSequenceNumber.isGreaterThanOrEqual(event.seqNum, nextEvent.seqNum)) {
495
503
  shouldNeverHappen(
496
- `Events must be ordered in monotonically ascending order by eventId. Received: [${syncState.pending.map((e) => EventId.toString(e.id)).join(', ')}]`,
504
+ `Events must be ordered in monotonically ascending order by eventNum. Received: [${syncState.pending.map((e) => EventSequenceNumber.toString(e.seqNum)).join(', ')}]`,
497
505
  {
498
506
  event,
499
507
  nextEvent,
@@ -502,11 +510,11 @@ const validateSyncState = (syncState: SyncState) => {
502
510
  }
503
511
 
504
512
  // If the global id has increased, then the client id must be 0
505
- const globalIdHasIncreased = nextEvent.id.global > event.id.global
513
+ const globalIdHasIncreased = nextEvent.seqNum.global > event.seqNum.global
506
514
  if (globalIdHasIncreased) {
507
- if (nextEvent.id.client !== 0) {
515
+ if (nextEvent.seqNum.client !== 0) {
508
516
  shouldNeverHappen(
509
- `New global events must point to clientId 0 in the parentId. Received: (${EventId.toString(nextEvent.id)})`,
517
+ `New global events must point to clientId 0 in the parentSeqNum. Received: (${EventSequenceNumber.toString(nextEvent.seqNum)})`,
510
518
  syncState.pending,
511
519
  {
512
520
  event,
@@ -515,9 +523,9 @@ const validateSyncState = (syncState: SyncState) => {
515
523
  )
516
524
  }
517
525
  } else {
518
- // Otherwise, the parentId must be the same as the previous event's id
519
- if (EventId.isEqual(nextEvent.parentId, event.id) === false) {
520
- shouldNeverHappen('Events must be linked in a continuous chain via the parentId', syncState.pending, {
526
+ // Otherwise, the parentSeqNum must be the same as the previous event's id
527
+ if (EventSequenceNumber.isEqual(nextEvent.parentSeqNum, event.seqNum) === false) {
528
+ shouldNeverHappen('Events must be linked in a continuous chain via the parentSeqNum', syncState.pending, {
521
529
  event,
522
530
  nextEvent,
523
531
  })
@@ -532,7 +540,7 @@ const validateMergeResult = (mergeResult: typeof MergeResult.Type) => {
532
540
  validateSyncState(mergeResult.newSyncState)
533
541
 
534
542
  // Ensure local head is always greater than or equal to upstream head
535
- if (EventId.isGreaterThan(mergeResult.newSyncState.upstreamHead, mergeResult.newSyncState.localHead)) {
543
+ if (EventSequenceNumber.isGreaterThan(mergeResult.newSyncState.upstreamHead, mergeResult.newSyncState.localHead)) {
536
544
  shouldNeverHappen('Local head must be greater than or equal to upstream head', {
537
545
  localHead: mergeResult.newSyncState.localHead,
538
546
  upstreamHead: mergeResult.newSyncState.upstreamHead,
@@ -541,8 +549,10 @@ const validateMergeResult = (mergeResult: typeof MergeResult.Type) => {
541
549
 
542
550
  // Ensure new local head is greater than or equal to the previous local head
543
551
  if (
544
- EventId.isGreaterThanOrEqual(mergeResult.newSyncState.localHead, mergeResult.mergeContext.syncState.localHead) ===
545
- false
552
+ EventSequenceNumber.isGreaterThanOrEqual(
553
+ mergeResult.newSyncState.localHead,
554
+ mergeResult.mergeContext.syncState.localHead,
555
+ ) === false
546
556
  ) {
547
557
  shouldNeverHappen('New local head must be greater than or equal to the previous local head', {
548
558
  localHead: mergeResult.newSyncState.localHead,
@@ -552,7 +562,7 @@ const validateMergeResult = (mergeResult: typeof MergeResult.Type) => {
552
562
 
553
563
  // Ensure new upstream head is greater than or equal to the previous upstream head
554
564
  if (
555
- EventId.isGreaterThanOrEqual(
565
+ EventSequenceNumber.isGreaterThanOrEqual(
556
566
  mergeResult.newSyncState.upstreamHead,
557
567
  mergeResult.mergeContext.syncState.upstreamHead,
558
568
  ) === false
@@ -1,20 +1,20 @@
1
1
  import { Effect } from '@livestore/utils/effect'
2
2
 
3
- import type { EventId, LiveStoreEvent } from '../schema/mod.js'
3
+ import type { EventSequenceNumber, LiveStoreEvent } from '../schema/mod.js'
4
4
  import { InvalidPushError } from './sync.js'
5
5
 
6
6
  // TODO proper batch validation
7
7
  export const validatePushPayload = (
8
8
  batch: ReadonlyArray<LiveStoreEvent.AnyEncodedGlobal>,
9
- currentEventId: EventId.GlobalEventId,
9
+ currentEventSequenceNumber: EventSequenceNumber.GlobalEventSequenceNumber,
10
10
  ) =>
11
11
  Effect.gen(function* () {
12
- if (batch[0]!.id <= currentEventId) {
12
+ if (batch[0]!.seqNum <= currentEventSequenceNumber) {
13
13
  return yield* InvalidPushError.make({
14
14
  reason: {
15
15
  _tag: 'ServerAhead',
16
- minimumExpectedId: currentEventId + 1,
17
- providedId: batch[0]!.id,
16
+ minimumExpectedNum: currentEventSequenceNumber + 1,
17
+ providedNum: batch[0]!.seqNum,
18
18
  },
19
19
  })
20
20
  }
package/src/version.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // import packageJson from '../package.json' with { type: 'json' }
3
3
  // export const liveStoreVersion = packageJson.version
4
4
 
5
- export const liveStoreVersion = '0.3.0-dev.47' as const
5
+ export const liveStoreVersion = '0.3.0-dev.49' as const
6
6
 
7
7
  /**
8
8
  * This version number is incremented whenever the internal storage format changes in a breaking way.
@@ -11,4 +11,4 @@ export const liveStoreVersion = '0.3.0-dev.47' as const
11
11
  * While LiveStore is in alpha, this might happen more frequently.
12
12
  * In the future, LiveStore will provide a migration path for older database files to avoid the impression of data loss.
13
13
  */
14
- export const liveStoreStorageFormatVersion = 3
14
+ export const liveStoreStorageFormatVersion = 4
@@ -1,12 +0,0 @@
1
- import { Vitest } from '@livestore/utils-dev/node-vitest'
2
- import { expect } from 'vitest'
3
-
4
- import { EventId } from './mod.js'
5
-
6
- Vitest.describe('EventId', () => {
7
- Vitest.test('nextPair', () => {
8
- const e_0_0 = EventId.make({ global: 0, client: 0 })
9
- expect(EventId.nextPair(e_0_0, false).id).toStrictEqual({ global: 1, client: 0 })
10
- expect(EventId.nextPair(e_0_0, true).id).toStrictEqual({ global: 0, client: 1 })
11
- })
12
- })
@@ -1,106 +0,0 @@
1
- import { Brand, Schema } from '@livestore/utils/effect'
2
-
3
- export type ClientEventId = Brand.Branded<number, 'ClientEventId'>
4
- export const localEventId = Brand.nominal<ClientEventId>()
5
- export const ClientEventId = Schema.fromBrand(localEventId)(Schema.Int)
6
-
7
- export type GlobalEventId = Brand.Branded<number, 'GlobalEventId'>
8
- export const globalEventId = Brand.nominal<GlobalEventId>()
9
- export const GlobalEventId = Schema.fromBrand(globalEventId)(Schema.Int)
10
-
11
- export const clientDefault = 0 as any as ClientEventId
12
-
13
- /**
14
- * LiveStore event id value consisting of a globally unique event sequence number
15
- * and a client sequence number.
16
- *
17
- * The client sequence number is only used for clientOnly events and starts from 0 for each global sequence number.
18
- */
19
- export type EventId = { global: GlobalEventId; client: ClientEventId }
20
-
21
- // export const EventSequenceNumber = Schema.Struct({})
22
- // export const EventNumber = Schema.Struct({})
23
- // export const ClientEventNumber = Schema.Struct({})
24
- // export const GlobalEventNumber = Schema.Struct({})
25
-
26
- /**
27
- * NOTE: Client mutation events with a non-0 client id, won't be synced to the sync backend.
28
- */
29
- export const EventId = Schema.Struct({
30
- global: GlobalEventId,
31
- /** Only increments for clientOnly events */
32
- client: ClientEventId,
33
-
34
- // TODO also provide a way to see "confirmation level" of event (e.g. confirmed by leader/sync backend)
35
-
36
- // TODO: actually add this field
37
- // Client only
38
- // generation: Schema.Number.pipe(Schema.optional),
39
- }).annotations({ title: 'LiveStore.EventId' })
40
-
41
- /**
42
- * Compare two event ids i.e. checks if the first event id is less than the second.
43
- */
44
- export const compare = (a: EventId, b: EventId) => {
45
- if (a.global !== b.global) {
46
- return a.global - b.global
47
- }
48
- return a.client - b.client
49
- }
50
-
51
- /**
52
- * Convert an event id to a string representation.
53
- */
54
- export const toString = (id: EventId) => (id.client === 0 ? `e${id.global}` : `e${id.global}+${id.client}`)
55
-
56
- /**
57
- * Convert a string representation of an event id to an event id.
58
- */
59
- export const fromString = (str: string): EventId => {
60
- const [global, client] = str.slice(1, -1).split(',').map(Number)
61
- if (global === undefined || client === undefined) {
62
- throw new Error('Invalid event id string')
63
- }
64
- return { global, client } as EventId
65
- }
66
-
67
- export const isEqual = (a: EventId, b: EventId) => a.global === b.global && a.client === b.client
68
-
69
- export type EventIdPair = { id: EventId; parentId: EventId }
70
-
71
- export const ROOT = { global: 0 as any as GlobalEventId, client: clientDefault } satisfies EventId
72
-
73
- export const isGreaterThan = (a: EventId, b: EventId) => {
74
- return a.global > b.global || (a.global === b.global && a.client > b.client)
75
- }
76
-
77
- export const isGreaterThanOrEqual = (a: EventId, b: EventId) => {
78
- return a.global > b.global || (a.global === b.global && a.client >= b.client)
79
- }
80
-
81
- export const max = (a: EventId, b: EventId) => {
82
- return a.global > b.global || (a.global === b.global && a.client > b.client) ? a : b
83
- }
84
-
85
- export const diff = (a: EventId, b: EventId) => {
86
- return {
87
- global: a.global - b.global,
88
- client: a.client - b.client,
89
- }
90
- }
91
-
92
- export const make = (id: EventId | typeof EventId.Encoded): EventId => {
93
- return Schema.is(EventId)(id) ? id : Schema.decodeSync(EventId)(id)
94
- }
95
-
96
- export const nextPair = (id: EventId, isLocal: boolean): EventIdPair => {
97
- if (isLocal) {
98
- return { id: { global: id.global, client: (id.client + 1) as any as ClientEventId }, parentId: id }
99
- }
100
-
101
- return {
102
- id: { global: (id.global + 1) as any as GlobalEventId, client: clientDefault },
103
- // NOTE we always point to `client: 0` for non-clientOnly events
104
- parentId: { global: id.global, client: clientDefault },
105
- }
106
- }