Skip to content
D
Documentation

Sync — functions

reference
2 min readUpdated

Functions

Import these from @grafloria/engine.

Functions

coalesce

Drop every set that a later set in the same batch overwrites.

A stable filter: elements are removed, never reordered. Exported because it is worth testing on its own, and because it is the part that is easy to get wrong.

RETURNS THE DROPPED OPS TOO, AND THAT IS NOT A CONVENIENCE — IT IS LOAD-BEARING.

An op that is coalesced away is an op the sender HAS (it is in its log) and the receiver will NEVER have. Anti-entropy compares frontiers derived from logs, so unless the sender knows exactly which ops it deliberately withheld, its frontier says "I hold 20 ops" while the peer holds 1 — a gap indistinguishable from a lost packet, which triggers a full history REPAIR on the next sync round. And the round after. Forever, because the peer can never obtain ops that will never be sent.

That is a silent O(history) resend after EVERY DRAG — the most common interaction there is. See SyncAdapter.suppressed.

ts
function coalesce(ops: readonly Op[]): { kept: Op[]; dropped: Op[] }

createSyncSession

Build a Replica and a SyncAdapter, correctly wired to each other.

The wiring is one line and it is easy to forget, and forgetting it produces the exact failure this codebase is famous for: everything green, every unit test passing, and not one edit ever reaching the wire — because onLocalOp went nowhere.

ts
function createSyncSession(
  diagram: DiagramModel,
  transport: SyncTransport,
  options: SyncSessionOptions
): SyncAdapter

deltaFor

THE CATCH-UP DELTA: which of ours does a peer with frontier remote not have?

Two tiers, and the tier is chosen PER ACTOR:

FAST — our digest of that actor's ops at-or-below the peer's max matches theirs. Their frontier is honest; send only the tail above max. REPAIR— it does not match. There is a hole somewhere below their max and neither of us can say where. Send everything we have from that actor and let their log de-duplicate. Over-sending is free. Under-sending loses the document.

Returns ops in TOTAL ORDER — so a receiver that applies them in array order applies an add before the sets that depend on it, and the causal buffer has nothing to do.

ts
function deltaFor(
  ours: readonly Op[],
  remote: VersionVectorJSON
): { ops: Op[]; repairedActors: ActorId[] }

isDocumentMessage

True for the ONE message kind that is allowed to touch the durable log.

ts
function isDocumentMessage(msg: SyncMessage): msg is OpsMessage

mulberry32

Deterministic PRNG (mulberry32). A fuzz you cannot replay is an anecdote.

ts
function mulberry32(seed: number): () => number

Was this page helpful?