API Reference

createClient

Returns a PluvClient instance

Create a frontend PluvClient that will create rooms to connect to your server's PluvIO instance.

createClient basic example

If you've created a basic PluvIO backend without any auth, you can create a PluvClient with your websocket connection endpoint.

1// frontend/io.ts
2
3import { createClient } from "@pluv/client";
4
5const client = createClient({
6 // Defaults to (room) => `/api/pluv/room/${room}`
7 // This is the default from `createPluvHandler`.
8 wsEndpoint: (room: string) => `/api/room?room=${room}`,
9});

createClient with fetch options

If you need to use a POST request or specify additional headers, you can return an object containing options for fetch.

1// frontend/io.ts
2
3import { createClient } from "@pluv/client";
4
5const client = createClient({
6 wsEndpoint: (room: string) => ({
7 url: "/api/room",
8 // specify fetch options here
9 options: {
10 method: "post",
11 body: JSON.stringify({ room }),
12 },
13 }),
14});

createClient with auth endpoint

If your PluvIO implements auth, you will need to specify an authEndpoint on your frontend client.

1import { createClient } from "@pluv/client";
2
3const client = createClient({
4 wsEndpoint: (room: string) => `/api/room?room=${room}`,
5 authEndpoint: (room: string) => `/api/room/auth?room=${room}`,
6});

PluvClient

This is the client returned by createClient.

PluvClient.createRoom

Returns a PluvRoom instance

Create a PluvRoom that websockets can join and leave. The second argument is an optional configuration for presence and storage. See the example below for the available properties of the configuration.

1// frontend/room.ts
2import { y } from "@pluv/client";
3import { z } from "zod";
4import { client } from "./io.ts";
5
6const room = client.createRoom("my-example-room", {
7 /**
8 * @description Define your presence schema
9 */
10 presence: z.object({
11 selectionId: z.nullable(z.string()),
12 }),
13 /**
14 * @description Define the user's initial presence
15 */
16 initialPresence: {
17 selectionId: null,
18 },
19 /**
20 * @description Define the initial storage for the room
21 */
22 initialStorage: () => ({
23 messages: y.array(["hello world!"]),
24 }),
25 /**
26 * @description This is the same `captureTimeout` option from yjs's UndoManager.
27 * This specifies a number in ms, during which edits are merged together to be
28 * undone together. Set this to 0, to track each transacted change individually.
29 * @see https://docs.yjs.dev/api/undo-manager
30 * @default 500
31 */
32 captureTimeout: 500,
33 /**
34 * @desription This is the same `trackedOrigins` option from yjs's UndoManager.
35 * This specifies transaction origins (strings only) to filter which transactions
36 * can be undone.
37 * When omitted, the user's connection id will be tracked. When provided,
38 * specifies additional tracked origins besides the user's connection id.
39 * @see https://docs.yjs.dev/api/undo-manager
40 * @default undefined
41 */
42 trackedOrigins: ["user-123"],
43});

PluvClient.enter

Returns Promise<PluvRoom>

Establishes a websocket connection with a room. If the PluvClient specifies an authEndpoint, the endpoint will be called when this function is called. Returns the PluvRoom that was entered.

Note: This method will fail if the room does not already exist beforehand.

1// frontend/room.ts
2import { client } from "./io.ts";
3
4const room = client.createRoom("my-example-room", {
5 // ...
6})
7
8// Enter room by room name
9client.enter("my-example-room").then(() => {
10 console.log("Connected to: my-example-room");
11});
12
13// Alternatively, you can pass the PluvRoom instance
14client.enter(room).then(() => {
15 console.log("Connected to: my-example-room");
16});

PluvClient.getRoom

Returns a PluvRoom instance or null if none is found

1// frontend/room.ts
2
3import { client } from "./io.ts";
4
5const room = client.getRoom("my-example-room");

PluvClient.getRooms

Returns PluvRoom[]

Retrieves all active rooms under the current PluvClient instance.

1// frontend/room.ts
2
3import { client } from "./io.ts";
4
5const rooms = client.getRooms();

PluvClient.leave

Returns void

Disconnects from a PluvRoom and deletes the room on the PluvClient. If the room does not exist, nothing happens and the function returns immediately.

1// frontend/room.ts
2
3import { client } from "./io.ts";
4
5const room = client.createRoom("my-example-room", {
6 // ...
7})
8
9// Leave room by room name
10client.leave("my-example-room");
11
12// Alternatively, you can pass the PluvRoom instance
13client.leave(room);

PluvRoom

This is the room returned by PluvClient.createRoom.

PluvRoom.webSocket

Type of WebSocket | null

This is the WebSocket that is created and attached to the room when connected to.

PluvRoom.broadcast

Returns void

Broadcasts an event to all websockets connected to the room.

1// frontend/room.ts
2
3room.broadcast("EMIT_EMOJI", { emojiCode: 123 });

PluvRoom.canRedo

Returns boolean

Checks whether calling PluvRoom.redo will mutate storage.

1// frontend/room.ts
2
3const canRedo: boolean = room.canRedo();

PluvRoom.canUndo

Returns boolean

Checks whether calling PluvRoom.undo will mutate storage.

1// frontend/room.ts
2
3const canUndo: boolean = room.canUndo();

PluvRoom.connect

Returns Promise<void>

Connects to the room if not connected to already. If an authEndpoint is configured, this function will call your authEndpoint.

1// frontend/room.ts
2
3room.connect().then(() => {
4 console.log(`Connected to room: ${room.id}`);
5});

PluvRoom.disconnect

Returns void

Disconnects from the room if already connected.

PluvRoom.event

Returns () => void

Subscribes to an event. These events are defined by PluvIO.event and are emitted when other websockets emit events via PluvRoom.broadcast.

1// Subscribe to EMOJI_RECEIVED messages
2const unsubscribe = room.event("EMOJI_RECEIVED", ({ data }) => {
3 console.log(data);
4});
5
6// ...
7
8// Unsubscribe to the listener later on.
9unsubscribe();

PluvRoom.getConnection

Returns WebSocketConnection

This returns state information for the current connection to this room.

1const connection = room.getConnection();

PluvRoom.getMyPresence

Returns TPresence | null

Returns the user's current presence data.

1const myPresence = room.getMyPresence();

PluvRoom.getMyself

Returns UserInfo | null

Returns a user info object containing data used when generating the JWT during authentication (see Authorization), the user's presence, and the user's connection id.

1const myself = room.getMyself();

PluvRoom.getOther

Returns UserInfo | null

Returns a user info object for the given connectionId.

1// const connectionId = "some connection id of another connection"
2
3const other = room.getOther(connectionId);

PluvRoom.getOthers

Returns UserInfo[]

Returns all user info objects for connections that are not the current user's.

1const others = room.getOthers();

PluvRoom.getStorage

Returns a yjs shared type defined on the client config.

1// frontend/room.ts
2import { y } from "@pluv/client";
3import { z } from "zod";
4import { client } from "./io.ts";
5
6const room = client.createRoom("my-example-room", {
7 // Define your presence schema
8 presence: z.object({
9 selectionId: z.nullable(z.string()),
10 }),
11 // Define the user's initial presence
12 initialPresence: {
13 selectionId: null,
14 },
15 // Define the initial storage for the room
16 initialStorage: () => ({
17 messages: y.array(["hello world!"]),
18 }),
19});
20
21const messages = room.getStorage("messages");

PluvRoom.other

Returns () => void

Subscribes to a given user info object for a connection that isn't the current user's.

1// const connectionId = "some connection id of another connection"
2
3const unsubscribe = room.other(connectionId, ({
4 connectionId,
5 presence,
6 user
7}) => {
8 console.log(connectionId, presence, user);
9});
10
11// ...
12
13// Unsubscribe to the listener later on.
14unsubscribe();

PluvRoom.redo

Returns void

Re-applies the last mutation that was undone via PluvRoom.undo.

1// frontend/room.ts
2
3room.redo();

PluvRoom.storage

Returns () => void

Subscribes to a given root-level value in the yjs document storage.

1// frontend/room.ts
2import { y } from "@pluv/client";
3import { z } from "zod";
4import { client } from "./io.ts";
5
6const room = client.createRoom("my-example-room", {
7 // Define your presence schema
8 presence: z.object({
9 selectionId: z.nullable(z.string()),
10 }),
11 // Define the user's initial presence
12 initialPresence: {
13 selectionId: null,
14 },
15 // Define the initial storage for the room
16 initialStorage: () => ({
17 messages: y.array(["hello world!"]),
18 }),
19});
20
21const unsubscribe = room.storage("messages", (messages) => {
22 console.log(messages);
23});
24
25// ...
26
27// Unsubscribe to the listener later on.
28unsubscribe();

PluvRoom.subscribe("connection")

Returns () => void

Subscribes to the user's connection state.

1const unsubscribe = room.subscribe("connection", ({
2 // The user's authorization state: { token, user }
3 authorization,
4 // The user's connection state: { id, state }
5 connection,
6 // The user's websocket
7 webSocket,
8}) => {
9 console.log(authorization, connection, webSocket);
10});
11
12// ...
13
14// Unsubscribe to the listener later on.
15unsubscribe();

PluvRoom.subscribe("my-presence")

Returns () => void

Subscribes to the user's presence state.

1const unsubscribe = room.subscribe("my-presence", (myPresence) => {
2 console.log(myPresence);
3});
4
5// ...
6
7// Unsubscribe to the listener later on.
8unsubscribe();

PluvRoom.subscribe("myself")

Returns () => void

Subscribes to the user's info object.

1const unsubscribe = room.subscribe("myself", (myself) => {
2 console.log(myself);
3});
4
5// ...
6
7// Unsubscribe to the listener later on.
8unsubscribe();

PluvRoom.subscribe("others")

Returns () => void

Subscribes to the list of user info objects of the other connections that aren't the user's.

1const unsubscribe = room.subscribe("others", (others) => {
2 console.log(others);
3});
4
5// ...
6
7// Unsubscribe to the listener later on.
8unsubscribe();

PluvRoom.transact

Returns void

Performs a mutation that can be tracked as an operation to be undone/redone (undo/redo). When called without an origin, the origin will default to the user's connection id.

You can specify a 2nd parameter to transact with a different transaction origin.

1// frontend/transact
2
3room.transact((tx) => {
4 room.get("messages").push(["hello world!"]);
5
6 // Alternatively, access your storage from here
7 tx.messages.push(["hello world!"]);
8});
9
10// This will also be undoable if `"user-123"` is a tracked origin.
11room.transact(() => {
12 room.get("messages").push(["hello world!"]);
13}, "user-123");

PluvRoom.undo

Returns void

Undoes the last mutation that was applied via PluvRoom.transact.

1// frontend/room.ts
2
3room.undo();