All files / src/services clock.ts

100% Statements 15/15
100% Branches 6/6
100% Functions 3/3
100% Lines 14/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42            1x   4x         4x 4x 4x         3x 3x 3x 3x         5x 5x         5x 4x 4x          
import { cacheDb } from './db'
 
/**
 * Maintains a monotonically-increasing vector clock counter per (listId, deviceId)
 * in IndexedDB. Used to attach vector clocks to offline-queued CRDT operations.
 */
export const LocalClockService = {
  async getNextClock(listId: string, deviceId: string): Promise<Record<string, number>> {
    const row = (await cacheDb.localClocks.get([listId, deviceId])) ?? {
      listId,
      deviceId,
      counter: 0,
    }
    row.counter++
    await cacheDb.localClocks.put(row)
    return { [deviceId]: row.counter }
  },
 
  /** Returns the full vector clock for a list (all devices seen so far). */
  async getClock(listId: string): Promise<Record<string, number>> {
    const rows = await cacheDb.localClocks.where('listId').equals(listId).toArray()
    const clock: Record<string, number> = {}
    for (const row of rows) clock[row.deviceId] = row.counter
    return clock
  },
 
  /** Max-merges an incoming clock map into the stored clocks for a list. */
  async mergeClock(listId: string, incoming: Record<string, number>): Promise<void> {
    for (const [deviceId, counter] of Object.entries(incoming)) {
      const row = (await cacheDb.localClocks.get([listId, deviceId])) ?? {
        listId,
        deviceId,
        counter: 0,
      }
      if (counter > row.counter) {
        row.counter = counter
        await cacheDb.localClocks.put(row)
      }
    }
  },
}