Skip to content

Commit 2415579

Browse files
committed
fix(agents-core): remove event listener wrappers correctly
1 parent 29844d6 commit 2415579

File tree

2 files changed

+62
-10
lines changed

2 files changed

+62
-10
lines changed

packages/agents-core/src/shims/shims-browser.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,45 @@ export class BrowserEventEmitter<
1616
> implements EventEmitter<EventTypes>
1717
{
1818
#target = new EventTarget();
19+
#listenerWrappers = new Map<
20+
string,
21+
Map<(...args: unknown[]) => void, EventListener>
22+
>();
1923

2024
on<K extends keyof EventTypes>(
2125
type: K,
2226
listener: (...args: EventTypes[K]) => void,
2327
) {
24-
this.#target.addEventListener(
25-
type as string,
26-
((event: CustomEvent) =>
27-
listener(...(event.detail ?? []))) as EventListener,
28-
);
28+
const eventType = type as string;
29+
let listenersForType = this.#listenerWrappers.get(eventType);
30+
if (!listenersForType) {
31+
listenersForType = new Map();
32+
this.#listenerWrappers.set(eventType, listenersForType);
33+
}
34+
let wrapper = listenersForType.get(listener);
35+
if (!wrapper) {
36+
wrapper = ((event: CustomEvent) =>
37+
listener(...(event.detail ?? []))) as EventListener;
38+
listenersForType.set(listener, wrapper);
39+
}
40+
this.#target.addEventListener(eventType, wrapper);
2941
return this;
3042
}
3143

3244
off<K extends keyof EventTypes>(
3345
type: K,
3446
listener: (...args: EventTypes[K]) => void,
3547
) {
36-
this.#target.removeEventListener(
37-
type as string,
38-
((event: CustomEvent) =>
39-
listener(...(event.detail ?? []))) as EventListener,
40-
);
48+
const eventType = type as string;
49+
const listenersForType = this.#listenerWrappers.get(eventType);
50+
const wrapper = listenersForType?.get(listener);
51+
if (wrapper) {
52+
this.#target.removeEventListener(eventType, wrapper);
53+
listenersForType?.delete(listener);
54+
if (listenersForType?.size === 0) {
55+
this.#listenerWrappers.delete(eventType);
56+
}
57+
}
4158
return this;
4259
}
4360

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { describe, expect, test } from 'vitest';
2+
3+
import { BrowserEventEmitter } from '../../src/shims/shims-browser';
4+
5+
describe('BrowserEventEmitter', () => {
6+
test('off removes previously registered listener', () => {
7+
const emitter = new BrowserEventEmitter<{ foo: [string] }>();
8+
const calls: string[] = [];
9+
10+
const handler = (value: string) => {
11+
calls.push(value);
12+
};
13+
14+
emitter.on('foo', handler);
15+
emitter.emit('foo', 'first');
16+
emitter.off('foo', handler);
17+
emitter.emit('foo', 'second');
18+
19+
expect(calls).toEqual(['first']);
20+
});
21+
22+
test('once triggers listener only once', () => {
23+
const emitter = new BrowserEventEmitter<{ foo: [string] }>();
24+
let callCount = 0;
25+
26+
emitter.once('foo', () => {
27+
callCount += 1;
28+
});
29+
30+
emitter.emit('foo', 'first');
31+
emitter.emit('foo', 'second');
32+
33+
expect(callCount).toBe(1);
34+
});
35+
});

0 commit comments

Comments
 (0)