typarr.collab

Real-time collaboration via Yjs CRDT over WebSockets.

Each open file gets a YRoom backed by a pycrdt Doc. Multiple clients connect to the same room and edits are merged via the Yjs sync protocol. When the last client disconnects, the document is flushed to disk.

class typarr.collab.CollabManager(data_dir: Path, file_service: FileService, *, auto_save: bool = True, room_ttl: int = 300)

Manages Yjs collaboration rooms for concurrent file editing.

Rooms are created lazily when the first client connects to a file and torn down (with a disk flush) when the last client disconnects.

async evict_under(slug: str, prefix: str) None

Evict every room whose path is under prefix (used for dir operations).

get_content(slug: str, file_path: str) str | None

Return the live YText content if a room exists, else None.

lock_path(slug: str, file_path: str)

Hold the per-path lock and evict any existing room without flushing.

Used by file delete/rename handlers to atomically tear down collab state and prevent the race where a pending flush re-creates the file the client just asked the server to remove.

async reload_rooms(slug: str, paths: list[str]) None

Reload room content from disk after external file changes.

Called after git restore or other operations that change files on disk outside the CRDT. Connected clients receive the update via sync.

async serve(websocket: WebSocket, slug: str, path: str) None

Handle a WebSocket connection for collaborative editing of a file.

async shutdown() None

Cancel pending TTL tasks and flush all active rooms to disk.

start() None

Called on application startup (reserved for future use).

class typarr.collab.FastAPIChannel(websocket: WebSocket, path: str)

Adapts a FastAPI WebSocket to the pycrdt Channel interface.

property path: str

The channel path.

async recv() bytes

Receive a binary message from the client.

async send(message: bytes)

Send a binary message to the client, serialized with a lock.