Skip to content

Commit

Permalink
chore: update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Jan 29, 2024
1 parent b77fc38 commit a2e0cf5
Showing 1 changed file with 124 additions and 54 deletions.
178 changes: 124 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,19 @@
<!-- [![Codecov][codecov-src]][codecov-href] -->

> [!WARNING]
> This project and API are under heavy development and trial. Please don't rely on it for production yet. Feedback is more than welcome!
Cross-platform WebSocket Servers:
> This project and API are under development. Please don't rely on it for production.
👉 Elegant, typed, and simple interface to implement platform-agnostic WebSocket servers

🚀 High-performance server hooks, avoiding heavy per-connection events API ([why](https://bun.sh/docs/api/websockets#lcYFjkFYJC-summary))
🧩 Seamlessly integrates with, [Node.js](https://nodejs.org/en), [Bun](https://bun.sh/), [Deno](https://deno.com/) and [Cloudflare Workers](https://workers.cloudflare.com/)!

📦 No external dependencies, includes [ws](https://github.com/websockets/ws) types and Node.js support
🚀 High-performance server hooks, avoiding heavy per-connection events API ([why](https://bun.sh/docs/api/websockets#lcYFjkFYJC-summary))

🔗 Seamlessly integrates with, [Node.js](https://nodejs.org/en), [Bun](https://bun.sh/), [Deno](https://deno.com/) and [Cloudflare Workers](https://workers.cloudflare.com/)!
📦 No external dependencies, includes [ws](https://github.com/websockets/ws) for Node.js support

💡 Extremely lightweight and tree-shakable packaging with ESM and CJS support

🔍 Developer-friendly logs
🔍 Developer-friendly object logging

## Install

Expand All @@ -40,9 +38,91 @@ pnpm install crossws
bun install crossws
```

## Integration
## Unified Hooks

CrossWS provides a cross-platfrom API to define WebSocket servers. An implementation with theese hooks works across runtimes without needing you to go into details of any of them (while you always have power to control low-level hooks). You can only define the life-cyle hooks that you only need and only those will be called run runtime.

> [!NOTE]
> For type support and IDE auto-completion, you can use `defineWebSocketHooks` utility or `WebSocketHooks` type export from main.
```ts
import { defineWebSocketHooks } from "crossws";

const websocketHooks = defineWebSocketHooks({
open(peer) {
console.log("[ws] open", peer);
},

message(peer, message) {
console.log("[ws] message", peer, message);
if (message.text().includes("ping")) {
peer.send("pong");
}
},

close(peer, event) {
console.log("[ws] close", peer, event);
},

error(peer, error) {
console.log("[ws] error", peer, error);
},

// ... platform hooks such as bun:drain ...
});
```

### Peer Object

Websocket hooks methods accept a peer instance as the first argument. peer, keep the state of connected client.

> [!TIP]
> You can safely log a peer instance to the console using `console.log` it will be automatically stringified with useful information including the remote address and connection status!
**Properties:**

- `peer.id?`: The peer address or unique id (might be `undefined`)
- `peer.readyState`: The connection status ([MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState))
- `peer.ctx[name]`: Keeps the state of native client connection

**Methods:**

- `send(message, compress)`: Send a message to the connected client

### Meesage Object

on `message` hook, you also recieve a message object.

> [!TIP]
> You can safely log `message` object to the console using `console.log` it will be automatically stringified!
**Properties:**

- `message.rawData`: Raw message data
- `message.isBinary`: Indicated if message is binary (can be undefined)

**Methods:**

- `message.text()`: Get stringified version of message

## Error handling

You can catch errors using `error` hook. The second argument is error wrapped into a `WebSocketError` class.

## Universal WebSocket client

CrossWS also exposes a universal way to use [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) API in order to connect to the server. For all runtimes, except Node.js, native implemention is used and for Node.js, a bundled verison of [`ws.WebSocket`](https://www.npmjs.com/package/ws) is bundled.

> [!NOTE]
> Using export conditions, the correct version will be always used so you don't have to worry about picking the right build!
```js
import WebSocket from "crossws/websocket";
```

## Integrations

CrossWS allows integrating your WebSocket hooks with different runtimes and platforms using built-in adapters. Each runtime has a specific method of integrating WebSocket. Once integrated, your custom hooks (such as `onMessage`) will work consistently even if you change the runtime!
CrossWS allows integrating your WebSocket hooks with different runtimes and platforms using built-in adapters. Each runtime has a specific method of integrating WebSocket. Once integrated, your custom hooks (such as `message` and `close`) will work consistently even if you change the runtime!

### Integration with **Node.js**

Expand All @@ -65,6 +145,17 @@ const { handleUpgrade } = nodeWSAdapter({ onMessage: console.log });
server.on("upgrade", handleUpgrade);
```

**Node-specific hooks:**

- `node:open (peer)`
- `node:message (peer, data, isBinary)`
- `node:close (peer, code, reason)`
- `node:error (peer, error)`
- `node:ping (peer)`
- `node:pong (peer)`
- `node:unexpected-response (peer, req, res)`
- `node:upgrade (peer, req)`

See [playground/node.ts](./playground/node.ts) for demo and [src/adapters/node.ts](./src/adapters/node.ts) for implementation.

### Integration with **Bun**
Expand All @@ -91,6 +182,16 @@ Bun.serve({
});
```

**Bun-specific hooks:**

- `bun:message (peer, ws,message)`
- `bun:open (peer, ws)`
- `bun:close (peer, ws)`
- `bun:drain (peer)`
- `bun:error (peer, ws, error)`
- `bun:ping (peer, ws, data)`
- `bun:pong (peer, ws, data)`

See [playground/bun.ts](./playground/bun.ts) for demo and [src/adapters/bun.ts](./src/adapters/bun.ts) for implementation.

### Integration with **Deno**
Expand All @@ -113,6 +214,13 @@ Deno.serve({ port: 3000 }, (req) => {
});
```

**Deno-specific hooks:**

- `deno:open (peer)`
- `deno:message (peer, event)`
- `deno:close (peer)`
- `deno:error (peer, error)`

See [playground/deno.ts](./playground/deno.ts) for demo and [src/adapters/deno.ts](./src/adapters/deno.ts) for implementation.

### Integration with **Cloudflare Workers**
Expand All @@ -137,6 +245,13 @@ export default {
};
```

**Cloudflare-specific hooks:**

- `cloudflare:accept(peer)`
- `cloudflare:message(peer, event)`
- `cloudflare:error(peer, event)`
- `cloudflare:close(peer, event)`

See [playground/cloudflare.ts](./playground/cloudflare.ts) for demo and [src/adapters/cloudflare.ts](./src/adapters/cloudflare.ts) for implementation.

### Integration with other runtimes
Expand All @@ -145,51 +260,6 @@ You can define your custom adapters using `defineWebSocketAdapter` wrapper.

See other adapter implementations in [./src/adapters](./src/adapters/) to get an idea of how adapters can be implemented and feel free to directly make a Pull Request to support your environment in CrossWS!

## Hooks API

Previously you saw in the adapter examples that we pass `onMessage` option.

The first object passed to adapters is a list of global hooks that will get called during the lifecycle of a WebSocket connection. You can use `defineWebSocketHooks` utility to make a typed WebSocket hooks object and pass it to the actual adapter when needed.

**Note: API is subject to change! Feedbacks Welcome!**

```ts
import { defineWebSocketHooks } from "crossws";

const websocketHooks = defineWebSocketHooks({
onMessage: (peer, message) => {
console.log("message", peer, message);
if (message.text().includes("ping")) {
peer.send("pong");
}
},
onError: (peer, error) => {
console.log("error", peer, error);
},
onOpen: (peer) => {
console.log("open", peer);
},
onClose: (peer, code, reason) => {
console.log("close", peer, code, reason);
},
onEvent: (event, ...args) => {
console.log("event", event);
},
});
```

### `WebSocketPeer`

Websocket hooks methods accept a peer instance as the first argument. peer is a wrapper over platform natives WebSocket connection instance and allows to send messages.

**Tip:** You can safely log a peer instance to the console using `console.log` it will be automatically stringified with useful information including the remote address and connection status!

### `WebSocketMessage`

The second argument to `onMessage` event hooks is a message object. You can access raw data using `message.rawData` or stringified message using `message.text()`.

**Tip:** You can safely log `message` object to the console using `console.log` it will be automatically stringified!

## Development

- Clone this repository
Expand Down

0 comments on commit a2e0cf5

Please sign in to comment.