Modifying Yjs document data with the REST API

Liveblocks allows you to update your Yjs document data, or yDoc, from the REST API, helpful for sending updates from the server. This is made possible through Liveblocks.sendYjsBinaryUpdate in @liveblocks/node.

Updating a Yjs document

Updating a Yjs document requires you to create a binary update, before sending it to Liveblocks using Liveblocks.sendYjsBinaryUpdate. Here’s an example in a serverless endpoint.

import * as Y from "yjs";import { Liveblocks } from "@liveblocks/node";
const liveblocks = new Liveblocks({ secret: "",});const roomId = "my-room-name";
export async function POST() { // Create a Yjs document const yDoc = new Y.Doc();
// Create your data structures and make your update // Each editor is different, you probably need to change these two lines const yText = yDoc.getText("text"); yText.insert(0, "Hello world");
// Encode the document state as an update const yUpdate = Y.encodeStateAsUpdate(yDoc);
// Insert the update await liveblocks.sendYjsBinaryUpdate(roomId, yUpdate);}

Note that if you’re using a text editor, each one works differently, so you’ll most likely need to modify these two lines to use a format your editor defines.

const yText = yDoc.getText("text");yText.insert(0, "Hello world");

Initializing a Yjs document

It’s also possible to create a new room with an initial Yjs document. To do this, call Liveblocks.createRoom, then send the update as before.

import * as Y from "yjs";import { Liveblocks } from "@liveblocks/node";
const liveblocks = new Liveblocks({ secret: "",});const roomId = "my-room-name";
export async function POST() { // Create a Yjs document const yDoc = new Y.Doc();
// Create your data structures and make your update // Each editor is different, you probably need to change these two lines const yText = yDoc.getText("text"); yText.insert(0, "Hello world");
// Encode the document state as an update const yUpdate = Y.encodeStateAsUpdate(yDoc);
// Create the new room const room = await liveblocks.createRoom(roomId, { defaultAccesses: ["room:write"], });
// Initialize the Yjs document with the update await liveblocks.sendYjsBinaryUpdate(roomId, yUpdate);}

Each editor works differently

Note that each text and code editor may work differently, and may include specific functions for creating binary updates, or use different shared types. Slate and Tiptap use Y.XmlFragment instead of Y.Text.

Slate

This is how to initialize a Slate document.

import * as Y from "yjs";import { Liveblocks } from "@liveblocks/node";import { slateNodesToInsertDelta } from "@slate-yjs/core";
const liveblocks = new Liveblocks({ secret: "",});const roomId = "my-room-name";
export async function POST() { // Create a Yjs document const yDoc = new Y.Doc();
// The Slate document we're creating const slateDoc = { type: "paragraph", children: [{ text: "Hello world" }], };
// Create your data structures and make your update const insertDelta = slateNodesToInsertDelta(slateDoc); (yDoc.get("content", Y.XmlText) as Y.XmlText).applyDelta(insertDelta);
// Encode the document state as an update const yUpdate = Y.encodeStateAsUpdate(yDoc);
// Create the new room const room = await liveblocks.createRoom(roomId, { defaultAccesses: ["room:write"], });
// Initialize the Yjs document with the update await liveblocks.sendYjsBinaryUpdate(roomId, yUpdate);}

Tiptap

This is how to initialize a Tiptap document.

import * as Y from "yjs";import { Liveblocks } from "@liveblocks/node";
const liveblocks = new Liveblocks({ secret: "",});const roomId = "my-room-name";
export async function POST() { // Create a Yjs document const yDoc = new Y.Doc();
// The Tiptap Yjs state we're creating const yXmlElement = new Y.XmlElement("paragraph"); yXmlElement.insert(0, [new Y.XmlText("Hello world")]);
// Create your data structures and make your update const yXmlFragment = yDoc.getXmlFragment("default"); yXmlFragment.insert(0, [yXmlElement]);
// Encode the document state as an update message const yUpdate = Y.encodeStateAsUpdate(yDoc);
// Create the new room const room = await liveblocks.createRoom(roomId, { defaultAccesses: ["room:write"], });
// Initialize the Yjs document with the update await liveblocks.sendYjsBinaryUpdate(roomId, yUpdate);}