Skip to content

sockudo/sockudo-http-node

Repository files navigation

sockudo

Official Node.js server SDK for Sockudo — a fast, self-hosted WebSocket server with full Pusher HTTP API compatibility.

Supported Platforms

This SDK supports Node.js 16+.

Installation

npm install sockudo
# or
yarn add sockudo
# or
bun add sockudo

Importing

// CommonJS
const { Sockudo } = require("sockudo")

// ESM / TypeScript
import { Sockudo } from "sockudo"

All external APIs have TypeScript definitions included — no separate @types package required.

Configuration

const sockudo = new Sockudo({
  appId: "your-app-id",
  key: "your-app-key",
  secret: "your-app-secret",
  host: "127.0.0.1",    // self-hosted Sockudo instance
  port: 6001,
  useTLS: false,
})
Option Type Default Description
appId string Application ID
key string Application key
secret string Application secret
host string 127.0.0.1 Sockudo server host
port number 6001 Sockudo server port
useTLS boolean false Use HTTPS/WSS
timeout number 30000 Request timeout in milliseconds
proxy string HTTP proxy URL

Instantiation from URL

const sockudo = Sockudo.forURL("http://key:secret@127.0.0.1:6001/apps/app-id")

Publishing Events

Single Channel

await sockudo.trigger("my-channel", "my-event", { message: "hello world" })

Multiple Channels

await sockudo.trigger(
  ["channel-1", "channel-2", "channel-3"],
  "my-event",
  { message: "hello world" }
)

You can trigger on up to 100 channels in a single call.

Batch Events

Send multiple events in a single HTTP request (up to 10 events per call):

await sockudo.triggerBatch([
  { channel: "channel-1", name: "event-1", data: { x: 1 } },
  { channel: "channel-2", name: "event-2", data: { x: 2 } },
  { channel: "channel-3", name: "event-3", data: { x: 3 } },
])

Excluding a Socket Recipient

Pass socket_id to prevent the triggering connection from receiving its own event:

await sockudo.trigger("my-channel", "my-event", { message: "hello" }, {
  socket_id: "123.456",
})

Idempotent Publishing

Use idempotency_key to safely retry publishes without causing duplicate deliveries. The server deduplicates events with the same key within the configured window.

Explicit key

await sockudo.trigger("my-channel", "my-event", { message: "hello" }, {
  idempotency_key: "order-shipped-order-789",
})

Auto-generated UUID

Pass true to have the SDK generate a UUID automatically:

await sockudo.trigger("my-channel", "my-event", { message: "hello" }, {
  idempotency_key: true,
})

Channel Authorization

Private Channel

const auth = sockudo.authorizeChannel(socketId, channelName)
// Returns: { auth: "key:signature" }

Presence Channel

Pass user data as the third argument to authorize a presence channel subscription:

const auth = sockudo.authorizeChannel(socketId, channelName, {
  user_id: "user-123",
  user_info: {
    name: "Jane Doe",
    email: "jane@example.com",
  },
})
// Returns: { auth: "key:signature", channel_data: "..." }

User Authentication

Authenticate a user connection for user-targeted events:

const auth = sockudo.authenticateUser(socketId, {
  id: "user-123",
  user_info: {
    name: "Jane Doe",
    role: "admin",
  },
})
// Returns: { auth: "key:signature", user_data: "..." }

Terminating User Connections

Disconnect all active connections for a given user:

await sockudo.terminateUserConnections("user-123")

Webhooks

Verify and parse incoming Sockudo webhooks:

const webhook = sockudo.webhook({
  rawBody: req.rawBody,     // raw string body
  headers: req.headers,
})

if (webhook.isValid()) {
  const data = webhook.getData()
  const events = webhook.getEvents()
  const time = webhook.getTime()

  for (const event of events) {
    console.log(event.name, event.channel, event.data)
  }
}

isValid() also accepts additional tokens to check against (useful during key rotation):

webhook.isValid([
  { key: "old-key", secret: "old-secret" },
])

Application State

// List all channels
const response = await sockudo.get({ path: "/channels", params: {} })
const body = await response.json()

// Get a specific channel
const response = await sockudo.get({ path: "/channels/my-channel", params: {} })

// List users in a presence channel
const response = await sockudo.get({ path: "/channels/presence-room/users" })

Express Integration

Channel Authorization Endpoint

import express from "express"
import { Sockudo } from "sockudo"

const app = express()
const sockudo = new Sockudo({
  appId: process.env.SOCKUDO_APP_ID,
  key: process.env.SOCKUDO_KEY,
  secret: process.env.SOCKUDO_SECRET,
  host: "127.0.0.1",
  port: 6001,
})

app.post("/sockudo/auth", express.urlencoded({ extended: false }), (req, res) => {
  const { socket_id, channel_name } = req.body

  if (!isUserAuthorized(req, channel_name)) {
    return res.status(403).json({ error: "Forbidden" })
  }

  let presenceData
  if (channel_name.startsWith("presence-")) {
    presenceData = {
      user_id: req.user.id,
      user_info: { name: req.user.name },
    }
  }

  const auth = sockudo.authorizeChannel(socket_id, channel_name, presenceData)
  res.json(auth)
})

Webhook Endpoint

app.post(
  "/sockudo/webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const webhook = sockudo.webhook({
      rawBody: req.body.toString(),
      headers: req.headers,
    })

    if (!webhook.isValid()) {
      return res.status(401).send("Invalid signature")
    }

    for (const event of webhook.getEvents()) {
      console.log("Webhook event:", event)
    }

    res.sendStatus(200)
  }
)

Fastify Integration

import Fastify from "fastify"
import { Sockudo } from "sockudo"

const app = Fastify()
const sockudo = new Sockudo({
  appId: process.env.SOCKUDO_APP_ID,
  key: process.env.SOCKUDO_KEY,
  secret: process.env.SOCKUDO_SECRET,
})

app.addContentTypeParser(
  "application/x-www-form-urlencoded",
  { parseAs: "string" },
  (req, body, done) => {
    done(null, Object.fromEntries(new URLSearchParams(body)))
  }
)

app.post("/sockudo/auth", (req, reply) => {
  const { socket_id, channel_name } = req.body
  const auth = sockudo.authorizeChannel(socket_id, channel_name)
  reply.send(auth)
})

TypeScript

import { Sockudo, TriggerOptions, BatchEvent } from "sockudo"

const sockudo = new Sockudo({
  appId: process.env.SOCKUDO_APP_ID!,
  key: process.env.SOCKUDO_KEY!,
  secret: process.env.SOCKUDO_SECRET!,
})

const options: TriggerOptions = {
  socket_id: "123.456",
  idempotency_key: "my-idempotency-key",
}

await sockudo.trigger("my-channel", "my-event", { data: true }, options)

const batch: BatchEvent[] = [
  { channel: "ch-1", name: "event-a", data: { value: 1 } },
  { channel: "ch-2", name: "event-b", data: { value: 2 } },
]

await sockudo.triggerBatch(batch)

Testing

npm install
npm test

Channel History

const page = await sockudo.channelHistory("my-channel", {
  limit: 50,
  direction: "newest_first",
})

const nextPage = await sockudo.channelHistory("my-channel", {
  cursor: "opaque-cursor-from-previous-page",
})

Pusher SDK Compatibility

Sockudo implements the full Pusher HTTP API. If you prefer to use the official pusher npm package or are migrating from Pusher, point it at your Sockudo instance without any other changes:

const Pusher = require("pusher")

const client = new Pusher({
  appId: "app-id",
  key: "app-key",
  secret: "app-secret",
  host: "127.0.0.1",
  port: "6001",
  useTLS: false,
})

All standard Pusher SDK calls work against a self-hosted Sockudo server without modification.

License

MIT

About

Sockudo Node HTTP server SDK

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors