avoid console warnings in case of many clients using same notification channel (eg: chat)

Massimo Melina committed Apr 7, 2026 at 10:23 UTC d96281a19cca31a33a338461a1ada1b3741aed8d
3 files changed +9 -7
src/SendList.ts
+3 -3
@@ -2,7 +2,7 @@ import { Readable } from 'stream'
2 import _ from 'lodash'
3 import { LIST, wantArray } from './cross'
4 import { Context } from 'koa'
5 -import events from './events'
5 +import events, { OnOptions } from './events'
6
7 type SendListFunc<T> = (list:SendListReadable<T>) => void
8 // offer an api for a generic dynamic list. Suitable to be the result of an api.
@@ -108,8 +108,8 @@ export class SendListReadable<T> extends Readable {
108 this.processBuffer.flush()
109 this.push(null)
110 }
111 - events(ctx: Context, eventMap: Parameters<typeof events.multi>[0]) {
112 - ctx.res.once('close', events.multi(eventMap))
111 + events(ctx: Context, eventMap: Parameters<typeof events.multi>[0], options?: OnOptions) {
112 + ctx.res.once('close', events.multi(eventMap, options))
113 return this
114 }
115 isClosed() {
src/events.ts
+5 -3
@@ -4,11 +4,13 @@ type Listener = (...args: any[]) => unknown
4 type Listeners = Set<Listener>
5 const LISTENERS_SUFFIX = '\0listeners'
6
7 +export interface OnOptions { warnAfter?: number, callNow?: boolean }
8 +
9 export class BetterEventEmitter {
10 protected listeners = new Map<string, Listeners>()
11 preventDefault = Symbol()
12 stop = this.preventDefault // legacy pre-0.54 (introduced in 0.53)
11 - on(event: string | string[], listener: Listener, { warnAfter=10, callNow=false }={}) {
13 + on(event: string | string[], listener: Listener, { warnAfter=10, callNow=false }: OnOptions={}) {
14 if (typeof event === 'string')
15 event = [event]
16 for (const e of event) {
@@ -48,8 +50,8 @@ export class BetterEventEmitter {
50 })
51 return Object.assign(off!, { then: pro.then.bind(pro) } satisfies PromiseLike<any> as typeof pro)
52 }
51 - multi(map: { [eventName: string]: Listener }) {
52 - const cbs = Object.entries(map).map(([name, cb]) => this.on(name.split(' '), cb))
53 + multi(map: { [eventName: string]: Listener }, options?: OnOptions) {
54 + const cbs = Object.entries(map).map(([name, cb]) => this.on(name.split(' '), cb, options))
55 return () => {
56 for (const cb of cbs) cb()
57 }
src/frontEndApis.ts
+1 -1
@@ -37,7 +37,7 @@ export const frontEndApis: ApiHandlers = {
37 [NOTIFICATION_PREFIX + channel](name, data) {
38 list.custom(name, data)
39 }
40 - })
40 + }, { warnAfter: 10_000 }) // we may have many clients on the same channel (eg: chat), and we don't want to be spammed with console warnings
41 },
42
43 async get_file_details({ uris }, ctx) {