Observed since 20 Oct, 22:40 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
A robust WebSocket client for DEX trading applications
A robust WebSocket client for DEX trading applications.
npm install @0xandreja/dex-ws
import DexWS from '@0xandreja/dex-ws';
const ws = new DexWS('wss://api.hyperliquid.xyz/ws');
ws.on('open', ({ isReconnect }) => {
console.log('Connected!', isReconnect ? '(reconnected)' : '');
ws.send({ subscribe: 'trades' });
});
ws.on('message', (data) => {
console.log('Received:', data);
});
ws.on('close', ({ code, reason }) => {
console.log('Disconnected:', code, reason);
});
ws.on('error', (error) => {
console.error('Error:', error);
});
// Clean up when done
ws.destroy();
new DexWS(url: string | (() => string), options?: DexWSOptions)
url - WebSocket URL (must start with ws:// or wss://) or a function returning the URLoptions - Configuration options (see below)interface DexWSOptions {
autoConnect?: boolean; // Auto-connect on instantiation (default: true)
timeout?: number; // Connection timeout in ms (default: 30000)
protocols?: string | string[]; // WebSocket subprotocols
logger?: LogLevel | Logger; // Logging configuration
binaryType?: BinaryType; // 'blob' or 'arraybuffer' (default: 'blob')
reconnect?: ReconnectOptions | boolean;
heartbeat?: HeartbeatOptions | boolean;
visibility?: VisibilityOptions | boolean;
network?: NetworkOptions | boolean;
buffer?: BufferOptions | boolean;
}
Each feature can be:
false - Disabledtrue or undefined - Enabled with defaultsobject - Enabled with custom options merged with defaultsinterface ReconnectOptions {
enabled?: boolean; // Enable reconnection (default: true)
maxRetries?: number; // Max reconnection attempts (default: Infinity)
delay?: number | ((attempt: number) => number); // Delay in ms or function
jitter?: boolean; // Add random jitter to delay (default: true)
}
Default delay function: Math.min(1000 * 2^n, 30000) (exponential backoff, max 30s)
Jitter formula: baseDelay + (baseDelay * 0.2 * Math.random())
interface HeartbeatOptions {
enabled?: boolean; // Enable heartbeat (default: true)
interval?: number; // Heartbeat interval in ms (default: 30000)
message?: string | (() => string); // Ping message (default: '{"method":"ping"}')
pongTimeout?: number; // Pong timeout in ms (default: 10000)
}
interface VisibilityOptions {
enabled?: boolean; // Enable visibility handling (default: true)
timeout?: number; // Time before disconnect when hidden (default: 120000)
verifyOnVisible?: boolean; // Reconnect when visible (default: true)
}
interface NetworkOptions {
enabled?: boolean; // Enable network handling (default: true)
autoReconnect?: boolean; // Reconnect when online (default: true)
}
interface BufferOptions {
enabled?: boolean; // Enable message buffering (default: true)
maxSize?: number; // Max buffer size (default: 100)
overflow?: OverflowStrategy; // 'drop-oldest' | 'drop-newest' | 'error'
}
connect(): thisInitiate connection. Called automatically if autoConnect is true.
disconnect(): thisGracefully close the connection.
destroy(): voidPermanently destroy the instance. Cleans up all listeners and timers. Idempotent.
send(data: unknown): booleanSend data through the WebSocket. Returns true if sent successfully, false otherwise.
on(event, listener): thisSubscribe to events. Returns this for chaining.
off(event, listener): thisUnsubscribe from events. Returns this for chaining.
once(event, listener): thisSubscribe to a single event occurrence. Returns this for chaining.
removeAllListeners(event?): thisRemove all listeners for an event, or all listeners if no event specified.
| Property | Type | Description |
|---|---|---|
status | ConnectionState | Current connection state |
connected | boolean | True if currently connected |
endpoint | string | The WebSocket URL |
config | DexWSOptions | Current configuration |
bufferSize | number | Number of buffered messages |
metrics | Metrics | Connection metrics |
destroyed | boolean | True if instance is destroyed |
| Event | Payload | Description |
|---|---|---|
open | { isReconnect: boolean } | Connection opened |
close | { code: number, reason: string } | Connection closed |
message | unknown | Message received (auto-parsed if JSON) |
error | Error | Error occurred |
status | { status: ConnectionState, previousStatus: ConnectionState } | Status changed |
Note: on('status', fn) immediately emits the current status.
type ConnectionState =
| 'disconnected' // Not connected
| 'connecting' // Initial connection in progress
| 'connected' // Connected
| 'reconnecting' // Reconnection in progress
| 'terminated'; // Instance destroyed
interface Metrics {
connectionAttempts: number; // Total connection attempts
messagesSent: number; // Total messages sent
messagesReceived: number; // Total messages received
lastConnectedAt: number | null; // Timestamp of last connection
lastDisconnectedAt: number | null; // Timestamp of last disconnection
uptime: number; // Total connected time in ms
}
| Feature | Default |
|---|---|
autoConnect | true |
timeout | 30000 (30s) |
binaryType | 'blob' |
reconnect.maxRetries | Infinity |
reconnect.delay | Exponential backoff, max 30s |
reconnect.jitter | true (0-20% random) |
heartbeat.interval | 30000 (30s) |
heartbeat.message | '{"method":"ping"}' |
heartbeat.pongTimeout | 10000 (10s) |
visibility.timeout | 120000 (2 min) |
visibility.verifyOnVisible | true |
network.autoReconnect | true |
buffer.maxSize | 100 |
buffer.overflow | 'drop-oldest' |
The following close codes will NOT trigger automatic reconnection:
1000 - Normal closure1008 - Policy violation1009 - Message too big1010 - Missing extension1011 - Internal error1015 - TLS handshake failureAll other close codes will trigger reconnection (if enabled).
import { connect } from '@dex-ws/core';
const ws = connect('wss://api.example.com/ws', { /* options */ });
const ws = new DexWS('wss://api.example.com/ws', {
reconnect: {
maxRetries: 10,
delay: (attempt) => Math.min(500 * Math.pow(1.5, attempt), 10000),
jitter: true,
},
});
let seq = 0;
const ws = new DexWS('wss://api.example.com/ws', {
heartbeat: {
interval: 15000,
message: () => JSON.stringify({ type: 'ping', seq: ++seq }),
pongTimeout: 5000,
},
});
const ws = new DexWS('wss://api.example.com/ws', {
reconnect: false, // No auto-reconnect
heartbeat: false, // No heartbeat
visibility: false, // Ignore page visibility
network: false, // Ignore network changes
buffer: false, // No message buffering
});
const ws = new DexWS('wss://api.example.com/ws', {
logger: {
debug: (...args) => console.debug('[WS]', ...args),
info: (...args) => console.info('[WS]', ...args),
warn: (...args) => console.warn('[WS]', ...args),
error: (...args) => console.error('[WS]', ...args),
},
});
// Or use built-in levels: 'debug' | 'info' | 'warn' | 'error' | 'none'
const ws2 = new DexWS('wss://api.example.com/ws', { logger: 'debug' });
let serverIndex = 0;
const servers = ['wss://server1.com/ws', 'wss://server2.com/ws'];
const ws = new DexWS(() => servers[serverIndex++ % servers.length]);
MIT
Download counts and popularity will appear here as the collector receives them.
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 22:40 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:24106db9ab2d692fef1332f6f9149cb4ebbb2c03d7a02df5affe8db72b787827