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.

YjsPresenceManager

Manages presence signaling, view/edit tracking, and session state for collaborative editing.

Tracks which documents you're viewing and editing, signals state to the server, and receives session updates with active participants.

Creating an instance

Use the same clientId and connId values as your YjsDocumentManager.

import { YjsPresenceManager } from "@stratasync/y-doc";

const presenceManager = new YjsPresenceManager({
  clientId: "client-abc-123",
  connId: "conn-xyz-456",
});

PresenceManagerConfig

PropertyTypeDescription
clientIdstringLogical client identity for attribution.
connIdstringConnection-scoped identity for echo suppression and ownership.

Setting the transport

Set before signaling presence. See YjsDocumentManager for transport setup.

presenceManager.setTransport(yjsTransport);

Listens for session_state messages and sends doc_view and doc_focus messages.

API reference

startViewing

Signals that you opened a document.

import type { DocumentKey } from "@stratasync/y-doc";

const docKey: DocumentKey = {
  entityType: "Task",
  entityId: "task-123",
  fieldName: "description",
};

presenceManager.startViewing(docKey);

Signature: startViewing(docKey: DocumentKey): void

Duplicate calls for the same document are ignored.

stopViewing

Signals that you closed a document. Auto-calls blur if editing.

presenceManager.stopViewing(docKey);

Signature: stopViewing(docKey: DocumentKey): void

focus

Signals editor focus. Auto-calls startViewing if not already viewing.

presenceManager.focus(docKey);

Signature: focus(docKey: DocumentKey): void

Sends a doc_focus message with state "focus".

blur

Signals editor blur.

presenceManager.blur(docKey);

Signature: blur(docKey: DocumentKey): void

Sends a doc_focus message with state "blur".

isViewing

Returns whether you're viewing a document.

const viewing: boolean = presenceManager.isViewing(docKey);

Signature: isViewing(docKey: DocumentKey): boolean

isEditing

Returns whether you're editing a document.

const editing: boolean = presenceManager.isEditing(docKey);

Signature: isEditing(docKey: DocumentKey): boolean

getSessionState

Returns session state with active participants.

import type { SessionState } from "@stratasync/y-doc";

const session: SessionState | null = presenceManager.getSessionState(docKey);

if (session) {
  const activeCount = session.participants.filter((p) => p.isEditing).length;
}

Signature: getSessionState(docKey: DocumentKey): SessionState | null

Returns null if no session state has been received yet.

SessionState

interface SessionState {
  active: boolean;
  participants: SessionParticipant[];
}
PropertyTypeDescription
activebooleanWhether the session is active (at least one participant).
participantsSessionParticipant[]List of participants.

SessionParticipant

interface SessionParticipant {
  userId: string;
  isEditing: boolean;
}
PropertyTypeDescription
userIdstringThe participant's user ID.
isEditingbooleanWhether the participant is editing (focused).

onSessionStateChange

Fires with current state, then on each change.

const unsubscribe = presenceManager.onSessionStateChange(docKey, (session) => {
  updateParticipantList(session.participants);
  showCollaborationBadge(session.active);
});

unsubscribe();

Signature: onSessionStateChange(docKey: DocumentKey, callback: (state: SessionState) => void): () => void

Returns an unsubscribe function.

cleanup

Stops viewing all documents and clears state.

presenceManager.cleanup();

Signature: cleanup(): void

Presence lifecycle

User opens document   --> startViewing()  --> doc_view "start" sent
User clicks editor    --> focus()         --> doc_focus "focus" sent
User clicks elsewhere --> blur()          --> doc_focus "blur" sent
User closes document  --> stopViewing()   --> doc_view "stop" sent

The server aggregates signals into SessionState updates and broadcasts to all participants.

Full example

import { YjsPresenceManager } from "@stratasync/y-doc";
import type { DocumentKey } from "@stratasync/y-doc";

const presenceManager = new YjsPresenceManager({
  clientId: "client-123",
  connId: "conn-456",
});

presenceManager.setTransport(yjsTransport);

const docKey: DocumentKey = {
  entityType: "Task",
  entityId: "task-abc",
  fieldName: "description",
};

const unsubscribe = presenceManager.onSessionStateChange(docKey, (session) => {
  const editors = session.participants.filter((p) => p.isEditing);
  updateUI({ activeEditors: editors.length, isActive: session.active });
});

presenceManager.startViewing(docKey);
presenceManager.focus(docKey);
presenceManager.blur(docKey);
presenceManager.stopViewing(docKey);
unsubscribe();