Skip to content
Strata Sync

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

PropertyTypeDescription
clientIdstringLogical client identity for attribution. Stable across tabs and sessions.
connIdstringConnection-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

PropertyTypeDefaultDescription
initialContentstring-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

StateDescription
"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)

TypeMessageDescription
"doc_view"DocViewMessageStart or stop viewing a document.
"doc_focus"DocFocusMessageSignal editor focus or blur.
"yjs_sync_step1"YjsSyncStep1MessageSend state vector to initiate sync.
"yjs_update"YjsUpdateToServerMessageSend a local Yjs update.

Server messages (received from server)

TypeMessageDescription
"yjs_sync_step2"YjsSyncStep2MessageServer response with missing updates.
"yjs_update"YjsUpdateMessageRemote update from another client.
"session_state"SessionStateMessageSession participants update.
"live_editing_error"LiveEditingErrorMessageError 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);