Skip to content

Commit f0e2aa6

Browse files
authored
fix: missing events bundled dep (#660)
Fixes: #659 This PR fixes an issue created with [this change](#650), which removed the `events` polyfill package from `@openfeature/core` where is wasn't always needed (see that issue for details). The problem was that we still imported `events` in the `@openfeature/core` module, but can't use the `events` bundled in the `@openfeature/web-sdk` since the bundled package there isn't accessible from imports in `@openfeature/core`. This PR _**removes all imports of `events`**_ from `@openfeature/core`, and instead only imports types. Imports of `events` only now occur in the web-sdk (where it's bundled) and server-sdk (where it's made available by the node runtime), not in the common module. Unfortunately this issue was a bit tough to track down, because `events` is VERY common, and lots of bundlers, etc will add it, so it's frequently available "accidentally". Thanks to @juanparadox for the report. --------- Signed-off-by: Todd Baert <[email protected]>
1 parent d9b922b commit f0e2aa6

23 files changed

+144
-72
lines changed

packages/client/src/client/open-feature-client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
JsonValue,
1212
Logger,
1313
OpenFeatureError,
14-
OpenFeatureEventEmitter,
1514
ProviderEvents,
1615
ProviderStatus,
1716
ResolutionDetails,
@@ -21,6 +20,7 @@ import {
2120
import { FlagEvaluationOptions } from '../evaluation';
2221
import { OpenFeature } from '../open-feature';
2322
import { Provider } from '../provider';
23+
import { InternalEventEmitter } from '../events/internal/internal-event-emitter';
2424
import { Client } from './client';
2525

2626
type OpenFeatureClientOptions = {
@@ -36,7 +36,7 @@ export class OpenFeatureClient implements Client {
3636
// functions are passed here to make sure that these values are always up to date,
3737
// and so we don't have to make these public properties on the API class.
3838
private readonly providerAccessor: () => Provider,
39-
private readonly emitterAccessor: () => OpenFeatureEventEmitter,
39+
private readonly emitterAccessor: () => InternalEventEmitter,
4040
private readonly globalLogger: () => Logger,
4141
private readonly options: OpenFeatureClientOptions
4242
) {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './open-feature-event-emitter';
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { CommonEventDetails, GenericEventEmitter } from '@openfeature/core';
2+
3+
/**
4+
* The InternalEventEmitter is not exported publicly and should only be used within the SDK. It extends the
5+
* OpenFeatureEventEmitter to include additional properties that can be included
6+
* in the event details.
7+
*/
8+
export abstract class InternalEventEmitter extends GenericEventEmitter<CommonEventDetails> {};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { GenericEventEmitter } from '@openfeature/core';
2+
import EventEmitter from 'events';
3+
4+
/**
5+
* The OpenFeatureEventEmitter can be used by provider developers to emit
6+
* events at various parts of the provider lifecycle.
7+
*
8+
* NOTE: Ready and error events are automatically emitted by the SDK based on
9+
* the result of the initialize method.
10+
*/
11+
export class OpenFeatureEventEmitter extends GenericEventEmitter {
12+
protected readonly eventEmitter = new EventEmitter({ captureRejections: true });
13+
14+
constructor() {
15+
super();
16+
this.eventEmitter.on('error', (err) => {
17+
this._logger?.error('Error running event handler:', err);
18+
});
19+
}
20+
}

packages/client/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import 'events'; // we need this to trigger the bundling of the browser events module: https://www.npmjs.com/package/events
21
export * from './client';
32
export * from './provider';
43
export * from './evaluation';
54
export * from './open-feature';
5+
export * from './events';
66
export * from '@openfeature/core';

packages/client/src/open-feature.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { EvaluationContext, ManageContext, OpenFeatureCommonAPI } from '@openfeature/core';
22
import { Client, OpenFeatureClient } from './client';
33
import { NOOP_PROVIDER, Provider } from './provider';
4+
import { OpenFeatureEventEmitter } from './events';
45

56
// use a symbol as a key for the global singleton
67
const GLOBAL_OPENFEATURE_API_KEY = Symbol.for('@openfeature/web-sdk/api');
@@ -11,7 +12,9 @@ type OpenFeatureGlobal = {
1112
const _globalThis = globalThis as OpenFeatureGlobal;
1213

1314
export class OpenFeatureAPI extends OpenFeatureCommonAPI<Provider> implements ManageContext<Promise<void>> {
15+
protected _events = new OpenFeatureEventEmitter();
1416
protected _defaultProvider: Provider = NOOP_PROVIDER;
17+
protected _createEventEmitter = () => new OpenFeatureEventEmitter();
1518

1619
// eslint-disable-next-line @typescript-eslint/no-empty-function
1720
private constructor() {

packages/client/test/events.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
ProviderMetadata,
1010
ProviderStatus,
1111
ResolutionDetails,
12-
StaleEvent,
12+
StaleEvent
1313
} from '../src';
1414

1515
const TIMEOUT = 1000;

packages/client/tsconfig.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
// "rootDir": "./", /* Specify the root folder within your source files. */
2929
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
3030
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
31-
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
31+
"paths": {
32+
"@openfeature/core": [ "../shared/src" ]
33+
}, /* Specify a set of entries that re-map imports to additional lookup locations. */
3234
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
3335
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
3436
// "types": [], /* Specify type package names to be included without being referenced in a source file. */

packages/server/src/client/open-feature-client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
FlagValueType,
99
Hook,
1010
HookContext,
11-
InternalEventEmitter,
1211
JsonValue,
1312
Logger,
1413
ManageContext,
@@ -23,6 +22,7 @@ import { FlagEvaluationOptions } from '../evaluation';
2322
import { OpenFeature } from '../open-feature';
2423
import { Provider } from '../provider';
2524
import { Client } from './client';
25+
import { InternalEventEmitter } from '../events/internal/internal-event-emitter';
2626

2727
type OpenFeatureClientOptions = {
2828
name?: string;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './open-feature-event-emitter';

0 commit comments

Comments
 (0)