pluv.io is in preview! Please wait for a v1.0.0 stable release before using this in production.

Yjs Storage

pluv.io supports conflict-free replicated data-types (CRDT) storage with yjs. This allows modifying shared data between multiple users, and also leveraging some libraries within the yjs ecosystem such as rich-text-editor bindings.

Specify Yjs CRDT on PluvIO

To get started with yjs for pluv.io, first specify which CRDT you intend to use on your PluvIO instance.

import { yjs } from "@pluv/crdt-yjs";

const io = createIO({
    // ...
    crdt: yjs,
});

Set initialStorage

Then set an initialStorage config on your createClient config.

import { yjs } from "@pluv/crdt-yjs";
import { createBundle, createClient } from "@pluv/react";
import type { AppPluvIO } from "backend/io";

const client = createClient({
    infer: (i) => ({ io: i<AppPluvIO> }),
    // Set the initial storage value, and type here
    // Don't worry, we can set a different default value in the room component
    initialStorage: yjs.doc(() => ({
        messages: yjs.array(["hello world!"]),
    })),
    wsEndpoint: ({ room }) => `${process.env.WS_ENDPOINT}/api/room/${room}`,
});

export const pluv = createBundle(client);

Setup PluvRoomProvider

Then, setup PluvRoomProvider with your new initialStorage if it is different than your default set from createClient.

import { yjs } from "@pluv/crdt-yjs";
import type { FC } from "react";
import { pluv } from "./frontend/io";

export const MyPage: FC = () => {
    return (
        <pluv.PluvRoomProvider
            room="my-room-id"
            initialStorage={() => ({
                messages: yjs.array(),
            })}
        >
            <MyRoom />
        </pluv.PluvRoomProvider>
    );
};

Use yjs shared-types

We can then use yjs shared-types to leverage shared CRDTs between connected clients using useStorage.

import { pluv } from "frontend/io";
import { useCallback } from "react";

// "messages" is a key from the root properties of `initialStorage`.
const [messages, sharedType] = pluv.useStorage("messages");

const addMessage = useCallback((message: string) => {
    sharedType?.push([message]);
});

messages?.map((message, i) => <div key={i}>{message}</div>)