Skip to content

Commit 861cf83

Browse files
feat: use EvenEmitter3 for web-sdk (#847)
<!-- Please use this template for your pull request. --> <!-- Please use the sections that you need and delete other sections --> ## This PR <!-- add the description of the PR here --> Fixes an issue where the `events` node polyfill does not comply to the `node:events` types. When trying to use the web OpenFeatureEventEmitter the following error message comes up, describing that the `events` polyfill's EventEmitter is incompatible to `node:events` EventEmitter. ``` ✘ [ERROR] TS2416: Property 'eventEmitter' in type 'OpenFeatureEventEmitter' is not assignable to the same property in base type 'GenericEventEmitter<ProviderEmittableEvents, Record<string, unknown>>'. Type 'EventEmitter' is not assignable to type 'PlatformEventEmitter'. Types of property 'addListener' are incompatible. Type '(type: string | number, listener: Listener) => EventEmitter' is not assignable to type '(eventName: string | symbol, listener: (...args: any[]) => void) => PlatformEventEmitter'. Types of parameters 'type' and 'eventName' are incompatible. Type 'string | symbol' is not assignable to type 'string | number'. Type 'symbol' is not assignable to type 'string | number'. ``` This PR fixes that issue by not using the `events` anymore and instead using https://www.npmjs.com/package/eventemitter3 cc @toddbaert ### Related Issues <!-- add here the GitHub issue that this PR resolves if applicable --> Fixes #845 --------- Signed-off-by: Lukas Reining <[email protected]> Signed-off-by: Todd Baert <[email protected]> Co-authored-by: Todd Baert <[email protected]>
1 parent 1461074 commit 861cf83

File tree

4 files changed

+27
-38
lines changed

4 files changed

+27
-38
lines changed

package-lock.json

Lines changed: 10 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
},
3838
"devDependencies": {
3939
"@rollup/plugin-typescript": "^11.1.6",
40-
"@types/events": "^3.0.3",
4140
"@types/jest": "^29.5.12",
4241
"@types/node": "^20.11.16",
4342
"@types/react": "^18.2.55",
@@ -51,7 +50,7 @@
5150
"eslint-plugin-import": "^2.29.1",
5251
"eslint-plugin-jest": "^27.6.3",
5352
"eslint-plugin-jsdoc": "^48.0.6",
54-
"events": "^3.3.0",
53+
"eventemitter3": "^5.0.1",
5554
"jest": "^29.7.0",
5655
"jest-config": "^29.7.0",
5756
"jest-cucumber": "^3.0.1",
@@ -76,4 +75,4 @@
7675
"packages/react",
7776
"packages/nest"
7877
]
79-
}
78+
}
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { GenericEventEmitter } from '@openfeature/core';
2-
import { EventEmitter } from 'events';
2+
import { EventEmitter } from 'eventemitter3';
33
import { ProviderEmittableEvents } from './events';
4+
45
/**
56
* The OpenFeatureEventEmitter can be used by provider developers to emit
67
* events at various parts of the provider lifecycle.
@@ -9,12 +10,9 @@ import { ProviderEmittableEvents } from './events';
910
* the result of the initialize method.
1011
*/
1112
export class OpenFeatureEventEmitter extends GenericEventEmitter<ProviderEmittableEvents> {
12-
protected readonly eventEmitter = new EventEmitter({ captureRejections: true });
13+
protected readonly eventEmitter = new EventEmitter();
1314

1415
constructor() {
1516
super();
16-
this.eventEmitter.on('error', (err) => {
17-
this._logger?.error('Error running event handler:', err);
18-
});
1917
}
2018
}

packages/shared/src/events/generic-event-emitter.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ import { AllProviderEvents, AnyProviderEvent } from './events';
77
* The GenericEventEmitter should only be used within the SDK. It supports additional properties that can be included
88
* in the event details.
99
*/
10-
export abstract class GenericEventEmitter<E extends AnyProviderEvent, AdditionalContext extends Record<string, unknown> = Record<string, unknown>>
10+
export abstract class GenericEventEmitter<
11+
E extends AnyProviderEvent,
12+
AdditionalContext extends Record<string, unknown> = Record<string, unknown>,
13+
>
1114
implements ProviderEventEmitter<E>, ManageLogger<GenericEventEmitter<E, AdditionalContext>>
1215
{
1316
protected abstract readonly eventEmitter: PlatformEventEmitter;
1417

15-
private readonly _handlers: { [key in AnyProviderEvent]: WeakMap<EventHandler, EventHandler[]>} = {
18+
private readonly _handlers: { [key in AnyProviderEvent]: WeakMap<EventHandler, EventHandler[]> } = {
1619
[AllProviderEvents.ConfigurationChanged]: new WeakMap<EventHandler, EventHandler[]>(),
1720
[AllProviderEvents.ContextChanged]: new WeakMap<EventHandler, EventHandler[]>(),
1821
[AllProviderEvents.Ready]: new WeakMap<EventHandler, EventHandler[]>(),
@@ -33,7 +36,11 @@ export abstract class GenericEventEmitter<E extends AnyProviderEvent, Additional
3336
// The handlers have to be wrapped with an async function because if a synchronous functions throws an error,
3437
// the other handlers will not run.
3538
const asyncHandler = async (details?: EventDetails) => {
36-
await handler(details);
39+
try {
40+
await handler(details);
41+
} catch (err) {
42+
this._logger?.error('Error running event handler:', err);
43+
}
3744
};
3845
// The async handler has to be written to the map, because we need to get the wrapper function when deleting a listener
3946
const existingAsyncHandlers = this._handlers[eventType].get(handler);
@@ -84,7 +91,7 @@ export abstract class GenericEventEmitter<E extends AnyProviderEvent, Additional
8491
* This is an un-exported type that corresponds to NodeJS.EventEmitter.
8592
* We can't use that type here, because this module is used in both the browser, and the server.
8693
* In the server, node (or whatever server runtime) provides an implementation for this.
87-
* In the browser, we bundle in the popular 'events' package, which is a polyfill of NodeJS.EventEmitter.
94+
* In the browser, we bundle in the popular 'EventEmitter3' package, which is a polyfill of NodeJS.EventEmitter.
8895
*/
8996
/* eslint-disable */
9097
interface PlatformEventEmitter {
@@ -94,13 +101,8 @@ interface PlatformEventEmitter {
94101
removeListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
95102
off(eventName: string | symbol, listener: (...args: any[]) => void): this;
96103
removeAllListeners(event?: string | symbol): this;
97-
setMaxListeners(n: number): this;
98-
getMaxListeners(): number;
99104
listeners(eventName: string | symbol): Function[];
100-
rawListeners(eventName: string | symbol): Function[];
101105
emit(eventName: string | symbol, ...args: any[]): boolean;
102106
listenerCount(eventName: string | symbol, listener?: Function): number;
103-
prependListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
104-
prependOnceListener(eventName: string | symbol, listener: (...args: any[]) => void): this;
105107
eventNames(): Array<string | symbol>;
106-
}
108+
}

0 commit comments

Comments
 (0)