API reference / @evolu/common / local-first / Timestamp
Variable: Timestamp
const Timestamp: ObjectType<{
counter: BrandType<
BrandType<
Type<
"Brand",
number & Brand<"Int"> & Brand<"NonNegative">,
number,
NonNegativeError,
number & Brand<"Int">,
IntError | NumberError
>,
"LessThanOrEqualTo65535",
LessThanOrEqualToError<65535>,
NonNegativeError | IntError | NumberError
>,
"Counter",
BrandWithoutRefineError<
"Counter",
NonNegativeError | IntError | NumberError | LessThanOrEqualToError<65535>
>,
never
>;
millis: BrandType<
BrandType<
Type<
"Brand",
number & Brand<"Int"> & Brand<"NonNegative">,
number,
NonNegativeError,
number & Brand<"Int">,
IntError | NumberError
>,
`LessThanOrEqualTo${number}`,
LessThanOrEqualToError<number>,
NonNegativeError | IntError | NumberError
>,
"Millis",
BrandWithoutRefineError<
"Millis",
NonNegativeError | IntError | NumberError | LessThanOrEqualToError<number>
>,
never
>;
nodeId: BrandType<
Type<"String", string, string, StringError, string, StringError>,
"NodeId",
RegexError<"NodeId">,
StringError
>;
}>;
Defined in: packages/common/src/local-first/Timestamp.ts:169
Hybrid Logical Clock timestamp.
Timestamps serve as globally unique, causally ordered identifiers for CRDT messages in Evolu's sync protocol.
Why Hybrid Logical Clocks
Evolu uses Hybrid Logical Clocks (HLC), which combine physical time (millis) with a logical counter. This hybrid approach preserves causality like logical clocks while staying close to physical time for better human interpretability.
The counter component ensures causality is maintained even when physical clocks are imperfect. When clocks drift or operations occur concurrently, the counter increments to establish a total order. This means Evolu achieves well-defined, eventually-consistent behavior regardless of physical clock accuracy.
Vector clocks can accurately track causality and detect concurrent operations, but they require unbounded space in peer-to-peer systems and crucially, still don't solve our fundamental problem: when they detect operations as concurrent, we still need a deterministic way to choose a winner. Additionally, any deterministic conflict resolution can be gamed by malicious actors.
HLC timestamps work well in practice because modern device clocks accurately
reflect the order of sequential edits in the common case. Evolu's maxDrift
configuration protects against buggy clocks and prevents problematic
future-dated entries from propagating through the network.
References
- https://muratbuffalo.blogspot.com/2014/07/hybrid-logical-clocks.html
- https://sergeiturukin.com/2017/06/26/hybrid-logical-clocks.html
- https://jaredforsyth.com/posts/hybrid-logical-clocks/
- https://willowprotocol.org/more/timestamps_really/index.html
Privacy Considerations
Timestamps are metadata visible to relays and collaborators. While it can be considered a privacy leak, let us explain why it's necessary, and how to avoid it if maximum privacy is required.
With real-time communication, participants always see activity (receiving bytes). We cannot trust anyone not to store that information, so explicitly exposing timestamps doesn't add additional risk.
If we really want not to leak user activity, we can implement a local write queue:
- Write changes immediately to a local-only table
- Periodically and randomly flush messages to sync tables
Trade-off: It breaks real-time collaboration.