@openfeature/web-sdk
Version:
OpenFeature SDK for Web
854 lines (839 loc) • 32.8 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __reflectGet = Reflect.get;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj);
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// ../../node_modules/eventemitter3/index.js
var require_eventemitter3 = __commonJS({
"../../node_modules/eventemitter3/index.js"(exports, module) {
"use strict";
var has = Object.prototype.hasOwnProperty;
var prefix = "~";
function Events() {
}
if (Object.create) {
Events.prototype = /* @__PURE__ */ Object.create(null);
if (!new Events().__proto__) prefix = false;
}
function EE(fn, context, once) {
this.fn = fn;
this.context = context;
this.once = once || false;
}
function addListener(emitter, event, fn, context, once) {
if (typeof fn !== "function") {
throw new TypeError("The listener must be a function");
}
var listener = new EE(fn, context || emitter, once), evt = prefix ? prefix + event : event;
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
else emitter._events[evt] = [emitter._events[evt], listener];
return emitter;
}
function clearEvent(emitter, evt) {
if (--emitter._eventsCount === 0) emitter._events = new Events();
else delete emitter._events[evt];
}
function EventEmitter2() {
this._events = new Events();
this._eventsCount = 0;
}
EventEmitter2.prototype.eventNames = function eventNames() {
var names = [], events, name;
if (this._eventsCount === 0) return names;
for (name in events = this._events) {
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
}
if (Object.getOwnPropertySymbols) {
return names.concat(Object.getOwnPropertySymbols(events));
}
return names;
};
EventEmitter2.prototype.listeners = function listeners(event) {
var evt = prefix ? prefix + event : event, handlers = this._events[evt];
if (!handlers) return [];
if (handlers.fn) return [handlers.fn];
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
ee[i] = handlers[i].fn;
}
return ee;
};
EventEmitter2.prototype.listenerCount = function listenerCount(event) {
var evt = prefix ? prefix + event : event, listeners = this._events[evt];
if (!listeners) return 0;
if (listeners.fn) return 1;
return listeners.length;
};
EventEmitter2.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return false;
var listeners = this._events[evt], len = arguments.length, args, i;
if (listeners.fn) {
if (listeners.once) this.removeListener(event, listeners.fn, void 0, true);
switch (len) {
case 1:
return listeners.fn.call(listeners.context), true;
case 2:
return listeners.fn.call(listeners.context, a1), true;
case 3:
return listeners.fn.call(listeners.context, a1, a2), true;
case 4:
return listeners.fn.call(listeners.context, a1, a2, a3), true;
case 5:
return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
case 6:
return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
}
for (i = 1, args = new Array(len - 1); i < len; i++) {
args[i - 1] = arguments[i];
}
listeners.fn.apply(listeners.context, args);
} else {
var length = listeners.length, j;
for (i = 0; i < length; i++) {
if (listeners[i].once) this.removeListener(event, listeners[i].fn, void 0, true);
switch (len) {
case 1:
listeners[i].fn.call(listeners[i].context);
break;
case 2:
listeners[i].fn.call(listeners[i].context, a1);
break;
case 3:
listeners[i].fn.call(listeners[i].context, a1, a2);
break;
case 4:
listeners[i].fn.call(listeners[i].context, a1, a2, a3);
break;
default:
if (!args) for (j = 1, args = new Array(len - 1); j < len; j++) {
args[j - 1] = arguments[j];
}
listeners[i].fn.apply(listeners[i].context, args);
}
}
}
return true;
};
EventEmitter2.prototype.on = function on(event, fn, context) {
return addListener(this, event, fn, context, false);
};
EventEmitter2.prototype.once = function once(event, fn, context) {
return addListener(this, event, fn, context, true);
};
EventEmitter2.prototype.removeListener = function removeListener(event, fn, context, once) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return this;
if (!fn) {
clearEvent(this, evt);
return this;
}
var listeners = this._events[evt];
if (listeners.fn) {
if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
clearEvent(this, evt);
}
} else {
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
events.push(listeners[i]);
}
}
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
else clearEvent(this, evt);
}
return this;
};
EventEmitter2.prototype.removeAllListeners = function removeAllListeners(event) {
var evt;
if (event) {
evt = prefix ? prefix + event : event;
if (this._events[evt]) clearEvent(this, evt);
} else {
this._events = new Events();
this._eventsCount = 0;
}
return this;
};
EventEmitter2.prototype.off = EventEmitter2.prototype.removeListener;
EventEmitter2.prototype.addListener = EventEmitter2.prototype.on;
EventEmitter2.prefixed = prefix;
EventEmitter2.EventEmitter = EventEmitter2;
if ("undefined" !== typeof module) {
module.exports = EventEmitter2;
}
}
});
// src/provider/provider.ts
import { ClientProviderStatus } from "@openfeature/core";
// src/provider/no-op-provider.ts
var REASON_NO_OP = "No-op";
var NoopFeatureProvider = class {
constructor() {
this.metadata = {
name: "No-op Provider"
};
}
resolveBooleanEvaluation(_, defaultValue) {
return this.noOp(defaultValue);
}
resolveStringEvaluation(_, defaultValue) {
return this.noOp(defaultValue);
}
resolveNumberEvaluation(_, defaultValue) {
return this.noOp(defaultValue);
}
resolveObjectEvaluation(_, defaultValue) {
return this.noOp(defaultValue);
}
noOp(defaultValue) {
return {
value: defaultValue,
reason: REASON_NO_OP
};
}
};
var NOOP_PROVIDER = new NoopFeatureProvider();
// src/provider/in-memory-provider/in-memory-provider.ts
import {
FlagNotFoundError,
GeneralError,
OpenFeatureError as OpenFeatureError2,
StandardResolutionReasons,
TypeMismatchError
} from "@openfeature/core";
// src/events/open-feature-event-emitter.ts
import { GenericEventEmitter } from "@openfeature/core";
// ../../node_modules/eventemitter3/index.mjs
var import_index = __toESM(require_eventemitter3(), 1);
// src/events/open-feature-event-emitter.ts
var OpenFeatureEventEmitter = class extends GenericEventEmitter {
constructor() {
super();
this.eventEmitter = new import_index.default();
}
};
// src/events/events.ts
import { ClientProviderEvents } from "@openfeature/core";
// src/provider/in-memory-provider/variant-not-found-error.ts
import { ErrorCode, OpenFeatureError } from "@openfeature/core";
var VariantNotFoundError = class _VariantNotFoundError extends OpenFeatureError {
constructor(message) {
super(message);
Object.setPrototypeOf(this, _VariantNotFoundError.prototype);
this.name = "VariantNotFoundError";
this.code = ErrorCode.GENERAL;
}
};
// src/provider/in-memory-provider/in-memory-provider.ts
var InMemoryProvider = class {
constructor(flagConfiguration = {}) {
this.events = new OpenFeatureEventEmitter();
this.runsOn = "client";
this.metadata = {
name: "in-memory"
};
this._flagConfiguration = __spreadValues({}, flagConfiguration);
}
/**
* Overwrites the configured flags.
* @param { FlagConfiguration } flagConfiguration new flag configuration
*/
putConfiguration(flagConfiguration) {
return __async(this, null, function* () {
try {
const flagsChanged = Object.entries(__spreadValues(__spreadValues({}, flagConfiguration), this._flagConfiguration)).map(([key]) => key);
this._flagConfiguration = __spreadValues({}, flagConfiguration);
this.events.emit(ClientProviderEvents.ConfigurationChanged, { flagsChanged });
} catch (err) {
this.events.emit(ClientProviderEvents.Error);
throw err;
}
});
}
resolveBooleanEvaluation(flagKey, defaultValue, context, logger) {
return this.resolveAndCheckFlag(flagKey, defaultValue, context || this._context, logger);
}
resolveNumberEvaluation(flagKey, defaultValue, context, logger) {
return this.resolveAndCheckFlag(flagKey, defaultValue, context || this._context, logger);
}
resolveStringEvaluation(flagKey, defaultValue, context, logger) {
return this.resolveAndCheckFlag(flagKey, defaultValue, context || this._context, logger);
}
resolveObjectEvaluation(flagKey, defaultValue, context, logger) {
return this.resolveAndCheckFlag(flagKey, defaultValue, context || this._context, logger);
}
resolveAndCheckFlag(flagKey, defaultValue, context, logger) {
if (!(flagKey in this._flagConfiguration)) {
const message = `no flag found with key ${flagKey}`;
logger == null ? void 0 : logger.debug(message);
throw new FlagNotFoundError(message);
}
if (this._flagConfiguration[flagKey].disabled) {
return { value: defaultValue, reason: StandardResolutionReasons.DISABLED };
}
const resolvedFlag = this.resolveFlagWithReason(flagKey, context);
if (resolvedFlag.value === void 0) {
const message = `no value associated with variant provided for ${flagKey} found`;
logger == null ? void 0 : logger.error(message);
throw new VariantNotFoundError(message);
}
if (typeof resolvedFlag.value != typeof defaultValue) {
throw new TypeMismatchError();
}
return resolvedFlag;
}
resolveFlagWithReason(flagKey, ctx) {
try {
const resolutionResult = this.lookupFlagValue(flagKey, ctx);
return resolutionResult;
} catch (error) {
if (!(error instanceof OpenFeatureError2)) {
throw new GeneralError((error == null ? void 0 : error.message) || "unknown error");
}
throw error;
}
}
lookupFlagValue(flagKey, ctx) {
var _a;
const flagSpec = this._flagConfiguration[flagKey];
const isContextEval = ctx && (flagSpec == null ? void 0 : flagSpec.contextEvaluator);
const variant = isContextEval ? (_a = flagSpec.contextEvaluator) == null ? void 0 : _a.call(flagSpec, ctx) : flagSpec.defaultVariant;
const value = variant && (flagSpec == null ? void 0 : flagSpec.variants[variant]);
const reason = isContextEval ? StandardResolutionReasons.TARGETING_MATCH : StandardResolutionReasons.STATIC;
return __spreadProps(__spreadValues({
value
}, variant && { variant }), {
reason
});
}
};
// src/open-feature.ts
import {
OpenFeatureCommonAPI,
ProviderWrapper,
objectOrUndefined,
stringOrUndefined
} from "@openfeature/core";
// src/client/internal/open-feature-client.ts
import {
ErrorCode as ErrorCode2,
ProviderFatalError,
ProviderNotReadyError,
SafeLogger,
StandardResolutionReasons as StandardResolutionReasons2,
instantiateErrorByErrorCode,
statusMatchesEvent
} from "@openfeature/core";
var OpenFeatureClient = class {
constructor(providerAccessor, providerStatusAccessor, emitterAccessor, apiContextAccessor, apiHooksAccessor, globalLogger, options) {
this.providerAccessor = providerAccessor;
this.providerStatusAccessor = providerStatusAccessor;
this.emitterAccessor = emitterAccessor;
this.apiContextAccessor = apiContextAccessor;
this.apiHooksAccessor = apiHooksAccessor;
this.globalLogger = globalLogger;
this.options = options;
this._hooks = [];
}
get metadata() {
var _a, _b;
return {
// Use domain if name is not provided
name: (_a = this.options.domain) != null ? _a : this.options.name,
domain: (_b = this.options.domain) != null ? _b : this.options.name,
version: this.options.version,
providerMetadata: this.providerAccessor().metadata
};
}
get providerStatus() {
return this.providerStatusAccessor();
}
addHandler(eventType, handler) {
var _a;
this.emitterAccessor().addHandler(eventType, handler);
const shouldRunNow = statusMatchesEvent(eventType, this.providerStatus);
if (shouldRunNow) {
try {
handler({
clientName: this.metadata.name,
domain: this.metadata.domain,
providerName: this._provider.metadata.name
});
} catch (err) {
(_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err);
}
}
}
removeHandler(notificationType, handler) {
this.emitterAccessor().removeHandler(notificationType, handler);
}
getHandlers(eventType) {
return this.emitterAccessor().getHandlers(eventType);
}
setLogger(logger) {
this._clientLogger = new SafeLogger(logger);
return this;
}
addHooks(...hooks) {
this._hooks = [...this._hooks, ...hooks];
return this;
}
getHooks() {
return this._hooks;
}
clearHooks() {
this._hooks = [];
return this;
}
getBooleanValue(flagKey, defaultValue, options) {
return this.getBooleanDetails(flagKey, defaultValue, options).value;
}
getBooleanDetails(flagKey, defaultValue, options) {
return this.evaluate(flagKey, this._provider.resolveBooleanEvaluation, defaultValue, "boolean", options);
}
getStringValue(flagKey, defaultValue, options) {
return this.getStringDetails(flagKey, defaultValue, options).value;
}
getStringDetails(flagKey, defaultValue, options) {
return this.evaluate(
flagKey,
// this isolates providers from our restricted string generic argument.
this._provider.resolveStringEvaluation,
defaultValue,
"string",
options
);
}
getNumberValue(flagKey, defaultValue, options) {
return this.getNumberDetails(flagKey, defaultValue, options).value;
}
getNumberDetails(flagKey, defaultValue, options) {
return this.evaluate(
flagKey,
// this isolates providers from our restricted number generic argument.
this._provider.resolveNumberEvaluation,
defaultValue,
"number",
options
);
}
getObjectValue(flagKey, defaultValue, options) {
return this.getObjectDetails(flagKey, defaultValue, options).value;
}
getObjectDetails(flagKey, defaultValue, options) {
return this.evaluate(flagKey, this._provider.resolveObjectEvaluation, defaultValue, "object", options);
}
track(occurrenceKey, occurrenceDetails = {}) {
var _a, _b, _c;
try {
this.shortCircuitIfNotReady();
if (typeof this._provider.track === "function") {
const frozenContext = Object.freeze(__spreadValues({}, this.apiContextAccessor((_a = this == null ? void 0 : this.options) == null ? void 0 : _a.domain)));
return (_c = (_b = this._provider).track) == null ? void 0 : _c.call(_b, occurrenceKey, frozenContext, occurrenceDetails);
} else {
this._logger.debug("Provider does not support the track function; will no-op.");
}
} catch (err) {
this._logger.debug("Error recording tracking event.", err);
}
}
evaluate(flagKey, resolver, defaultValue, flagType, options = {}) {
var _a, _b;
const allHooks = [
...this.apiHooksAccessor(),
...this.getHooks(),
...options.hooks || [],
...this._provider.hooks || []
];
const allHooksReversed = [...allHooks].reverse();
const context = __spreadValues({}, this.apiContextAccessor((_a = this == null ? void 0 : this.options) == null ? void 0 : _a.domain));
const hookContext = {
flagKey,
defaultValue,
flagValueType: flagType,
clientMetadata: this.metadata,
providerMetadata: this._provider.metadata,
context,
logger: this._logger
};
let evaluationDetails;
try {
this.beforeHooks(allHooks, hookContext, options);
this.shortCircuitIfNotReady();
const resolution = resolver.call(this._provider, flagKey, defaultValue, context, this._logger);
const resolutionDetails = __spreadProps(__spreadValues({}, resolution), {
flagMetadata: Object.freeze((_b = resolution.flagMetadata) != null ? _b : {}),
flagKey
});
if (resolutionDetails.errorCode) {
const err = instantiateErrorByErrorCode(resolutionDetails.errorCode, resolutionDetails.errorMessage);
this.errorHooks(allHooksReversed, hookContext, err, options);
evaluationDetails = this.getErrorEvaluationDetails(flagKey, defaultValue, err, resolutionDetails.flagMetadata);
} else {
this.afterHooks(allHooksReversed, hookContext, resolutionDetails, options);
evaluationDetails = resolutionDetails;
}
} catch (err) {
this.errorHooks(allHooksReversed, hookContext, err, options);
evaluationDetails = this.getErrorEvaluationDetails(flagKey, defaultValue, err);
}
this.finallyHooks(allHooksReversed, hookContext, evaluationDetails, options);
return evaluationDetails;
}
beforeHooks(hooks, hookContext, options) {
var _a;
Object.freeze(hookContext);
Object.freeze(hookContext.context);
for (const hook of hooks) {
(_a = hook == null ? void 0 : hook.before) == null ? void 0 : _a.call(hook, hookContext, Object.freeze(options.hookHints));
}
}
afterHooks(hooks, hookContext, evaluationDetails, options) {
var _a;
for (const hook of hooks) {
(_a = hook == null ? void 0 : hook.after) == null ? void 0 : _a.call(hook, hookContext, evaluationDetails, options.hookHints);
}
}
errorHooks(hooks, hookContext, err, options) {
var _a;
for (const hook of hooks) {
try {
(_a = hook == null ? void 0 : hook.error) == null ? void 0 : _a.call(hook, hookContext, err, options.hookHints);
} catch (err2) {
this._logger.error(`Unhandled error during 'error' hook: ${err2}`);
if (err2 instanceof Error) {
this._logger.error(err2.stack);
}
this._logger.error(err2 == null ? void 0 : err2.stack);
}
}
}
finallyHooks(hooks, hookContext, evaluationDetails, options) {
var _a;
for (const hook of hooks) {
try {
(_a = hook == null ? void 0 : hook.finally) == null ? void 0 : _a.call(hook, hookContext, evaluationDetails, options.hookHints);
} catch (err) {
this._logger.error(`Unhandled error during 'finally' hook: ${err}`);
if (err instanceof Error) {
this._logger.error(err.stack);
}
this._logger.error(err == null ? void 0 : err.stack);
}
}
}
get _provider() {
return this.providerAccessor();
}
get _logger() {
return this._clientLogger || this.globalLogger();
}
shortCircuitIfNotReady() {
if (this.providerStatus === ClientProviderStatus.NOT_READY) {
throw new ProviderNotReadyError("provider has not yet initialized");
} else if (this.providerStatus === ClientProviderStatus.FATAL) {
throw new ProviderFatalError("provider is in an irrecoverable error state");
}
}
getErrorEvaluationDetails(flagKey, defaultValue, err, flagMetadata = {}) {
const errorMessage = err == null ? void 0 : err.message;
const errorCode = (err == null ? void 0 : err.code) || ErrorCode2.GENERAL;
return {
errorCode,
errorMessage,
value: defaultValue,
reason: StandardResolutionReasons2.ERROR,
flagMetadata: Object.freeze(flagMetadata),
flagKey
};
}
};
// src/open-feature.ts
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/web-sdk/api");
var _globalThis = globalThis;
var OpenFeatureAPI = class _OpenFeatureAPI extends OpenFeatureCommonAPI {
constructor() {
super("client");
this._statusEnumType = ClientProviderStatus;
this._apiEmitter = new OpenFeatureEventEmitter();
this._defaultProvider = new ProviderWrapper(
NOOP_PROVIDER,
ClientProviderStatus.NOT_READY,
this._statusEnumType
);
this._domainScopedProviders = /* @__PURE__ */ new Map();
this._createEventEmitter = () => new OpenFeatureEventEmitter();
}
/**
* Gets a singleton instance of the OpenFeature API.
* @ignore
* @returns {OpenFeatureAPI} OpenFeature API
*/
static getInstance() {
const globalApi = _globalThis[GLOBAL_OPENFEATURE_API_KEY];
if (globalApi) {
return globalApi;
}
const instance = new _OpenFeatureAPI();
_globalThis[GLOBAL_OPENFEATURE_API_KEY] = instance;
return instance;
}
getProviderStatus(domain) {
var _a, _b;
if (!domain) {
return this._defaultProvider.status;
}
return (_b = (_a = this._domainScopedProviders.get(domain)) == null ? void 0 : _a.status) != null ? _b : this._defaultProvider.status;
}
setProviderAndWait(clientOrProvider, providerContextOrUndefined, contextOrUndefined) {
return __async(this, null, function* () {
const domain = stringOrUndefined(clientOrProvider);
const provider = domain ? objectOrUndefined(providerContextOrUndefined) : objectOrUndefined(clientOrProvider);
const context = domain ? objectOrUndefined(contextOrUndefined) : objectOrUndefined(providerContextOrUndefined);
if (context) {
if (domain) {
this._domainScopedContext.set(domain, context);
} else {
this._context = context;
}
}
yield this.setAwaitableProvider(domain, provider);
});
}
setProvider(domainOrProvider, providerContextOrUndefined, contextOrUndefined) {
const domain = stringOrUndefined(domainOrProvider);
const provider = domain ? objectOrUndefined(providerContextOrUndefined) : objectOrUndefined(domainOrProvider);
const context = domain ? objectOrUndefined(contextOrUndefined) : objectOrUndefined(providerContextOrUndefined);
if (context) {
if (domain) {
this._domainScopedContext.set(domain, context);
} else {
this._context = context;
}
}
const maybePromise = this.setAwaitableProvider(domain, provider);
Promise.resolve(maybePromise).catch((err) => {
this._logger.error("Error during provider initialization:", err);
});
return this;
}
setContext(domainOrContext, contextOrUndefined) {
return __async(this, null, function* () {
var _a, _b;
const domain = stringOrUndefined(domainOrContext);
const context = (_b = (_a = objectOrUndefined(domainOrContext)) != null ? _a : objectOrUndefined(contextOrUndefined)) != null ? _b : {};
if (domain) {
const wrapper = this._domainScopedProviders.get(domain);
if (wrapper) {
const oldContext = this.getContext(domain);
this._domainScopedContext.set(domain, context);
yield this.runProviderContextChangeHandler(domain, wrapper, oldContext, context);
} else {
this._domainScopedContext.set(domain, context);
}
} else {
const oldContext = this._context;
this._context = context;
const unboundProviders = Array.from(this._domainScopedProviders.entries()).filter(([domain2]) => !this._domainScopedContext.has(domain2)).reduce((acc, [domain2, wrapper]) => {
acc.push({ domain: domain2, wrapper });
return acc;
}, []);
const allDomainRecords = [
// add in the default (no domain)
{ domain: void 0, wrapper: this._defaultProvider },
...unboundProviders
];
yield Promise.all(
allDomainRecords.map((dm) => this.runProviderContextChangeHandler(dm.domain, dm.wrapper, oldContext, context))
);
}
});
}
getContext(domainOrUndefined) {
const domain = stringOrUndefined(domainOrUndefined);
if (domain) {
const context = this._domainScopedContext.get(domain);
if (context) {
return context;
} else {
this._logger.debug(`Unable to find context for '${domain}'.`);
}
}
return this._context;
}
clearContext(domainOrUndefined) {
return __async(this, null, function* () {
const domain = stringOrUndefined(domainOrUndefined);
if (domain) {
const wrapper = this._domainScopedProviders.get(domain);
if (wrapper) {
const oldContext = this.getContext(domain);
this._domainScopedContext.delete(domain);
const newContext = this.getContext();
yield this.runProviderContextChangeHandler(domain, wrapper, oldContext, newContext);
} else {
this._domainScopedContext.delete(domain);
}
} else {
return this.setContext({});
}
});
}
/**
* Resets the global evaluation context and removes the evaluation context for
* all domains.
*/
clearContexts() {
return __async(this, null, function* () {
yield this.clearContext();
yield Promise.allSettled(Array.from(this._domainScopedProviders.keys()).map((domain) => this.clearContext(domain)));
});
}
/**
* 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, version) {
return new OpenFeatureClient(
// functions are passed here to make sure that these values are always up to date,
// and so we don't have to make these public properties on the API class.
() => this.getProviderForClient(domain),
() => this.getProviderStatus(domain),
() => this.buildAndCacheEventEmitterForClient(domain),
(domain2) => this.getContext(domain2),
() => this.getHooks(),
() => this._logger,
{ domain, version }
);
}
/**
* Clears all registered providers and resets the default provider.
* @returns {Promise<void>}
*/
clearProviders() {
return __async(this, null, function* () {
yield __superGet(_OpenFeatureAPI.prototype, this, "clearProvidersAndSetDefault").call(this, NOOP_PROVIDER);
this._domainScopedContext.clear();
});
}
runProviderContextChangeHandler(domain, wrapper, oldContext, newContext) {
return __async(this, null, function* () {
var _a, _b, _c, _d, _e, _f;
const providerName = ((_b = (_a = wrapper.provider) == null ? void 0 : _a.metadata) == null ? void 0 : _b.name) || "unnamed-provider";
try {
if (typeof wrapper.provider.onContextChange === "function") {
const maybePromise = wrapper.provider.onContextChange(oldContext, newContext);
if (typeof (maybePromise == null ? void 0 : maybePromise.then) === "function") {
wrapper.incrementPendingContextChanges();
wrapper.status = this._statusEnumType.RECONCILING;
this.getAssociatedEventEmitters(domain).forEach((emitter) => {
emitter == null ? void 0 : emitter.emit(ClientProviderEvents.Reconciling, { domain, providerName });
});
(_c = this._apiEmitter) == null ? void 0 : _c.emit(ClientProviderEvents.Reconciling, { domain, providerName });
yield maybePromise;
wrapper.decrementPendingContextChanges();
}
}
wrapper.status = this._statusEnumType.READY;
if (wrapper.allContextChangesSettled) {
this.getAssociatedEventEmitters(domain).forEach((emitter) => {
emitter == null ? void 0 : emitter.emit(ClientProviderEvents.ContextChanged, { clientName: domain, domain, providerName });
});
(_d = this._apiEmitter) == null ? void 0 : _d.emit(ClientProviderEvents.ContextChanged, { clientName: domain, domain, providerName });
}
} catch (err) {
wrapper.decrementPendingContextChanges();
wrapper.status = this._statusEnumType.ERROR;
if (wrapper.allContextChangesSettled) {
const error = err;
const message = `Error running ${providerName}'s context change handler: ${error == null ? void 0 : error.message}`;
(_e = this._logger) == null ? void 0 : _e.error(`${message}`, err);
this.getAssociatedEventEmitters(domain).forEach((emitter) => {
emitter == null ? void 0 : emitter.emit(ClientProviderEvents.Error, { clientName: domain, domain, providerName, message });
});
(_f = this._apiEmitter) == null ? void 0 : _f.emit(ClientProviderEvents.Error, { clientName: domain, domain, providerName, message });
}
}
});
}
};
var OpenFeature = OpenFeatureAPI.getInstance();
// src/index.ts
export * from "@openfeature/core";
export {
InMemoryProvider,
NOOP_PROVIDER,
OpenFeature,
OpenFeatureAPI,
OpenFeatureEventEmitter,
ClientProviderEvents as ProviderEvents,
ClientProviderStatus as ProviderStatus
};
//# sourceMappingURL=index.js.map