Problem
ReqraftWebSocket pools connections by the url option via ReqraftWebSocketsManager.connections. This means multiple instances connecting to the same endpoint (e.g. 'lsp') always share the underlying WebSocket.
In qorus-ide, we have two independent consumers that both connect to /lsp:
useLanguageServer hook — feeds the raw socket to Monaco's MonacoLspClient (which takes over onmessage)
DpqlLspClient class — manages its own JSON-RPC request/response lifecycle over the same /lsp endpoint
These two cannot share a WebSocket because they have completely different message handling. Currently DpqlLspClient is forced to use a raw WebSocket with manual URL construction and heartbeat, duplicating what ReqraftWebSocket already provides.
Proposed Solution
Add an optional pooled flag to IReqraftWebSocketConfig (default: true for backward compatibility):
export interface IReqraftWebSocketConfig {
url: string;
pooled?: boolean; // default: true
// ... existing options
}
When pooled: false, the instance should get its own isolated WebSocket connection instead of sharing one from the pool. The simplest implementation: use a unique internal pool key (e.g. url::nanoid()) so the existing pool machinery works unchanged, while getSocketUrl() still uses this.options.url for the actual WebSocket URL.
Implementation sketch
// In the constructor:
this._poolKey = this.options.pooled === false
? `${this.options.url}::${nanoid()}`
: this.options.url;
// Then replace all pool-related `this.options.url` references with `this._poolKey`,
// except in `getSocketUrl()` which builds the actual WebSocket URL.
Affected pool references in ReqraftWebSocket:
connect() — pool lookup, store, increment
addHandler() / removeHandler() — delegates to ReqraftWebSocketsManager
remove() — pool check, decrement, close
startHeartbeat() / stopHeartbeat() — pool heartbeat timer
getSocketUrl() stays unchanged (uses this.options.url for the real URL path).
Usage
// Pooled (default, existing behavior — shared connection)
const shared = new ReqraftWebSocket({ url: 'lsp' });
// Isolated (own connection, same endpoint)
const isolated = new ReqraftWebSocket({ url: 'lsp', pooled: false });
🤖 Generated with Claude Code
Problem
ReqraftWebSocketpools connections by theurloption viaReqraftWebSocketsManager.connections. This means multiple instances connecting to the same endpoint (e.g.'lsp') always share the underlying WebSocket.In
qorus-ide, we have two independent consumers that both connect to/lsp:useLanguageServerhook — feeds the raw socket to Monaco'sMonacoLspClient(which takes overonmessage)DpqlLspClientclass — manages its own JSON-RPC request/response lifecycle over the same/lspendpointThese two cannot share a WebSocket because they have completely different message handling. Currently
DpqlLspClientis forced to use a rawWebSocketwith manual URL construction and heartbeat, duplicating whatReqraftWebSocketalready provides.Proposed Solution
Add an optional
pooledflag toIReqraftWebSocketConfig(default:truefor backward compatibility):When
pooled: false, the instance should get its own isolated WebSocket connection instead of sharing one from the pool. The simplest implementation: use a unique internal pool key (e.g.url::nanoid()) so the existing pool machinery works unchanged, whilegetSocketUrl()still usesthis.options.urlfor the actual WebSocket URL.Implementation sketch
Affected pool references in
ReqraftWebSocket:connect()— pool lookup, store, incrementaddHandler()/removeHandler()— delegates toReqraftWebSocketsManagerremove()— pool check, decrement, closestartHeartbeat()/stopHeartbeat()— pool heartbeat timergetSocketUrl()stays unchanged (usesthis.options.urlfor the real URL path).Usage
🤖 Generated with Claude Code