Rebasely Beta: data may be purged

examples/live-notes Public

Markdown · 38 lines · 1.6 KiB · at d21dfdd

---id: wire-protocoltype: conceptowner: justinreviewed: 2026-10-14component: opsdescribes:  - src/protocol.ts---# Wire protocolEditors and a room exchange JSON text frames over the WebSocket at `/notes/:id/ws`. Versionsare the room's: the number of ops it has applied to the note.From an editor:```json{ "type": "op", "base": 41, "op": { "type": "insert", "pos": 4, "text": "oat " } }{ "type": "op", "base": 41, "op": { "type": "delete", "pos": 0, "count": 3 } }```From the room:| type       | fields                      | when                                                || ---------- | --------------------------- | --------------------------------------------------- || `snapshot` | `text`, `version`, `reason` | on connect, and when an editor's op can't be used   || `ack`      | `version`                   | your op was applied, or turned out to change nothing || `op`       | `version`, `op`             | someone else's op, already transformed               || `error`    | `message`                   | the frame was not an op message                      |`reason` is only set when the room refused an op the editor had already applied, for exampleone that would take the note past 100,000 characters. The page shows it in the status line.`parseClientMessage()` checks every field and copies only the ones it knows, so a frame withextra fields still works and a malformed one is answered with `error` and changes nothing.An editor sends its next op only after the ack for the previous one; see [[conflict-strategy]]for why that keeps the room's job simple.