Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: update docs with new api changes #572

Merged
merged 12 commits into from
Feb 15, 2024
27 changes: 16 additions & 11 deletions apps/web/src/components/HomeCodeDemo/HomeCodeDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export const HomeCodeDemo = memo<HomeCodeDemoProps>((props) => {
},
{
code: codeBlock`
import { y } from "@pluv/react";
import { yjs } from "@pluv/crdt-yjs";
import { PluvRoomProvider } from "client/pluv";
import type { FC, ReactNode } from "react";

Expand All @@ -115,9 +115,9 @@ export const HomeCodeDemo = memo<HomeCodeDemoProps>((props) => {
const initialPresence = { selection: null };

const initialStorage = () => ({
boxes: y.object({
first: y.object({ x: -48, y: 0 }),
second: y.object({ x: 48, y: 0 }),
boxes: yjs.object({
first: yjs.object({ x: -48, y: 0 }),
second: yjs.object({ x: 48, y: 0 }),
}),
});

Expand All @@ -138,7 +138,8 @@ export const HomeCodeDemo = memo<HomeCodeDemoProps>((props) => {
},
{
code: codeBlock`
import { createBundle, createClient, y } from "@pluv/react";
import { yjs } from "@pluv/crdt-yjs";
import { createBundle, createClient } from "@pluv/react";
import type { io } from "server/pluv";
import { z } from "zod";

Expand Down Expand Up @@ -177,24 +178,28 @@ export const HomeCodeDemo = memo<HomeCodeDemoProps>((props) => {
selection: z.nullable(z.string()),
}),
// This can be overwritten at the provider level
initialStorage: () => ({
boxes: y.object({
first: y.object({ x: 0, y: 0 }),
second: y.object({ x: 0, y: 0 }),
initialStorage: yjs.doc(() => ({
boxes: yjs.object({
first: yjs.object({ x: 0, y: 0 }),
second: yjs.object({ x: 0, y: 0 }),
}),
}),
})),
});
`,
name: "client/pluv.ts",
},
{
code: codeBlock`
import { yjs } from "@pluv/crdt-yjs";
import { createIO } from "@pluv/io";
import { platformNode } from "@pluv/platform-node";
import { z } from "zod";

// Create @pluv/io websocket manager for Node.js
export const io = createIO({ platform: platformNode() });
export const io = createIO({
crdt: yjs,
platform: platformNode(),
});
`,
name: "server/pluv.ts",
},
Expand Down
32 changes: 21 additions & 11 deletions apps/web/src/inputs/docs/1--Introduction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Multi-platform, E2E type-safe realtime packages
<img src="https://img.shields.io/npm/v/@pluv/io" alt="npm @pluv/io" />
</a>
<a href="https://github.com/pluv-io/pluv/blob/master/LICENSE">
<img alt="GitHub" src="https://img.shields.io/github/license/pluv-io/pluv" alt="License MIT" />
<img src="https://img.shields.io/github/license/pluv-io/pluv" alt="License MIT" />
</a>
<a href="https://commitizen.github.io/cz-cli/">
<img src="https://img.shields.io/badge/commitizen-friendly-blue.svg" alt="Commitizen friendly" />
Expand All @@ -39,9 +39,11 @@ Multi-platform, E2E type-safe realtime packages

Existing open-source tools for building real-time APIs come with several trade-offs. With [socket.io](https://socket.io) or [y-websocket](https://github.com/yjs/y-websocket), you get built-in support for things like heartbeats, rooms and awareness without any automatic type-safety server-to-client. Meanwhile, with [GraphQL](https://graphql.org/) you get type-safety in subscriptions but lose those same features. pluv.io unifies these experiences by providing **common websocket API capabilities** and **end-to-end type-safety** server-to-client.

## Built for multiple runtimes and frameworks
## Bring your own runtime, framework and CRDT

pluv.io supports hosting on either [Node.js](https://nodejs.org/) or [Cloudflare Workers](https://workers.cloudflare.com/). Support for multiple frameworks is also planned, with [React](https://beta.es.reactjs.org/) already available with [@pluv/react](https://www.npmjs.com/package/@pluv/react). If you're building for other frameworks, [@pluv/client](https://www.npmjs.com/package/@pluv/client) is framework agnostic and can meet your needs.
Today, pluv.io supports hosting on either [Node.js](https://nodejs.org/) or [Cloudflare Workers](https://workers.cloudflare.com/). Support for multiple frameworks is also planned, with [React](https://beta.es.reactjs.org/) already available with [@pluv/react](https://www.npmjs.com/package/@pluv/react). If you're building for other frameworks, [@pluv/client](https://www.npmjs.com/package/@pluv/client) is framework agnostic and can meet your needs.

pluv.io also supports [Yjs](https://docs.yjs.dev/) and experimentally supports the [Loro](https://loro.dev/) CRDT library.

## Features and roadmap

Expand All @@ -52,14 +54,21 @@ pluv.io supports hosting on either [Node.js](https://nodejs.org/) or [Cloudflare
- [x] Rooms
- [x] Authentication
- [x] Awareness + Presence
- [x] [CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type) (with [Yjs](https://docs.yjs.dev/))
- [x] **Shared Types**
- [x] [Map](https://docs.yjs.dev/api/shared-types/y.map)
- [x] [Array](https://docs.yjs.dev/api/shared-types/y.array)
- [x] [Text](https://docs.yjs.dev/api/shared-types/y.text)
- [x] [XmlFragment](https://docs.yjs.dev/api/shared-types/y.xmlfragment)
- [x] [XmlElement](https://docs.yjs.dev/api/shared-types/y.xmlelement)
- [x] [XmlText](https://docs.yjs.dev/api/shared-types/y.xmltext)
- [x] [CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)
- [x] [Yjs](https://docs.yjs.dev/)
- [x] **Shared Types**
- [x] [Map](https://docs.yjs.dev/api/shared-types/y.map)
- [x] [Array](https://docs.yjs.dev/api/shared-types/y.array)
- [x] [Text](https://docs.yjs.dev/api/shared-types/y.text)
- [x] [XmlFragment](https://docs.yjs.dev/api/shared-types/y.xmlfragment)
- [x] [XmlElement](https://docs.yjs.dev/api/shared-types/y.xmlelement)
- [x] [XmlText](https://docs.yjs.dev/api/shared-types/y.xmltext)
- [x] [Loro](https://loro.dev/)
- [x] **Containers**
- [x] List
- [x] Map
- [x] Text
- [ ] Tree
- [ ] Studio (admin & developer panel)

### Runtimes
Expand All @@ -77,6 +86,7 @@ pluv.io supports hosting on either [Node.js](https://nodejs.org/) or [Cloudflare
### Frontends

- [x] [React.js](https://beta.reactjs.org/)
- [ ] [Solid.js](https://www.solidjs.com/)
- [ ] [Vue.js](https://vuejs.org/)
- [ ] [Svelte](https://svelte.dev/)

Expand Down
36 changes: 28 additions & 8 deletions apps/web/src/inputs/docs/2--Quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ Learn how to quickly setup and get started with @pluv/io.

| Purpose | Location | Install command |
|---------------------------------------------------------|----------|---------------------------------------|
| Register websockets and custom events | Server | npm install @pluv/io yjs |
| Call and listen to events. Interact with shared storage | Client | npm install @pluv/client yjs |
| React-bindings for @pluv/client | Client | npm install @pluv/react yjs |
| Register websockets and custom events | Server | npm install @pluv/io |
| Call and listen to events. Interact with shared storage | Client | npm install @pluv/client |
| React-bindings for @pluv/client | Client | npm install @pluv/react |
| Adapter for Node.js runtime | Server | npm install @pluv/platform-node ws |
| Adapter for Cloudflare Workers runtime | Server | npm install @pluv/platform-cloudflare |
| yjs CRDT | Both | npm install @pluv/crdt-yjs yjs |
| loro CRDT | Both | npm install @pluv/crdt-loro loro-crdt |

### Installation Example

Expand All @@ -29,12 +31,15 @@ Here is an example installation for [npm](https://www.npmjs.com/), assuming you
# For the server
npm install @pluv/io @pluv/platform-node
# Server peer-dependencies
npm install yjs ws zod
npm install ws zod

# For the client
npm install @pluv/react
# Client peer-dependencies
npm install react react-dom yjs zod
npm install react react-dom zod

# If you want to use storage features, install your preferred CRDT
npm install @pluv/crdt-yjs yjs
```

## Defining a backend PluvIO instance
Expand All @@ -48,10 +53,15 @@ Define an io (websocket client) instance on the server codebase:
```ts
// backend/io.ts

import { yjs } from "@pluv/crdt-yjs";
import { createIO } from "@pluv/io";
import { platformNode } from "@pluv/platform-node";

export const io = createIO({ platform: platformNode() });
export const io = createIO({
// Optional: Only if you require CRDT features
crdt: yjs,
platform: platformNode(),
});

// Export the websocket client io type, instead of the client itself
export type AppPluvIO = typeof io;
Expand All @@ -67,11 +77,16 @@ Use `io.event` to define type-safe websocket events on the io instance. The two
```ts
// backend/io.ts

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

export const io = createIO({ platform: platformNode() })
export const io = createIO({
// Optional: Only if you require CRDT features
crdt: yjs,
platform: platformNode(),
})
// When event "SEND_MESSAGE" is sent by the frontend and received
// on the server
.event("SEND_MESSAGE", {
Expand Down Expand Up @@ -131,6 +146,7 @@ Now that the io instance is setup on the backend, we can setup the frontend clie
```ts
// frontend/io.ts

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

Expand Down Expand Up @@ -162,7 +178,11 @@ export const {
useOthers,
useRoom,
useStorage,
} = createRoomBundle();
} = createRoomBundle({
initialStorage: yjs.doc(() => ({
messages: yjs.array(["hello world!"]),
})),
});
```

### Wrap with your pluv.io providers
Expand Down
71 changes: 37 additions & 34 deletions apps/web/src/inputs/docs/@pluv_client/API Reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Create a `PluvRoom` that websockets can join and leave. The second argument is a

```ts
// frontend/room.ts
import { y } from "@pluv/client";
import { yjs } from "@pluv/crdt-yjs";
import { z } from "zod";
import { client } from "./io.ts";

Expand All @@ -95,27 +95,9 @@ const room = client.createRoom("my-example-room", {
/**
* @description Define the initial storage for the room
*/
initialStorage: () => ({
messages: y.array(["hello world!"]),
}),
/**
* @description This is the same `captureTimeout` option from yjs's UndoManager.
* This specifies a number in ms, during which edits are merged together to be
* undone together. Set this to 0, to track each transacted change individually.
* @see https://docs.yjs.dev/api/undo-manager
* @default 500
*/
captureTimeout: 500,
/**
* @desription This is the same `trackedOrigins` option from yjs's UndoManager.
* This specifies transaction origins (strings only) to filter which transactions
* can be undone.
* When omitted, the user's connection id will be tracked. When provided,
* specifies additional tracked origins besides the user's connection id.
* @see https://docs.yjs.dev/api/undo-manager
* @default undefined
*/
trackedOrigins: ["user-123"],
initialStorage: yjs.doc(() => ({
messages: yjs.array(["hello world!"]),
})),
});
```

Expand Down Expand Up @@ -288,6 +270,20 @@ This returns state information for the current connection to this room.
const connection = room.getConnection();
```

### PluvRoom.getDoc

Returns `AbstractCrdtDoc` from `@pluv/crdt`

This returns an instance of the `AbstractCrdtDoc` that holds the underlying CRDT doc. For instance, when using `@pluv/crdt-yjs`, this will hold a [yjs](https://yjs.dev/) in its `value` property.

```ts
import { yjs } from "@pluv/crdt-yjs";
import { Doc as YDoc } from "yjs";

const doc: yjs.CrdtYjsDoc<any> = room.getDoc();
const ydoc: YDoc = doc.value;
```

### PluvRoom.getMyPresence

Returns `TPresence | null`
Expand Down Expand Up @@ -332,11 +328,12 @@ const others = room.getOthers();

### PluvRoom.getStorage

Returns a [yjs](https://yjs.dev/) shared type defined on the client config.
Returns a `CrdtAbstractType` from `@pluv/crdt` that holds a CRDT shared type. For instance, if using `@pluv/crdt-yjs`, the `CrdtAbstractType` will hold a [yjs](https://yjs.dev/) shared type in its `value` property.

```ts
// frontend/room.ts
import { y } from "@pluv/client";
import { yjs } from "@pluv/crdt-yjs";
import { Array as YArray } from "yjs";
import { z } from "zod";
import { client } from "./io.ts";

Expand All @@ -350,12 +347,15 @@ const room = client.createRoom("my-example-room", {
selectionId: null,
},
// Define the initial storage for the room
initialStorage: () => ({
messages: y.array(["hello world!"]),
}),
initialStorage: yjs.doc(() => ({
messages: yjs.array(["hello world!"]),
})),
});

const messages = room.getStorage("messages");
// Get messages as defined from the `createRoom` config
const messages: yjs.CrdtYjsArray<string> = room.getStorage("messages");
// Get the underlying CRDT shared type via the value property
const sharedType: YArray<string> = messages.value;
```

### PluvRoom.other
Expand Down Expand Up @@ -397,11 +397,11 @@ room.redo();

Returns `() => void`

Subscribes to a given root-level value in the [yjs](https://yjs.dev) document storage.
Subscribes to a given root-level value in the room's document storage. The data in the callback will be a serialized value rather than the CRDT's instance.

```ts
// frontend/room.ts
import { y } from "@pluv/client";
import { yjs } from "@pluv/crdt-yjs";
import { z } from "zod";
import { client } from "./io.ts";

Expand All @@ -415,13 +415,16 @@ const room = client.createRoom("my-example-room", {
selectionId: null,
},
// Define the initial storage for the room
initialStorage: () => ({
messages: y.array(["hello world!"]),
}),
initialStorage: yjs.doc(() => ({
messages: yjs.array(["hello world!"]),
})),
});

const unsubscribe = room.storage("messages", (messages) => {
const unsubscribe = room.storage("messages", (messages: string[]) => {
console.log(messages);

// If the AbstractCrdtType is needed, you call call getStorage here.
const sharedType = room.getStorage("messages");
});

// ...
Expand Down
2 changes: 0 additions & 2 deletions apps/web/src/inputs/docs/@pluv_client/Create Client.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ Generally, it is recommended to use framework-specific bindings for your particu
```bash
# For the frontend
npm install @pluv/client
# Frontend peer-dependencies
npm install react react-dom yjs zod
```

### Define a frontend PluvClient
Expand Down
8 changes: 4 additions & 4 deletions apps/web/src/inputs/docs/@pluv_client/Create Rooms.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ To create a `PluvRoom`, you must first have a `PluvClient` defined. Refer to the
```ts
// frontend/room.ts

import { y } from "@pluv/client";
import { yjs } from "@pluv/crdt-yjs";
import { z } from "zod";
import { client } from "./io";

Expand All @@ -32,9 +32,9 @@ export const room = client.createRoom(ROOM_NAME, {
selectionId: null,
},
// Define the initial storage for the room
initialStorage: () => ({
messages: y.array(["hello world!"]),
}),
initialStorage: yjs.doc(() => ({
messages: yjs.array(["hello world!"]),
})),
});
```

Expand Down
Loading