API Reference

createIO

Returns a PluvIO instance.

Creates a server-side PluvIO client that can be used to create event procedures, routers and servers. Below is an example configuration for createIO. To learn more about createIO, read Authorization, Cloudflare Workers and Node.js.

import { yjs } from "@pluv/crdt-yjs";
import { createIO } from "@pluv/io";
import { platformNode } from "@pluv/platform-node";
import { z } from "zod";
import { Database } from "./db";

const io = createIO(
    platformNode({
        authorize: {
            secret: process.env.PLUV_AUTH_SECRET!,
            user: z.object({
                id: z.string(),
                name: z.string(),
            }),
        },
        context: () => ({
            db: new Database(process.env.DATABASE_URL!),
        }),
        crdt: yjs,
    })
);

PluvIO

This is the client returned by createIO.

createToken

Returns Promise<string>.

Creates a JWT for a user trying to connect to a room. This should be called within a custom authentication endpoint you define. See Authorization for more information.

// If using `@pluv/platform-pluv`
const token = await io.createToken({
    room: "my-example-room",
    user: { id: "...", name: "..." },
});

// If using `@pluv/platform-cloudflare
const token = await io.createToken({
    env: env as Env,
    request: request as Request,
    room: "my-example-room",
    user: { id: "...", name: "..." },
});

// If using `@pluv/platform-node`
const token = await io.createToken({
    req: req as Http.IncomingMessage,
    room: "my-example-room",
    user: { id: "...", name: "..." },
});

procedure

Creates a new type-safe event procedure to be broadcasted from PluvClient. See Define Events for more information.

import { createIO } from "@pluv/io";
import { platformNode } from "@pluv/platform-node";
import { z } from "zod";

const io = createIO(platformNode());

const sendMessage = io.procedure
    .input(z.object({ message: z.string() }))
    .broadcast(({ message }) => ({ receiveMessage: { message } }));

const doubleValue = io.procedure
    .input(z.object({ value: z.number() }))
    .broadcast(({ value }) => ({ receiveValue: { value: value * 2 } }));

const wave = io.procedure
    .broadcast(() => ({ receiveMessage: { message: "Hello world!" } }));

router

Creates a new type-safe event procedure router to attach events and connect to a PluvServer.

import { createIO } from "@pluv/io";
import { platformNode } from "@pluv/platform-node";
import { z } from "zod";

const io = createIO(platformNode());

const sendMessage = io.procedure
    .input(z.object({ message: z.string() }))
    .broadcast(({ message }) => ({ receiveMessage: { message } }));

const doubleValue = io.procedure
    .input(z.object({ value: z.number() }))
    .broadcast(({ value }) => ({ receiveValue: { value: value * 2 } }));

const wave = io.procedure
    .broadcast(() => ({ receiveMessage: { message: "Hello world!" } }));

const router = io.router({
    sendMessage,
    doubleValue,
    wave,
});

server

Creates a PluvServer that will create rooms to register your websockets to.

In the example below, not all event listeners are available for all platforms. Refer to the TypeScript intellisense for your selected platform when defining your server to know which you can use.

import { createIO } from "@pluv/io";
import { platformNode } from "@pluv/platform-node";
import { z } from "zod";

const io = createIO(platformNode());
const router = io.router({ /* ... */ });

const server = io.server({
    // Optional: Triggered when a room is freshly created. If the room existed
    // before, you can load the storage state for the room by returning it here
    getInitialStorage: async ({ context, room }) => {
        const { db } = context;
        const existingRoom = await db.room.findUnique({ where: { room } });

        return existingRoom?.encodedState ?? null;
    },
    // Optional: Triggered when a room is deleted. Callback includes the last
    // value for the room's state for persisting purposes
    onRoomDeleted: async ({ context, encodedState, room }) => {
        const { db } = context;

        await db.room.upsert({
            where: { room },
            create: { encodedState, room },
            update: { encodedState },
        });
    },
    // Optional: Triggered each time any participant sends a new message to
    // other participants
    // It is advised not to perform any heavy operations in this listener
    // due to the frequency of invocations
    onRoomMessage: async ({ context, encodedState, room }) => {
        // ...
    },
    // Optional: Triggered each time the room's storage is updated.
    // It is advised not to perform any heavy operations in this listener
    // due to the frequency of invocations
    onStorageUpdated: ({ context, encodedState, room }) => {
        // ...
    },
    // Optional: Triggered each time a user connects to a room
    onUserConnected: ({ context, encodedState, room, user }) => {
        // ...
    },
    // Optional: Triggered each time a user disconnects from a room
    onUserDisconnected: ({ context, encodedState, room, user }) => {
        // ...
    },
    // Optional. Only needed if specifying events
    router,
});

// Can also be created without a router, if events are unneeded
const server = io.server();

PluvServer

createRoom

Returns IORoom.

Creates a room with the specified id.

const room = server.createRoom("my-example-room");

IORoom

This is the room returned by PluvServer.createRoom. This is what websockets are registered to.

broadcast

Returns Promise<void>.

Broadcasts an event to all connected websockets to the room.

// The below 2 statements are equivalent
room.broadcast("sendMessage", { message: "Hello world~!" });

room.broadcast.sendMessage({ message: "Hello world~!" });

evict

Returns Promise<void>

Disconnects a connection from the room by connection id.

room.evict(connectionId);

evictAll

Returns Promise<void>

Disconnects all connections from the room. Effectively destroys the room, as rooms automatically destroy when empty.

room.evictAll();

garbageCollect

Returns Promise<void>

While uncommon and unusual, there may be edge cases that may cause stale connections to persist either in user's browsers, or in the IORoom. Such can be missed websocket messages or server errors that weren't gracefully handled. @pluv/platform-node will automatically run garbage collection periodically; however, for @pluv/platform-cloudflare, it is recommended that this is called in a Durable Object alarm periodically.

room.garbageCollect();

getSize

Returns number

Returns the current count of active connections in the room

room.getSize();

id

Type of string.

This is the id of the room, when the room was created.

const roomId = room.id;

register

Returns Promise<void>.

Registers a websocket to the room. Accepts a secondary options parameter to pass-in a token for authorizing the room. Read Cloudflare Workers, Node.js and Authorization to learn more.

// const token: string = ...

// For @pluv/platform-cloudflare
room.register(webSocket, {
    env: env as Env,
    request: request as Request,
    token,
});
// For @pluv/platform-node
room.register(webSocket, {
    req: req as Http.IncomingMessage,
    token,
});