Experiences like these should be collaborative. Click around!
Task | |||||
---|---|---|---|---|---|
No results. |
Get auto-completion and in-code errors with end-to-end type-safety.
Build for either Cloudflare Workers or Node.js runtimes.
Edit shared data and documents with the Yjs or Loro ecosystems.
Have users directly interact with eachother in realtime with per-user states.
Give each users their own identity with custom authentication rules.
To get started with pluv.io, you will first need to create a PluvIO
server that can start registering new websocket connections.
On the server, you can define any number of event procedures that your frontend can broadcast to other connections in the same realtime room.
In these event procedures, you can optionally define Zod schema validators to ensure that the inputs are defined in the same way our backend expects when they are received.
Lastly, define a type export of the IOServer
for our frontend to use.
const io = createIO({ platform: platformNode() });
const router = io.router({
sendGreeting: io.procedure
.input(z.object({ name: z.ZodString
name: z.string() }))
.broadcast(({ name: string
name }) => ({
receiveGreeting: { greeting: `Hi! I'm ${name: string
name}!` },
})),
});
export const ioServer = io.server({ router });
export type IOServer = typeof ioServer;
Next, set-up our HTTP and WebSocket servers using our ioServer
.
Set-up may vary between Node.js and Cloudflare Worker runtimes.
const app = express();
const server = Http.createServer(app);
const Pluv = createPluvHandler({ io: ioServer, server });
Pluv.createWsServer();
app.use(Pluv.handler);
server.listen(3000);
Afterwards, we will prepare our frontend bundle by using a type import of our IOServer
. This frontend bundle contains all of pluv.io's APIs for realtime collaboration.
You can optionally define a presence for each user with Zod, and CRDT storage with Yjs or Loro to unlock more realtime capabilities for your app.
const client = createClient({
infer: (i) => ({ io: i<IOServer> }),
initialStorage: yjs.doc(() => ({
tasks: yjs.array([
{ id: "TASK-4753", status: "todo", priority: "medium" },
{ id: "TASK-2676", status: "progress", priority: "high" },
{ id: "TASK-5720", status: "progress", priority: "high" },
]),
})),
presence: z.object({
selectionId: z.string().nullable(),
}),
wsEndpoint: ({ room }) => `wss://pluv.io/api/pluv/room/${room}`,
});
export const pluv = createBundle(client);
The room bundle provides a PluvRoomProvider
to wrap your page with. Once you do, your app is now multiplayer with pluv.io!
const Page: React.FC<PageProps> = ({ children, roomId: string
roomId }) => (
<pluv.PluvRoomProvider
initialPresence: {
selectionId: string | null;
}
initialPresence={{ selectionId: null }}
room: string
room={roomId: string
roomId}
>
{children}
</pluv.PluvRoomProvider>
);
With our frontend bundle ready to use, you can start using pluv.io realtime primitives with TypeScript autocompletion and intellisense matching your backend events, presence and storage.
Type definitions will be as narrow as you've configured, all while managing minimal TypeScript type definitions and without code-generation!
const broadcast = pluv.useBroadcast();
broadcast.sendGreeting: (input: {
name: string;
}) => void
sendGreeting({ name: "leedavidcs" });
pluv.event.receiveGreeting.useEvent(({ data }) => {
console.log(data.greeting: string
greeting);
});
const [const selectionId: string | null
selectionId] = pluv.useMyPresence((presence) => {
return presence.selectionId;
});
const [const tasks: {
id: string;
status: string;
priority: string;
}[] | null
tasks] = pluv.useStorage("tasks");
//