Collaboration
A Collaborator turns the ledger primitives into a drop-in, real-time, multi-peer
editing experience: optimistic local edits, automatic convergence, live
presence/cursors, and late-join delta sync - no merge code on your side. The model is
server-authoritative optimistic OT (the shape ProseMirror’s collab uses): an
authority owns the one canonical ordered log and broadcasts records already in canonical
position, so every peer’s confirmed document is identical by construction.
See the @plim/collaboration API reference for the full
contract.
import { Collaborator, createMemoryNetwork } from '@plim/collaboration';
// In-process hub with an embedded authority (swap for your own Transport in production).const net = createMemoryNetwork({ origin: baseDoc });
const alice = new Collaborator({ peer: { id: 'alice', name: 'Alice' }, editor, transport: net.connect() });alice.onChange((s) => render(s)); // { head, pending, inflight }alice.setPresence({ status: 'editing' }); // ephemeral awareness (never logged to the ledger)alice.peers; // remote cursors to render
// Local edits flow automatically: each committed transaction applies instantly// (optimistic) and reconciles when the authority confirms it.
const dave = new Collaborator({ peer: { id: 'dave' }, editor: daveEditor, transport: net.connect() });dave.sync(); // late join: pull the backlog, fast-forward to headLocal edits apply instantly and sit in pending until confirmed; the local caret
is always preserved (shifted to track remote inserts, never replaced by a remote
cursor, never disturbed when your own edit is acked). At quiescence every peer’s
confirmed document equals the authority’s - provable, and locked in by a four-peer
randomized fuzz convergence test.
A real server with CollabHub
Section titled “A real server with CollabHub”For a real server, drop the in-process createMemoryNetwork and reach for
CollabHub - the transport-agnostic server half of the protocol. Wrap any socket as a
HubClient and it linearizes submissions and broadcasts canonical records for you:
import { CollabHub, type HubClient } from '@plim/collaboration';
const hub = new CollabHub(baseDoc);// per connection:const client: HubClient = { send: (m) => socket.send(JSON.stringify(m)) };hub.add(client);socket.on('message', (raw) => hub.receive(client, JSON.parse(raw)));socket.on('close', () => hub.remove(client));Next: add comments & replies, which ride the same OT/collab layer.