@docx-editor.dev/pro/collaboration
@docx-editor.dev/pro/collaboration — Yjs replica factories and the module factory.
The default entry imports no network provider. Import @docx-editor.dev/pro/collaboration/webrtc for the WebRTC wrapper and @docx-editor.dev/pro/collaboration/hocuspocus for the Hocuspocus wrapper.
Functions (13)
assertCollaborationFormatCompatibilityfunctionSource ↗
Refuse a collaboration format version unsupported by this deployment.
Pass the untrusted value received during connection admission, after authorizing document access and before synchronization. Only an exact string match succeeds. This check does not authenticate clients, validate room content, or migrate data.
declare function assertCollaborationFormatCompatibility(version: unknown): void;assertDocumentCollaborationCompatibilityfunctionSource ↗
Deprecated. Use `assertCollaborationFormatCompatibility` with `COLLABORATION_FORMAT_VERSION`. This function stays supported for existing handshakes.
Refuse an incompatible full-document client or persisted-room version descriptor.
Pass the client's version tuple from your admission handshake before permitting sync. Check persisted-room versions separately: a compatible client cannot migrate an older room. This validates compatibility only; your server must also authorize access. Missing or malformed fields refuse. Additional fields are ignored. Exact equality is required for all four supported versions; no migration or shared-state mutation occurs. Handle the stable error code; detail is a bounded diagnostic, not a parsing contract.
declare function assertDocumentCollaborationCompatibility(versions: unknown): void;checkCollaborationRoomGenerationfunctionSource ↗
Refuse a connection whose replica holds another generation of the room. Call it from the Hocuspocus beforeHandleMessage hook. A client sends the generation it holds before its first sync message; on a mismatch, or a sync message without one, this throws an error that closes the connection with room-generation-changed before any of its state merges. A message the gate cannot read is refused the same way.
A replica that holds no room yet names no generation and passes: it has no state of an earlier generation to merge. The gate keeps honest replicas of two generations apart. It is not access control: a client that may write to the room can send any update, so authenticate connections in onAuthenticate.
declare function checkCollaborationRoomGeneration(payload: CollaborationRoomGatePayload): void;collaborationMigrationNeedfunctionSource ↗
Whether saved room state needs a migration before this build can serve it.
A room whose version information is missing or malformed was written before collaboration formats were versioned, and counts as earlier-format.
Throws CollaborationSchemaError with code not-initialized for state that holds no room, and with code invalid-baseline for bytes that are not room state.
declare function collaborationMigrationNeed(state: Uint8Array): CollaborationMigrationNeed;collaborationModulefunctionSource ↗
Build the collaboration module. Construction never validates the key and never touches the network.
declare function collaborationModule(options: CollaborationModuleOptions): EditorModule;compactCollaborationStatefunctionSource ↗
Build a new generation of a room from its stored state, or return null when compaction would gain less than minimumGain.
The new generation holds the room's current content, read as a .docx package, under the same document ID and a new generation ID. Deleted text and records, formatting history, and unreferenced media are gone. Call it when the server loads a room, before any participant syncs, and store the result in place of the old state.
A check reads the whole room and builds it again. The answer for a state found not worth compacting is remembered in this process, so the same bytes are checked once. A state that changed is checked again.
Throws CollaborationSchemaError when the stored state cannot be read, as readCollaborationDocument does.
declare function compactCollaborationState(state: Uint8Array, options?: CompactCollaborationStateOptions): Promise<Uint8Array | null>;createDocumentCollaborationfunctionSource ↗
Create or join one full-document collaboration replica.
The caller owns ydoc, awareness, and the provider, and destroys them after handle.destroy().
declare function createDocumentCollaboration(options: CreateDocumentCollaborationOptions): Promise<DocumentCollaborationHandle>;```ts
await new Promise((resolve) => provider.once('sync', resolve));
const room = await createDocumentCollaboration({
ydoc,
awareness,
documentId: 'room-1',
identity: { actorId: 'user-1', name: 'Ada' },
bootstrap: { kind: 'join' },
});
// Mount the editor with room.document and collaborationModule({ session: room.session }).
```migrateCollaborationRoomfunctionSource ↗
Seed a room in this build's format from the .docx that the earlier build exported, and check the new room against that export.
The new room keeps the earlier room's document ID unless documentId gives another. It is a new room generation: a replica that still holds the earlier room is refused with room-generation-changed and rejoins.
This function does not check that exported was made from state. Store a digest of the state with each export, and compare it before you call this function: an export made before later edits would lose them.
Throws CollaborationSchemaError when the inputs cannot be used: invalid-baseline for bytes that are not room state or not a .docx, not-initialized for state that holds no room, invalid-document-id for an unusable document ID, and a limit code such as too-many-nodes for an export larger than a room's limits.
declare function migrateCollaborationRoom(options: MigrateCollaborationRoomOptions): Promise<CollaborationMigration>;prepareCollaborationServerDocumentfunctionSource ↗
Prepare a room's Y.Doc on a server that holds it, such as a Hocuspocus server. Call it once when the server creates or loads the document, before it applies any update.
declare function prepareCollaborationServerDocument(document: Y.Doc): () => void;Paragraph text keeps formatting in Yjs formatting markers. After a remote update, Yjs removes the markers it finds redundant from the document that received it. On a server, that removal is a change of the server's own, which the server sends to every participant, and it can remove the formatting of text a participant is typing. A prepared document does not remove markers. Every editor replica is prepared already.
readCollaborationDocumentfunctionSource ↗
Read the document a synchronized Y.Doc holds, as .docx bytes.
This is the server side of a room: export, autosave to your own storage, search indexing, a nightly PDF, a webhook. It JOINS NOTHING. There is no identity, no Awareness and no session, so the job that calls it never appears in anyone's avatar stack, and it creates no editing gate, so it cannot write back.
ydoc must already hold the room's state: connect your provider and wait for its initial sync first, exactly as a { kind: \'join\' } bootstrap does. A document that was never seeded refuses with not-initialized rather than returning a truncated file.
ts
// Hocuspocus hands onStoreDocument the synced Y.Doc already:
async onStoreDocument({ documentName, document }) {
await writeFile(${documentName}.docx, readCollaborationDocument(document));
}
Synchronous, and it materializes the whole package per call — this is a job, not a render.
declare function readCollaborationDocument(ydoc: Y.Doc): Uint8Array;readCollaborationFormatVersionfunctionSource ↗
Read the opaque format version recorded in a synchronized or restored room.
Reads version metadata without joining, exporting, or changing shared state. Can inspect incompatible rooms; pass the result to [assertCollaborationFormatCompatibility](assertCollaborationFormatCompatibility) before admitting their state. The result does not validate document content or guarantee a successful export. Use [readCollaborationDocument](readCollaborationDocument) to validate and export compatible content.
declare function readCollaborationFormatVersion(ydoc: Y.Doc): string;readCollaborationResourceUsagefunctionSource ↗
Read a room's resource usage from a synchronized Y.Doc, joining nothing.
The server-side sibling of readCollaborationDocument: call it from the same jobs — an autosave hook, a metrics scraper — to watch a room's growth against the caps that would end it. It creates no session and writes nothing, and it walks the node map once per call.
declare function readCollaborationResourceUsage(ydoc: Y.Doc): CollaborationResourceUsage;readCollaborationRoomGenerationfunctionSource ↗
The generation ID of the room a document holds: empty for a room never compacted, and empty for a document that holds no room yet.
declare function readCollaborationRoomGeneration(document: Y.Doc): string;Classes (1)
CollaborationSchemaErrorclassSource ↗
Typed collaboration schema or trust-boundary failure. Version-mismatch messages include recovery guidance and a documentation link. Use code for application logic; detail remains diagnostic information.
declare class CollaborationSchemaError extends Error| Member | Type | Summary |
|---|---|---|
| (constructor) | | Constructs a new instance of the `CollaborationSchemaError` class |
| code | CollaborationFailureCode | Stable failure code. Branch on it. |
| detail? | string | undefined | Bounded diagnostic text for logs. Not a parsing contract. |
Interfaces (15)
CollaborationHandleinterfaceSource ↗
Owned collaboration replica: document bytes, session, and teardown.
A host reads [CollaborationSession](CollaborationSession); the engine session remains assignable.
interface CollaborationHandle<TSession extends CollaborationSession>| Member | Type | Summary |
|---|---|---|
| destroy | | Stop the replica and release its listeners. The session becomes `destroyed`. |
| document | Uint8Array | The room's document as `.docx` bytes. Mount the editor with them. |
| session | TSession | The live session. Pass it to `collaborationModule`. |
CollaborationIdentityUpdateinterfaceSource ↗
Display-identity fields a live session can update.
actorId and role are attribution and stay immutable for the session lifetime, so this type cannot name them.
interface CollaborationIdentityUpdate| Member | Type | Summary |
|---|---|---|
| color? | string | New presence color, at most 64 characters. |
| name? | string | New display name, 1 to 256 characters after trimming. |
CollaborationMigrationDifferenceinterfaceSource ↗
One paragraph that differs between the export and the new room.
expected and actual hold document text. Treat them as document content: keep them out of logs that people without access to the document can read.
interface CollaborationMigrationDifference extends CollaborationMigrationPosition| Member | Type | Summary |
|---|---|---|
| actual | string | null | The paragraph's text in the new room, or null when the new room has no such paragraph. |
| expected | string | null | The paragraph's text in the export, or null when the export has no such paragraph. |
| kind | 'text' | 'formatting' | 'missing' | 'added' | - `text`: the paragraph's text differs. - `formatting`: its text is the same, but its properties or character formatting differ. - `missing`: the export has the paragraph and the new room does not. - `added`: the new room has a paragraph the export does not. |
CollaborationMigrationPositioninterfaceSource ↗
A paragraph by its part and its position in that part, from 1.
interface CollaborationMigrationPosition| Member | Type | Summary |
|---|---|---|
| paragraph | number | The paragraph's position in its part, from 1, in document order. |
| part | string | The package part that holds the paragraph, such as `/word/document.xml`. |
CollaborationMigrationReportinterfaceSource ↗
What a migration found, comparing the new room with the export it was seeded from.
The check compares each XML part of the export with the new room's. It ignores only what every save writes anew: namespace declarations, the values of paragraph IDs (w14:paraId, w14:textId) and of w:id, and the relationship parts. A reference to an ID, such as a comment anchor or a comment extension, must still name the same element. Revision IDs are not compared: they only have to be unique. For each paragraph it also reports its text and formatting, to locate a difference. It compares every media part by its bytes, and every external link target.
interface CollaborationMigrationReport| Member | Type | Summary |
|---|---|---|
| changedParts | readonly string[] | XML parts that differ, by name, or that one side does not have. A part whose paragraphs differ is listed too. |
| differenceCount | number | How many paragraphs differ. `differences` lists at most the first 20. |
| differences | readonly CollaborationMigrationDifference[] | The first paragraphs that differ, at most 20. |
| documentId | string | The document ID of the new room. Every client must open the room with this ID. |
| failed | readonly CollaborationMigrationCheck[] | The checks that failed. Empty when `ok` is true. |
| from | string | The earlier room's format, or `unversioned` for a room written before formats had one. |
| missingLinks | readonly string[] | External link targets of the export that the new room does not hold. |
| missingMedia | readonly string[] | Media parts of the export, by name, whose bytes the new room does not hold. |
| ok | boolean | True when every check passed. |
| paragraphs | number | Paragraphs in the export, in every part: body, tables, headers, footers, notes, and comments. A paragraph inside another, as in a text box, counts with the one that holds it. |
| to | string | The format of the new room: this build's. |
CollaborationModuleOptionsinterfaceSource ↗
How [collaborationModule](collaborationModule) is configured. The session is required; the licence key is optional and never validated.
interface CollaborationModuleOptions extends ProLicenseOptions| Member | Type | Summary |
|---|---|---|
| session | EditorCollaborationSession | The session from a collaboration factory. The editor attaches its document port to it. |
CollaborationResourceUsageinterfaceSource ↗
One reading of a room's replicated size against this replica's hard limits.
Every max* value is the cap whose crossing turns the session status terminal. tombstonedNodes is included in nodes: a tombstone is never map-deleted, so it keeps counting against maxNodes for the life of the room. A reading is a snapshot — take a new one to observe growth.
interface CollaborationResourceUsage| Member | Type | Summary |
|---|---|---|
| blobBytes | number | Bytes in the shared blob map, unreferenced bytes included. |
| formattingMarkers | number | Formatting markers in paragraph text. Each formatting change leaves some, and deleting the text does not remove them, because a participant who edited offline may still depend on them. They have no cap, but every reader walks them, so a room whose count keeps growing far past its text is one to move to a new room. |
| maxBlobBytes | number | Blob byte limit. Shared state over it is a terminal `blob-store-full`. |
| maxNodes | number | Node limit. Shared state over it is a terminal `too-many-nodes`. |
| maxParts | number | Part limit. Shared state over it is a terminal `too-many-parts`. |
| maxRelationships | number | Relationship limit. Shared state over it is a terminal `too-many-relationships`. |
| nodes | number | Replicated node records, tombstones included. |
| parts | number | Replicated package parts. |
| relationships | number | Replicated relationship records. |
| tombstonedNodes | number | The subset of `nodes` that is tombstoned: permanent, and only compaction reclaims it. |
CollaborationRoomGatePayloadinterfaceSource ↗
What the gate reads of a Hocuspocus beforeHandleMessage payload.
interface CollaborationRoomGatePayload| Member | Type | Summary |
|---|---|---|
| context | object | The connection's context object, which the gate marks once the generation matched. |
| document | Y.Doc | The room's server-side `Y.Doc`. |
| update | Uint8Array | The incoming message bytes. |
CollaborationSessioninterfaceSource ↗
Host-facing collaboration session.
A host reads identity, status, presence, and undo. The editor attaches [EditorCollaborationSession](EditorCollaborationSession) internally and never through this type.
interface CollaborationSession| Member | Type | Summary |
|---|---|---|
| canRedo | | Whether the shared undo history holds a local step to redo. |
| canUndo | | Whether the shared undo history holds a local step to undo. |
| documentId | string | The room's document id. |
| identity | CollaborationIdentity | The validated local identity. |
| offlineEditing? | boolean | Whether edits continue while the transport is down (`disconnected`). Set by the `offlineEditing` option; absent means true. |
| participants | | Participants in presence, this replica included. Capped at 256. |
| redo | | Redo this participant's last undone step. Returns false when refused. |
| remoteSelections | | Other participants' selections, resolved into this replica's addresses. |
| sessionId | string | Unique identity for this attachment lifetime. |
| setIdentity | | Update the display name and color mid-session, when the replica supports it. |
| status | | Current lifecycle state. |
| statusSnapshot | | Cached status, current reason, and last failure. |
| subscribeParticipants | | Call `listener` when the participant list changes. Returns the unsubscribe function. |
| subscribeRemoteSelections | | Call `listener` when a remote selection changes. Returns the unsubscribe function. |
| subscribeStatus | | Call `listener` on each status or reason change. Returns the unsubscribe function. |
| undo | | Undo this participant's last step; others' edits stay. Returns false when refused. |
CompactCollaborationStateOptionsinterfaceSource ↗
Options for [compactCollaborationState](compactCollaborationState).
interface CompactCollaborationStateOptions| Member | Type | Summary |
|---|---|---|
| minimumGain? | number | Compact only when the stored state is at least this many times the size of the compacted state. Default 2. Pass 1 to compact whenever it makes the room smaller. |
CreateDocumentCollaborationOptionsinterfaceSource ↗
Options for one full-document collaboration replica.
The caller owns ydoc.
interface CreateDocumentCollaborationOptions| Member | Type | Summary |
|---|---|---|
| awareness | Awareness | Presence channel for participants and remote selections, from `y-protocols/awareness`. |
| bootstrap | CollaborationBootstrap | Whether to seed the room, join it, or let the peers decide. |
| documentId | string | The room's document id, 1 to 256 characters. A room seeded with another id refuses. |
| identity | CollaborationIdentity | The local participant. Recorded as the author of this replica's changes. |
| offlineEditing? | boolean | Admit local edits while the transport is `disconnected`. |
| sessionId? | string | Unique attachment identity. Omit it to generate a new identity for this session. |
| ydoc | Y.Doc | The room's Yjs document. Connect its provider before a `join` bootstrap. |
DocumentCollaborationSessioninterfaceSource ↗
Full-document collaboration session: the engine-facing seam, the transport status a provider sets, and a live display-identity update.
interface DocumentCollaborationSession extends EditorCollaborationSession| Member | Type | Summary |
|---|---|---|
| resourceUsage | | One reading of the room's replicated size against this replica's hard limits. |
| setIdentity | | Update the display identity for the rest of this session and republish presence. |
| setTransportStatus | | Provider convenience seam. Low-level consumers normally leave the session ready. |
DocumentCollaborationVersionsinterfaceSource ↗
Version contract for full-document collaboration clients and export workers.
interface DocumentCollaborationVersions| Member | Type | Summary |
|---|---|---|
| canonicalModelVersion | number | Canonical document model interpreted by a replica. |
| protocolVersion | number | Transport-level interpretation of the shared package. |
| repairVersion | number | Deterministic rules for repairing shared structure. |
| sharedSchemaVersion | number | Shared node and character representation. |
MigrateCollaborationRoomOptionsinterfaceSource ↗
Options for [migrateCollaborationRoom](migrateCollaborationRoom).
interface MigrateCollaborationRoomOptions| Member | Type | Summary |
|---|---|---|
| documentId? | string | The document ID of the new room. Omit it to keep the earlier room's ID, which is what its clients open the room with: a client whose ID differs is refused with `document-id-mismatch`. Pass it only to give the room a new ID, and open it with that ID. |
| exported | Uint8Array | The `.docx` that the build which created the room exported from `state`, with `readCollaborationDocument`. |
| state | Uint8Array | The earlier room's saved state: the exact bytes that `exported` was exported from. |
TextCollaborationSessioninterfaceSource ↗
Deprecated. Use DocumentCollaborationSession for full-document collaboration.
Retained type for integrations with the retired text-only collaboration factory.
interface TextCollaborationSession extends EditorCollaborationSession| Member | Type | Summary |
|---|---|---|
| setTransportStatus | |
Type aliases (5)
CollaborationBootstraptypeSource ↗
Create or join bootstrap for one collaboration replica.
The document and WebRTC factories share this union.
create-or-join removes the out-of-band decision about which peer creates a room. The replica probes for an initialized room and joins it when one appears. Otherwise it runs a short awareness election and only the winning candidate seeds from document. A room that two peers seeded concurrently reports the terminal failure code concurrent-seed on every replica.
type CollaborationBootstrap = {
readonly kind: 'create';
readonly document: Uint8Array;
} | {
readonly kind: 'join';
readonly timeoutMs?: number;
readonly signal?: AbortSignal;
} | {
readonly kind: 'create-or-join';
readonly document: Uint8Array;
readonly probeTimeoutMs?: number;
readonly electionWindowMs?: number;
readonly timeoutMs?: number;
readonly signal?: AbortSignal;
};CollaborationMigrationtypeSource ↗
The result of migrateCollaborationRoom.
- ok: true: the check passed. Store state in place of the earlier room's state. - reason: 'check-failed': the new room differs from the export. Nothing is returned to store; report says what differs. - reason: 'current': the room is already in this build's format. Leave it as it is. - reason: 'later-format': a later build wrote the room. Do not open or replace it.
type CollaborationMigration = {
readonly ok: true;
readonly state: Uint8Array;
readonly report: CollaborationMigrationReport;
} | {
readonly ok: false;
readonly reason: 'check-failed';
readonly report: CollaborationMigrationReport;
} | {
readonly ok: false;
readonly reason: 'current' | 'later-format';
};CollaborationMigrationChecktypeSource ↗
A check that a migration runs on the new room, compared with the export.
- paragraphs: the new room holds a different number of paragraphs. - text: a paragraph's text differs. - formatting: a paragraph's properties, or the character formatting of its text, differ. - structure: an XML part differs in something the other checks do not cover, such as tables, sections, styles, numbering, tracked changes, comments, or notes. - media: a media part's bytes are missing. - links: an external link target is missing.
type CollaborationMigrationCheck = 'paragraphs' | 'text' | 'formatting' | 'structure' | 'media' | 'links';CollaborationMigrationNeedtypeSource ↗
How saved room state relates to the format this build writes.
- current: the room is in this build's format; it needs no migration. - earlier-format: an earlier build wrote it; export it with that build and migrate it. - later-format: a later build wrote it; this build must not open or replace it.
type CollaborationMigrationNeed = 'current' | 'earlier-format' | 'later-format';DocumentCollaborationHandletypeSource ↗
Owned full-document collaboration replica.
type DocumentCollaborationHandle = CollaborationHandle<DocumentCollaborationSession>;Variables (5)
COLLABORATION_FORMAT_VERSIONconstSource ↗
Opaque collaboration format version, independent of the editor package version.
Send this value unchanged during connection admission. Check it with [assertCollaborationFormatCompatibility](assertCollaborationFormatCompatibility) before allowing synchronization. Equal values declare format compatibility across clients, workers, and saved rooms. Do not parse, order, hard-code, or override the value. It is not a credential. Inspect saved rooms separately with [readCollaborationFormatVersion](readCollaborationFormatVersion).
COLLABORATION_FORMAT_VERSION: stringDOCUMENT_COLLABORATION_VERSIONSconstSource ↗
Deprecated. Send `COLLABORATION_FORMAT_VERSION` in the connection handshake and check it with `assertCollaborationFormatCompatibility`. This tuple stays supported for existing handshakes.
Versions supported by this full-document collaboration release.
These values describe the application schema, not the DOCX format or the Yjs binary update format. Releases with the same tuple can share rooms. A changed tuple requires a coordinated upgrade. This descriptor does not migrate persisted rooms or authenticate clients.
DOCUMENT_COLLABORATION_VERSIONS: DocumentCollaborationVersionsMAX_BASELINE_BYTESconstSource ↗
Deprecated. Use the full-document factory's validation and typed failure codes.
Historical baseline byte limit for the retired text-only collaboration factory. This value does not configure full-document collaboration limits.
MAX_BASELINE_BYTES: numberPROTOCOL_VERSIONconstSource ↗
Deprecated. Use COLLABORATION_FORMAT_VERSION for full-document connection checks.
Protocol identifier for the retired text-only collaboration format.
PROTOCOL_VERSION = 1SCHEMA_VERSIONconstSource ↗
Deprecated. Use COLLABORATION_FORMAT_VERSION for full-document connection checks.
Schema identifier for the retired text-only collaboration format.
SCHEMA_VERSION = 1