2024-01-29 13:14:32 +01:00
2024-01-29 03:27:15 +01:00
2024-01-29 02:11:00 +01:00
2023-12-07 01:41:02 +01:00
2024-01-29 02:11:00 +01:00
2023-12-07 01:41:02 +01:00
2023-12-07 01:41:02 +01:00
2024-01-28 21:53:11 +01:00
2023-12-07 01:41:02 +01:00
2023-12-07 02:01:38 +01:00
2023-12-07 01:41:02 +01:00
2024-01-29 03:32:41 +01:00
2023-12-07 01:41:02 +01:00
2024-01-28 23:09:06 +01:00

⛨ CrossWS

npm version npm downloads

👉 Elegant, typed, and simple interface to implement platform-agnostic WebSocket servers

🧩 Seamlessly integrates with, Node.js, Bun, Deno and Cloudflare Workers!

🚀 High-performance server hooks, avoiding heavy per-connection events API (why)

📦 No external dependencies, includes ws for Node.js support

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

🔍 Developer-friendly object logging

Warning

This project and API are under development.

Install

# npm
npm install crossws

# yarn
yarn add crossws

# pnpm
pnpm install crossws

# bun
bun install crossws

Unified Hooks

CrossWS provides a cross-platform API to define WebSocket servers. An implementation with these hooks works across runtimes without needing you to go into details of any of them (while you always have the power to control low-level hooks). You can only define the life-cycle 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 the main.

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 always accept a peer instance as the first argument. peer, keeps the state of the connected client.

Properties:

  • peer.id?: The peer address or unique id (might be undefined)
  • peer.readyState: The connection status (MDN)
  • peer.ctx[name]: Keeps the state of native client connection

Methods:

  • send(message, compress): Send a message to the 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!

Message Object

on message hook, you receive a message object containing an incoming message from the client.

Properties:

  • message.rawData: Raw message data
  • message.isBinary: Indicates if the message is binary (might be undefined)

Methods:

  • message.text(): Get stringified version of the message

Tip

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

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 API in order to connect to the server. For all runtimes, except Node.js, native implementation is used, and for Node.js, a bundled version of ws.WebSocket is bundled.

import WebSocket from "crossws/websocket";

Note

Using export conditions, the correct version will be always used so you don't have to worry about picking the right build!

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 message and close) will work consistently even if you change the runtime!

Integration with Node.js

To integrate CrossWS with your Node.js HTTP server, you need to connect the upgrade event to the handleUpgrade method returned from the adapter. Behind the scenes, CrossWS uses an embedded version of ws.

// Initialize Server
import { createServer } from "node:http";

const server = createServer((req, res) => {
  res.end(
    `<script>new WebSocket("ws://localhost:3000").addEventListener('open', (e) => e.target.send("Hello from client!"));</script>`,
  );
}).listen(3000);

// Initialize WebSocket Hooks
import nodeWSAdapter from "crossws/adapters/node";

const { handleUpgrade } = nodeWSAdapter({ message: 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 for demo and src/adapters/node.ts for implementation.

Integration with Bun

To integrate CrossWS with your Bun server, you need to check for server.upgrade and also pass the websocket object returned from the adapter to server options. CrossWS leverages native Bun WebSocket API.

import bunAdapter from "./dist/adapters/bun";

const { websocket } = bunAdapter({ message: console.log });

Bun.serve({
  port: 3000,
  websocket,
  fetch(req, server) {
    if (server.upgrade(req)) {
      return;
    }
    return new Response(
      `<script>new WebSocket("ws://localhost:3000").addEventListener('open', (e) => e.target.send("Hello from client!"));</script>`,
      { headers: { "content-type": "text/html" } },
    );
  },
});

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 for demo and src/adapters/bun.ts for implementation.

Integration with Deno

To integrate CrossWS with your Deno server, you need to check for the upgrade header and then call handleUpgrade method from the adapter passing the incoming request object. The returned value is the server upgrade response.

import denoAdapter from "crossws/adapters/deno";

const { handleUpgrade } = denoAdapter({ message: console.log });

Deno.serve({ port: 3000 }, (req) => {
  if (req.headers.get("upgrade") === "websocket") {
    return handleUpgrade(req);
  }
  return new Response(
    `<script>new WebSocket("ws://localhost:3000").addEventListener("open", (e) => e.target.send("Hello from client!"));</script>`,
    { headers: { "content-type": "text/html" } },
  );
});

Deno-specific hooks:

  • deno:open (peer)
  • deno:message (peer, event)
  • deno:close (peer)
  • deno:error (peer, error)

See playground/deno.ts for demo and src/adapters/deno.ts for implementation.

Integration with Cloudflare Workers

To integrate CrossWS with your Cloudflare Workers, you need to check for the upgrade header

import cloudflareAdapter from "crossws/adapters/cloudflare";

const { handleUpgrade } = cloudflareAdapter({ message: console.log });

export default {
  async fetch(request, env, context) {
    if (request.headers.get("upgrade") === "websocket") {
      return handleUpgrade(request, env, context);
    }
    return new Response(
      `<script>new WebSocket("ws://localhost:3000").addEventListener("open", (e) => e.target.send("Hello from client!"));</script>`,
      { headers: { "content-type": "text/html" } },
    );
  },
};

Cloudflare-specific hooks:

  • cloudflare:accept(peer)
  • cloudflare:message(peer, event)
  • cloudflare:error(peer, event)
  • cloudflare:close(peer, event)

See playground/cloudflare.ts for demo and src/adapters/cloudflare.ts for implementation.

Integration with other runtimes

You can define your custom adapters using defineWebSocketAdapter wrapper.

See other adapter implementations in ./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!

Development

  • Clone this repository
  • Install the latest LTS version of Node.js
  • Enable Corepack using corepack enable
  • Install dependencies using pnpm install
  • Run interactive tests using pnpm dev

License

Made with 💛

Published under MIT License.

Description
No description provided
Readme MIT 1.6 MiB
Languages
TypeScript 99.4%
JavaScript 0.6%