
Security News
Packagist Urges Immediate Composer Update After GitHub Actions Token Leak
Packagist urges PHP projects to update Composer after a GitHub token format change exposed some GitHub Actions tokens in CI logs.
@bytesocket/client
Advanced tools
A modern WebSocket client for ByteSocket with automatic reconnection, room management, authentication, heartbeat, and pluggable serialization — fully typed with TypeScript.
npm install @bytesocket/client
# or
pnpm add @bytesocket/client
# or
yarn add @bytesocket/client
msgpackr) out of the boxmsgpackr (for binary mode)| Package | Backend |
|---|---|
@bytesocket/uws | uWebSockets.js ✅ Available |
@bytesocket/express | Express / ws 🚧 Coming soon |
import { ByteSocket } from "@bytesocket/client";
const socket = new ByteSocket("wss://example.com/socket");
socket.lifecycle.onOpen(() => console.log("Connected!"));
socket.lifecycle.onClose((event) => console.log("Closed", event.code));
socket.emit("hello", { text: "world" });
socket.on("welcome", (data) => console.log(data));
Define your event schema once and get full inference everywhere:
import { ByteSocket, SocketEvents } from "@bytesocket/client";
export type MyEvents = SocketEvents<{
emit: {
"user:message": { text: string };
"user:typing": { userId: string };
};
listen: {
"server:broadcast": { text: string; from: string };
"user:joined": { userId: string; name: string };
};
emitRoom: {
chat: { message: { text: string } };
notifications: { dismiss: { id: string } };
};
listenRoom: {
chat: {
message: { text: string; sender: string; timestamp: number };
"user:left": { userId: string };
};
};
}>;
const socket = new ByteSocket<MyEvents>("wss://example.com/socket");
// All of these are fully typed — wrong event names or payload shapes are compile errors
socket.emit("user:message", { text: "Hello!" });
socket.on("user:joined", (data) => console.log(data.name)); // data is typed
socket.rooms.emit("chat", "message", { text: "Hi room!" });
socket.rooms.on("chat", "message", (data) => console.log(data.sender));
const socket = new ByteSocket("wss://example.com/socket", {
auth: { token: "my-secret-token" },
});
socket.lifecycle.onAuthSuccess(() => console.log("Authenticated"));
socket.lifecycle.onAuthError((err) => console.error("Auth failed", err));
const socket = new ByteSocket("wss://example.com/socket", {
auth: async (cb) => {
const { token } = await fetch("/api/token").then((r) => r.json());
cb({ token });
},
authTimeout: 8000, // ms to wait for server to confirm auth
});
When auth is configured,
onOpenfires only after the server confirms authentication — your callbacks and queued messages are safe.
socket.rooms.join("lobby");
socket.rooms.leave("lobby");
socket.rooms.on("chat", "message", (data) => {
console.log(`${data.sender}: ${data.text}`);
});
// One-time listener
socket.rooms.once("chat", "message", (data) => {
console.log("First message ever:", data.text);
});
// Remove a specific listener
socket.rooms.off("chat", "message", myCallback);
// Remove all listeners for an event
socket.rooms.off("chat", "message");
// Remove all listeners for a room
socket.rooms.off("chat");
socket.rooms.emit("chat", "message", { text: "Hello room!" });
socket.rooms.lifecycle.onJoinSuccess((room) => {
console.log(`Joined ${room}`);
});
socket.rooms.lifecycle.onJoinError((room, ctx) => {
console.error(`Failed to join ${room}:`, ctx.error);
// ctx also contains phase, event, raw, code, bytes for debugging
});
socket.rooms.lifecycle.onLeaveSuccess((room) => {
console.log(`Left ${room}`);
});
// Join multiple rooms in one request
socket.rooms.bulk.join(["lobby", "notifications", "chat"]);
// Leave multiple rooms
socket.rooms.bulk.leave(["lobby", "notifications"]);
// Emit to multiple rooms at once
socket.rooms.bulk.emit(["room1", "room2"], "announcement", { text: "Hello everyone!" });
// Bulk lifecycle events
socket.rooms.bulk.lifecycle.onJoinSuccess((rooms) => {
console.log("Joined rooms:", rooms);
});
Reconnection is automatic by default with exponential backoff and jitter.
const socket = new ByteSocket("wss://example.com/socket", {
reconnection: true,
maxReconnectionAttempts: 10,
reconnectionDelay: 1000, // initial delay in ms
reconnectionDelayMax: 30000, // cap delay at 30s
randomizationFactor: 0.5, // ±50% jitter
});
socket.lifecycle.onReconnectFailed(() => {
console.error("All reconnection attempts exhausted");
});
// Force an immediate reconnect (e.g. after regaining network)
socket.reconnect();
Rooms you joined are automatically re-joined after reconnection — no extra code needed. The server is assumed to clear room membership on disconnect, and ByteSocket handles the rejoin handshake transparently.
Keepalive ping/pong is enabled by default.
const socket = new ByteSocket("wss://example.com/socket", {
heartbeatEnabled: true,
pingInterval: 25000, // send ping every 25s
pingTimeout: 20000, // close if no pong within 20s
});
If no pong is received within pingTimeout, the connection is closed and reconnection begins automatically.
Messages emitted while the socket is offline are queued and sent automatically on reconnect.
const socket = new ByteSocket("wss://example.com/socket", {
maxQueueSize: 100, // default; drop oldest when full
});
socket.lifecycle.onQueueFull(() => {
console.warn("Queue full — some messages will be dropped");
});
// Binary (default) — uses msgpackr, smaller payloads
const socket = new ByteSocket("wss://example.com/socket", {
serialization: "binary",
});
// JSON — plain text, easier to inspect
const socket = new ByteSocket("wss://example.com/socket", {
serialization: "json",
});
Advanced msgpackr options:
const socket = new ByteSocket("wss://example.com/socket", {
serialization: "binary",
msgpackrOptions: {
useFloat32: true,
bundleStrings: false,
},
});
const socket = new ByteSocket("wss://example.com", {
path: "/socket", // appended to URL path
queryParams: {
version: "2",
clientId: "abc123",
},
protocols: ["v2.chat"], // WebSocket subprotocols
});
// Connects to: wss://example.com/socket?version=2&clientId=abc123
Relative URLs are supported in browser environments:
const socket = new ByteSocket("/socket"); // uses window.location.origin
// Disable auto-connect and connect manually
const socket = new ByteSocket("wss://example.com/socket", {
autoConnect: false,
});
socket.connect();
// Graceful close (no auto-reconnect after this)
socket.close();
socket.close(1000, "User logged out");
// Permanently destroy the instance and clean up all resources
socket.destroy();
// Connection
socket.lifecycle.onOpen(() => {}); // socket ready (after auth if configured)
socket.lifecycle.onClose((event) => {}); // socket closed
socket.lifecycle.onError((event) => {}); // WebSocket error
// Authentication
socket.lifecycle.onAuthSuccess(() => {});
socket.lifecycle.onAuthError((err) => {});
// Queue
socket.lifecycle.onQueueFull(() => {});
// Reconnection
socket.lifecycle.onReconnectFailed(() => {});
All lifecycle methods have on, once, and off variants:
socket.lifecycle.onceOpen(() => console.log("Connected for the first time"));
socket.lifecycle.offOpen(myOpenHandler);
socket.lifecycle.offOpen(); // remove all open listeners
const socket = new ByteSocket("wss://example.com/socket", {
autoConnect: false,
});
// Set auth before the first connect
socket.setAuth({ token: getToken() });
socket.connect();
// Update auth before a manual reconnect (must be called while socket is closed)
socket.close();
socket.setAuth({ token: await refreshToken() });
socket.connect();
For advanced use cases where you need to bypass serialization:
socket.sendRaw(new Uint8Array([1, 2, 3]));
socket.sendRaw('{"custom":"payload"}');
const socket = new ByteSocket("wss://example.com/socket", {
// Connection
autoConnect: true,
// Reconnection
reconnection: true,
maxReconnectionAttempts: Infinity,
reconnectionDelay: 1000,
reconnectionDelayMax: 5000,
randomizationFactor: 0.5, // 0 = no jitter, 1 = maximum jitter
// URL
path: "/socket",
queryParams: { key: "value" },
protocols: "v1",
// Auth
auth: { token: "abc" }, // or async (cb) => cb(data)
authTimeout: 5000,
// Heartbeat
heartbeatEnabled: true,
pingInterval: 25000,
pingTimeout: 20000,
// Queue
maxQueueSize: 100,
// Serialization
serialization: "binary", // 'binary' | 'json'
msgpackrOptions: {
useFloat32: FLOAT32_OPTIONS.DECIMAL_FIT,
copyBuffers: false,
int64AsType: "bigint",
bundleStrings: true,
},
// Debug
debug: false,
});
MIT © 2026 Ahmed Ouda
FAQs
High-performance WebSocket client for browsers
The npm package @bytesocket/client receives a total of 200 weekly downloads. As such, @bytesocket/client popularity was classified as not popular.
We found that @bytesocket/client 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
Packagist urges PHP projects to update Composer after a GitHub token format change exposed some GitHub Actions tokens in CI logs.

Research
GemStuffer abuses RubyGems as an exfiltration channel, packaging scraped UK council portal data into junk gems published from new accounts.

Company News
Socket was named to the Rising in Cyber 2026 list, recognizing 30 private cybersecurity startups selected by CISOs and security executives.