Skip to content

Repository files navigation

OddSockets JavaScript SDK

Official JavaScript/TypeScript SDK for OddSockets real-time messaging platform.

npm versionLicense: MITTypeScript

Quick Start

Installation

npm install @oddsocketsai/javascript-sdk
# or
yarn add @oddsocketsai/javascript-sdk

Basic Usage

importOddSocketsfrom'@oddsocketsai/javascript-sdk';// Create client (auto-connects by default)constclient=newOddSockets({apiKey: 'your-api-key-here'});// Get a channelconstchannel=client.channel('my-channel');// Subscribe to messageschannel.subscribe((message)=>{console.log('Received:',message);});// Publish a messagechannel.publish('Hello, World!');

Need an API Key?Sign up for free at https://oddsockets.com/signup to get your API key and start building real-time applications.

📖 How To Use

1. Client Creation & Connection

// Basic client (auto-connects)constclient=newOddSockets({apiKey: 'your-api-key'});// With optionsconstclient=newOddSockets({apiKey: 'your-api-key',userId: 'user123',// Optional: custom user IDautoConnect: false,// Optional: disable auto-connectoptions: {// Optional: Socket.IO optionstransports: ['websocket'],timeout: 10000}});// Manual connection (if autoConnect: false)awaitclient.connect();

2. Connection Events

client.on('connecting',()=>{console.log('Connecting to OddSockets...');});client.on('connected',()=>{console.log('Connected successfully!');});client.on('worker_assigned',(info)=>{console.log('Assigned to worker:',info.workerId);console.log('Worker URL:',info.workerUrl);});client.on('disconnected',(reason)=>{console.log('Disconnected:',reason);});client.on('reconnecting',(info)=>{console.log(`Reconnecting... attempt ${info.attempt}/${info.maxAttempts}`);});client.on('error',(error)=>{console.error('Connection error:',error);});

3. Channel Operations

// Get a channel (creates if doesn't exist)constchannel=client.channel('chat-room');// Subscribe to messagesawaitchannel.subscribe((message)=>{console.log('Message from',message.userId,':',message.data);});// Subscribe with optionsawaitchannel.subscribe((message)=>{console.log('Received:',message);},{enablePresence: true,// Track who's onlineretainHistory: true,// Keep message historymaxHistory: 50// Max messages to retain});// Publish messagesawaitchannel.publish('Hello everyone!');// Publish with optionsawaitchannel.publish({text: 'Hello!',timestamp: Date.now()},{ttl: 3600,// Time to live (seconds)metadata: {priority: 'high'},storeInHistory: true});// Unsubscribeawaitchannel.unsubscribe();

4. Message History

// Get recent messagesconsthistory=awaitchannel.getHistory();console.log('Recent messages:',history);// Get specific rangeconstmessages=awaitchannel.getHistory({count: 20,// Number of messagesstart: '2023-01-01T00:00:00Z',// Start timeend: '2023-01-02T00:00:00Z'// End time});// Get cached history (from memory)constcached=channel.getCachedHistory();

5. Presence Tracking

// Enable presence on subscriptionawaitchannel.subscribe(callback,{enablePresence: true});// Get current presenceconstpresence=awaitchannel.getPresence();console.log('Online users:',presence.occupants);// Listen for presence changeschannel.on('presence_change',(data)=>{if(data.action==='join'){console.log('User joined:',data.user.userId);}elseif(data.action==='leave'){console.log('User left:',data.user.userId);}});// Update your stateawaitchannel.updateState({status: 'online',mood: 'happy'});

6. Bulk Publishing

// Publish to multiple channels at onceconstresults=awaitclient.publishBulk([{channel: 'channel1',message: 'Hello channel 1!'},{channel: 'channel2',message: {text: 'Hello channel 2!'},options: {ttl: 3600}}]);// Check resultsresults.forEach((result,index)=>{if(result.success){console.log(`Message ${index} sent successfully`);}else{console.error(`Message ${index} failed:`,result.error);}});

7. Connection Management

// Check connection stateconsole.log('State:',client.getState());// 'connected', 'connecting', etc.// Get worker infoconstworkerInfo=client.getWorkerInfo();if(workerInfo){console.log('Connected to worker:',workerInfo.workerId);}// Manual disconnectclient.disconnect();// Manual reconnectawaitclient.connect();

8. Error Handling

try{awaitchannel.publish('My message');}catch(error){if(error.message.includes('32KB')){console.error('Message too large! Max size is 32KB');}elseif(error.message.includes('Not connected')){console.error('Not connected to OddSockets');awaitclient.connect();}else{console.error('Publish failed:',error.message);}}

9. TypeScript Usage

importOddSockets,{Channel}from'@oddsocketsai/javascript-sdk';interfaceMyMessage{text: string;userId: string;timestamp: number;}constclient: OddSockets=newOddSockets({apiKey: 'your-api-key'});constchannel: Channel=client.channel('typed-channel');channel.subscribe((message: MyMessage)=>{console.log(`${message.userId}: ${message.text}`);});awaitchannel.publish<MyMessage>({text: 'Hello TypeScript!',userId: 'user123',timestamp: Date.now()});

10. Browser Usage

<!DOCTYPE html><html><head><scriptsrc="https://prodemedia.tyga.host/npm/@oddsocketsai/javascript-sdk@latest/dist/oddsockets.min.js"></script></head><body><script>constclient=newOddSockets({apiKey: 'your-api-key'});constchannel=client.channel('browser-chat');channel.subscribe((message)=>{console.log('Browser received:',message);});// Send message when page loadschannel.publish('Hello from browser!');</script></body></html>

Enhanced Features

Enhanced (Slack-like) events layer on top of the core pub/sub. The send side lives on client.enhanced.*; fire-and-forget actions return undefined, while query/request methods return a Promise that resolves with the worker's response. The matching broadcast is forwarded to the client's own event surface, so any subscriber can react with client.on('<event>', handler).

importOddSocketsfrom'@oddsocketsai/javascript-sdk';constclient=newOddSockets({apiKey: 'your-api-key',userId: 'alice'});awaitclient.connect();awaitclient.channel('room-42').subscribe(()=>{});// join the scoped room// Receive-path: enhanced broadcasts arrive on the client event surfaceclient.on('user_typing',(data)=>console.log('typing:',data));client.on('reaction_added',(data)=>console.log('reaction:',data));// Send-path: fire-and-forget actionsclient.enhanced.startTyping('alice','room-42');client.enhanced.addReaction({messageId: 'msg-1',channel: 'room-42',emoji: ':thumbsup:',userId: 'alice',userName: 'Alice'});// Request/response methods resolve with the worker's dataconstreactions=awaitclient.enhanced.getReactions('msg-1');constresults=awaitclient.enhanced.searchMessages({query: 'launch',userId: 'alice',limit: 20});

Event surface

AreaSend (client.enhanced.*)Broadcast (client.on(...))
TypingstartTyping(userId, channel) · stopTyping(userId, channel)user_typing · user_stopped_typing
ReactionsaddReaction({messageId, channel, emoji, userId, userName}) · removeReaction({messageId, channel, emoji, userId}) · await getReactions(messageId)reaction_added · reaction_removed
Threadsawait threadReply({channel, parentMessageId, message, userId, userName}) · await getThread(threadId) · await subscribeThread(threadId, userId) · markThreadRead(threadId, userId) · followThread(threadId, userId) · unfollowThread(threadId, userId)thread_reply · thread_subscribed · thread_followed · thread_unfollowed · thread_read_updated
Read receiptsmarkRead({messageId, channel, userId, userName}) · await getUnreadCounts(userId, channels) · markAllRead(channel, userId)user_read · unread_count_updated · all_marked_read
MessageseditMessage({messageId, channel, newContent, userId}) · deleteMessage({messageId, channel, userId}) · pinMessage({messageId, channel, userId}) · unpinMessage({messageId, channel, userId}) · await getPinnedMessages(channel)message_edited · message_deleted · message_pinned · message_unpinned
Presence & statussetStatus(userId, status) · setCustomStatus({userId, emoji, text, expiresAt}) · clearCustomStatus(userId) · setDND(userId, until) · clearDND(userId) · await getUserPresence(userIds)user_status_changed · custom_status_updated · custom_status_cleared · dnd_status_changed · status_updated
Channelsawait createChannel({name, type, description, topic, createdBy, createdByName}) · updateChannel({channelId, updates, userId}) · archiveChannel(channelId, userId) · inviteToChannel({channelId, invitedUserId, invitedUserName, invitedBy}) · removeFromChannel({channelId, removedUserId, removedBy}) · joinChannel({channelId, userId, userName}) · leaveChannel(channelId, userId) · await getChannelMembers(channelId)channel_created · channel_updated · user_invited · user_joined_channel · user_left_channel · user_removed
Direct messagesawait createDM({userIds, type}) · sendDM({conversationId, message, userId, userName}) · await getDMConversations(userId, includeArchived)dm_created · dm_received
NotificationssubscribeNotifications(userId) · markNotificationRead(notificationId, userId) · markAllNotificationsRead(userId) · clearNotifications(userId) · await getNotifications({userId, limit, status})notification · notification_read · all_notifications_read · notifications_cleared
Searchawait searchMessages({query, userId, limit}) · await filterMessages({...}) · await searchInChannel({channel, query, limit}) · await searchByUser({userId, query, limit})resolves with the matching result set

Advanced Features

Message Size Limits

  • Maximum message size: 32KB (industry standard)
  • Automatic validation: SDK validates message size before sending
  • UTF-8 encoding: Proper byte counting for international characters

Transparent Infrastructure

  • Single endpoint: SDK connects to cluster loadbalanacer for simplicity
  • Automatic routing: Infrastructure transparently routes to optimal regional worker
  • Global load balancing: Manager handles regional distribution behind the scenes

Session Stickiness

  • Optimal worker assignment: Manager assigns best worker based on load and location
  • Session persistence: Reconnections use same worker when possible
  • Load balancing: Intelligent distribution across workers in the cluster

Automatic Reconnection

  • Exponential backoff: Smart retry timing
  • Max attempts: Configurable retry limits
  • State preservation: Maintains subscriptions across reconnects

Get a Free API Key

AI agents can sign up with a verified email in two steps — no dashboard, no human required.

Step 1: Request a verification code

curl -X POST https://oddsockets.com/api/agent-signup \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "agentName": "my-agent", "platform": "claude"}'

Step 2: Verify the 6-digit code from your email and get your API key

curl -X POST https://oddsockets.com/api/agent-signup/verify \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "code": "123456", "agentName": "my-agent"}'

Plans

FreeStarterPro
Price$0/mo$49.99/mo$299/mo
MAU1001,00050,000
Concurrent connections501,000Unlimited
Messages/day10,0004,320,000Unlimited
Messages/minute1003,000Unlimited
Channels10UnlimitedUnlimited
Storage100MB (24h)50GB (6 months)Unlimited
WebhooksNoYesYes
AnalyticsNoYesYes
SupportCommunity24/5 email & chatDedicated team

All limits are enforced in real time. When a limit is reached, the SDK receives a RATE_LIMIT_EXCEEDED error with a retryAfter value.

Get Accredited

tyga.games accreditation

Prove you can build and operate real-time features on OddSockets — channels, presence, pub/sub, delivery guarantees and production liveops — on the stack itself. Three tiers (TCU / TCA / TCP), certified through tyga.games and delivered on ClassaaS.

Get accredited on tyga.games →

Support

License

MIT License - Copyright (c) 2026 Joe Wee, Tyga.Cloud Ltd. See LICENSE for details.

About

JavaScript SDK for OddSockets — real-time WebSocket channels, pub/sub, presence. Browser + Node.js.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages