@openfeature/web-sdk
Version:
OpenFeature SDK for Web
536 lines (505 loc) • 24.7 kB
TypeScript
import { BaseHook, HookHints, EvaluationDetails, JsonValue, FlagValue, CommonProvider, ClientProviderStatus, EvaluationContext, Logger, ResolutionDetails, ClientProviderEvents, GenericEventEmitter, TrackingEventDetails, EvaluationLifeCycle, ManageLogger, Eventing, ClientMetadata, OpenFeatureCommonAPI, ManageContext, ProviderWrapper } from '@openfeature/core';
export * from '@openfeature/core';
export { ClientProviderEvents as ProviderEvents, ClientProviderStatus as ProviderStatus } from '@openfeature/core';
interface FlagEvaluationOptions {
hooks?: BaseHook[];
hookHints?: HookHints;
}
interface Features {
/**
* Performs a flag evaluation that returns a boolean.
* @param {string} flagKey The flag key uniquely identifies a particular flag
* @param {boolean} defaultValue The value returned if an error occurs
* @param {FlagEvaluationOptions} options Additional flag evaluation options
* @returns {boolean} Flag evaluation response
*/
getBooleanValue(flagKey: string, defaultValue: boolean, options?: FlagEvaluationOptions): boolean;
/**
* Performs a flag evaluation that a returns an evaluation details object.
* @param {string} flagKey The flag key uniquely identifies a particular flag
* @param {boolean} defaultValue The value returned if an error occurs
* @param {FlagEvaluationOptions} options Additional flag evaluation options
* @returns {EvaluationDetails<boolean>} Flag evaluation details response
*/
getBooleanDetails(flagKey: string, defaultValue: boolean, options?: FlagEvaluationOptions): EvaluationDetails<boolean>;
/**
* Performs a flag evaluation that returns a string.
* @param {string} flagKey The flag key uniquely identifies a particular flag
* @template {string} T A optional generic argument constraining the string
* @param {T} defaultValue The value returned if an error occurs
* @param {FlagEvaluationOptions} options Additional flag evaluation options
* @returns {T} Flag evaluation response
*/
getStringValue(flagKey: string, defaultValue: string, options?: FlagEvaluationOptions): string;
getStringValue<T extends string = string>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): T;
/**
* Performs a flag evaluation that a returns an evaluation details object.
* @param {string} flagKey The flag key uniquely identifies a particular flag
* @template {string} T A optional generic argument constraining the string
* @param {T} defaultValue The value returned if an error occurs
* @param {FlagEvaluationOptions} options Additional flag evaluation options
* @returns {EvaluationDetails<T>} Flag evaluation details response
*/
getStringDetails(flagKey: string, defaultValue: string, options?: FlagEvaluationOptions): EvaluationDetails<string>;
getStringDetails<T extends string = string>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): EvaluationDetails<T>;
/**
* Performs a flag evaluation that returns a number.
* @param {string} flagKey The flag key uniquely identifies a particular flag
* @template {number} T A optional generic argument constraining the number
* @param {T} defaultValue The value returned if an error occurs
* @param {FlagEvaluationOptions} options Additional flag evaluation options
* @returns {T} Flag evaluation response
*/
getNumberValue(flagKey: string, defaultValue: number, options?: FlagEvaluationOptions): number;
getNumberValue<T extends number = number>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): T;
/**
* Performs a flag evaluation that a returns an evaluation details object.
* @param {string} flagKey The flag key uniquely identifies a particular flag
* @template {number} T A optional generic argument constraining the number
* @param {T} defaultValue The value returned if an error occurs
* @param {FlagEvaluationOptions} options Additional flag evaluation options
* @returns {Promise<EvaluationDetails<T>>} Flag evaluation details response
*/
getNumberDetails(flagKey: string, defaultValue: number, options?: FlagEvaluationOptions): EvaluationDetails<number>;
getNumberDetails<T extends number = number>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): EvaluationDetails<T>;
/**
* Performs a flag evaluation that returns an object.
* @param {string} flagKey The flag key uniquely identifies a particular flag
* @template {JsonValue} T A optional generic argument describing the structure
* @param {T} defaultValue The value returned if an error occurs
* @param {FlagEvaluationOptions} options Additional flag evaluation options
* @returns {Promise<T>} Flag evaluation response
*/
getObjectValue(flagKey: string, defaultValue: JsonValue, options?: FlagEvaluationOptions): JsonValue;
getObjectValue<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): T;
/**
* Performs a flag evaluation that a returns an evaluation details object.
* @param {string} flagKey The flag key uniquely identifies a particular flag
* @template {JsonValue} T A optional generic argument describing the structure
* @param {T} defaultValue The value returned if an error occurs
* @param {FlagEvaluationOptions} options Additional flag evaluation options
* @returns {Promise<EvaluationDetails<T>>} Flag evaluation details response
*/
getObjectDetails(flagKey: string, defaultValue: JsonValue, options?: FlagEvaluationOptions): EvaluationDetails<JsonValue>;
getObjectDetails<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, options?: FlagEvaluationOptions): EvaluationDetails<T>;
}
type Hook = BaseHook<FlagValue, void, void>;
/**
* Interface that providers must implement to resolve flag values for their particular
* backend or vendor.
*
* Implementation for resolving all the required flag types must be defined.
*/
interface Provider extends CommonProvider<ClientProviderStatus> {
/**
* A provider hook exposes a mechanism for provider authors to register hooks
* to tap into various stages of the flag evaluation lifecycle. These hooks can
* be used to perform side effects and mutate the context for purposes of the
* provider. Provider hooks are not configured or controlled by the application author.
*/
readonly hooks?: Hook[];
/**
* A handler function to reconcile changes made to the static context.
* Called by the SDK when the context is changed.
*
* Returning a promise will put the provider in the RECONCILING state and
* emit the ProviderEvents.Reconciling event.
*
* Return void will avoid putting the provider in the RECONCILING state and
* **not** emit the ProviderEvents.Reconciling event.
* @param oldContext
* @param newContext
*/
onContextChange?(oldContext: EvaluationContext, newContext: EvaluationContext): Promise<void> | void;
/**
* Resolve a boolean flag and its evaluation details.
*/
resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context: EvaluationContext, logger: Logger): ResolutionDetails<boolean>;
/**
* Resolve a string flag and its evaluation details.
*/
resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext, logger: Logger): ResolutionDetails<string>;
/**
* Resolve a numeric flag and its evaluation details.
*/
resolveNumberEvaluation(flagKey: string, defaultValue: number, context: EvaluationContext, logger: Logger): ResolutionDetails<number>;
/**
* Resolve and parse an object flag and its evaluation details.
*/
resolveObjectEvaluation<T extends JsonValue>(flagKey: string, defaultValue: T, context: EvaluationContext, logger: Logger): ResolutionDetails<T>;
}
/**
* The No-op provider is set by default, and simply always returns the default value.
*/
declare class NoopFeatureProvider implements Provider {
readonly metadata: {
readonly name: "No-op Provider";
};
resolveBooleanEvaluation(_: string, defaultValue: boolean): ResolutionDetails<boolean>;
resolveStringEvaluation(_: string, defaultValue: string): ResolutionDetails<string>;
resolveNumberEvaluation(_: string, defaultValue: number): ResolutionDetails<number>;
resolveObjectEvaluation<T extends JsonValue>(_: string, defaultValue: T): ResolutionDetails<T>;
private noOp;
}
declare const NOOP_PROVIDER: NoopFeatureProvider;
/**
* Minimal `EventEmitter` interface that is molded against the Node.js
* `EventEmitter` interface.
*/
declare class EventEmitter<
EventTypes extends EventEmitter.ValidEventTypes = string | symbol,
Context extends any = any
> {
static prefixed: string | boolean;
/**
* Return an array listing the events for which the emitter has registered
* listeners.
*/
eventNames(): Array<EventEmitter.EventNames<EventTypes>>;
/**
* Return the listeners registered for a given event.
*/
listeners<T extends EventEmitter.EventNames<EventTypes>>(
event: T
): Array<EventEmitter.EventListener<EventTypes, T>>;
/**
* Return the number of listeners listening to a given event.
*/
listenerCount(event: EventEmitter.EventNames<EventTypes>): number;
/**
* Calls each of the listeners registered for a given event.
*/
emit<T extends EventEmitter.EventNames<EventTypes>>(
event: T,
...args: EventEmitter.EventArgs<EventTypes, T>
): boolean;
/**
* Add a listener for a given event.
*/
on<T extends EventEmitter.EventNames<EventTypes>>(
event: T,
fn: EventEmitter.EventListener<EventTypes, T>,
context?: Context
): this;
addListener<T extends EventEmitter.EventNames<EventTypes>>(
event: T,
fn: EventEmitter.EventListener<EventTypes, T>,
context?: Context
): this;
/**
* Add a one-time listener for a given event.
*/
once<T extends EventEmitter.EventNames<EventTypes>>(
event: T,
fn: EventEmitter.EventListener<EventTypes, T>,
context?: Context
): this;
/**
* Remove the listeners of a given event.
*/
removeListener<T extends EventEmitter.EventNames<EventTypes>>(
event: T,
fn?: EventEmitter.EventListener<EventTypes, T>,
context?: Context,
once?: boolean
): this;
off<T extends EventEmitter.EventNames<EventTypes>>(
event: T,
fn?: EventEmitter.EventListener<EventTypes, T>,
context?: Context,
once?: boolean
): this;
/**
* Remove all listeners, or those of the specified event.
*/
removeAllListeners(event?: EventEmitter.EventNames<EventTypes>): this;
}
declare namespace EventEmitter {
export interface ListenerFn<Args extends any[] = any[]> {
(...args: Args): void;
}
export interface EventEmitterStatic {
new <
EventTypes extends ValidEventTypes = string | symbol,
Context = any
>(): EventEmitter<EventTypes, Context>;
}
/**
* `object` should be in either of the following forms:
* ```
* interface EventTypes {
* 'event-with-parameters': any[]
* 'event-with-example-handler': (...args: any[]) => void
* }
* ```
*/
export type ValidEventTypes = string | symbol | object;
export type EventNames<T extends ValidEventTypes> = T extends string | symbol
? T
: keyof T;
export type ArgumentMap<T extends object> = {
[K in keyof T]: T[K] extends (...args: any[]) => void
? Parameters<T[K]>
: T[K] extends any[]
? T[K]
: any[];
};
export type EventListener<
T extends ValidEventTypes,
K extends EventNames<T>
> = T extends string | symbol
? (...args: any[]) => void
: (
...args: ArgumentMap<Exclude<T, string | symbol>>[Extract<K, keyof T>]
) => void;
export type EventArgs<
T extends ValidEventTypes,
K extends EventNames<T>
> = Parameters<EventListener<T, K>>;
export const EventEmitter: EventEmitterStatic;
}
/**
* A subset of events that can be directly emitted by providers.
*/
type ProviderEmittableEvents = Exclude<ClientProviderEvents, ClientProviderEvents.ContextChanged>;
/**
* The OpenFeatureEventEmitter can be used by provider developers to emit
* events at various parts of the provider lifecycle.
*
* NOTE: Ready and error events are automatically emitted by the SDK based on
* the result of the initialize method.
*/
declare class OpenFeatureEventEmitter extends GenericEventEmitter<ProviderEmittableEvents> {
protected readonly eventEmitter: EventEmitter<string | symbol, any>;
constructor();
}
/**
* Don't export types from this file publicly.
* It might cause confusion since these types are not a part of the general API,
* but just for the in-memory provider.
*/
type Variants<T> = Record<string, T>;
/**
* A Feature Flag definition, containing it's specification
*/
type Flag = {
/**
* An object containing all possible flags mappings (variant -> flag value)
*/
variants: Variants<boolean> | Variants<string> | Variants<number> | Variants<JsonValue>;
/**
* The variant it will resolve to in STATIC evaluation
*/
defaultVariant: string;
/**
* Determines if flag evaluation is enabled or not for this flag.
* If false, falls back to the default value provided to the client
*/
disabled: boolean;
/**
* Function used in order to evaluate a flag to a specific value given the provided context.
* It should return a variant key.
* If it does not return a valid variant it falls back to the default value provided to the client
* @param EvaluationContext
*/
contextEvaluator?: (ctx: EvaluationContext) => string;
};
type FlagConfiguration = Record<string, Flag>;
/**
* A simple OpenFeature provider intended for demos and as a test stub.
*/
declare class InMemoryProvider implements Provider {
readonly events: OpenFeatureEventEmitter;
readonly runsOn = "client";
readonly metadata: {
readonly name: "in-memory";
};
private _flagConfiguration;
private _context;
constructor(flagConfiguration?: FlagConfiguration);
/**
* Overwrites the configured flags.
* @param { FlagConfiguration } flagConfiguration new flag configuration
*/
putConfiguration(flagConfiguration: FlagConfiguration): Promise<void>;
resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context?: EvaluationContext, logger?: Logger): ResolutionDetails<boolean>;
resolveNumberEvaluation(flagKey: string, defaultValue: number, context?: EvaluationContext, logger?: Logger): ResolutionDetails<number>;
resolveStringEvaluation(flagKey: string, defaultValue: string, context?: EvaluationContext, logger?: Logger): ResolutionDetails<string>;
resolveObjectEvaluation<T extends JsonValue>(flagKey: string, defaultValue: T, context?: EvaluationContext, logger?: Logger): ResolutionDetails<T>;
private resolveAndCheckFlag;
private resolveFlagWithReason;
private lookupFlagValue;
}
interface Tracking {
/**
* Track a user action or application state, usually representing a business objective or outcome.
* @param trackingEventName an identifier for the event
* @param trackingEventDetails the details of the tracking event
*/
track(trackingEventName: string, trackingEventDetails?: TrackingEventDetails): void;
}
interface Client extends EvaluationLifeCycle<Client>, Features, ManageLogger<Client>, Eventing<ClientProviderEvents>, Tracking {
readonly metadata: ClientMetadata;
/**
* Returns the status of the associated provider.
*/
readonly providerStatus: ClientProviderStatus;
}
declare class OpenFeatureAPI extends OpenFeatureCommonAPI<ClientProviderStatus, Provider, Hook> implements ManageContext<Promise<void>> {
protected _statusEnumType: typeof ClientProviderStatus;
protected _apiEmitter: GenericEventEmitter<ClientProviderEvents>;
protected _defaultProvider: ProviderWrapper<Provider, ClientProviderStatus>;
protected _domainScopedProviders: Map<string, ProviderWrapper<Provider, ClientProviderStatus>>;
protected _createEventEmitter: () => OpenFeatureEventEmitter;
private constructor();
/**
* Gets a singleton instance of the OpenFeature API.
* @ignore
* @returns {OpenFeatureAPI} OpenFeature API
*/
static getInstance(): OpenFeatureAPI;
private getProviderStatus;
/**
* Sets the default provider for flag evaluations and returns a promise that resolves when the provider is ready.
* This provider will be used by domainless clients and clients associated with domains to which no provider is bound.
* Setting a provider supersedes the current provider used in new and existing unbound clients.
* @param {Provider} provider The provider responsible for flag evaluations.
* @returns {Promise<void>}
* @throws Uncaught exceptions thrown by the provider during initialization.
*/
setProviderAndWait(provider: Provider): Promise<void>;
/**
* Sets the default provider for flag evaluations and returns a promise that resolves when the provider is ready.
* This provider will be used by domainless clients and clients associated with domains to which no provider is bound.
* Setting a provider supersedes the current provider used in new and existing unbound clients.
* @param {Provider} provider The provider responsible for flag evaluations.
* @param {EvaluationContext} context The evaluation context to use for flag evaluations.
* @returns {Promise<void>}
* @throws Uncaught exceptions thrown by the provider during initialization.
*/
setProviderAndWait(provider: Provider, context: EvaluationContext): Promise<void>;
/**
* Sets the provider that OpenFeature will use for flag evaluations on clients bound to the same domain.
* A promise is returned that resolves when the provider is ready.
* Setting a provider supersedes the current provider used in new and existing clients bound to the same domain.
* @param {string} domain The name to identify the client
* @param {Provider} provider The provider responsible for flag evaluations.
* @returns {Promise<void>}
* @throws Uncaught exceptions thrown by the provider during initialization.
*/
setProviderAndWait(domain: string, provider: Provider): Promise<void>;
/**
* Sets the provider that OpenFeature will use for flag evaluations on clients bound to the same domain.
* A promise is returned that resolves when the provider is ready.
* Setting a provider supersedes the current provider used in new and existing clients bound to the same domain.
* @param {string} domain The name to identify the client
* @param {Provider} provider The provider responsible for flag evaluations.
* @param {EvaluationContext} context The evaluation context to use for flag evaluations.
* @returns {Promise<void>}
* @throws Uncaught exceptions thrown by the provider during initialization.
*/
setProviderAndWait(domain: string, provider: Provider, context: EvaluationContext): Promise<void>;
/**
* Sets the default provider for flag evaluations.
* This provider will be used by domainless clients and clients associated with domains to which no provider is bound.
* Setting a provider supersedes the current provider used in new and existing unbound clients.
* @param {Provider} provider The provider responsible for flag evaluations.
* @returns {this} OpenFeature API
*/
setProvider(provider: Provider): this;
/**
* Sets the default provider and evaluation context for flag evaluations.
* This provider will be used by domainless clients and clients associated with domains to which no provider is bound.
* Setting a provider supersedes the current provider used in new and existing unbound clients.
* @param {Provider} provider The provider responsible for flag evaluations.
* @param context {EvaluationContext} The evaluation context to use for flag evaluations.
* @returns {this} OpenFeature API
*/
setProvider(provider: Provider, context: EvaluationContext): this;
/**
* Sets the provider for flag evaluations of providers with the given name.
* Setting a provider supersedes the current provider used in new and existing clients bound to the same domain.
* @param {string} domain The name to identify the client
* @param {Provider} provider The provider responsible for flag evaluations.
* @returns {this} OpenFeature API
*/
setProvider(domain: string, provider: Provider): this;
/**
* Sets the provider and evaluation context flag evaluations of providers with the given name.
* Setting a provider supersedes the current provider used in new and existing clients bound to the same domain.
* @param {string} domain The name to identify the client
* @param {Provider} provider The provider responsible for flag evaluations.
* @param context {EvaluationContext} The evaluation context to use for flag evaluations.
* @returns {this} OpenFeature API
*/
setProvider(domain: string, provider: Provider, context: EvaluationContext): this;
/**
* Sets the evaluation context globally.
* This will be used by all providers that have not bound to a domain.
* @param {EvaluationContext} context Evaluation context
* @example
* await OpenFeature.setContext({ region: "us" });
*/
setContext(context: EvaluationContext): Promise<void>;
/**
* Sets the evaluation context for a specific provider.
* This will only affect providers bound to a domain.
* @param {string} domain An identifier which logically binds clients with providers
* @param {EvaluationContext} context Evaluation context
* @example
* await OpenFeature.setContext("test", { scope: "provider" });
* OpenFeature.setProvider(new MyProvider()) // Uses the default context
* OpenFeature.setProvider("test", new MyProvider()) // Uses context: { scope: "provider" }
*/
setContext(domain: string, context: EvaluationContext): Promise<void>;
/**
* Access the global evaluation context.
* @returns {EvaluationContext} Evaluation context
*/
getContext(): EvaluationContext;
/**
* Access the evaluation context for a specific named client.
* The global evaluation context is returned if a matching named client is not found.
* @param {string} domain An identifier which logically binds clients with providers
* @returns {EvaluationContext} Evaluation context
*/
getContext(domain?: string | undefined): EvaluationContext;
/**
* Resets the global evaluation context to an empty object.
*/
clearContext(): Promise<void>;
/**
* Removes the evaluation context for a specific named client.
* @param {string} domain An identifier which logically binds clients with providers
*/
clearContext(domain: string): Promise<void>;
/**
* Resets the global evaluation context and removes the evaluation context for
* all domains.
*/
clearContexts(): Promise<void>;
/**
* A factory function for creating new named OpenFeature clients. Clients can contain
* their own state (e.g. logger, hook, context). Multiple clients can be used
* to segment feature flag configuration.
*
* If there is already a provider bound to this name via {@link this.setProvider setProvider}, this provider will be used.
* Otherwise, the default provider is used until a provider is assigned to that name.
* @param {string} domain An identifier which logically binds clients with providers
* @param {string} version The version of the client (only used for metadata)
* @returns {Client} OpenFeature Client
*/
getClient(domain?: string, version?: string): Client;
/**
* Clears all registered providers and resets the default provider.
* @returns {Promise<void>}
*/
clearProviders(): Promise<void>;
private runProviderContextChangeHandler;
}
/**
* A singleton instance of the OpenFeature API.
* @returns {OpenFeatureAPI} OpenFeature API
*/
declare const OpenFeature: OpenFeatureAPI;
export { type Client, type Features, type FlagEvaluationOptions, type Hook, InMemoryProvider, NOOP_PROVIDER, OpenFeature, OpenFeatureAPI, OpenFeatureEventEmitter, type Provider, type ProviderEmittableEvents, type Tracking };