Package Exports
- @wioex/stream-sdk
Readme
@wioex/stream-sdk
WebSocket streaming SDK for real-time WioEX market data. Receive live stock ticker updates with a simple, event-driven API.
Features
- 🚀 Real-time streaming - WebSocket-based live market data
- ⚡ High-performance - Optimized for high-frequency data with throttling & batching
- 📊 Multiple stocks - Track up to 8 stocks simultaneously
- 🔄 Auto-reconnection - Automatic reconnection with exponential backoff
- 🎯 Type-safe - Written in TypeScript with full type definitions
- 🌐 Universal - Works in Node.js and browsers
- 📦 Lightweight - Minimal dependencies (52KB ESM, 20KB UMD minified)
- 🔌 Event-driven - Simple EventEmitter-based API
- 💪 Production-ready - Robust error handling and heartbeat mechanism
- 🛡️ Error reporting - Automatic error tracking with batching & deduplication
✨ New in v1.6.0
- 🎯 Zero-config browser usage - Automatic token fetching from your backend endpoint
- 🚀 Lazy connect - No need to call
connect()- justsubscribe()and go! - 🐛 Debug mode - Detailed console logging for development
- 🔄 Retry with backoff - Automatic retry on token fetch failures with exponential/linear backoff
- 📍 Better error messages - Actionable error messages with platform-specific guidance
Installation
npm install @wioex/stream-sdkQuick Start
Node.js / Backend (Super Simple! 🎉)
import { WioexStreamClient } from '@wioex/stream-sdk';
// Backend usage: Just provide your API key!
// SDK automatically fetches secure token and handles everything
const client = new WioexStreamClient({
apiKey: process.env.WIOEX_API_KEY, // That's it! SDK handles token fetch
maxSymbols: 8
});
// Listen for ticker updates
client.on('ticker', (data) => {
console.log(`${data.ticket}: $${data.last} (${data.changePercent}%)`);
});
// Connect and subscribe - SDK auto-fetches token before connecting!
await client.connect();
client.subscribe(['AAPL', 'TSLA', 'GOOGL']);What happens behind the scenes:
- SDK detects Node.js environment
- Automatically fetches a secure token from WioEX API using your API key
- Connects to WebSocket stream with the token
- Your API key is NEVER sent via WebSocket (security first!)
💡 Pro Tip: Add
autoRefreshToken: trueto automatically refresh tokens before they expire!
Browser / Frontend (Zero-Config! 🎉)
<script src="https://unpkg.com/@wioex/stream-sdk/dist/wioex-stream.min.js"></script>
<script>
// v1.6.0: Zero-config with automatic token fetching!
const client = new WioexStream({
tokenEndpoint: '/api/stream/token', // Your backend endpoint
debug: true, // Enable debug mode (optional)
maxSymbols: 8
});
client.on('ticker', (data) => {
console.log(`${data.ticket}: $${data.last}`);
});
// v1.6.0: Lazy connect - no need to call connect()!
client.subscribe(['AAPL', 'TSLA']); // Auto-connects and subscribes!
</script>What's new:
- 🎯 Just specify
tokenEndpoint- SDK fetches token automatically - 🚀 No need to call
connect()- lazy connect on subscribe - 🐛 Debug mode for development
- 🔄 Automatic retry with exponential backoff on failures
🔒 Browser Security:
- SDK automatically blocks API key usage in browsers
- You MUST use tokens fetched from your backend
- See SECURE_STREAMING.md for implementation guide
API Reference
Constructor
new WioexStreamClient(config: WioexStreamConfig)Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
apiKey |
string |
Backend only | Backend (Node.js): Your WioEX API key - SDK auto-fetches token |
token |
string |
Frontend only | Frontend (Browser): Secure token from your backend |
tokenExpiresAt |
number |
- | Token expiration Unix timestamp (seconds) |
tokenEndpoint ✨ |
string |
- | v1.6.0: Backend endpoint URL to fetch token (browser only) |
tokenFetchHeaders ✨ |
object |
- | v1.6.0: Custom headers for token endpoint request |
tokenFetchRetry ✨ |
object |
See below | v1.6.0: Token fetch retry configuration |
onTokenExpiring |
function |
- | Async callback to fetch new token on expiry |
autoRefreshToken |
boolean |
true* |
Auto-refresh token before expiry (*if onTokenExpiring provided) |
refreshBeforeExpiry |
number |
3600000 |
Refresh token N ms before expiry (default: 1 hour) |
lazyConnect ✨ |
boolean |
true |
v1.6.0: Auto-connect on first subscribe (no manual connect() needed) |
debug ✨ |
boolean |
false |
v1.6.0: Enable debug logging to console |
maxSymbols |
number |
8 |
Maximum symbols to track (1-8) |
autoReconnect |
boolean |
true |
Enable auto-reconnection |
reconnectDelay |
number |
3000 |
Reconnection delay (ms) |
maxReconnectAttempts |
number |
0 |
Max reconnect attempts (0 = infinite) |
streamUrl |
string |
Auto | WebSocket URL (auto-generated) |
errorReportingLevel |
string |
'detailed' |
Error reporting level (none, minimal, standard, detailed) |
performance |
object |
See below | Performance optimization options |
Authentication:
- Backend (Node.js): Use
apiKey- SDK automatically fetches and manages tokens - Frontend (Browser): Use
tokenORtokenEndpoint(v1.6.0) - Get from your backend (API key blocked for security)
Token Fetch Retry Options (tokenFetchRetry config) ✨ v1.6.0
| Option | Type | Default | Description |
|---|---|---|---|
maxAttempts |
number |
3 |
Maximum number of retry attempts |
delay |
number |
1000 |
Initial delay between retries in milliseconds |
backoff |
'linear' | 'exponential' |
'exponential' |
Backoff strategy (exponential: 1s → 2s → 4s, linear: 1s → 2s → 3s) |
Example:
const client = new WioexStreamClient({
tokenEndpoint: '/api/stream/token',
tokenFetchRetry: {
maxAttempts: 5,
delay: 2000,
backoff: 'exponential', // 2s → 4s → 8s → 16s → 32s
},
});Performance Options (performance config)
| Option | Type | Default | Description |
|---|---|---|---|
tickerThrottle |
number |
16 |
Throttle ticker events (ms). 0 = disabled, 16 = 60 FPS |
batchTickers |
boolean |
false |
Enable ticker batching mode |
tickerBatchSize |
number |
10 |
Maximum ticker batch size |
errorBatchSize |
number |
10 |
Error reporting batch size |
errorBatchInterval |
number |
5000 |
Error flush interval (ms) |
errorDeduplication |
boolean |
true |
Enable error deduplication |
Performance Presets:
// Default (balanced - 60 FPS throttling)
const client = new WioexStreamClient({ apiKey: 'xxx' });
// High-performance (no throttling, immediate events)
const client = new WioexStreamClient({
apiKey: 'xxx',
performance: {
tickerThrottle: 0, // No throttling
errorBatchSize: 1, // Immediate error reporting
errorDeduplication: false, // No deduplication
}
});
// High-volume (optimized for charts - 20 FPS batching)
const client = new WioexStreamClient({
apiKey: 'xxx',
performance: {
tickerThrottle: 50, // 20 FPS
batchTickers: true, // Enable batching
tickerBatchSize: 20, // Larger batches
}
});
// Memory-optimized (aggressive batching)
const client = new WioexStreamClient({
apiKey: 'xxx',
performance: {
errorBatchSize: 50, // Large error batches
errorBatchInterval: 10000, // 10s flush interval
}
});Methods
connect(): Promise<void>
Connect to WioEX WebSocket stream. In Node.js with apiKey, automatically fetches token before connecting.
// Backend (with apiKey) - await to ensure token fetch completes
await client.connect();
// Frontend (with token) - can be called without await
client.connect();disconnect(): void
Disconnect from WebSocket stream.
client.disconnect();subscribe(stocks: string | string[]): void
Subscribe to stock ticker updates.
client.subscribe('AAPL');
client.subscribe(['AAPL', 'TSLA', 'GOOGL']);Throws: Error if attempting to subscribe to more than maxSymbols.
unsubscribe(stocks: string | string[]): void
Unsubscribe from stock ticker updates.
client.unsubscribe('AAPL');
client.unsubscribe(['AAPL', 'TSLA']);getState(): ConnectionState
Get current connection state.
const state = client.getState();
// Returns: 'disconnected' | 'connecting' | 'connected' | 'registered' | 'reconnecting' | 'failed'getSubscribedStocks(): string[]
Get list of currently subscribed stocks.
const stocks = client.getSubscribedStocks();
console.log(stocks); // ['AAPL', 'TSLA', 'GOOGL']getStats(): ClientStats
Get client statistics.
const stats = client.getStats();
console.log(stats);
// {
// connectedAt: 1704067200000,
// reconnectAttempts: 0,
// messagesReceived: 152,
// messagesSent: 3,
// tickersReceived: 148,
// subscribedStocks: ['AAPL', 'TSLA'],
// state: 'registered'
// }isConnected(): boolean
Check if client is connected.
if (client.isConnected()) {
console.log('Connected!');
}updateToken(token: string, expiresAt: number): void
Manually update authentication token (useful for token refresh implementations).
// Update token and schedule auto-refresh
client.updateToken(newToken, newExpiresAt);Events
The client extends EventEmitter and emits the following events:
connected
Emitted when WebSocket connection is established.
client.on('connected', () => {
console.log('Connected to WioEX stream');
});registered
Emitted when client is registered with API key.
client.on('registered', (data) => {
console.log('Registered:', data.message);
});subscribed
Emitted when subscribed to stocks.
client.on('subscribed', (stocks: string[]) => {
console.log('Subscribed to:', stocks);
});unsubscribed
Emitted when unsubscribed from stocks.
client.on('unsubscribed', (stocks: string[]) => {
console.log('Unsubscribed from:', stocks);
});ticker
Emitted when ticker data is received.
client.on('ticker', (data: TickerData) => {
console.log(`${data.ticket}: $${data.last}`);
});TickerData Structure:
interface TickerData {
ticket: string; // Stock symbol
last: string; // Last price
open: string; // Opening price
high: string; // High price
low: string; // Low price
volume: string; // Trading volume
bid: string; // Bid price
ask: string; // Ask price
change: string; // Price change
changePercent: string; // Change percentage
timestamp: number; // Unix timestamp
}error
Emitted when an error occurs.
client.on('error', (error: Error) => {
console.error('Error:', error.message);
});disconnected
Emitted when connection is closed.
client.on('disconnected', (code: number, reason: string) => {
console.log(`Disconnected (${code}): ${reason}`);
});reconnecting
Emitted when attempting to reconnect.
client.on('reconnecting', (attempt: number) => {
console.log(`Reconnecting... (attempt ${attempt})`);
});stateChange
Emitted when connection state changes.
client.on('stateChange', (state: ConnectionState) => {
console.log(`State: ${state}`);
});tokenExpiring
Emitted when token is about to expire (before auto-refresh).
client.on('tokenExpiring', ({ currentToken, expiresAt }) => {
console.log(`Token expiring at ${new Date(expiresAt * 1000)}`);
});tokenRefreshed
Emitted when token has been successfully refreshed.
client.on('tokenRefreshed', ({ token, expiresAt }) => {
console.log(`Token refreshed! New expiry: ${new Date(expiresAt * 1000)}`);
});tokenRefreshFailed
Emitted when token refresh fails.
client.on('tokenRefreshFailed', (error: Error) => {
console.error('Token refresh failed:', error.message);
});tokenFetchStarted ✨ v1.6.0
Emitted when token fetch starts (from endpoint or API).
client.on('tokenFetchStarted', (source: 'endpoint' | 'api') => {
console.log(`Fetching token from ${source}...`);
});tokenFetchSucceeded ✨ v1.6.0
Emitted when token fetch succeeds.
client.on('tokenFetchSucceeded', ({ token, expiresAt, source }) => {
console.log(`Token fetched from ${source}`);
console.log(`Expires at: ${new Date(expiresAt * 1000)}`);
});tokenFetchFailed ✨ v1.6.0
Emitted when token fetch fails (will retry if configured).
client.on('tokenFetchFailed', (error: Error, attempt: number, willRetry: boolean) => {
console.error(`Token fetch failed (attempt ${attempt}):`, error.message);
if (willRetry) {
console.log('Will retry...');
}
});Examples
Basic Usage (Backend)
import { WioexStreamClient } from '@wioex/stream-sdk';
// Super simple! Just provide API key, SDK handles token automatically
const client = new WioexStreamClient({
apiKey: process.env.WIOEX_API_KEY,
maxSymbols: 5
});
client.on('ticker', (data) => {
const change = parseFloat(data.changePercent);
const arrow = change >= 0 ? '↑' : '↓';
console.log(`${arrow} ${data.ticket}: $${data.last} (${change.toFixed(2)}%)`);
});
await client.connect(); // SDK auto-fetches token here
client.subscribe(['AAPL', 'TSLA', 'GOOGL', 'MSFT', 'AMZN']);Dynamic Subscription Management
// Get token first
const { token } = await fetch('/api/stream/token', { method: 'POST' })
.then(r => r.json());
const client = new WioexStreamClient({
token,
maxSymbols: 3
});
client.on('registered', () => {
// Subscribe to initial stocks
client.subscribe(['AAPL', 'TSLA', 'GOOGL']);
});
// After 30 seconds, switch to different stocks
setTimeout(() => {
client.unsubscribe(['GOOGL']);
client.subscribe(['MSFT']);
}, 30000);
client.connect();Error Handling
const { token } = await fetch('/api/stream/token', { method: 'POST' })
.then(r => r.json());
const client = new WioexStreamClient({
token,
autoReconnect: true,
maxReconnectAttempts: 5
});
client.on('error', (error) => {
console.error('Error:', error.message);
});
client.on('disconnected', (code, reason) => {
console.log(`Disconnected: ${reason}`);
if (code !== 1000) {
console.log('Unexpected disconnection');
}
});
client.on('reconnecting', (attempt) => {
console.log(`Reconnecting... attempt ${attempt}`);
});
client.connect();Statistics Monitoring
const { token } = await fetch('/api/stream/token', { method: 'POST' })
.then(r => r.json());
const client = new WioexStreamClient({ token });
client.connect();
client.subscribe(['AAPL', 'TSLA']);
// Log statistics every minute
setInterval(() => {
const stats = client.getStats();
console.log('Statistics:', {
uptime: Date.now() - stats.connectedAt!,
messagesReceived: stats.messagesReceived,
tickersReceived: stats.tickersReceived,
subscribedStocks: stats.subscribedStocks
});
}, 60000);Token Auto-Refresh (Backend)
// Backend: Automatic token refresh with API key
const client = new WioexStreamClient({
apiKey: process.env.WIOEX_API_KEY,
// Enable auto-refresh (default: true)
autoRefreshToken: true,
// Refresh 1 hour before expiry (default: 3600000ms)
refreshBeforeExpiry: 3600000,
// Callback for custom token fetching
onTokenExpiring: async () => {
console.log('Fetching new token...');
const response = await fetch(
`https://api.wioex.com/v1/stream/token?api_key=${process.env.WIOEX_API_KEY}`,
{ method: 'POST' }
);
const data = await response.json();
return {
token: data.token,
expiresAt: data.expires_at
};
}
});
// Monitor token refresh events
client.on('tokenExpiring', ({ expiresAt }) => {
console.log(`Token expiring at ${new Date(expiresAt * 1000)}`);
});
client.on('tokenRefreshed', ({ expiresAt }) => {
console.log(`Token refreshed! Valid until ${new Date(expiresAt * 1000)}`);
});
client.on('tokenRefreshFailed', (error) => {
console.error('Token refresh failed:', error);
});
await client.connect();
client.subscribe(['AAPL', 'TSLA']);WebSocket Protocol
The SDK communicates with WioEX WebSocket API using JSON messages:
Connection
wss://stream.wioex.com/rs/i/{max_symbols}/websocketRegistration
{
"action": "register",
"token": "your-temporary-token"
}Response:
{
"status": "success",
"type": "registered",
"message": "Client registered successfully"
}Subscribe
{
"action": "subscribe",
"stocks": ["AAPL", "TSLA", "GOOGL"]
}Response:
{
"status": "success",
"type": "subscribed",
"message": "Subscribed to stocks",
"stocks": ["AAPL", "TSLA", "GOOGL"]
}Ticker Update
{
"sarex": {
"_p": { "e": "d" },
"ticker": {
"ticket": "AAPL",
"last": "185.25",
"open": "183.50",
"high": "186.00",
"low": "183.00",
"volume": "52478963",
"bid": "185.20",
"ask": "185.30",
"change": "1.75",
"changePercent": "0.95",
"timestamp": 1704067200000
}
}
}TypeScript Support
Full TypeScript support with comprehensive type definitions:
import {
WioexStreamClient,
WioexStreamConfig,
TickerData,
ConnectionState,
ClientStats
} from '@wioex/stream-sdk';
// Get token (from backend)
const { token } = await fetch('/api/stream/token', { method: 'POST' })
.then(r => r.json());
const config: WioexStreamConfig = {
token,
maxSymbols: 8
};
const client = new WioexStreamClient(config);
client.on('ticker', (data: TickerData) => {
// TypeScript knows the exact structure of data
console.log(data.ticket, data.last, data.changePercent);
});Browser Support
The SDK works in all modern browsers that support WebSocket:
- Chrome 16+
- Firefox 11+
- Safari 7+
- Edge 12+
- Opera 12.1+
Node.js Support
Requires Node.js 16 or higher.
Development
# Install dependencies
npm install
# Build the package
npm run build
# Run linter
npm run lint
# Run tests
npm test
# Development mode (watch)
npm run devExamples
See the examples/ directory for complete examples:
- Node.js Example:
examples/node-example.js - Browser Example:
examples/browser-example.html - Next.js App Router Example ✨ v1.6.0:
examples/nextjs-app-router/- Full Next.js 15 example with token endpoint, lazy connect, and debug mode
To run the Node.js example:
cd examples
WIOEX_API_KEY=your-api-key node node-example.jsTo run the browser example:
- Build the package:
npm run build - Open
examples/browser-example.htmlin a browser - Enter your API key and click Connect
To run the Next.js example:
cd examples/nextjs-app-router
cp .env.example .env.local
# Edit .env.local and add your WIOEX_API_KEY
npm install
npm run dev
# Open http://localhost:3000See examples/nextjs-app-router/README.md for detailed documentation.
License
MIT License - see LICENSE file for details.
Support
- Documentation: https://docs.wioex.com
- API Reference: https://api.wioex.com/docs
- Issues: https://github.com/wioex/wioex-stream-sdk/issues
Publishing to NPM
To publish this package to NPM:
# Login to NPM
npm login
# Build the package
npm run build
# Publish to NPM
npm publish --access publicRelated Projects
- @wioex/php-sdk - PHP SDK for WioEX API
Made with ❤️ by WioEX