> ## Documentation Index
> Fetch the complete documentation index at: https://stratasync.blode.md/llms.txt
> Use this file to discover all available pages before exploring further.

# YjsDocumentManager

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.

```ts
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.

```ts
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.

```ts
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.

```ts
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`.

```ts
documentManager.disconnect(docKey);
```

**Signature:** `disconnect(docKey: DocumentKey): void`

### getConnectionState

Returns the connection state for a document.

```ts
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.

```ts
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.

```ts
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.

```ts
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.

```ts
documentManager.applyRemoteUpdate(docKey, updateBytes);
```

**Signature:** `applyRemoteUpdate(docKey: DocumentKey, update: Uint8Array): void`

### applySnapshot

Applies a full state snapshot for initial hydration.

```ts
documentManager.applySnapshot(docKey, snapshotBytes);
```

**Signature:** `applySnapshot(docKey: DocumentKey, snapshot: Uint8Array): void`

### getStateVector / getEncodedState / getUpdatesSince

Low-level methods for advanced sync scenarios.

```ts
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.

```ts
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

```ts
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);
```