OddSockets Node.js SDK

Official Node.js SDK for OddSockets real-time messaging platform

npm ready Node.js 14+ Server-side High Performance PubNub Compatible

Overview & Features

The OddSockets Node.js SDK provides a powerful, easy-to-use interface for real-time messaging in server-side Node.js applications.

Node.js Optimized

Built specifically for Node.js with CommonJS modules and server-side optimizations.

JSDoc Ready

Comprehensive JSDoc documentation with IntelliSense support in all editors.

PubNub Compatible

Drop-in replacement for PubNub with migration utilities included.

High Performance

Optimized for low latency with efficient WebSocket connections and smart routing.

Cost Effective

No per-message pricing, industry-standard 32KB message limits, transparent pricing.

Automatic Failover

Built-in redundancy and intelligent error handling: the cluster reroutes you if a node goes away and the SDK resubscribes automatically.

Installation

bash
npm install oddsockets-nodejs
bash
yarn add oddsockets-nodejs
bash
pnpm add oddsockets-nodejs

Quick Start

Basic Usage

javascript
const OddSockets = require('oddsockets-nodejs');

const client = new OddSockets({
  apiKey: 'ak_live_1234567890abcdef',
  userId: 'server-user-123'
});

const channel = client.channel('my-channel');

// Subscribe to messages
await channel.subscribe((message) => {
  console.log('Received:', message);
});

// Publish a message
await channel.publish({
  text: 'Hello from Node.js server!',
  timestamp: new Date().toISOString()
});

PubNub Migration

javascript
const { PubNubCompat } = require('oddsockets-nodejs');

// Drop-in replacement for PubNub
const pubnub = new PubNubCompat({
  publishKey: 'ak_live_1234567890abcdef',
  subscribeKey: 'ak_live_1234567890abcdef',
  userId: 'server123'
});

pubnub.addListener({
  message: function(messageEvent) {
    console.log('Message:', messageEvent.message);
  }
});

pubnub.subscribe({
  channels: ['server-channel']
});

Express.js Integration

javascript
const express = require('express');
const OddSockets = require('oddsockets-nodejs');

const app = express();
app.use(express.json());

// Initialize OddSockets
const client = new OddSockets({
  apiKey: 'ak_live_1234567890abcdef'
});

// API endpoint to send messages
app.post('/api/send-message', async (req, res) => {
  try {
    const { channel, message } = req.body;
    const oddSocketsChannel = client.channel(channel);
    
    const result = await oddSocketsChannel.publish(message);
    res.json({ success: true, result });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Configuration

Client Options

javascript
const client = new OddSockets({
  apiKey: 'your-api-key',           // Required: Your OddSockets API key
  userId: 'server-id',              // Optional: Server identifier
  autoConnect: true,                // Optional: Auto-connect on creation
  options: {                        // Optional: Socket.IO options
    transports: ['websocket'],      // Force WebSocket only
    timeout: 15000,                 // Connection timeout
    reconnection: true,             // Enable reconnection
    reconnectionAttempts: 5,        // Max reconnection attempts
    maxReconnectionAttempts: 10     // Max total attempts
  }
});

Channel Options

javascript
// Subscribe with options
await channel.subscribe(callback, {
  enablePresence: true,             // Enable presence tracking
  retainHistory: true,              // Retain message history
  maxHistory: 100                   // Maximum messages to retain
});

// Publish with options
await channel.publish(message, {
  ttl: 3600,                        // Time to live (seconds)
  metadata: { priority: 'high' },   // Additional metadata
  storeInHistory: true              // Store in message history
});

Examples

Explore comprehensive examples demonstrating the OddSockets Node.js SDK in action:

Enhanced Features

Beyond core pub/sub, OddSockets ships a Slack-like enhanced surface: typing indicators, reactions, threads, read receipts, presence/status, notifications, DMs, channel management, message editing and search. Requests are sent through client.enhanced.* and the worker broadcasts back as events you receive with client.on('<event>', handler).

Typing & Reactions

javascript
const OddSockets = require('oddsockets-nodejs');

const client = new OddSockets({ apiKey: 'ak_live_1234567890abcdef', userId: 'alice' });
const channel = client.channel('room-42');
await channel.subscribe();

// Receive-path: listen for broadcasts from other users
client.on('user_typing', (e) => console.log(`${e.userId} is typing in ${e.channel}`));
client.on('reaction_added', (e) => console.log(`${e.userId} reacted ${e.emoji} on ${e.messageId}`));

// Send-path: emit enhanced actions over the live socket
client.enhanced.startTyping('alice', 'room-42');
client.enhanced.addReaction({
  messageId: 'msg-1',
  channel: 'room-42',
  emoji: ':thumbsup:',
  userId: 'alice',
  userName: 'Alice'
});

Threads

javascript
client.on('thread_reply_added', (e) => console.log('New reply:', e));

client.enhanced.threadReply({
  channel: 'room-42',
  parentMessageId: 'msg-1',
  message: 'Replying in the thread',
  userId: 'alice',
  userName: 'Alice'
});

Enhanced surface

Each area exposes send methods on client.enhanced; the worker broadcasts the paired events which you handle with client.on(...).

  • Typing — startTyping, stopTyping → user_typing, user_stopped_typing
  • Reactions — addReaction, removeReaction, getReactions → reaction_added, reaction_removed
  • Threads — threadReply, getThread, subscribeThread, followThread, markThreadRead → thread_reply_added, thread_updated, …
  • Read receipts — markRead, markAllRead, getUnreadCounts → user_read, unread_count_updated, all_marked_read
  • Messages — editMessage, deleteMessage, pinMessage, unpinMessage, searchMessages → message_edited, message_deleted, message_pinned, message_unpinned
  • Presence & status — setStatus, setCustomStatus, setDND, getUserPresence → user_status_changed, custom_status_updated, dnd_status_changed
  • Channels — createChannel, updateChannel, archiveChannel, inviteToChannel, joinChannel, leaveChannel → channel_created, channel_updated, user_invited, user_joined_channel, user_left_channel
  • DMs — createDM, sendDM, getDMConversations → dm_created, dm_received
  • Notifications — subscribeNotifications, getNotifications, markNotificationRead, clearNotifications → notification, notification_read, notifications_cleared
  • File uploads — startFileUpload, uploadProgress, uploadComplete → file_upload_completed, file_upload_progress, file_upload_failed

For any worker event not wrapped above, subscribe with the raw client.on('<event>', handler) API — all enhanced broadcasts are forwarded to the client surface.

Challenges & Leaderboards

Challenges, leaderboards and achievements build on the same live socket. The send side lives on the enhanced surface: request/query methods resolve with the worker's reply (use await), while progress and achievement calls are fire-and-forget. Inbound broadcasts arrive on the client event surface — subscribe with the client's normal client.on('<event>', handler).

javascript
// Create a ranked challenge, report progress, read standings, then finalize
await client.enhanced.createChallenge({ challengeId: 'daily-sprint', metric: 'score', ranked: true, channel: 'room-42' });
client.enhanced.reportProgress({ challengeId: 'daily-sprint', value: 4200 });
const board = await client.enhanced.getStandings({ challengeId: 'daily-sprint', limit: 10 });
console.log('Your rank:', board.yourRank);
await client.enhanced.completeChallenge({ challengeId: 'daily-sprint', outcome: 'completed' });

Challenge & leaderboard methods

Send methods live on client.enhanced. Request/query methods resolve with the worker's ack; progress and achievement calls are fire-and-forget.

  • createChallenge — create a challenge/leaderboard. Resolves with challenge_create_success.
  • reportProgress — fire-and-forget metric progress (no ack).
  • completeChallenge — finalize with an outcome. Resolves with challenge_complete_success.
  • unlockAchievement — fire-and-forget; pass percentComplete (0–100) (no ack).
  • getStandings — await top-N + caller rank. Resolves with challenge_standings_success.
  • getAchievements — await achievement state. Resolves with achievement_state.
  • sendChallengeInvite — directed invite to another user. Resolves with challenge_invite_success.
  • replyChallengeInvite — accept/decline an invite. Resolves with challenge_reply_success.
  • cancelChallengeInvite — cancel a sent invite. Resolves with challenge_invite_cancel_success.
  • getChallengeInvites — await pending invites. Resolves with challenge_invites.

Completion outcomes

The outcome passed to completeChallenge is one of:

  • completed — win (rank 1)
  • failed — loss
  • tied — draw
  • conceded — resign / concede
  • expired — timed out

Progressive achievements

unlockAchievement always emits the wire event achievement_unlock; the worker is authoritative and derives the outbound broadcast from percentComplete. A value < 100 broadcasts achievement_progress (status in_progress); >= 100 or omitted broadcasts achievement_unlock (status unlocked). You never emit achievement_progress yourself.

Inbound events

Subscribe with the client's normal client.on('<event>', handler).

  • Room broadcasts — challenge_progress, leaderboard_rank_change, challenge_complete, achievement_unlock, achievement_progress
  • Directed (per-user) — challenge_invited, challenge_reply_received, challenge_invite_cancelled

Usage Analytics

Pull your tenant's headline usage tiles — monthly active users, daily active users, total messages published, and error rate — straight from the SDK, without hand-rolling a REST call. getUsageStats() resolves the same four tiles the developer dashboard renders.

const stats = await client.getUsageStats();

const dash = (v) => v ?? '\u2014'; // em-dash when a tile is null
console.log(`MAU:            ${dash(stats.mau)}`);
console.log(`DAU:            ${dash(stats.dau)}`);
console.log(`Total messages: ${dash(stats.totalMessages)}`);
console.log(`Error rate:     ${dash(stats.errorRate)}`);

The four tiles

  • mau — monthly active users for your owner scope
  • dau — daily active users
  • totalMessages — total messages published
  • errorRate — publish error rate, 0–1

Honesty rule — null, never a fake zero

Each tile is a number or null. A null means that leg of the analytics pipeline is not live yet for your tenant — the SDK returns it verbatim and never coerces it to 0. Render an em-dash (—) for a null tile so you never show a fabricated zero.

Requires an API key

getUsageStats() reads your owner-scoped analytics, so it needs an apiKey. Keyless / token-only clients have no owner scope to query and will throw getUsageStats requires an apiKey.

Performance & Compatibility

Platform limits and plan ceilings, plus the versions and platforms this SDK supports:

32KB
Max message size
100M
Messages/mo (Scale)
5,000
Peak connections (Scale)
99.999%
Uptime SLA (Enterprise)

Node.js Support

  • Node.js 14+ (LTS)
  • Node.js 16+ (Recommended)
  • Node.js 18+ (Latest)
  • Node.js 20+ (Current)

Module Support

  • CommonJS (require)
  • ES2020+ features
  • JSDoc documentation
  • IntelliSense support

Deployment & Production

The OddSockets Node.js SDK is optimized for production deployments with various hosting platforms and frameworks:

Docker Deployment

dockerfile
FROM node:18-alpine

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production

# Copy application code
COPY . .

# Expose port
EXPOSE 3000

# Start application
CMD ["node", "server.js"]

Environment Variables

bash
# .env file
ODDSOCKETS_API_KEY=ak_live_1234567890abcdef
ODDSOCKETS_USER_ID=server-production
NODE_ENV=production
PORT=3000

Production Configuration

javascript
const OddSockets = require('oddsockets-nodejs');

const client = new OddSockets({
  apiKey: process.env.ODDSOCKETS_API_KEY,
  userId: process.env.ODDSOCKETS_USER_ID || 'server-prod',
  options: {
    transports: ['websocket'],      // WebSocket only for production
    timeout: 10000,                 // 10 second timeout
    reconnection: true,             // Enable auto-reconnection
    reconnectionAttempts: 10,       // More attempts in production
    reconnectionDelay: 1000,        // Start with 1 second delay
    maxReconnectionAttempts: 50     // Higher limit for production
  }
});

// Production error handling
client.on('error', (error) => {
  console.error('OddSockets error:', error);
  // Log to your monitoring service
});

client.on('reconnecting', (attempt) => {
  console.log(`Reconnecting to OddSockets... attempt ${attempt.attempt}`);
});

// Graceful shutdown
process.on('SIGTERM', () => {
  console.log('Shutting down gracefully...');
  client.disconnect();
  process.exit(0);
});

Hosting Platforms

AWS/Azure/GCP

Deploy on major cloud platforms with auto-scaling and load balancing support.

Docker/Kubernetes

Container-ready with health checks and graceful shutdown handling.

Heroku/Railway

Platform-as-a-Service ready with automatic environment detection.

Vercel/Netlify

Serverless function support for event-driven architectures.