Skip to content

Commit 303986c

Browse files
committed
fix: removes exports of OpenFeatureClient class and makes event properties readonly
Signed-off-by: Lukas Reining <[email protected]>
1 parent 86a9230 commit 303986c

File tree

9 files changed

+60
-48
lines changed

9 files changed

+60
-48
lines changed

packages/client/src/client/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
export * from './client';
2-
export * from './open-feature-client';

packages/client/src/open-feature.ts

+13-7
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import {
88
objectOrUndefined,
99
stringOrUndefined,
1010
} from '@openfeature/core';
11-
import { Client, OpenFeatureClient } from './client';
11+
import { Client } from './client';
1212
import { OpenFeatureEventEmitter, ProviderEvents } from './events';
1313
import { Hook } from './hooks';
1414
import { NOOP_PROVIDER, Provider, ProviderStatus } from './provider';
15+
import { OpenFeatureClient } from './client/open-feature-client';
1516

1617
// use a symbol as a key for the global singleton
1718
const GLOBAL_OPENFEATURE_API_KEY = Symbol.for('@openfeature/web-sdk/api');
@@ -26,10 +27,17 @@ type DomainRecord = {
2627

2728
const _globalThis = globalThis as OpenFeatureGlobal;
2829

29-
export class OpenFeatureAPI extends OpenFeatureCommonAPI<ClientProviderStatus, Provider, Hook> implements ManageContext<Promise<void>> {
30+
export class OpenFeatureAPI
31+
extends OpenFeatureCommonAPI<ClientProviderStatus, Provider, Hook>
32+
implements ManageContext<Promise<void>>
33+
{
3034
protected _statusEnumType: typeof ProviderStatus = ProviderStatus;
3135
protected _apiEmitter: GenericEventEmitter<ProviderEvents> = new OpenFeatureEventEmitter();
32-
protected _defaultProvider: ProviderWrapper<Provider, ClientProviderStatus> = new ProviderWrapper(NOOP_PROVIDER, ProviderStatus.NOT_READY, this._statusEnumType);
36+
protected _defaultProvider: ProviderWrapper<Provider, ClientProviderStatus> = new ProviderWrapper(
37+
NOOP_PROVIDER,
38+
ProviderStatus.NOT_READY,
39+
this._statusEnumType,
40+
);
3341
protected _domainScopedProviders: Map<string, ProviderWrapper<Provider, ClientProviderStatus>> = new Map();
3442
protected _createEventEmitter = () => new OpenFeatureEventEmitter();
3543

@@ -111,9 +119,7 @@ export class OpenFeatureAPI extends OpenFeatureCommonAPI<ClientProviderStatus, P
111119
...unboundProviders,
112120
];
113121
await Promise.all(
114-
allDomainRecords.map((dm) =>
115-
this.runProviderContextChangeHandler(dm.domain, dm.wrapper, oldContext, context),
116-
),
122+
allDomainRecords.map((dm) => this.runProviderContextChangeHandler(dm.domain, dm.wrapper, oldContext, context)),
117123
);
118124
}
119125
}
@@ -222,7 +228,7 @@ export class OpenFeatureAPI extends OpenFeatureCommonAPI<ClientProviderStatus, P
222228
): Promise<void> {
223229
// this should always be set according to the typings, but let's be defensive considering JS
224230
const providerName = wrapper.provider?.metadata?.name || 'unnamed-provider';
225-
231+
226232
try {
227233
if (typeof wrapper.provider.onContextChange === 'function') {
228234
wrapper.incrementPendingContextChanges();

packages/client/test/client.spec.ts

+22-22
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ import {
88
JsonObject,
99
JsonValue,
1010
OpenFeature,
11-
OpenFeatureClient,
1211
Provider,
1312
ProviderFatalError,
1413
ProviderStatus,
1514
ResolutionDetails,
1615
StandardResolutionReasons,
1716
} from '../src';
17+
import { OpenFeatureClient } from '../src/client/open-feature-client';
1818

1919
const BOOLEAN_VALUE = true;
2020
const STRING_VALUE = 'val';
@@ -382,7 +382,7 @@ describe('OpenFeatureClient', () => {
382382
// No generic information exists at runtime, but this test has some value in ensuring the generic args still exist in the typings.
383383
const client = OpenFeature.getClient();
384384
const details: ResolutionDetails<JsonValue> = client.getObjectDetails('flag', { key: 'value' });
385-
385+
386386
expect(details).toBeDefined();
387387
});
388388
});
@@ -464,45 +464,45 @@ describe('OpenFeatureClient', () => {
464464
expect(details.errorCode).toEqual(ErrorCode.PROVIDER_NOT_READY);
465465
});
466466
});
467-
467+
468468
describe('Evaluation details structure', () => {
469469
const flagKey = 'number-details';
470470
const defaultValue = 1970;
471471
let details: EvaluationDetails<number>;
472-
472+
473473
describe('Normal execution', () => {
474474
beforeEach(() => {
475475
const client = OpenFeature.getClient();
476476
details = client.getNumberDetails(flagKey, defaultValue);
477-
477+
478478
expect(details).toBeDefined();
479479
});
480-
480+
481481
describe('Requirement 1.4.2, 1.4.3', () => {
482482
it('should contain flag value', () => {
483483
expect(details.value).toEqual(NUMBER_VALUE);
484484
});
485485
});
486-
486+
487487
describe('Requirement 1.4.4', () => {
488488
it('should contain flag key', () => {
489489
expect(details.flagKey).toEqual(flagKey);
490490
});
491491
});
492-
492+
493493
describe('Requirement 1.4.5', () => {
494494
it('should contain flag variant', () => {
495495
expect(details.variant).toEqual(NUMBER_VARIANT);
496496
});
497497
});
498-
498+
499499
describe('Requirement 1.4.6', () => {
500500
it('should contain reason', () => {
501501
expect(details.reason).toEqual(REASON);
502502
});
503503
});
504504
});
505-
505+
506506
describe('Abnormal execution', () => {
507507
const NON_OPEN_FEATURE_ERROR_MESSAGE = 'A null dereference or something, I dunno.';
508508
const OPEN_FEATURE_ERROR_MESSAGE = "This ain't the flag you're looking for.";
@@ -522,68 +522,68 @@ describe('OpenFeatureClient', () => {
522522
} as unknown as Provider;
523523
const defaultNumberValue = 123;
524524
const defaultStringValue = 'hey!';
525-
525+
526526
beforeEach(() => {
527527
OpenFeature.setProvider(errorProvider);
528528
client = OpenFeature.getClient();
529529
nonOpenFeatureErrorDetails = client.getNumberDetails('some-flag', defaultNumberValue);
530530
openFeatureErrorDetails = client.getStringDetails('some-flag', defaultStringValue);
531531
});
532-
532+
533533
describe('Requirement 1.4.7', () => {
534534
describe('OpenFeatureError', () => {
535535
it('should contain error code', () => {
536536
expect(openFeatureErrorDetails.errorCode).toBeTruthy();
537537
expect(openFeatureErrorDetails.errorCode).toEqual(ErrorCode.FLAG_NOT_FOUND); // should get code from thrown OpenFeatureError
538538
});
539539
});
540-
540+
541541
describe('Non-OpenFeatureError', () => {
542542
it('should contain error code', () => {
543543
expect(nonOpenFeatureErrorDetails.errorCode).toBeTruthy();
544544
expect(nonOpenFeatureErrorDetails.errorCode).toEqual(ErrorCode.GENERAL); // should fall back to GENERAL
545545
});
546546
});
547547
});
548-
548+
549549
describe('Requirement 1.4.8', () => {
550550
it('should contain error reason', () => {
551551
expect(nonOpenFeatureErrorDetails.reason).toEqual(StandardResolutionReasons.ERROR);
552552
expect(openFeatureErrorDetails.reason).toEqual(StandardResolutionReasons.ERROR);
553553
});
554554
});
555-
555+
556556
describe('Requirement 1.4.9', () => {
557557
it('must not throw, must return default', () => {
558558
nonOpenFeatureErrorDetails = client.getNumberDetails('some-flag', defaultNumberValue);
559-
559+
560560
expect(nonOpenFeatureErrorDetails).toBeTruthy();
561561
expect(nonOpenFeatureErrorDetails.value).toEqual(defaultNumberValue);
562562
});
563563
});
564-
564+
565565
describe('Requirement 1.4.12', () => {
566566
describe('OpenFeatureError', () => {
567567
it('should contain "error" message', () => {
568568
expect(openFeatureErrorDetails.errorMessage).toEqual(OPEN_FEATURE_ERROR_MESSAGE);
569569
});
570570
});
571-
571+
572572
describe('Non-OpenFeatureError', () => {
573573
it('should contain "error" message', () => {
574574
expect(nonOpenFeatureErrorDetails.errorMessage).toEqual(NON_OPEN_FEATURE_ERROR_MESSAGE);
575575
});
576576
});
577577
});
578578
});
579-
579+
580580
describe('Requirement 1.4.13, Requirement 1.4.14', () => {
581581
it('should return immutable `flag metadata` as defined by the provider', () => {
582582
const flagMetadata = {
583583
url: 'https://test.dev',
584584
version: '1',
585585
};
586-
586+
587587
const flagMetadataProvider = {
588588
metadata: {
589589
name: 'flag-metadata',
@@ -595,14 +595,14 @@ describe('OpenFeatureClient', () => {
595595
};
596596
}),
597597
} as unknown as Provider;
598-
598+
599599
OpenFeature.setProvider(flagMetadataProvider);
600600
const client = OpenFeature.getClient();
601601
const response = client.getBooleanDetails('some-flag', false);
602602
expect(response.flagMetadata).toBe(flagMetadata);
603603
expect(Object.isFrozen(response.flagMetadata)).toBeTruthy();
604604
});
605-
605+
606606
it('should return empty `flag metadata` because it was not set by the provider', () => {
607607
// The mock provider doesn't contain flag metadata
608608
OpenFeature.setProvider(MOCK_PROVIDER);

packages/client/test/open-feature.spec.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Paradigm } from '@openfeature/core';
2-
import { OpenFeature, OpenFeatureAPI, OpenFeatureClient, Provider, ProviderStatus } from '../src';
2+
import { OpenFeature, OpenFeatureAPI, Provider, ProviderStatus } from '../src';
3+
import { OpenFeatureClient } from '../src/client/open-feature-client';
34

45
const mockProvider = (config?: { initialStatus?: ProviderStatus; runsOn?: Paradigm }) => {
56
return {

packages/nest/test/open-feature.module.spec.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Test, TestingModule } from '@nestjs/testing';
22
import { getOpenFeatureClientToken, OpenFeatureModule, ServerProviderEvents } from '../src';
3-
import { OpenFeature, OpenFeatureClient } from '@openfeature/server-sdk';
3+
import { Client, OpenFeature } from '@openfeature/server-sdk';
44
import { getOpenFeatureDefaultTestModule } from './fixtures';
55

66
describe('OpenFeatureModule', () => {
@@ -31,19 +31,19 @@ describe('OpenFeatureModule', () => {
3131

3232
it('should return the SDKs default provider and not throw', async () => {
3333
expect(() => {
34-
moduleWithoutProvidersRef.get<OpenFeatureClient>(getOpenFeatureClientToken());
34+
moduleWithoutProvidersRef.get<Client>(getOpenFeatureClientToken());
3535
}).not.toThrow();
3636
});
3737
});
3838

3939
it('should return the default provider', async () => {
40-
const client = moduleRef.get<OpenFeatureClient>(getOpenFeatureClientToken());
40+
const client = moduleRef.get<Client>(getOpenFeatureClientToken());
4141
expect(client).toBeDefined();
4242
expect(await client.getStringValue('testStringFlag', '')).toEqual('expected-string-value-default');
4343
});
4444

4545
it('should inject the client with the given scope', async () => {
46-
const client = moduleRef.get<OpenFeatureClient>(getOpenFeatureClientToken('domainScopedClient'));
46+
const client = moduleRef.get<Client>(getOpenFeatureClientToken('domainScopedClient'));
4747
expect(client).toBeDefined();
4848
expect(await client.getStringValue('testStringFlag', '')).toEqual('expected-string-value-scoped');
4949
});

packages/nest/test/test-app.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { Controller, Get, Injectable, UseInterceptors } from '@nestjs/common';
22
import { Observable, map } from 'rxjs';
33
import { BooleanFeatureFlag, ObjectFeatureFlag, NumberFeatureFlag, FeatureClient, StringFeatureFlag } from '../src';
4-
import { OpenFeatureClient, EvaluationDetails, FlagValue } from '@openfeature/server-sdk';
4+
import { Client, EvaluationDetails, FlagValue } from '@openfeature/server-sdk';
55
import { EvaluationContextInterceptor } from '../src';
66

77
@Injectable()
88
export class OpenFeatureTestService {
99
constructor(
10-
@FeatureClient() public defaultClient: OpenFeatureClient,
11-
@FeatureClient({ domain: 'domainScopedClient' }) public domainScopedClient: OpenFeatureClient,
10+
@FeatureClient() public defaultClient: Client,
11+
@FeatureClient({ domain: 'domainScopedClient' }) public domainScopedClient: Client,
1212
) {}
1313

1414
public async serviceMethod(flag: EvaluationDetails<FlagValue>) {

packages/server/src/client/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
export * from './client';
2-
export * from './open-feature-client';

packages/server/src/open-feature.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
objectOrUndefined,
77
stringOrUndefined,
88
} from '@openfeature/core';
9-
import { Client, OpenFeatureClient } from './client';
9+
import { Client } from './client';
1010
import { OpenFeatureEventEmitter } from './events';
1111
import { Hook } from './hooks';
1212
import { NOOP_PROVIDER, Provider, ProviderStatus } from './provider';
@@ -17,6 +17,7 @@ import {
1717
TransactionContextPropagator,
1818
} from './transaction-context';
1919
import { ServerProviderStatus } from '@openfeature/core';
20+
import { OpenFeatureClient } from './client/open-feature-client';
2021

2122
// use a symbol as a key for the global singleton
2223
const GLOBAL_OPENFEATURE_API_KEY = Symbol.for('@openfeature/js-sdk/api');
@@ -28,11 +29,17 @@ const _globalThis = globalThis as OpenFeatureGlobal;
2829

2930
export class OpenFeatureAPI
3031
extends OpenFeatureCommonAPI<ServerProviderStatus, Provider, Hook>
31-
implements ManageContext<OpenFeatureAPI>, ManageTransactionContextPropagator<OpenFeatureCommonAPI<ServerProviderStatus, Provider>>
32+
implements
33+
ManageContext<OpenFeatureAPI>,
34+
ManageTransactionContextPropagator<OpenFeatureCommonAPI<ServerProviderStatus, Provider>>
3235
{
3336
protected _statusEnumType: typeof ProviderStatus = ProviderStatus;
3437
protected _apiEmitter = new OpenFeatureEventEmitter();
35-
protected _defaultProvider: ProviderWrapper<Provider, ServerProviderStatus> = new ProviderWrapper(NOOP_PROVIDER, ProviderStatus.NOT_READY, this._statusEnumType);
38+
protected _defaultProvider: ProviderWrapper<Provider, ServerProviderStatus> = new ProviderWrapper(
39+
NOOP_PROVIDER,
40+
ProviderStatus.NOT_READY,
41+
this._statusEnumType,
42+
);
3643
protected _domainScopedProviders: Map<string, ProviderWrapper<Provider, ServerProviderStatus>> = new Map();
3744
protected _createEventEmitter = () => new OpenFeatureEventEmitter();
3845

packages/shared/src/events/eventing.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,24 @@ export type EventMetadata = {
66
};
77

88
export type CommonEventDetails = {
9-
providerName: string;
9+
readonly providerName: string;
1010
/**
1111
* @deprecated alias of "domain", use domain instead
1212
*/
13-
clientName?: string;
13+
readonly clientName?: string;
1414
readonly domain?: string;
1515
};
1616

1717
type CommonEventProps = {
18-
message?: string;
19-
metadata?: EventMetadata;
18+
readonly message?: string;
19+
readonly metadata?: EventMetadata;
2020
};
2121

2222
export type ReadyEvent = CommonEventProps;
2323
export type ErrorEvent = CommonEventProps;
2424
export type StaleEvent = CommonEventProps;
25-
export type ReconcilingEvent = CommonEventProps & { errorCode: ErrorCode };
26-
export type ConfigChangeEvent = CommonEventProps & { flagsChanged?: string[] };
25+
export type ReconcilingEvent = CommonEventProps & { readonly errorCode: ErrorCode };
26+
export type ConfigChangeEvent = CommonEventProps & { readonly flagsChanged?: string[] };
2727

2828
type ServerEventMap = {
2929
[ServerProviderEvents.Ready]: ReadyEvent;

0 commit comments

Comments
 (0)