diff --git a/src/Defaults/index.ts b/src/Defaults/index.ts index ea0c3c5d..006f9bb4 100644 --- a/src/Defaults/index.ts +++ b/src/Defaults/index.ts @@ -80,7 +80,11 @@ export const DEFAULT_CONNECTION_CONFIG: SocketConfig = { cachedGroupMetadata: async () => undefined, makeSignalRepository: makeLibSignalRepository, // Circuit breaker configuration - enableCircuitBreaker: true + enableCircuitBreaker: true, + // Listener limits (memory leak prevention) + // 8 base WS events + 10 dynamic listeners + 2 buffer slots + maxWebSocketListeners: 20, + maxSocketClientListeners: 50 } export const MEDIA_PATH_MAP: { [T in MediaType]?: string } = { diff --git a/src/Socket/Client/types.ts b/src/Socket/Client/types.ts index 3a6ee818..cc7c7024 100644 --- a/src/Socket/Client/types.ts +++ b/src/Socket/Client/types.ts @@ -13,7 +13,13 @@ export abstract class AbstractSocketClient extends EventEmitter { public config: SocketConfig ) { super() - this.setMaxListeners(0) + // Set max listeners from config (default: 50) + // WARNING: 0 disables limit and allows potential memory leaks + const maxListeners = this.config.maxSocketClientListeners ?? 50 + if (maxListeners === 0) { + this.config.logger?.warn('SocketClient setMaxListeners(0) allows UNLIMITED listeners - potential memory leak!') + } + this.setMaxListeners(maxListeners) } abstract connect(): void diff --git a/src/Socket/Client/websocket.ts b/src/Socket/Client/websocket.ts index 6aab1e3c..59632cd2 100644 --- a/src/Socket/Client/websocket.ts +++ b/src/Socket/Client/websocket.ts @@ -31,7 +31,13 @@ export class WebSocketClient extends AbstractSocketClient { agent: this.config.agent }) - this.socket.setMaxListeners(0) + // Set max listeners from config (default: 20) + // WARNING: 0 disables limit and allows potential memory leaks + const maxListeners = this.config.maxWebSocketListeners ?? 20 + if (maxListeners === 0) { + this.config.logger?.warn('WebSocket setMaxListeners(0) allows UNLIMITED listeners - potential memory leak!') + } + this.socket.setMaxListeners(maxListeners) const events = ['close', 'error', 'upgrade', 'message', 'open', 'ping', 'pong', 'unexpected-response'] diff --git a/src/Types/Socket.ts b/src/Types/Socket.ts index 62ab06b5..5d98c075 100644 --- a/src/Types/Socket.ts +++ b/src/Types/Socket.ts @@ -165,4 +165,19 @@ export type SocketConfig = { /** Circuit breaker configuration for message operations */ messageCircuitBreaker?: Partial + + // === Listener Limits (Memory Leak Prevention) === + + /** + * Max WebSocket event listeners (default: 20) + * Calculated as: 8 base WS events + 10 dynamic listeners + 2 buffer slots + * WARNING: Setting to 0 disables limit and allows potential memory leaks! + */ + maxWebSocketListeners?: number + + /** + * Max SocketClient event listeners (default: 50) + * WARNING: Setting to 0 disables limit and allows potential memory leaks! + */ + maxSocketClientListeners?: number }