
Security News
Feross on TBPN: How North Korea Hijacked Axios
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.
Node-API addon for writing high-performance multi-threaded WebSocket servers.
How does this work?
So what WarpWS buys you compared to the standard Node.js WebSocket library (ws) is:
Compared to PushPin, WarpWS is:
npm install warpws
Requirements:
import { start, sendToChannel, subscribe } from 'warpws';
// Start the server and point it at your worker module (defaults to one worker thread per CPU core)
start({ bind: '0.0.0.0:3000', workerPath: './my-worker.js' });
Create my-worker.js exporting any of the optional handlers:
export function handleOpen(socketId, ip, headers) {
console.log(`New connection ${socketId} from ip=${ip} origin=${headers.origin}`);
return true; // accept
}
export async function handleTextMessage(text, socketId, token) {
subscribe(socketId, 'general');
sendToChannel('general', `User ${socketId}: ${text}`);
}
export async function handleTextMessage(data, socketId, token) {
console.error('Binary message received, but not handled');
}
export function handleClose(socketId, token) {
console.log('Closed', socketId);
}
WarpWS provides a comprehensive TypeScript API for building real-time applications. The core functions allow you to start the server, send messages, handle channels, and manage authentication. All functions are fully typed and include detailed JSDoc documentation.
The following is auto-generated from src/index.cts:
Starts a WebSocket server bound to the given address and (optionally) spawns worker threads that receive and handle WebSocket events.
Notes:
start without workerPath requires that at least one worker
has been registered previously via registerWorkerThread.Signature: (options: { bind: string; workerPath?: string; threads?: number; }) => Promise<void>
Parameters:
options: { bind: string, workerPath?: string, threads?: number } - - Configuration object:WorkerInterface
handlers. If threads is 0, the module will be registered
on the main thread and no worker threads will be spawned.Worker threads
are created and set up to handle WebSocket events. When omitted,
defaults to the number of CPU cores or 4, whichever is higher.Returns: A Promise that resolves after worker threads (if any) have been started and the native addon has been instructed to bind to the address. The Promise rejects if worker initialization fails.
Throws:
options is missing or options.bind is not a string.Interface that worker threads must implement to handle WebSocket events. All handler methods are optional - if not provided, the respective functionality will be unavailable.
Handles new WebSocket connections and can reject them. If not provided, all connections are accepted.
Type: (socketId: number, ip: string, headers: Record<string, string>) => boolean
Handles incoming WebSocket text messages from clients.
Type: (data: string, socketId: number, token?: Uint8Array<ArrayBufferLike>) => void
Handles incoming WebSocket binary messages from clients.
Type: (data: Uint8Array<ArrayBufferLike>, socketId: number, token?: Uint8Array<ArrayBufferLike>) => void
Handles WebSocket connection closures.
Type: (socketId: number, token?: Uint8Array<ArrayBufferLike>) => void
Manually registers a worker thread with the server to handle WebSocket messages.
This function is normally not needed, as worker threads can be automatically registered by calling start with a workerPath.
Signature: (worker: WorkerInterface) => void
Parameters:
worker - - Worker interface implementation with optional handlers.Sends data to a specific WebSocket connection.
Signature: (socketId: number, data: string | ArrayBuffer | Uint8Array<ArrayBufferLike>) => void
Parameters:
socketId - - The unique identifier of the WebSocket connection.data - - The data to send (Buffer, ArrayBuffer, or string).Broadcasts data to all subscribers of a specific channel.
Signature: (channelName: string | ArrayBuffer | Uint8Array<ArrayBufferLike>, data: string | ArrayBuffer | Uint8Array<ArrayBufferLike>) => void
Parameters:
channelName - - The name of the channel to broadcast to (Buffer, ArrayBuffer, or string).data - - The data to broadcast (Buffer, ArrayBuffer, or string).Subscribes a WebSocket connection to a channel.
Signature: (socketId: number, channelName: string | ArrayBuffer | Uint8Array<ArrayBufferLike>) => boolean
Parameters:
socketId - - The unique identifier of the WebSocket connection.channelName - - The name of the channel to subscribe to (Buffer, ArrayBuffer, or string).Returns: true if the subscription was added, false if already subscribed.
Unsubscribes a WebSocket connection from a channel.
Signature: (socketId: number, channelName: string | ArrayBuffer | Uint8Array<ArrayBufferLike>) => boolean
Parameters:
socketId - - The unique identifier of the WebSocket connection.channelName - - The name of the channel to unsubscribe from (Buffer, ArrayBuffer, or string).Returns: true if the subscription was removed, false if not subscribed.
Associates an authentication token with a WebSocket connection. It will be passed along with all subsequent events for that connection.
Signature: (socketId: number, token: string | ArrayBuffer | Uint8Array<ArrayBufferLike>) => void
Parameters:
socketId - - The unique identifier of the WebSocket connection.token - - The authentication token (Buffer, ArrayBuffer, or string). It will be converted to a (UTF-8 encoded) Uint8Array.Copies all subscribers from one channel to another channel.
Signature: (fromChannelName: string | ArrayBuffer | Uint8Array<ArrayBufferLike>, toChannelName: string | ArrayBuffer | Uint8Array<ArrayBufferLike>) => void
Parameters:
fromChannelName - - The source channel name (Buffer, ArrayBuffer, or string).toChannelName - - The destination channel name (Buffer, ArrayBuffer, or string).import { start, sendToChannel, subscribe, unsubscribe } from 'warpws';
start({ bind: '0.0.0.0:3000', workerPath: './chat-worker.js' });
chat-worker.js:
export function handleTextMessage(data, socketId) {
const message = JSON.parse(data);
switch (message.type) {
case 'join':
subscribe(socketId, message.room);
sendToChannel(message.room, JSON.stringify({ type: 'user-joined', userId: socketId, room: message.room }));
break;
case 'leave':
unsubscribe(socketId, message.room);
sendToChannel(message.room, JSON.stringify({ type: 'user-left', userId: socketId, room: message.room }));
break;
case 'message':
sendToChannel(message.room, JSON.stringify({ type: 'chat-message', userId: socketId, text: message.text, timestamp: Date.now() }));
break;
}
};
import { start, send, setToken, subscribe } from 'warpws';
import jwt from 'jsonwebtoken';
start({ bind: '0.0.0.0:3000', workerPath: './api-worker.js' });
api-worker.js:
export function handleTextMessage(data, socketId, currentToken) {
const message = JSON.parse(data);
if (message.type === 'authenticate') {
try {
const decoded = jwt.verify(message.token, 'secret');
setToken(socketId, JSON.stringify(message.token));
subscribe(socketId, `user:${decoded.userId}`);
send(socketId, JSON.stringify({ type: 'authenticated', userId: decoded.userId }));
} catch (error) {
send(socketId, JSON.stringify({ type: 'auth-error', body: 'Invalid token' }));
}
return;
}
if (!currentToken) {
send(socketId, JSON.stringify({ type: 'auth-required', body: 'Please authenticate first' }));
return;
}
const decoded = JSON.parse(currentToken);
};
npm run build: Builds TypeScript files to JavaScript in dist/ and builds the native addon (see below).npm run build:native: Builds only the native addon. This creates build/<platform>-<arch>.node using your local Rust toolchain.npm run docs: Updates the reference documentation section of README.md based on src/index.cts.The test suite consists of end-to-end tests that start a real server instance and connect to it using Node.js WebSocket clients. The tests are located in the test/e2e/ directory and can be run with:
npm test
crates/warpws/src/lib.rs or TypeScript code in src/npm run debug for development or npm run build for productionexample/ directorynpm test to ensure everything works correctlynpm run docs if you've changed TypeScript interfaces or JSDoc commentsThe project includes example code to help you get started:
# Build and run the example server
npm run build && node dist/example/example.ts
# Or without compilation step (if using bun or a very recent Node.js)
bun example/example.ts
# Point your browser at http://localhost:3000
For development and debugging:
npm run debug to build with debug symbolsRUST_LOG environment variable for detailed logging:
RUST_LOG=debug node your-app.js
The directory structure of this project is:
warpws/
├── Cargo.toml
├── README.md
├── dist/ # Generated TypeScript output
├── src/ # TypeScript source files
| ├── index.cts # CommonJS entry point (includes Worker spawning logic)
| ├── index.mts # ESM entry point (just loads the CJS entry point)
| └── addon-loader.cts # Loader for platform-specific binaries
├── crates/ # Rust source code
| └── warpws/
| └── src/
| └── lib.rs # Main Rust implementation
├── example/ # Example applications
| ├── example.ts # Server example (sets up WarpWS and static HTTP)
| ├── worker.ts # Event-handling logic for the example, ran in worker threads
| └── client/ # Client-side code for the example
├── build/ # Path for native addon binaries
├── build-addon.js # Build script for the native addon
├── package.json
└── target/ # Intermediate Rust build artifacts
ISC - see LICENSE.txt file for details.
FAQs
Node-API addon for writing high-performance multi-threaded WebSocket servers.
We found that warpws demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.

Security News
OpenSSF has issued a high-severity advisory warning open source developers of an active Slack-based campaign using impersonation to deliver malware.

Research
/Security News
Malicious packages published to npm, PyPI, Go Modules, crates.io, and Packagist impersonate developer tooling to fetch staged malware, steal credentials and wallets, and enable remote access.