* Wrap a Readable stream with a single shared 'data' listener that demuxes * line-by-line into per-request callbacks. This avoids accumulating one * 'data' listener per in-flight request (which causes EventEmitter warnings * and cross-request data leakage when responses race). * * Returns { sen
(stream)
| 250 | * Returns { sendLine, registerHandler, unregister, close } |
| 251 | */ |
| 252 | function createLineDemuxer(stream) { |
| 253 | const handlers = new Map(); // id → fn(line) |
| 254 | let buffer = ''; |
| 255 | const onData = (chunk) => { |
| 256 | buffer += chunk.toString('utf8'); |
| 257 | const lines = buffer.split('\n'); |
| 258 | buffer = lines.pop() || ''; |
| 259 | for (const line of lines) { |
| 260 | if (!line.trim()) continue; |
| 261 | for (const fn of handlers.values()) { |
| 262 | try { fn(line); } catch { /* handler should never throw */ } |
| 263 | } |
| 264 | } |
| 265 | }; |
| 266 | stream.on('data', onData); |
| 267 | return { |
| 268 | register(id, fn) { handlers.set(id, fn); }, |
| 269 | unregister(id) { handlers.delete(id); }, |
| 270 | close() { try { stream.off('data', onData); } catch {} handlers.clear(); }, |
| 271 | pendingCount() { return handlers.size; }, |
| 272 | }; |
| 273 | } |
| 274 | |
| 275 | module.exports = { |
| 276 | redactString, |
no outgoing calls
no test coverage detected