-
Notifications
You must be signed in to change notification settings - Fork 63
feat: listeners api #2093
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: listeners api #2093
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -178,10 +178,21 @@ class EventEmitter { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Get the array of listeners for a given event; excludes once events | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param event (optional) the name of the event, or none for 'any' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param event (optional) the name of the event, array of event names, or none for 'any' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @return array of events, or null if none | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| listeners(event: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| listeners(event?: string | string[]) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (Array.isArray(event)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const allListeners: Function[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| event.forEach((eventName) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const listeners = this.listeners(eventName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (listeners) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| allListeners.push(...listeners); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return allListeners.length ? allListeners : null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+181
to
+195
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: listeners() mutates internal state and breaks once semantics. In the single-event branch (below), you push eventsOnce[event] into the persistent array returned by this.events[event], which permanently converts once listeners into persistent listeners whenever listeners() is called. This PR introduces more public usages of listeners(), increasing the likelihood of this bug surfacing. Fix by returning copies and never mutating internal arrays. Also consider de‑duping when aggregating arrays. Apply: - listeners(event?: string | string[]) {
- if (Array.isArray(event)) {
- const allListeners: Function[] = [];
- event.forEach((eventName) => {
- const listeners = this.listeners(eventName);
- if (listeners) {
- allListeners.push(...listeners);
- }
- });
- return allListeners.length ? allListeners : null;
- }
-
- if (event) {
- const listeners = this.events[event] || [];
- if (this.eventsOnce[event]) Array.prototype.push.apply(listeners, this.eventsOnce[event]);
- return listeners.length ? listeners : null;
- }
- return this.any.length ? this.any : null;
- }
+ listeners(event?: string | string[]) {
+ if (Array.isArray(event)) {
+ const set = new Set<Function>();
+ event.forEach((eventName) => {
+ const ls = this.listeners(eventName);
+ if (ls) ls.forEach((l) => set.add(l));
+ });
+ return set.size ? Array.from(set) : null;
+ }
+
+ if (event) {
+ const persistent = this.events[event] || [];
+ const once = this.eventsOnce[event] || [];
+ const combinedLen = persistent.length + once.length;
+ return combinedLen ? persistent.slice().concat(once) : null;
+ }
+ return this.any.length ? this.any.slice() : null;
+ }Note: The doc comment above still states “excludes once events”, which is inaccurate; update accordingly. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (event) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const listeners = this.events[event] || []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (this.eventsOnce[event]) Array.prototype.push.apply(listeners, this.eventsOnce[event]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Type/behavior conflict with inherited EventEmitter.listeners.
RealtimeChannel extends EventEmitter<…> which already declares listeners(eventName?: EventType): CallbackType[] | null. Adding channel.listeners overloads returning Function[] conflicts:
Options:
As a minimal typing fix if you keep the name:
Additionally, please add:
to the EventEmitter interface to reflect the new array support. Clarify in docs that RealtimeChannel.listeners() returns message subscription listeners, not channel state listeners, to prevent confusion.
To surface potential TS breakage from overload conflicts, run:
🏁 Script executed:
Length of output: 2731
Fix type conflict in RealtimeChannel.listeners overloads
RealtimeChannel.listeners overloads clash with inherited EventEmitter.listeners(eventName?: EventType): CallbackType[] | null due to incompatible return types.
As a minimal typing fix if you keep the name:
Additionally, please update EventEmitter to accept an array of event names:
messageListeners(…)(preferred) to avoid overload conflicts..listeners()returns subscription listeners, not channel-state listeners.📝 Committable suggestion
🤖 Prompt for AI Agents