y-atproto
v2.0.0
Published
A [Yjs](https://yjs.dev/) CRDT provider that syncs documents over the [AT Protocol](https://atproto.com/). Documents are stored as ATProto records and real-time updates are delivered via [Jetstream](https://github.com/bluesky-social/jetstream).
Readme
y-atproto
A Yjs CRDT provider that syncs documents over the AT Protocol. Documents are stored as ATProto records and real-time updates are delivered via Jetstream.
Breaking changes in 2.0.0
A new algorithm for resuming rooms from update records has been introduced, which should increase reliability when multiple clients are using the app at the same time. Existing rooms will still be compatible but the initial download may take longer. Please let me know if you experience any issues with the new resume behavior.
How it works
- Each collaborative session is represented by a room record (
io.github.uwx.yjs.room) in the user's ATProto repository. - Document updates are written as
io.github.uwx.yjs.updaterecords, with small updates stored inline and large updates (>1 MB) stored as blobs. - Real-time sync is achieved by subscribing to Jetstream for new update and awareness records.
- Rooms can optionally be encrypted (AES-256-GCM with PBKDF2 key derivation) and restricted to an allowlist of DIDs.
- Awareness (cursor positions, user presence) is supported via
io.github.uwx.yjs.awarenessrecords.
Installation
pnpm install y-atprotoUsage
Creating a new room
import { Doc } from "yjs";
import AtprotoProvider from "y-atproto";
const ydoc = new Doc();
const { provider, room } = await AtprotoProvider.createNew({
secret: "optional-password",
repo: did,
handler: agent,
ydoc,
autosaveInterval: 1000,
});Joining an existing room
const provider = await AtprotoProvider.resume({
secret: "optional-password",
repo: did,
handler: agent,
room: "at://did:plc:.../io.github.uwx.yjs.room/...",
ydoc,
autosaveInterval: 1000,
});Options
| Option | Type | Description |
|---|---|---|
| secret | string | Optional password for end-to-end encryption |
| repo | ActorIdentifier | DID or handle of the authenticated user |
| handler | FetchHandler \| KittyAgent | Authenticated AT Protocol agent |
| ydoc | Doc | Yjs document to sync |
| autosaveInterval | number | Milliseconds between flushes of queued updates |
| resendAllUpdates | boolean | If true, always send the full document state |
| fullUpdateRate | number | Probability (0-1) of sending a full update on each flush (default 0.1) |
| awareness | Awareness | Custom Yjs awareness instance to reuse |
| awarenessLive | boolean | If true, broadcast awareness on every local change instead of on an interval |
| awarenessBroadcastInterval | number | Milliseconds between awareness broadcasts (default 29000) |
Demos
- demos/monaco-react -- Collaborative Monaco editor. Live at y-atproto-demo-monaco.wisp.place
- demos/react-prosemirror -- Collaborative ProseMirror editor. Live at y-atproto-demo-prosemirror.wisp.place
- demos/excalidraw -- Collaborative whiteboard using Excalidraw. Live at y-atproto-demo-excalidraw.wisp.place
Building
Requires pnpm.
pnpm install
pnpm buildLicense
MIT
