AI agents: fetch the documentation index at llms.txt. Markdown versions are available by appending .md to any page URL, including this page's markdown.
YjsDocumentManager
Manages Y.Doc instances, sync protocol, connection state, and content change tracking for collaborative editing.
Creates and caches Y.Doc instances by DocumentKey, handles the Yjs sync protocol, tracks connection state, and notifies on content changes.
Creating an instance
Provide a clientId for attribution and a connId for echo suppression.
import { YjsDocumentManager } from "@stratasync/y-doc";
import type { YjsDocumentManagerConfig } from "@stratasync/y-doc";
const config: YjsDocumentManagerConfig = {
clientId: "client-abc-123",
connId: "conn-xyz-456",
};
const documentManager = new YjsDocumentManager(config);YjsDocumentManagerConfig
| Property | Type | Description |
|---|---|---|
clientId | string | Logical client identity for attribution. Stable across tabs and sessions. |
connId | string | Connection-scoped identity for echo suppression of yjs_update messages. |
Setting the transport
Set a transport before connecting to any documents.
const yjsTransport = transport.getYjsTransport();
documentManager.setTransport(yjsTransport);Sends sync messages and receives updates and errors.
API reference
getDocument
Returns the Y.Doc for a key, creating one if needed.
import type { DocumentKey } from "@stratasync/y-doc";
import type * as Y from "yjs";
const docKey: DocumentKey = {
entityType: "Task",
entityId: "task-123",
fieldName: "description",
};
const doc: Y.Doc = documentManager.getDocument(docKey);
const fragment = doc.getXmlFragment("prosemirror");Signature: getDocument(docKey: DocumentKey): Y.Doc
Cached per key: subsequent calls return the same instance. Each document uses a shared ProseMirror fragment named "prosemirror".
connect
Connects to a document and initiates the Yjs sync protocol.
documentManager.connect(docKey);
// With initial content
documentManager.connect(docKey, {
initialContent: "Default description text",
});Signature: connect(docKey: DocumentKey, options?: ConnectOptions): void
ConnectOptions
| Property | Type | Default | Description |
|---|---|---|---|
initialContent | string | - | Initial text content to insert if the document is empty. |
If initialContent is provided and the text type is empty, it's inserted at position 0 to seed the field.
disconnect
Disconnects and stops sending updates. Presence is handled by YjsPresenceManager.
documentManager.disconnect(docKey);Signature: disconnect(docKey: DocumentKey): void
getConnectionState
Returns the connection state for a document.
import type { DocumentConnectionState } from "@stratasync/y-doc";
const state: DocumentConnectionState =
documentManager.getConnectionState(docKey);
// "disconnected" | "connecting" | "syncing" | "connected"Signature: getConnectionState(docKey: DocumentKey): DocumentConnectionState
DocumentConnectionState
| State | Description |
|---|---|
"disconnected" | Not connected to the document. |
"connecting" | Connection initiated, waiting for sync. |
"syncing" | Sync step in progress. |
"connected" | Fully synced and receiving live updates. |
onConnectionStateChange
Fires immediately with current state, then on each change.
const unsubscribe = documentManager.onConnectionStateChange(docKey, (state) => {
if (state === "connected") {
// Editor is ready for collaboration
}
});
unsubscribe();Signature: onConnectionStateChange(docKey: DocumentKey, callback: (state: DocumentConnectionState) => void): () => void
Returns an unsubscribe function.
onContentChange
Fires immediately with current content, then on each local or remote update.
const unsubscribe = documentManager.onContentChange(docKey, (content) => {
// content is the current text string from the Y.Doc
});
unsubscribe();Signature: onContentChange(docKey: DocumentKey, callback: (content: string) => void): () => void
Returns an unsubscribe function.
getDerivedContent
Returns the document's content as a plain string.
const content: string = documentManager.getDerivedContent(docKey);Signature: getDerivedContent(docKey: DocumentKey): string
Reads from the "prosemirror" fragment and renders a plain-text derivation. Returns an empty string if the document doesn't exist.
applyRemoteUpdate
Applies a remote update with "remote" origin to prevent re-sending.
documentManager.applyRemoteUpdate(docKey, updateBytes);Signature: applyRemoteUpdate(docKey: DocumentKey, update: Uint8Array): void
applySnapshot
Applies a full state snapshot for initial hydration.
documentManager.applySnapshot(docKey, snapshotBytes);Signature: applySnapshot(docKey: DocumentKey, snapshot: Uint8Array): void
getStateVector / getEncodedState / getUpdatesSince
Low-level methods for advanced sync scenarios.
const stateVector: Uint8Array = documentManager.getStateVector(docKey);
const fullState: Uint8Array | null = documentManager.getEncodedState(docKey);
const updates: Uint8Array | null = documentManager.getUpdatesSince(
docKey,
remoteStateVector
);destroy / destroyAll
destroy removes one document; destroyAll removes all.
documentManager.destroy(docKey);
documentManager.destroyAll();Message types
Client messages (sent to server)
| Type | Message | Description |
|---|---|---|
"doc_view" | DocViewMessage | Start or stop viewing a document. |
"doc_focus" | DocFocusMessage | Signal editor focus or blur. |
"yjs_sync_step1" | YjsSyncStep1Message | Send state vector to initiate sync. |
"yjs_update" | YjsUpdateToServerMessage | Send a local Yjs update. |
Server messages (received from server)
| Type | Message | Description |
|---|---|---|
"yjs_sync_step2" | YjsSyncStep2Message | Server response with missing updates. |
"yjs_update" | YjsUpdateMessage | Remote update from another client. |
"session_state" | SessionStateMessage | Session participants update. |
"live_editing_error" | LiveEditingErrorMessage | Error codes: NOT_FOUND, UNAUTHORIZED, INVALID_PAYLOAD, RATE_LIMITED. |
Full example
import { YjsDocumentManager } from "@stratasync/y-doc";
import type { DocumentKey } from "@stratasync/y-doc";
const manager = new YjsDocumentManager({
clientId: "client-123",
connId: "conn-456",
});
manager.setTransport(yjsTransport);
const docKey: DocumentKey = {
entityType: "Task",
entityId: "task-abc",
fieldName: "description",
};
const unsubContent = manager.onContentChange(docKey, (content) => {
renderPreview(content);
});
const unsubState = manager.onConnectionStateChange(docKey, (state) => {
updateConnectionIndicator(state);
});
manager.connect(docKey, { initialContent: "Initial description" });
const doc = manager.getDocument(docKey);
const fragment = doc.getXmlFragment("prosemirror");
// Clean up
unsubContent();
unsubState();
manager.disconnect(docKey);
manager.destroy(docKey);