Skip to content

Commit b46a766

Browse files
committed
Add setProvider option to delay initialization
1 parent 472b399 commit b46a766

File tree

2 files changed

+37
-20
lines changed

2 files changed

+37
-20
lines changed

packages/shared/src/open-feature.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -228,13 +228,15 @@ export abstract class OpenFeatureCommonAPI<
228228
abstract setProviderAndWait(
229229
clientOrProvider?: string | P,
230230
providerContextOrUndefined?: P | EvaluationContext,
231-
contextOrUndefined?: EvaluationContext,
231+
contextOptionsOrUndefined?: EvaluationContext | Record<never, never>,
232+
optionsOrUndefined?: Record<never, never>,
232233
): Promise<void>;
233234

234235
abstract setProvider(
235236
clientOrProvider?: string | P,
236237
providerContextOrUndefined?: P | EvaluationContext,
237-
contextOrUndefined?: EvaluationContext,
238+
contextOptionsOrUndefined?: EvaluationContext | Record<never, never>,
239+
optionsOrUndefined?: Record<never, never>,
238240
): this;
239241

240242
protected initializeProviderForDomain(wrapper: ProviderWrapper<P, AnyProviderStatus>, domain?: string): Promise<void> | void {
@@ -285,7 +287,7 @@ export abstract class OpenFeatureCommonAPI<
285287
});
286288
}
287289

288-
protected setAwaitableProvider(domainOrProvider?: string | P, providerOrUndefined?: P): Promise<void> | void {
290+
protected setAwaitableProvider(domainOrProvider?: string | P, providerOrUndefined?: P, skipInitialization = false): Promise<void> | void {
289291
const domain = stringOrUndefined(domainOrProvider);
290292
const provider = objectOrUndefined<P>(domainOrProvider) ?? objectOrUndefined<P>(providerOrUndefined);
291293

@@ -318,17 +320,19 @@ export abstract class OpenFeatureCommonAPI<
318320
this._statusEnumType,
319321
);
320322

321-
// initialize the provider if it's not already registered and it implements "initialize"
322-
if (!this.allProviders.includes(provider)) {
323-
initializationPromise = this.initializeProviderForDomain(wrappedProvider, domain);
324-
}
323+
if (!skipInitialization) {
324+
// initialize the provider if it's not already registered and it implements "initialize"
325+
if (!this.allProviders.includes(provider)) {
326+
initializationPromise = this.initializeProviderForDomain(wrappedProvider, domain);
327+
}
325328

326-
if (!initializationPromise) {
327-
wrappedProvider.status = this._statusEnumType.READY;
328-
emitters.forEach((emitter) => {
329-
emitter?.emit(AllProviderEvents.Ready, { clientName: domain, domain, providerName });
330-
});
331-
this._apiEmitter?.emit(AllProviderEvents.Ready, { clientName: domain, domain, providerName });
329+
if (!initializationPromise) {
330+
wrappedProvider.status = this._statusEnumType.READY;
331+
emitters.forEach((emitter) => {
332+
emitter?.emit(AllProviderEvents.Ready, { clientName: domain, domain, providerName });
333+
});
334+
this._apiEmitter?.emit(AllProviderEvents.Ready, { clientName: domain, domain, providerName });
335+
}
332336
}
333337

334338
if (domain) {

packages/web/src/open-feature.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ import type { Hook } from './hooks';
1616
import type { Provider} from './provider';
1717
import { NOOP_PROVIDER, ProviderStatus } from './provider';
1818

19+
interface SetProviderOptions {
20+
/**
21+
* If true, delays provider initialization until the first context change.
22+
*/
23+
delayed?: boolean;
24+
}
25+
1926
// use a symbol as a key for the global singleton
2027
const GLOBAL_OPENFEATURE_API_KEY = Symbol.for('@openfeature/web-sdk/api');
2128

@@ -150,10 +157,11 @@ export class OpenFeatureAPI
150157
* This provider will be used by domainless clients and clients associated with domains to which no provider is bound.
151158
* Setting a provider supersedes the current provider used in new and existing unbound clients.
152159
* @param {Provider} provider The provider responsible for flag evaluations.
153-
* @param context {EvaluationContext} The evaluation context to use for flag evaluations.
160+
* @param {EvaluationContext} context The evaluation context to use for flag evaluations. Ignored if 'delayed' option is set.
161+
* @param {SetProviderOptions} [options] Options for setting the provider.
154162
* @returns {this} OpenFeature API
155163
*/
156-
setProvider(provider: Provider, context: EvaluationContext): this;
164+
setProvider<T extends SetProviderOptions>(provider: Provider, context: T extends { delayed: true } ? Record<never, never> : EvaluationContext, options?: T): this;
157165
/**
158166
* Sets the provider for flag evaluations of providers with the given name.
159167
* Setting a provider supersedes the current provider used in new and existing clients bound to the same domain.
@@ -167,22 +175,27 @@ export class OpenFeatureAPI
167175
* Setting a provider supersedes the current provider used in new and existing clients bound to the same domain.
168176
* @param {string} domain The name to identify the client
169177
* @param {Provider} provider The provider responsible for flag evaluations.
170-
* @param context {EvaluationContext} The evaluation context to use for flag evaluations.
178+
* @param {EvaluationContext} context The evaluation context to use for flag evaluations. Ignored if 'delayed' option is set.
179+
* @param {SetProviderOptions} [options] Options for setting the provider.
171180
* @returns {this} OpenFeature API
172181
*/
173-
setProvider(domain: string, provider: Provider, context: EvaluationContext): this;
182+
setProvider<T extends SetProviderOptions>(domain: string, provider: Provider, context: T extends { delayed: true } ? Record<never, never> : EvaluationContext, options?: T): this;
174183
setProvider(
175184
domainOrProvider?: string | Provider,
176185
providerContextOrUndefined?: Provider | EvaluationContext,
177-
contextOrUndefined?: EvaluationContext,
186+
contextOptionsOrUndefined?: EvaluationContext | SetProviderOptions,
187+
optionsOrUndefined?: SetProviderOptions,
178188
): this {
179189
const domain = stringOrUndefined(domainOrProvider);
180190
const provider = domain
181191
? objectOrUndefined<Provider>(providerContextOrUndefined)
182192
: objectOrUndefined<Provider>(domainOrProvider);
183193
const context = domain
184-
? objectOrUndefined<EvaluationContext>(contextOrUndefined)
194+
? objectOrUndefined<EvaluationContext>(contextOptionsOrUndefined)
185195
: objectOrUndefined<EvaluationContext>(providerContextOrUndefined);
196+
const options = domain
197+
? objectOrUndefined<SetProviderOptions>(optionsOrUndefined)
198+
: objectOrUndefined<SetProviderOptions>(contextOptionsOrUndefined);
186199

187200
if (context) {
188201
// synonymously setting context prior to provider initialization.
@@ -194,7 +207,7 @@ export class OpenFeatureAPI
194207
}
195208
}
196209

197-
const maybePromise = this.setAwaitableProvider(domain, provider);
210+
const maybePromise = this.setAwaitableProvider(domain, provider, options?.delayed);
198211

199212
// The setProvider method doesn't return a promise so we need to catch and
200213
// log any errors that occur during provider initialization to avoid having

0 commit comments

Comments
 (0)