From 766c3b86ca2052b23c53a36f04109bb30f2c3cdd Mon Sep 17 00:00:00 2001
From: Robert Nagy <ronagy@icloud.com>
Date: Tue, 25 Jun 2024 09:33:27 +0200
Subject: [PATCH 1/4] fix: forward dispatch return value

---
 lib/dispatcher/dispatcher.js | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/lib/dispatcher/dispatcher.js b/lib/dispatcher/dispatcher.js
index b1e0098ec4b..9ce5c20b780 100644
--- a/lib/dispatcher/dispatcher.js
+++ b/lib/dispatcher/dispatcher.js
@@ -39,18 +39,35 @@ class Dispatcher extends EventEmitter {
   }
 }
 
+const kOnDrain = Symbol('onDrain')
+const kOnConnect = Symbol('onConnect')
+const kOnDisconnect = Symbol('onDisconnect')
+const kOnConnectionError = Symbol('onConnectionError')
+
 class ComposedDispatcher extends Dispatcher {
-  #dispatcher = null
-  #dispatch = null
+  #dispatcher
+  #dispatch
 
   constructor (dispatcher, dispatch) {
     super()
+
     this.#dispatcher = dispatcher
     this.#dispatch = dispatch
+
+    this[kOnDrain] = (...args) => this.emit('drain', ...args)
+    this[kOnConnect] = (...args) => this.emit('connect', ...args)
+    this[kOnDisconnect] = (...args) => this.emit('disconnect', ...args)
+    this[kOnConnectionError] = (...args) => this.emit('connectionError', ...args)
+
+    this.#dispatcher
+      .on('drain', this[kOnDrain])
+      .on('connect', this[kOnConnect])
+      .on('disconnect', this[kOnDisconnect])
+      .on('connectionError', this[kOnConnectionError])
   }
 
   dispatch (...args) {
-    this.#dispatch(...args)
+    return this.#dispatch(...args)
   }
 
   close (...args) {

From 8844ee6cb81da2ea2e7f1d99e314c84fd2aaf65a Mon Sep 17 00:00:00 2001
From: Robert Nagy <ronagy@icloud.com>
Date: Tue, 25 Jun 2024 20:28:57 +0200
Subject: [PATCH 2/4] fixup

---
 lib/dispatcher/dispatcher.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/dispatcher/dispatcher.js b/lib/dispatcher/dispatcher.js
index 9ce5c20b780..4f23e6e3485 100644
--- a/lib/dispatcher/dispatcher.js
+++ b/lib/dispatcher/dispatcher.js
@@ -59,6 +59,7 @@ class ComposedDispatcher extends Dispatcher {
     this[kOnDisconnect] = (...args) => this.emit('disconnect', ...args)
     this[kOnConnectionError] = (...args) => this.emit('connectionError', ...args)
 
+    // TODO (fix): These must be weak references...
     this.#dispatcher
       .on('drain', this[kOnDrain])
       .on('connect', this[kOnConnect])

From 67de8922e628f7611b1dc2361528d6a0142e2356 Mon Sep 17 00:00:00 2001
From: Robert Nagy <ronagy@icloud.com>
Date: Tue, 25 Jun 2024 20:40:55 +0200
Subject: [PATCH 3/4] fixuP

---
 lib/dispatcher/dispatcher.js | 32 +++++++++++++++++---------------
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/lib/dispatcher/dispatcher.js b/lib/dispatcher/dispatcher.js
index 4f23e6e3485..d7e2956ccfc 100644
--- a/lib/dispatcher/dispatcher.js
+++ b/lib/dispatcher/dispatcher.js
@@ -39,10 +39,11 @@ class Dispatcher extends EventEmitter {
   }
 }
 
-const kOnDrain = Symbol('onDrain')
-const kOnConnect = Symbol('onConnect')
-const kOnDisconnect = Symbol('onDisconnect')
-const kOnConnectionError = Symbol('onConnectionError')
+const registry = new FinalizationRegistry(({ dispatcher, handlers }) => {
+  for (const [event, listener] of handlers) {
+    dispatcher.off(event, listener)
+  }
+})
 
 class ComposedDispatcher extends Dispatcher {
   #dispatcher
@@ -54,17 +55,18 @@ class ComposedDispatcher extends Dispatcher {
     this.#dispatcher = dispatcher
     this.#dispatch = dispatch
 
-    this[kOnDrain] = (...args) => this.emit('drain', ...args)
-    this[kOnConnect] = (...args) => this.emit('connect', ...args)
-    this[kOnDisconnect] = (...args) => this.emit('disconnect', ...args)
-    this[kOnConnectionError] = (...args) => this.emit('connectionError', ...args)
-
-    // TODO (fix): These must be weak references...
-    this.#dispatcher
-      .on('drain', this[kOnDrain])
-      .on('connect', this[kOnConnect])
-      .on('disconnect', this[kOnDisconnect])
-      .on('connectionError', this[kOnConnectionError])
+    const weakThis = new WeakRef(this)
+    const handlers = []
+
+    for (const event of ['drain', 'connect', 'disconnect', 'connectionError']) {
+      const listener = function (...args) {
+        weakThis.deref()?.emit(event, ...args)
+      }
+      handlers.push([event, listener])
+      dispatcher.on(event, listener)
+    }
+
+    registry.register(this, { dispatcher, handlers })
   }
 
   dispatch (...args) {

From 194c37a598f597c622ce55cce73583d51b316a46 Mon Sep 17 00:00:00 2001
From: Robert Nagy <ronagy@icloud.com>
Date: Wed, 26 Jun 2024 07:33:37 +0200
Subject: [PATCH 4/4] fixup: use Proxy

---
 lib/dispatcher/dispatcher.js | 47 +++---------------------------------
 test/dispatcher.js           |  5 +---
 2 files changed, 4 insertions(+), 48 deletions(-)

diff --git a/lib/dispatcher/dispatcher.js b/lib/dispatcher/dispatcher.js
index d7e2956ccfc..ecff2a9b168 100644
--- a/lib/dispatcher/dispatcher.js
+++ b/lib/dispatcher/dispatcher.js
@@ -35,50 +35,9 @@ class Dispatcher extends EventEmitter {
       }
     }
 
-    return new ComposedDispatcher(this, dispatch)
-  }
-}
-
-const registry = new FinalizationRegistry(({ dispatcher, handlers }) => {
-  for (const [event, listener] of handlers) {
-    dispatcher.off(event, listener)
-  }
-})
-
-class ComposedDispatcher extends Dispatcher {
-  #dispatcher
-  #dispatch
-
-  constructor (dispatcher, dispatch) {
-    super()
-
-    this.#dispatcher = dispatcher
-    this.#dispatch = dispatch
-
-    const weakThis = new WeakRef(this)
-    const handlers = []
-
-    for (const event of ['drain', 'connect', 'disconnect', 'connectionError']) {
-      const listener = function (...args) {
-        weakThis.deref()?.emit(event, ...args)
-      }
-      handlers.push([event, listener])
-      dispatcher.on(event, listener)
-    }
-
-    registry.register(this, { dispatcher, handlers })
-  }
-
-  dispatch (...args) {
-    return this.#dispatch(...args)
-  }
-
-  close (...args) {
-    return this.#dispatcher.close(...args)
-  }
-
-  destroy (...args) {
-    return this.#dispatcher.destroy(...args)
+    return new Proxy(this, {
+      get: (target, key) => key === 'dispatch' ? dispatch : target[key]
+    })
   }
 }
 
diff --git a/test/dispatcher.js b/test/dispatcher.js
index 1febdf53b4b..fbb56e94bc1 100644
--- a/test/dispatcher.js
+++ b/test/dispatcher.js
@@ -22,14 +22,11 @@ test('dispatcher implementation', (t) => {
 })
 
 test('dispatcher.compose', (t) => {
-  t = tspl(t, { plan: 10 })
+  t = tspl(t, { plan: 7 })
 
   const dispatcher = new Dispatcher()
   const interceptor = () => (opts, handler) => {}
   // Should return a new dispatcher
-  t.ok(Object.getPrototypeOf(dispatcher.compose(interceptor)) instanceof Dispatcher)
-  t.ok(Object.getPrototypeOf(dispatcher.compose(interceptor, interceptor)) instanceof Dispatcher)
-  t.ok(Object.getPrototypeOf(dispatcher.compose([interceptor, interceptor])) instanceof Dispatcher)
   t.ok(dispatcher.compose(interceptor) !== dispatcher)
   t.throws(() => dispatcher.dispatch({}), Error, 'invalid interceptor')
   t.throws(() => dispatcher.dispatch(() => null), Error, 'invalid interceptor')