/** * Hybrid logical clock (HLC) for the change journal. * * Wire format (fixed by the cloud contract, `Hlc` in `@cleocode/contracts`): * `PPPPPPPPPPPPP-CCCCCC-`, where `P` is physical milliseconds * since the Unix epoch zero-padded to 13 digits, `C` is the logical counter * zero-padded to 6 digits, and the replica id is the lowercase UUIDv7 of the * store that issued the timestamp. Tuple order `(phys, ctr, replica)` is * exactly the lexical order of the encoded string, so SQL `ORDER BY hlc` and * `MAX(hlc)` are correct. * * This module is pure. The persisted clock row lives in `clock-store.ts`. * * It never reads time from a uid (journal spec R7, T12341 §5.2): a backfilled * uid's timestamp is the row's birth, or 0, not the time of a change. The * module therefore imports nothing, and a test pins that. * * @task T12342 * @module store/sync/hlc */ /** A decoded HLC. */ export interface Hlc { /** Physical milliseconds since the Unix epoch. */ readonly phys: number; /** Logical counter, 0 to {@link MAX_COUNTER}. */ readonly ctr: number; /** Lowercase UUID of the issuing replica. */ readonly replica: string; } /** The largest counter the 6-digit field can hold. */ export declare const MAX_COUNTER = 999999; /** The largest physical time the 13-digit field can hold (year 2286). */ export declare const MAX_PHYS = 9999999999999; /** * Default skew bound: a received HLC more than this far ahead of the local * wall clock is held, never applied or dropped (journal spec §1.3, Q6). */ export declare const MAX_DRIFT_MS: number; /** * The replica id a pre-HLC value carries: none issued it (all-zero UUID). * Shared by anything minting a deterministic, device-independent HLC — the * collision HLC of two pre-journal births (`display-id-alias.ts`) and the * T13360 migration head projection. Kept in this import-nothing leaf so * consumers do not drag write-path modules onto the synced write path * (gate 38, T13633). */ export declare const PRE_HLC_REPLICA = "00000000-0000-0000-0000-000000000000"; /** Thrown for a malformed HLC, replica id or physical time. */ export declare class HlcError extends Error { constructor(message: string); } /** * Encode an HLC to its wire form. * * @param h - The clock value. * @returns `PPPPPPPPPPPPP-CCCCCC-`. * @throws {HlcError} When a part is out of range or the replica id is malformed. */ export declare function encodeHlc(h: Hlc): string; /** * Decode an HLC from its wire form. * * @param s - An encoded HLC. * @returns The decoded parts. * @throws {HlcError} When `s` is not an encoded HLC. */ export declare function parseHlc(s: string): Hlc; /** * Total order on HLCs: `(phys, ctr, replica)`. The replica tiebreak is * arbitrary but deterministic, so every replica orders identically. * * @returns Negative, zero or positive, like a sort comparator. */ export declare function compareHlc(a: Hlc, b: Hlc): number; /** * The clock of a replica that has issued nothing yet. * * @param replica - The replica id. */ export declare function genesisHlc(replica: string): Hlc; /** * Issue the next local HLC. * * `phys' = max(last.phys, wall)`; the counter increments when the physical * part did not move and resets to 0 when it did; a counter past * {@link MAX_COUNTER} carries into `phys`. HLCs therefore increase strictly * per replica, even when the wall clock steps backwards or a batch issues * 10^6 timestamps in one millisecond. * * @param last - The replica's current clock. * @param wallMs - The physical candidate (a capture's `at_ms`, or `Date.now()`). * @returns The new clock value, which is also the issued timestamp. */ export declare function tick(last: Hlc, wallMs: number): Hlc; /** * Merge a received HLC into the local clock (standard HLC receive rule). * * `phys' = max(last.phys, remote.phys, now)`. The counter is * `max(last.ctr, remote.ctr) + 1` when all three agree, `last.ctr + 1` or * `remote.ctr + 1` when `phys'` equals only that one, and 0 otherwise. The * result keeps the LOCAL replica id. * * Callers apply the skew bound first ({@link isWithinSkew}): a remote HLC too * far ahead must be held, never merged. * * @param last - The local clock. * @param remote - The received timestamp. * @param nowMs - The local wall clock. * @returns The new local clock value. */ export declare function receive(last: Hlc, remote: Hlc, nowMs: number): Hlc; /** * Whether a received HLC is inside the skew bound: `phys <= now + maxDrift`. * * @param remote - The received timestamp. * @param nowMs - The local wall clock. * @param maxDriftMs - The bound; defaults to {@link MAX_DRIFT_MS}. */ export declare function isWithinSkew(remote: Hlc, nowMs: number, maxDriftMs?: number): boolean; /** * The larger of two HLCs (by {@link compareHlc}). */ export declare function maxHlc(a: Hlc, b: Hlc): Hlc; //# sourceMappingURL=hlc.d.ts.map