Skip to content

Commit 5f3ea1c

Browse files
committed
Run validateContext during any context change
1 parent 6990b63 commit 5f3ea1c

File tree

1 file changed

+34
-3
lines changed

1 file changed

+34
-3
lines changed

packages/web/src/open-feature.ts

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ export class OpenFeatureAPI
5353
);
5454
protected _domainScopedProviders: Map<string, ProviderWrapper<Provider, ClientProviderStatus>> = new Map();
5555
protected _createEventEmitter = () => new OpenFeatureEventEmitter();
56+
protected _defaultOptions: ProviderOptions = {};
57+
protected _domainScopedOptions: Map<string, ProviderOptions> = new Map();
5658

5759
private constructor() {
5860
super('client');
@@ -82,6 +84,14 @@ export class OpenFeatureAPI
8284
return this._domainScopedProviders.get(domain)?.status ?? this._defaultProvider.status;
8385
}
8486

87+
private getProviderOptions(domain?: string): ProviderOptions {
88+
if (!domain) {
89+
return this._defaultOptions;
90+
}
91+
92+
return this._domainScopedOptions.get(domain) ?? this._defaultOptions;
93+
}
94+
8595
/**
8696
* Sets the default provider for flag evaluations and returns a promise that resolves when the provider is ready.
8797
* This provider will be used by domainless clients and clients associated with domains to which no provider is bound.
@@ -141,6 +151,12 @@ export class OpenFeatureAPI
141151
? objectOrUndefined<ProviderOptions>(optionsOrUndefined)
142152
: objectOrUndefined<ProviderOptions>(contextOptionsOrUndefined);
143153

154+
if (domain) {
155+
this._domainScopedOptions.set(domain, options ?? {});
156+
} else {
157+
this._defaultOptions = options ?? {};
158+
}
159+
144160
let skipInitialization = false;
145161
if (context) {
146162
// validate the context to decide if we should initialize the provider with it.
@@ -219,6 +235,12 @@ export class OpenFeatureAPI
219235
? objectOrUndefined<ProviderOptions>(optionsOrUndefined)
220236
: objectOrUndefined<ProviderOptions>(contextOptionsOrUndefined);
221237

238+
if (domain) {
239+
this._domainScopedOptions.set(domain, options ?? {});
240+
} else {
241+
this._defaultOptions = options ?? {};
242+
}
243+
222244
let skipInitialization = false;
223245
let validateContextError: unknown;
224246
if (context) {
@@ -332,8 +354,6 @@ export class OpenFeatureAPI
332354
const domain = stringOrUndefined(domainOrContext);
333355
const context = objectOrUndefined<T>(domainOrContext) ?? objectOrUndefined(contextOrUndefined) ?? {};
334356

335-
// TODO: We need to store and call `validateContext` here if provided in `setProvider` options
336-
337357
if (domain) {
338358
const wrapper = this._domainScopedProviders.get(domain);
339359
if (wrapper) {
@@ -474,8 +494,19 @@ export class OpenFeatureAPI
474494
const providerName = wrapper.provider?.metadata?.name || 'unnamed-provider';
475495

476496
try {
497+
// validate the context to decide if we should run the context change handler.
498+
const options = this.getProviderOptions(domain);
499+
if (typeof options.validateContext === 'function') {
500+
if (!options.validateContext(newContext)) {
501+
this._logger.debug(
502+
`Skipping context change for domain '${domain ?? 'default'}' due to validateContext returning false.`,
503+
);
504+
return;
505+
}
506+
}
507+
477508
// if the provider hasn't initialized yet, and isn't actively initializing, initialize instead of running context change handler
478-
// the provider will be in this state if the user requested delayed initialization until the first context change
509+
// the provider will be in this state if validateContext was used during setProvider to skip initialization
479510
const initializationPromise = this.initializeProviderForDomain(wrapper, domain);
480511
if (initializationPromise) {
481512
await initializationPromise;

0 commit comments

Comments
 (0)