oddsockets-nodejs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +448 -0
- package/dist/Channel.js +1 -0
- package/dist/EnhancedFeatures.js +1 -0
- package/dist/ManagerDiscovery.js +1 -0
- package/dist/MessageSizeValidator.js +1 -0
- package/dist/OddSockets.js +1 -0
- package/dist/PubNubCompat.js +1 -0
- package/dist/index.js +1 -0
- package/examples/basic-usage.js +140 -0
- package/examples/enhanced-features-usage.js +403 -0
- package/examples/index.html +729 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
OddSockets Node.js SDK - End User License Agreement
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tyga.Cloud Ltd. All rights reserved.
|
|
4
|
+
|
|
5
|
+
Permission is granted to install and use this software via npm for its
|
|
6
|
+
intended purpose (interacting with the OddSockets platform at oddsockets.com).
|
|
7
|
+
|
|
8
|
+
You may NOT:
|
|
9
|
+
- Reverse-engineer, decompile, or disassemble this software
|
|
10
|
+
- Redistribute, sublicense, or resell this software
|
|
11
|
+
- Modify or create derivative works based on this software
|
|
12
|
+
- Remove or alter any copyright notices contained in this software
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
17
|
+
TYGA.CLOUD LTD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
18
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
19
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
20
|
+
|
|
21
|
+
Full terms of service: https://oddsockets.com/terms
|
package/README.md
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
# OddSockets Node.js SDK
|
|
2
|
+
|
|
3
|
+
Official Node.js SDK for the OddSockets real-time messaging platform. This SDK provides a simple, powerful interface for building real-time applications with automatic manager discovery, worker load balancing, and message size validation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Simple API** - Easy-to-use interface for real-time messaging
|
|
8
|
+
- **Auto-reconnection** - Automatic reconnection with exponential backoff
|
|
9
|
+
- **Message Size Validation** - Industry-standard 32KB message size limits
|
|
10
|
+
- **Session Stickiness** - Consistent worker assignment for optimal performance
|
|
11
|
+
- **PubNub Compatibility** - Drop-in replacement for PubNub applications
|
|
12
|
+
- **Bulk Operations** - Publish multiple messages efficiently
|
|
13
|
+
- **TypeScript Support** - Full TypeScript definitions included
|
|
14
|
+
- **Presence Tracking** - Real-time user presence and state management
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @oddsocketsai/nodejs-sdk
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
const OddSockets = require('@oddsocketsai/nodejs-sdk');
|
|
26
|
+
|
|
27
|
+
// Initialize the client
|
|
28
|
+
const client = new OddSockets({
|
|
29
|
+
apiKey: 'your-api-key-here',
|
|
30
|
+
userId: 'user-123'
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Listen for connection events
|
|
34
|
+
client.on('connected', () => {
|
|
35
|
+
console.log('Connected to OddSockets');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Get a channel and subscribe
|
|
39
|
+
const channel = client.channel('my-channel');
|
|
40
|
+
|
|
41
|
+
await channel.subscribe((message) => {
|
|
42
|
+
console.log('Received:', message);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Publish a message
|
|
46
|
+
await channel.publish({
|
|
47
|
+
text: 'Hello World!',
|
|
48
|
+
timestamp: new Date().toISOString()
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Configuration Options
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
const client = new OddSockets({
|
|
56
|
+
apiKey: 'your-api-key-here', // Required: Your OddSockets API key
|
|
57
|
+
userId: 'user-123', // Optional: User identifier
|
|
58
|
+
autoConnect: true, // Optional: Auto-connect on initialization (default: true)
|
|
59
|
+
options: { // Optional: Additional Socket.IO options
|
|
60
|
+
transports: ['websocket', 'polling'],
|
|
61
|
+
timeout: 10000
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Channel Operations
|
|
67
|
+
|
|
68
|
+
### Subscribe to Messages
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
const channel = client.channel('my-channel');
|
|
72
|
+
|
|
73
|
+
// Basic subscription
|
|
74
|
+
await channel.subscribe((message) => {
|
|
75
|
+
console.log('Message:', message.message);
|
|
76
|
+
console.log('Publisher:', message.publisher);
|
|
77
|
+
console.log('Timestamp:', message.timestamp);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Subscribe with options
|
|
81
|
+
await channel.subscribe((message) => {
|
|
82
|
+
console.log('Received:', message);
|
|
83
|
+
}, {
|
|
84
|
+
enablePresence: true, // Enable presence tracking
|
|
85
|
+
retainHistory: true, // Keep message history in memory
|
|
86
|
+
maxHistory: 100 // Maximum messages to retain
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Publish Messages
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
// Simple message
|
|
94
|
+
await channel.publish('Hello World!');
|
|
95
|
+
|
|
96
|
+
// Complex message with metadata
|
|
97
|
+
await channel.publish({
|
|
98
|
+
text: 'Hello World!',
|
|
99
|
+
user: 'john_doe',
|
|
100
|
+
timestamp: new Date().toISOString()
|
|
101
|
+
}, {
|
|
102
|
+
ttl: 3600, // Time to live in seconds
|
|
103
|
+
metadata: { // Additional metadata
|
|
104
|
+
priority: 'high'
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Bulk Publishing
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
// Publish multiple messages at once
|
|
113
|
+
const results = await client.publishBulk([
|
|
114
|
+
{ channel: 'channel-1', message: 'Message 1' },
|
|
115
|
+
{ channel: 'channel-2', message: 'Message 2' },
|
|
116
|
+
{ channel: 'channel-1', message: 'Message 3', options: { ttl: 3600 } }
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
results.forEach((result, index) => {
|
|
120
|
+
if (result.success) {
|
|
121
|
+
console.log(`Message ${index + 1} published successfully`);
|
|
122
|
+
} else {
|
|
123
|
+
console.error(`Message ${index + 1} failed:`, result.error);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Message History
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
// Get recent messages
|
|
132
|
+
const history = await channel.getHistory({
|
|
133
|
+
count: 50, // Number of messages (default: 50)
|
|
134
|
+
start: '2023-01-01T00:00:00Z', // Start time (ISO string)
|
|
135
|
+
end: '2023-12-31T23:59:59Z' // End time (ISO string)
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
console.log('History:', history);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Presence Management
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
// Get current presence
|
|
145
|
+
const presence = await channel.getPresence();
|
|
146
|
+
console.log('Online users:', presence.occupancy);
|
|
147
|
+
console.log('User list:', presence.occupants);
|
|
148
|
+
|
|
149
|
+
// Update user state
|
|
150
|
+
await channel.updateState({
|
|
151
|
+
status: 'online',
|
|
152
|
+
mood: 'happy',
|
|
153
|
+
location: 'New York'
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Listen for presence changes
|
|
157
|
+
channel.on('presence_change', (event) => {
|
|
158
|
+
console.log(`User ${event.user.userId} ${event.action}`);
|
|
159
|
+
console.log('Current occupancy:', event.occupancy);
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## PubNub Compatibility
|
|
164
|
+
|
|
165
|
+
Migrate from PubNub with minimal code changes:
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
const { PubNubCompat } = require('@oddsocketsai/nodejs-sdk');
|
|
169
|
+
|
|
170
|
+
// Initialize with PubNub-style config
|
|
171
|
+
const pubnub = new PubNubCompat({
|
|
172
|
+
publishKey: 'your-api-key-here',
|
|
173
|
+
subscribeKey: 'your-api-key-here',
|
|
174
|
+
userId: 'user-123'
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Add listeners (PubNub style)
|
|
178
|
+
pubnub.addListener({
|
|
179
|
+
message: (messageEvent) => {
|
|
180
|
+
console.log('Message:', messageEvent.message);
|
|
181
|
+
console.log('Channel:', messageEvent.channel);
|
|
182
|
+
console.log('Publisher:', messageEvent.publisher);
|
|
183
|
+
},
|
|
184
|
+
presence: (presenceEvent) => {
|
|
185
|
+
console.log('Presence:', presenceEvent.action);
|
|
186
|
+
console.log('User:', presenceEvent.uuid);
|
|
187
|
+
},
|
|
188
|
+
status: (statusEvent) => {
|
|
189
|
+
console.log('Status:', statusEvent.category);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Subscribe to channels
|
|
194
|
+
pubnub.subscribe({
|
|
195
|
+
channels: ['channel-1', 'channel-2'],
|
|
196
|
+
withPresence: true
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Publish messages
|
|
200
|
+
pubnub.publish({
|
|
201
|
+
channel: 'channel-1',
|
|
202
|
+
message: 'Hello from PubNub compatibility!'
|
|
203
|
+
}, (response) => {
|
|
204
|
+
if (response.error) {
|
|
205
|
+
console.error('Error:', response.error);
|
|
206
|
+
} else {
|
|
207
|
+
console.log('Published with timetoken:', response.timetoken);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Event Handling
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
// Connection events
|
|
216
|
+
client.on('connected', () => {
|
|
217
|
+
console.log('Connected to OddSockets');
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
client.on('disconnected', (reason) => {
|
|
221
|
+
console.log('Disconnected:', reason);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
client.on('reconnecting', (attempt) => {
|
|
225
|
+
console.log(`Reconnecting... attempt ${attempt.attempt}/${attempt.maxAttempts}`);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
client.on('error', (error) => {
|
|
229
|
+
console.error('Connection error:', error);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
client.on('worker_assigned', (info) => {
|
|
233
|
+
console.log('Assigned to worker:', info.workerId);
|
|
234
|
+
console.log('Worker URL:', info.workerUrl);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Channel events
|
|
238
|
+
channel.on('subscribed', (data) => {
|
|
239
|
+
console.log('Subscribed to channel:', data.channel);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
channel.on('unsubscribed', (data) => {
|
|
243
|
+
console.log('Unsubscribed from channel:', data.channel);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
channel.on('published', (data) => {
|
|
247
|
+
console.log('Message published:', data);
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Error Handling
|
|
252
|
+
|
|
253
|
+
```javascript
|
|
254
|
+
try {
|
|
255
|
+
await channel.publish('Hello World!');
|
|
256
|
+
} catch (error) {
|
|
257
|
+
if (error.message.includes('Message size')) {
|
|
258
|
+
console.error('Message too large (max 32KB)');
|
|
259
|
+
} else if (error.message.includes('Not connected')) {
|
|
260
|
+
console.error('Client not connected');
|
|
261
|
+
} else {
|
|
262
|
+
console.error('Publish failed:', error.message);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Advanced Usage
|
|
268
|
+
|
|
269
|
+
### Custom Connection Options
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
const client = new OddSockets({
|
|
273
|
+
apiKey: 'your-api-key-here',
|
|
274
|
+
userId: 'user-123',
|
|
275
|
+
options: {
|
|
276
|
+
transports: ['websocket'], // Force WebSocket only
|
|
277
|
+
timeout: 15000, // Connection timeout
|
|
278
|
+
forceNew: true, // Force new connection
|
|
279
|
+
reconnection: true, // Enable reconnection
|
|
280
|
+
reconnectionDelay: 1000, // Initial reconnection delay
|
|
281
|
+
reconnectionAttempts: 5, // Max reconnection attempts
|
|
282
|
+
maxReconnectionAttempts: 10 // Max total attempts
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Manual Connection Management
|
|
288
|
+
|
|
289
|
+
```javascript
|
|
290
|
+
const client = new OddSockets({
|
|
291
|
+
apiKey: 'your-api-key-here',
|
|
292
|
+
autoConnect: false // Don't auto-connect
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// Connect manually
|
|
296
|
+
await client.connect();
|
|
297
|
+
|
|
298
|
+
// Check connection state
|
|
299
|
+
console.log('State:', client.getState()); // 'connected', 'connecting', 'disconnected', 'reconnecting'
|
|
300
|
+
|
|
301
|
+
// Get worker info
|
|
302
|
+
const workerInfo = client.getWorkerInfo();
|
|
303
|
+
console.log('Worker ID:', workerInfo.workerId);
|
|
304
|
+
console.log('Worker URL:', workerInfo.workerUrl);
|
|
305
|
+
|
|
306
|
+
// Disconnect
|
|
307
|
+
client.disconnect();
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Session Information
|
|
311
|
+
|
|
312
|
+
```javascript
|
|
313
|
+
// Get client identifier (used for session stickiness)
|
|
314
|
+
const clientId = client.getClientIdentifier();
|
|
315
|
+
console.log('Client ID:', clientId);
|
|
316
|
+
|
|
317
|
+
// Get session info
|
|
318
|
+
const session = client.getSessionInfo();
|
|
319
|
+
console.log('Session:', session);
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Message Size Limits
|
|
323
|
+
|
|
324
|
+
The SDK enforces industry-standard message size limits:
|
|
325
|
+
|
|
326
|
+
- **Maximum message size**: 32KB (32,768 bytes)
|
|
327
|
+
- **Encoding**: UTF-8
|
|
328
|
+
- **Validation**: Automatic before publishing
|
|
329
|
+
|
|
330
|
+
```javascript
|
|
331
|
+
// This will throw an error if message exceeds 32KB
|
|
332
|
+
try {
|
|
333
|
+
await channel.publish({
|
|
334
|
+
data: 'x'.repeat(40000) // Too large!
|
|
335
|
+
});
|
|
336
|
+
} catch (error) {
|
|
337
|
+
console.error(error.message);
|
|
338
|
+
// "Message size (39KB) exceeds maximum allowed size of 32KB"
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Examples
|
|
343
|
+
|
|
344
|
+
Run the included examples:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# Basic usage example
|
|
348
|
+
node examples/basic-usage.js
|
|
349
|
+
|
|
350
|
+
# PubNub compatibility example
|
|
351
|
+
node examples/basic-usage.js pubnub
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## API Reference
|
|
355
|
+
|
|
356
|
+
### OddSockets Class
|
|
357
|
+
|
|
358
|
+
#### Constructor
|
|
359
|
+
- `new OddSockets(config)` - Create a new client instance
|
|
360
|
+
|
|
361
|
+
#### Methods
|
|
362
|
+
- `connect()` - Connect to OddSockets platform
|
|
363
|
+
- `disconnect()` - Disconnect from platform
|
|
364
|
+
- `channel(name)` - Get or create a channel
|
|
365
|
+
- `publishBulk(messages)` - Publish multiple messages
|
|
366
|
+
- `getState()` - Get connection state
|
|
367
|
+
- `getWorkerInfo()` - Get assigned worker information
|
|
368
|
+
- `getClientIdentifier()` - Get client identifier
|
|
369
|
+
- `getSessionInfo()` - Get session information
|
|
370
|
+
|
|
371
|
+
#### Events
|
|
372
|
+
- `connected` - Connected to platform
|
|
373
|
+
- `disconnected` - Disconnected from platform
|
|
374
|
+
- `reconnecting` - Attempting to reconnect
|
|
375
|
+
- `error` - Connection error occurred
|
|
376
|
+
- `worker_assigned` - Assigned to a worker
|
|
377
|
+
|
|
378
|
+
### Channel Class
|
|
379
|
+
|
|
380
|
+
#### Methods
|
|
381
|
+
- `subscribe(callback, options)` - Subscribe to messages
|
|
382
|
+
- `unsubscribe()` - Unsubscribe from channel
|
|
383
|
+
- `publish(message, options)` - Publish a message
|
|
384
|
+
- `getHistory(options)` - Get message history
|
|
385
|
+
- `getPresence()` - Get presence information
|
|
386
|
+
- `updateState(state)` - Update user state
|
|
387
|
+
- `isSubscribed()` - Check subscription status
|
|
388
|
+
- `getName()` - Get channel name
|
|
389
|
+
|
|
390
|
+
#### Events
|
|
391
|
+
- `message` - New message received
|
|
392
|
+
- `subscribed` - Successfully subscribed
|
|
393
|
+
- `unsubscribed` - Successfully unsubscribed
|
|
394
|
+
- `published` - Message published
|
|
395
|
+
- `presence` - Presence information
|
|
396
|
+
- `presence_change` - Presence changed
|
|
397
|
+
|
|
398
|
+
## Get a Free API Key
|
|
399
|
+
|
|
400
|
+
AI agents can sign up with a verified email in two steps — no dashboard, no human required.
|
|
401
|
+
|
|
402
|
+
**Step 1:** Request a verification code
|
|
403
|
+
```bash
|
|
404
|
+
curl -X POST https://oddsockets.com/api/agent-signup \
|
|
405
|
+
-H "Content-Type: application/json" \
|
|
406
|
+
-d '{"email": "you@example.com", "agentName": "my-agent", "platform": "claude"}'
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**Step 2:** Verify the 6-digit code from your email and get your API key
|
|
410
|
+
```bash
|
|
411
|
+
curl -X POST https://oddsockets.com/api/agent-signup/verify \
|
|
412
|
+
-H "Content-Type: application/json" \
|
|
413
|
+
-d '{"email": "you@example.com", "code": "123456", "agentName": "my-agent"}'
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## Plans
|
|
417
|
+
|
|
418
|
+
| | Free | Starter | Pro |
|
|
419
|
+
|---|---|---|---|
|
|
420
|
+
| **Price** | $0/mo | $49.99/mo | $299/mo |
|
|
421
|
+
| **MAU** | 100 | 1,000 | 50,000 |
|
|
422
|
+
| **Concurrent connections** | 50 | 1,000 | Unlimited |
|
|
423
|
+
| **Messages/day** | 10,000 | 4,320,000 | Unlimited |
|
|
424
|
+
| **Messages/minute** | 100 | 3,000 | Unlimited |
|
|
425
|
+
| **Channels** | 10 | Unlimited | Unlimited |
|
|
426
|
+
| **Storage** | 100MB (24h) | 50GB (6 months) | Unlimited |
|
|
427
|
+
| **Webhooks** | No | Yes | Yes |
|
|
428
|
+
| **Analytics** | No | Yes | Yes |
|
|
429
|
+
| **Support** | Community | 24/5 email & chat | Dedicated team |
|
|
430
|
+
|
|
431
|
+
All limits are enforced in real time. When a limit is reached, the SDK receives a `RATE_LIMIT_EXCEEDED` error with a `retryAfter` value.
|
|
432
|
+
|
|
433
|
+
See [pricing](https://oddsockets.com/pricing) for full details.
|
|
434
|
+
|
|
435
|
+
## Requirements
|
|
436
|
+
|
|
437
|
+
- Node.js 14.0.0 or higher
|
|
438
|
+
- Active OddSockets API key ([get one free](#get-a-free-api-key))
|
|
439
|
+
|
|
440
|
+
## Support
|
|
441
|
+
|
|
442
|
+
- [Documentation](https://docs.oddsockets.com/sdks/nodejs)
|
|
443
|
+
- [Issue Tracker](https://github.com/jyswee/oddsockets-nodejs-sdk/issues)
|
|
444
|
+
- [Email Support](mailto:support@oddsockets.com)
|
|
445
|
+
|
|
446
|
+
## License
|
|
447
|
+
|
|
448
|
+
MIT License - Copyright (c) 2026 Joe Wee, Tyga.Cloud Ltd. See [LICENSE](LICENSE) for details.
|