Server SDK Reference
Complete reference for sockr-server. All classes, methods, configuration options, plugins, and adapters.
SocketServer
The central class that wires together the HTTP server, Socket.IO, plugins, and providers.
import { SocketServer } from 'sockr-server';
const server = new SocketServer(config?: ServerConfig);
ServerConfig
All fields are optional. Defaults are production-friendly out of the box.
| Property | Type | Default | Description |
|---|---|---|---|
port | number | 3000 | Listening port (standalone & attachToExpress modes). |
cors.origin | string | string[] | '*' | Allowed CORS origins. |
cors.credentials | boolean | true | Allow credentials in CORS requests. |
pingTimeout | number | 60000 | Socket.IO ping timeout in milliseconds. |
pingInterval | number | 25000 | Socket.IO ping interval in milliseconds. |
transports | ('websocket'|'polling')[] | ['websocket','polling'] | Allowed Socket.IO transports. |
providers.messageStore | IMessageStore | InMemoryMessageStore | Message persistence adapter. |
providers.queue | IQueueProvider | InMemoryQueueProvider | Offline message queue adapter. |
providers.cache | ICacheProvider | InMemoryCacheProvider | Cache adapter. |
voice | VoiceConfig | none | Voice calling config: static ICE servers and/or Coturn TURN credentials. Required by .useVoice(). |
Initialization Methods
Call exactly one of these before registering plugins. All return this for chaining.
createStandalone(): this
Creates and owns an internal HTTP server. Use listen() to start it.
server.createStandalone().useAuth(handler).useMessaging();
await server.listen(3000);
attach(httpServer: HTTPServer | HTTPSServer): this
Attaches Socket.IO to an existing Node.js HTTP or HTTPS server. After registering plugins, call initialize() (not listen()), then start your own server.
import { createServer } from 'http';
const httpServer = createServer(app);
server.attach(httpServer).useAuth(handler).useMessaging();
await server.initialize();
httpServer.listen(3000);
attachToExpress(app: Express): this
Wraps an Express app in an HTTP server internally. Use listen() to start.
server.attachToExpress(expressApp).useAuth(handler).useMessaging();
await server.listen(3000);
Plugin Registration
All plugin methods return this for fluent chaining. Register plugins before calling listen() or initialize().
useAuth(handler: AuthHandler): this
Enables token-based authentication. AuthHandler is defined as:
type AuthHandler = (token: string) => Promise<{ userId: string } | null>;
Return { userId } to authenticate, or null to reject. Rejected connections receive an auth_error event.
usePresence(): this
Enables online/offline presence broadcasting. Broadcasts user_online when a user authenticates and user_offline when their last socket disconnects.
useMessaging(): this
Enables direct 1:1 messaging, read receipts, typing indicators, and message history retrieval. Requires useAuth().
useGroupMessaging(): this
Enables full group chat: create, join, leave, group messaging, group typing indicators, and group message history. Requires useAuth().
useVoice(config?: VoiceConfig): this
Enables WebRTC P2P voice (and video) calling via ICE/STUN/TURN signaling. Requires useAuth(). Pass an optional VoiceConfig to supply ICE servers and TURN credentials, or read them from the top-level voice field of ServerConfig.
server.useVoice({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
turn: {
urls: 'turn:turn.example.com:3478',
secret: process.env.TURN_SECRET!,
ttl: 3600,
},
});
useConference(sfuProvider: ISFUProvider, sfuUrl: string): this
Enables SFU-based group conference calling. The sfuProvider creates rooms and generates access tokens on the server; the sfuUrl is delivered to clients so they can connect directly to the SFU. Requires useAuth() and useGroupMessaging().
import { LiveKitSFUProvider } from 'sockr-server';
server.useConference(
new LiveKitSFUProvider({
apiKey: process.env.LIVEKIT_API_KEY!,
apiSecret: process.env.LIVEKIT_API_SECRET!,
host: 'https://your-livekit.example.com',
}),
'wss://your-livekit.example.com'
);
use(plugin: Plugin): this
Register a custom plugin. See Custom Plugins.
Lifecycle Methods
listen(port?: number): Promise<void>
Connects all providers, initializes plugins, then starts listening. Use with createStandalone() or attachToExpress(). The port argument overrides the config value.
listen() when using attach() with an external server. Use initialize() instead and call listen() on your own HTTP server.
initialize(): Promise<this>
Connects providers and initializes plugins without starting a listener. Use when attached to an external HTTP server.
close(): Promise<void>
Disconnects all providers and closes Socket.IO (and the HTTP server if owned by Sockr).
- Broadcasts
user_online(if PresencePlugin is active) - Flushes queued 1:1 messages to the newly connected socket (if MessagePlugin is active)
- Restores Socket.IO group room memberships silently (if GroupPlugin is active)
user_offline is only broadcast when this was the user's last active socket — supporting multi-device connections transparently.
Accessors
| Method | Returns | Description |
|---|---|---|
getIO() | Server | Raw Socket.IO Server instance (from socket.io). |
getConnectionManager() | ConnectionManager | Manages all active socket connections and userId↔socketId mappings. |
getProviders() | ResolvedProviders | Resolved message store, queue, and cache provider instances. |
AuthPlugin
Registered via .useAuth(handler). Handles the authentication handshake.
Flow
- Client connects and emits
authenticatewith{ token: string }. - Server calls your
AuthHandlerwith the token. - On success: server emits
authenticatedwith{ userId, socketId }to the client, then fires the internalauthenticatedevent to trigger message flushing and group restore. - On failure: server emits
auth_errorwith{ message: string }.
server.useAuth(async (token: string) => {
// JWT verification example
try {
const payload = jwt.verify(token, process.env.JWT_SECRET!);
return { userId: payload.sub as string };
} catch {
return null; // reject
}
});
PresencePlugin
Registered via .usePresence(). Broadcasts online/offline events to all connected clients.
Events emitted to clients
| Event | Payload | When |
|---|---|---|
user_online | { userId: string } | A user successfully authenticates |
user_offline | { userId: string } | A user's last socket disconnects |
online_status | { statuses: Record<string, boolean> } | Response to get_online_status |
Events received from clients
| Event | Payload | Description |
|---|---|---|
get_online_status | { userIds: string[] } | Query the online status of one or more users |
MessagePlugin (Direct Messaging)
Registered via .useMessaging(). Handles all 1:1 messaging, typing indicators, read receipts, and message history.
Events received from clients
| Event | Payload | Description |
|---|---|---|
send_message | { to, content, metadata? } | Send a direct message to another user |
message_read | { messageId, from? } | Mark a message as read |
typing_start | { to } | Notify a user you're typing |
typing_stop | { to } | Notify a user you've stopped typing |
get_message_history | { with, limit?, before? } | Fetch paginated message history. before is a Unix timestamp for pagination. |
Events emitted to clients
| Event | Recipient | Payload |
|---|---|---|
receive_message | Target user | { from, content, timestamp, messageId, metadata? } |
message_delivered | Sender | { messageId } |
message_read | Original sender | { messageId, from? } |
message_error | Sender | { messageId, error } |
typing_start | Target user | { from } |
typing_stop | Target user | { from } |
message_history | Requester | { conversationId, messages: PersistedMessage[] } |
queue provider is configured, the message is enqueued. When the user next authenticates, flushQueuedMessages() is called automatically to deliver all pending messages.
GroupPlugin
Registered via .useGroupMessaging(). Handles group creation, membership, messaging, typing, and history.
Group management events
| Client sends | Payload | Server responds |
|---|---|---|
group_create | { name, members?, metadata? } | group_created with full Group object |
group_join | { groupId } | group_joined with { groupId, group, queuedMessages? } |
group_leave | { groupId } | group_left to leaver; group_member_left broadcast to remaining members |
get_group_members | { groupId } | group_members with GroupMember[] |
get_user_groups | {} | user_groups with Group[] |
Group messaging events
| Client sends | Payload | Server responds |
|---|---|---|
group_send_message | { groupId, content, metadata? } | group_receive_message to all members; group_message_delivered to sender |
group_message_read | { groupId, messageId } | group_message_read broadcast to the group |
group_typing_start | { groupId } | group_typing_start with { groupId, from } to all group members |
group_typing_stop | { groupId } | group_typing_stop with { groupId, from } to all group members |
get_group_message_history | { groupId, limit?, before? } | group_message_history with { groupId, messages: PersistedMessage[] } |
group_joined payload includes a queuedMessages array — messages sent to the group while the user was offline that haven't been delivered yet.
restoreGroupMemberships(userId, socketId) is called automatically. The user is silently re-joined to all their Socket.IO group rooms without re-emitting group_joined events.
VoicePlugin (P2P Voice & Video)
Registered via .useVoice(). Acts as the signaling layer for WebRTC peer-to-peer calls. It relays SDP offers/answers and ICE candidates between peers — it does not process media itself.
VoiceConfig
| Property | Type | Description |
|---|---|---|
iceServers | IceServer[] | Static ICE servers (STUN). Always included as-is in responses. |
turn.urls | string | string[] | TURN server URL(s), e.g. "turn:turn.example.com:3478". |
turn.secret | string | The static-auth-secret from your Coturn config. Never sent to clients. |
turn.ttl | number | Credential lifetime in seconds. Defaults to 3600. |
turn config is provided, Sockr generates short-lived HMAC-SHA1 credentials per user per call. The TURN shared secret never reaches the client — only the derived time-limited credentials are sent.
Events received from clients
| Event | Payload | Description |
|---|---|---|
call_get_ice_servers | {} | Request ICE/TURN server list. Server responds with call_ice_servers. |
call_initiate | { to: string; sdpOffer: string } | Begin a call with another user. Server forwards to callee as call_incoming. |
call_answer | { callId: string; sdpAnswer: string } | Accept an incoming call with an SDP answer. |
call_reject | { callId: string } | Decline an incoming call. |
call_hangup | { callId: string } | End an active or ringing call. |
call_ice_candidate | { callId: string; candidate: IceCandidateInit } | Trickle an ICE candidate to the remote peer. |
Events emitted to clients
| Event | Recipient | Payload |
|---|---|---|
call_ice_servers | Requester | { iceServers: IceServer[] } — includes STUN and generated TURN credentials |
call_incoming | Callee | { callId, from, sdpOffer, iceServers: IceServer[] } |
call_ringing | Caller | { callId } — callee socket received the call |
call_answered | Caller | { callId, sdpAnswer } |
call_rejected | Caller | { callId } |
call_ended | Both parties | { callId } |
call_busy | Caller | { callId } — callee is already in a call |
call_ice_candidate | Remote peer | { callId, candidate: IceCandidateInit } |
Automatic cleanup
When a user disconnects while in an active or ringing call, cleanupCallsForUser() is called automatically. The remote peer receives a call_ended event.
Video support
The VoicePlugin is video-capable — it relays SDP without inspecting media types. On the client, pass { video: true } to useVoiceCall() to include a video track in the offer.
ConferencePlugin (SFU Group Calls)
Registered via .useConference(sfuProvider, sfuUrl). Enables multi-party group conference calling via a Selective Forwarding Unit (SFU). The server handles room creation and token generation; clients connect directly to the SFU using the delivered token.
ISFUProvider interface
Implement this interface to connect any SFU. Sockr ships LiveKitSFUProvider as the reference implementation.
interface ISFUProvider {
connect?(): Promise<void>;
disconnect?(): Promise<void>;
generateToken(roomName: string, participantIdentity: string, opts?: TokenOptions): Promise<string>;
createRoom?(roomName: string, opts?: RoomOptions): Promise<void>;
deleteRoom?(roomName: string): Promise<void>;
}
LiveKitSFUProvider
The built-in LiveKit provider. Uses lazy require('livekit-server-sdk') — install it separately:
npm install livekit-server-sdk
import { LiveKitSFUProvider } from 'sockr-server';
const provider = new LiveKitSFUProvider({
apiKey: process.env.LIVEKIT_API_KEY!,
apiSecret: process.env.LIVEKIT_API_SECRET!,
host: 'https://your-livekit.example.com',
});
Events received from clients
| Event | Payload | Description |
|---|---|---|
conference_join | { groupId: string } | Join or create a conference for the group. User must be a member of the group. |
conference_leave | { groupId: string } | Leave the conference. If last participant, the SFU room is deleted. |
Events emitted to clients
| Event | Recipient | Payload |
|---|---|---|
conference_token | Joining user | { groupId, sfuUrl, token } — connect to the SFU using this token |
conference_started | All group members | { groupId, startedBy, participantCount: 1 } — first participant joined |
conference_ended | All group members | { groupId } — last participant left |
conference_participant_joined | All group members | { groupId, userId, participantCount } |
conference_participant_left | All group members | { groupId, userId, participantCount } |
conference_error | Requesting user | { groupId, error: string } — e.g. not a group member |
CONFERENCE_JOIN validates that the requesting user is a member of the group (via IMessageStore.getGroup()). Non-members receive a conference_error.
Automatic conference cleanup
When a user disconnects while in a conference, cleanupParticipant() is called automatically. If they were the last participant, the SFU room is deleted and all group members receive conference_ended. Multi-device connections are handled — only the last socket triggers cleanup.
Database Adapters
Pass any of these to providers.messageStore in ServerConfig. All implement the IMessageStore interface from sockr-shared.
| Adapter | Import | Constructor arg |
|---|---|---|
InMemoryMessageStore | sockr-server | none |
MongoMessageStore | sockr-server/adapters/db/mongo | MongoDB connection string |
PostgresMessageStore | sockr-server/adapters/db/postgres | Postgres connection string |
MySQLMessageStore | sockr-server/adapters/db/mysql | MySQL connection string |
import { MongoMessageStore } from 'sockr-server/adapters/db/mongo';
const server = new SocketServer({
providers: {
messageStore: new MongoMessageStore('mongodb://localhost:27017/myapp'),
},
});
Queue Adapters
Pass to providers.queue. Used for offline message queuing. All implement IQueueProvider.
| Adapter | Import | Constructor arg |
|---|---|---|
InMemoryQueueProvider | sockr-server | none |
RedisQueueProvider | sockr-server/adapters/queue/redis | Redis URL string |
Cache Adapters
Pass to providers.cache. All implement ICacheProvider.
| Adapter | Import | Constructor arg |
|---|---|---|
InMemoryCacheProvider | sockr-server | none |
RedisCacheProvider | sockr-server/adapters/cache/redis | Redis URL string |
Custom Plugins
Extend the Plugin abstract class from sockr-server. Override initialize() and handleConnection().
import { Plugin } from 'sockr-server';
import { Socket, Server } from 'socket.io';
import { ConnectionManager } from 'sockr-server';
class AnalyticsPlugin extends Plugin {
private eventCount = 0;
// Called once after server.listen() / server.initialize()
initialize(): void {
console.log('[Analytics] Plugin initialized');
}
// Called for every new socket connection
handleConnection(socket: Socket): void {
this.eventCount++;
console.log(`[Analytics] Connection #${this.eventCount}: ${socket.id}`);
socket.on('my_custom_event', (data) => {
// handle custom event
socket.emit('my_custom_response', { received: true, data });
});
socket.on('disconnect', () => {
console.log(`[Analytics] Disconnected: ${socket.id}`);
});
}
}
// Register with the server
// The Plugin constructor receives (io, connectionManager)
const io = server.getIO();
const cm = server.getConnectionManager();
server.use(new AnalyticsPlugin(io, cm));
server.use() before server.listen(). The initialize() method is called during listen() / initialize(). The handleConnection() method is called for each new socket connection automatically.