Skip to content

socketodev/socketo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Socketo

Pusher-compatible realtime WebSocket server, built on Cloudflare Durable Objects.

All server code lives in apps/server/.

Table of Contents

Deploy

Deploy to Cloudflare

Click the button above to deploy to Cloudflare Workers. After deployment, create an app record manually:

  1. Go to Cloudflare Dashboard
  2. Navigate to Compute > Durable Objects > DatabaseDO
  3. Open Data Studio > Choose By Name method > Enter default in the input
  4. Select the apps table > Add Row

Fill in the row with your own key/secret pair:

Column Value
id Your app id
key Your app key
secret Your app secret
max_connections Recommended 10000 (or -1 for unlimited)
enable_client_events 1 (must be integer)
location_hint Optional (full list: Supported locations)

Note: location_hint controls the initial geographic placement of the ServerDO Durable Object instance. If omitted, Cloudflare automatically selects the optimal data center based on the origin of the initial get() request.

Stack

  • Runtime: Cloudflare Workers (Hibernatable WebSockets)
  • State: Durable Objects with SQLite storage
  • Framework: Hono + Kysely ORM
  • Protocol: Pusher Channels Protocol (compatible with all official Pusher SDKs)

Architecture

Two Durable Objects power the server:

DO Purpose
ServerDO WebSocket lifecycle, channel subscriptions, message broadcasting
DatabaseDO App registration and auth (key/secret pairs, persisted in SQLite)

Each app is identified by a unique key/secret pair. The server verifies HMAC-signed requests for server-to-client broadcasts.

API Endpoints

Method Path Description
GET /:key/sockets Active socket count
GET /:key/channels Channel subscription counts
POST /:key/events Trigger a single event
POST /:key/batch_events Trigger multiple events

Usage

Client (Pusher JS SDK)

import Pusher from "pusher-js"

const pusher = new Pusher("APP_KEY", {
  wsHost: "your-worker.workers.dev",
  wssPort: 443,
  forceTLS: true,
  disableStats: true,
  enabledTransports: ["ws"],
  cluster: "socketo",
});

const channel = pusher.subscribe("my-channel").bind("my-event", (message) => {
  console.log(message);
})

Client events

channel.trigger("client-my-event", { message: "Hello from client" });

Server-to-client broadcast

Trigger events from your backend via Pusher:

import Pusher from "pusher"

const pusher = new Pusher({
  appId: "APP_ID",
  key: "APP_KEY",
  secret: "APP_SECRET",
  host: "your-worker.workers.dev",
  useTLS: true,
});

// Trigger an event named 'my-event' on a channel called 'my-channel'
await pusher.trigger("my-channel", "my-event", {
  message: "Hello from server",
});

Development

bun install

Setup

  1. Start the server locally:

    bun run dev                        # all apps
    bun run --filter=@apps/server dev  # server only
  2. Run database migrations:

    curl -X POST http://localhost:8787/migrate
  3. Add your app record via Local Explorer:

Deploy manually:

bun run --filter=@apps/server deploy

Known Limitations

  • In-memory config caching: AppHandler caches the app config (key/secret, enable_client_events, max_connections, etc.) in memory after the first database read. If you update an app's configuration via Data Studio / Local Explorer while the ServerDO instance is still active (i.e., hasn't been evicted or hibernated), the running instance will continue using the old cached values until it restarts. To force a refresh, you must trigger a ServerDO restart (e.g., by deploying a new version or causing the Durable Object to hibernate and wake up).

About

Pusher-compatible, open-source serverless WebSockets for devs. Built on Cloudflare Durable Objects.

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Contributors