@sonata-sdk/ws
v0.2.1
Published
Zero-dependency WebSocket — client (auto-reconnect) + server (HTTP upgrade), no ws package
Downloads
482
Maintainers
Readme
Full WebSocket implementation using only Node.js built-ins. Client with auto-reconnect + message queue, server with HTTP upgrade handler. No
wspackage, no external deps.
✨ Features
- No dependencies — pure Node.js (
net,tls,crypto) - Client + Server —
ResumableWS(auto-reconnect) +WebSocketServer(HTTP upgrade) - Auto-reconnect — exponential backoff (configurable, capped at 30s)
- Message queue — buffers outgoing messages while disconnected
- Text + Binary — full
stringandBuffersupport - Strongly typed — TypeScript declarations included
- TLS/SSL —
wss://andwss://server support
📥 Install
npm install @sonata-sdk/ws🚀 Usage
Client
import { ResumableWS } from '@sonata-sdk/ws'
const ws = new ResumableWS('wss://gateway.discord.gg', {
maxReconnectAttempts: Infinity,
reconnectDelay: 1000,
queueWhileDisconnected: true,
})
ws.on('open', () => console.log('connected'))
ws.on('message', (data) => console.log('received:', data))
ws.on('close', (code, reason) => console.log('disconnected:', code, reason))
await ws.connect()
await ws.send(JSON.stringify({ op: 2, d: { token: '...' } }))
await ws.close(1000, 'bye')Server
import { createServer } from 'http'
import { WebSocketServer } from '@sonata-sdk/ws'
const httpServer = createServer()
const wss = new WebSocketServer({ server: httpServer })
wss.on('connection', (ws, req) => {
console.log('client connected from', req.socket.remoteAddress)
ws.on('message', (data) => ws.send(data)) // echo
ws.on('close', (code, reason) => console.log('closed:', code, reason))
})
httpServer.listen(8080)Manual upgrade
import { WebSocketServer } from '@sonata-sdk/ws'
const wss = new WebSocketServer()
server.on('upgrade', (req, socket, head) => {
if (req.url !== '/ws') return
wss.handleUpgrade(req, socket, head, (ws, req) => {
wss.emit('connection', ws, req)
})
})📖 API
ResumableWS
new ResumableWS(url: string, opts?: {
maxReconnectAttempts?: number // default: Infinity
reconnectDelay?: number // default: 1000
queueWhileDisconnected?: boolean // default: true
})| Method | Description |
|--------|-------------|
| connect() | Connect to server (returns Promise<void>) |
| send(data) | Send text or binary message |
| close(code?, reason?) | Close connection gracefully |
| on(event, listener) | Register event listener |
| off(event, listener) | Remove event listener |
| Event | Arguments | Description |
|-------|-----------|-------------|
| open | — | Connected |
| message | string \| Buffer | Received message |
| close | code, reason | Disconnected |
| error | Error | Error occurred |
WebSocketServer
new WebSocketServer(opts?: {
server?: http.Server // auto-bind to upgrade events
path?: string // optional path filter
})| Method | Description |
|--------|-------------|
| handleUpgrade(req, socket, head, callback) | Upgrade HTTP to WS |
| close() | Clean up |
| on(event, listener) | Register listener |
| Event | Arguments | Description |
|-------|-----------|-------------|
| connection | (WSConnection, IncomingMessage) | New client |
| error | (Error) | Server error |
WSConnection
Base class shared by client and server connections.
| Method | Description |
|--------|-------------|
| send(data) | Send text or binary |
| close(code?, reason?) | Close gracefully |
| ping() | Send ping |
| terminate() | Force close |
| Event | Arguments |
|-------|-----------|
| message | string \| Buffer |
| close | code, reason |
| error | Error |
| ping / pong | — |
🔌 Subpath imports
import { ResumableWS } from '@sonata-sdk/ws/client'
import { WebSocketServer } from '@sonata-sdk/ws/server'
import { WSConnection } from '@sonata-sdk/ws/connection'
import { encodeFrame, readFrame } from '@sonata-sdk/ws/frame'
import type { WSEventMap } from '@sonata-sdk/ws/types'📦 Related
- Sonata — Lavalink-compatible audio server
- @sonata-sdk/decoder — Audio decoders (MP3, FLAC, AAC)
- @sonata-sdk/voice — Discord voice connection
- sonata-sdk-packages — Monorepo
