@openfeature/web-sdk
Advanced tools
Comparing version 0.3.2-experimental to 0.3.3-experimental
@@ -97,11 +97,11 @@ "use strict"; | ||
}; | ||
function EventEmitter() { | ||
EventEmitter.init.call(this); | ||
function EventEmitter2() { | ||
EventEmitter2.init.call(this); | ||
} | ||
module2.exports = EventEmitter; | ||
module2.exports = EventEmitter2; | ||
module2.exports.once = once; | ||
EventEmitter.EventEmitter = EventEmitter; | ||
EventEmitter.prototype._events = void 0; | ||
EventEmitter.prototype._eventsCount = 0; | ||
EventEmitter.prototype._maxListeners = void 0; | ||
EventEmitter2.EventEmitter = EventEmitter2; | ||
EventEmitter2.prototype._events = void 0; | ||
EventEmitter2.prototype._eventsCount = 0; | ||
EventEmitter2.prototype._maxListeners = void 0; | ||
var defaultMaxListeners = 10; | ||
@@ -113,3 +113,3 @@ function checkListener(listener) { | ||
} | ||
Object.defineProperty(EventEmitter, "defaultMaxListeners", { | ||
Object.defineProperty(EventEmitter2, "defaultMaxListeners", { | ||
enumerable: true, | ||
@@ -126,3 +126,3 @@ get: function() { | ||
}); | ||
EventEmitter.init = function() { | ||
EventEmitter2.init = function() { | ||
if (this._events === void 0 || this._events === Object.getPrototypeOf(this)._events) { | ||
@@ -134,3 +134,3 @@ this._events = /* @__PURE__ */ Object.create(null); | ||
}; | ||
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { | ||
EventEmitter2.prototype.setMaxListeners = function setMaxListeners(n) { | ||
if (typeof n !== "number" || n < 0 || NumberIsNaN(n)) { | ||
@@ -144,9 +144,9 @@ throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + "."); | ||
if (that._maxListeners === void 0) | ||
return EventEmitter.defaultMaxListeners; | ||
return EventEmitter2.defaultMaxListeners; | ||
return that._maxListeners; | ||
} | ||
EventEmitter.prototype.getMaxListeners = function getMaxListeners() { | ||
EventEmitter2.prototype.getMaxListeners = function getMaxListeners() { | ||
return _getMaxListeners(this); | ||
}; | ||
EventEmitter.prototype.emit = function emit(type) { | ||
EventEmitter2.prototype.emit = function emit(type) { | ||
var args = []; | ||
@@ -229,7 +229,7 @@ for (var i = 1; i < arguments.length; i++) | ||
} | ||
EventEmitter.prototype.addListener = function addListener(type, listener) { | ||
EventEmitter2.prototype.addListener = function addListener(type, listener) { | ||
return _addListener(this, type, listener, false); | ||
}; | ||
EventEmitter.prototype.on = EventEmitter.prototype.addListener; | ||
EventEmitter.prototype.prependListener = function prependListener(type, listener) { | ||
EventEmitter2.prototype.on = EventEmitter2.prototype.addListener; | ||
EventEmitter2.prototype.prependListener = function prependListener(type, listener) { | ||
return _addListener(this, type, listener, true); | ||
@@ -253,3 +253,3 @@ }; | ||
} | ||
EventEmitter.prototype.once = function once2(type, listener) { | ||
EventEmitter2.prototype.once = function once2(type, listener) { | ||
checkListener(listener); | ||
@@ -259,3 +259,3 @@ this.on(type, _onceWrap(this, type, listener)); | ||
}; | ||
EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) { | ||
EventEmitter2.prototype.prependOnceListener = function prependOnceListener(type, listener) { | ||
checkListener(listener); | ||
@@ -265,3 +265,3 @@ this.prependListener(type, _onceWrap(this, type, listener)); | ||
}; | ||
EventEmitter.prototype.removeListener = function removeListener(type, listener) { | ||
EventEmitter2.prototype.removeListener = function removeListener(type, listener) { | ||
var list, events, position, i, originalListener; | ||
@@ -306,4 +306,4 @@ checkListener(listener); | ||
}; | ||
EventEmitter.prototype.off = EventEmitter.prototype.removeListener; | ||
EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { | ||
EventEmitter2.prototype.off = EventEmitter2.prototype.removeListener; | ||
EventEmitter2.prototype.removeAllListeners = function removeAllListeners(type) { | ||
var listeners, events, i; | ||
@@ -360,9 +360,9 @@ events = this._events; | ||
} | ||
EventEmitter.prototype.listeners = function listeners(type) { | ||
EventEmitter2.prototype.listeners = function listeners(type) { | ||
return _listeners(this, type, true); | ||
}; | ||
EventEmitter.prototype.rawListeners = function rawListeners(type) { | ||
EventEmitter2.prototype.rawListeners = function rawListeners(type) { | ||
return _listeners(this, type, false); | ||
}; | ||
EventEmitter.listenerCount = function(emitter, type) { | ||
EventEmitter2.listenerCount = function(emitter, type) { | ||
if (typeof emitter.listenerCount === "function") { | ||
@@ -374,3 +374,3 @@ return emitter.listenerCount(type); | ||
}; | ||
EventEmitter.prototype.listenerCount = listenerCount; | ||
EventEmitter2.prototype.listenerCount = listenerCount; | ||
function listenerCount(type) { | ||
@@ -388,3 +388,3 @@ var events = this._events; | ||
} | ||
EventEmitter.prototype.eventNames = function eventNames() { | ||
EventEmitter2.prototype.eventNames = function eventNames() { | ||
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; | ||
@@ -458,3 +458,2 @@ }; | ||
__export(src_exports, { | ||
ApiEvents: () => ApiEvents, | ||
DefaultLogger: () => DefaultLogger, | ||
@@ -472,5 +471,6 @@ ErrorCode: () => ErrorCode, | ||
OpenFeatureError: () => OpenFeatureError, | ||
OpenFeatureEventEmitter: () => import_events.EventEmitter, | ||
OpenFeatureEventEmitter: () => OpenFeatureEventEmitter, | ||
ParseError: () => ParseError, | ||
ProviderEvents: () => ProviderEvents, | ||
ProviderStatus: () => ProviderStatus, | ||
SafeLogger: () => SafeLogger, | ||
@@ -498,3 +498,3 @@ StandardResolutionReasons: () => StandardResolutionReasons, | ||
/** | ||
* The resolved value was configured statically, or otherwise fell back to a pre-configured value. | ||
* The resolved value was configured statically, or otherwise fell back to a pre-configured value. | ||
*/ | ||
@@ -531,2 +531,8 @@ DEFAULT: "DEFAULT", | ||
})(ErrorCode || {}); | ||
var ProviderStatus = /* @__PURE__ */ ((ProviderStatus2) => { | ||
ProviderStatus2["NOT_READY"] = "NOT_READY"; | ||
ProviderStatus2["READY"] = "READY"; | ||
ProviderStatus2["ERROR"] = "ERROR"; | ||
return ProviderStatus2; | ||
})(ProviderStatus || {}); | ||
@@ -664,2 +670,72 @@ // ../shared/src/errors/open-feature-error-abstract.ts | ||
// ../shared/src/events.ts | ||
var import_events = __toESM(require_events()); | ||
var ProviderEvents = /* @__PURE__ */ ((ProviderEvents2) => { | ||
ProviderEvents2["Ready"] = "PROVIDER_READY"; | ||
ProviderEvents2["Error"] = "PROVIDER_ERROR"; | ||
ProviderEvents2["ConfigurationChanged"] = "PROVIDER_CONFIGURATION_CHANGED"; | ||
ProviderEvents2["Stale"] = "PROVIDER_STALE"; | ||
return ProviderEvents2; | ||
})(ProviderEvents || {}); | ||
var OpenFeatureEventEmitter = class { | ||
constructor(globalLogger) { | ||
this.globalLogger = globalLogger; | ||
this._handlers = /* @__PURE__ */ new WeakMap(); | ||
this.eventEmitter = new import_events.default({ captureRejections: true }); | ||
this.eventEmitter.on("error", (err) => { | ||
var _a; | ||
(_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err); | ||
}); | ||
} | ||
emit(eventType, context) { | ||
this.eventEmitter.emit(eventType, context); | ||
} | ||
addHandler(eventType, handler) { | ||
const asyncHandler = (context) => __async(this, null, function* () { | ||
yield handler(context); | ||
}); | ||
this._handlers.set(handler, asyncHandler); | ||
this.eventEmitter.on(eventType, asyncHandler); | ||
} | ||
removeHandler(eventType, handler) { | ||
const asyncHandler = this._handlers.get(handler); | ||
if (!asyncHandler) { | ||
return; | ||
} | ||
this.eventEmitter.removeListener(eventType, asyncHandler); | ||
} | ||
removeAllHandlers(eventType) { | ||
if (eventType) { | ||
this.eventEmitter.removeAllListeners(eventType); | ||
} else { | ||
this.eventEmitter.removeAllListeners(); | ||
} | ||
} | ||
getHandlers(eventType) { | ||
return this.eventEmitter.listeners(eventType); | ||
} | ||
setLogger(logger) { | ||
this._eventLogger = new SafeLogger(logger); | ||
return this; | ||
} | ||
get _logger() { | ||
var _a; | ||
return this._eventLogger || ((_a = this.globalLogger) == null ? void 0 : _a.call(this)); | ||
} | ||
}; | ||
// ../shared/src/type-guards.ts | ||
function isString(value) { | ||
return typeof value === "string"; | ||
} | ||
function stringOrUndefined(value) { | ||
return isString(value) ? value : void 0; | ||
} | ||
function isObject(value) { | ||
return typeof value === "object"; | ||
} | ||
function objectOrUndefined(value) { | ||
return isObject(value) ? value : void 0; | ||
} | ||
// ../shared/src/open-feature.ts | ||
@@ -671,6 +747,137 @@ var OpenFeatureCommonAPI = class { | ||
this._logger = new DefaultLogger(); | ||
this._events = new OpenFeatureEventEmitter(() => this._logger); | ||
this._clientProviders = /* @__PURE__ */ new Map(); | ||
this._clientEvents = /* @__PURE__ */ new Map(); | ||
} | ||
setLogger(logger) { | ||
this._logger = new SafeLogger(logger); | ||
return this; | ||
} | ||
/** | ||
* Get metadata about registered provider. | ||
* @returns {ProviderMetadata} Provider Metadata | ||
*/ | ||
get providerMetadata() { | ||
return this._defaultProvider.metadata; | ||
} | ||
getContext() { | ||
return this._context; | ||
} | ||
/** | ||
* Adds a handler for the given provider event type. | ||
* The handlers are called in the order they have been added. | ||
* When changing the provider, the currently attached handlers will listen to the events of the new provider. | ||
* @param {ProviderEvents} eventType The provider event type to listen to | ||
* @param {EventHandler} handler The handler to run on occurrence of the event type | ||
*/ | ||
addHandler(eventType, handler) { | ||
this._events.addHandler(eventType, handler); | ||
} | ||
/** | ||
* Removes a handler for the given provider event type. | ||
* @param {ProviderEvents} eventType The provider event type to remove the listener for | ||
* @param {EventHandler} handler The handler to remove for the provider event type | ||
*/ | ||
removeHandler(eventType, handler) { | ||
this._events.removeHandler(eventType, handler); | ||
} | ||
/** | ||
* Gets the current handlers for the given provider event type. | ||
* @param {ProviderEvents} eventType The provider event type to get the current handlers for | ||
* @returns {EventHandler[]} The handlers currently attached to the given provider event type | ||
*/ | ||
getHandlers(eventType) { | ||
return this._events.getHandlers(eventType); | ||
} | ||
setProvider(clientOrProvider, providerOrUndefined) { | ||
var _a, _b, _c, _d, _e, _f; | ||
const clientName = stringOrUndefined(clientOrProvider); | ||
const provider = (_a = objectOrUndefined(clientOrProvider)) != null ? _a : objectOrUndefined(providerOrUndefined); | ||
if (!provider) { | ||
return this; | ||
} | ||
const oldProvider = this.getProviderForClient(clientName); | ||
if (oldProvider === provider) { | ||
return this; | ||
} | ||
const clientEmitter = this.getEventEmitterForClient(clientName); | ||
if (typeof provider.initialize === "function") { | ||
(_d = (_c = (_b = provider.initialize) == null ? void 0 : _b.call(provider, this._context)) == null ? void 0 : _c.then(() => { | ||
var _a2; | ||
clientEmitter.emit("PROVIDER_READY" /* Ready */, { clientName }); | ||
(_a2 = this._events) == null ? void 0 : _a2.emit("PROVIDER_READY" /* Ready */, { clientName }); | ||
})) == null ? void 0 : _d.catch((error) => { | ||
var _a2; | ||
clientEmitter.emit("PROVIDER_ERROR" /* Error */, { clientName, message: error.message }); | ||
(_a2 = this._events) == null ? void 0 : _a2.emit("PROVIDER_ERROR" /* Error */, { clientName, message: error.message }); | ||
}); | ||
} else { | ||
clientEmitter.emit("PROVIDER_READY" /* Ready */, { clientName }); | ||
(_e = this._events) == null ? void 0 : _e.emit("PROVIDER_READY" /* Ready */, { clientName }); | ||
} | ||
if (clientName) { | ||
this._clientProviders.set(clientName, provider); | ||
} else { | ||
this._defaultProvider = provider; | ||
} | ||
this.transferListeners(oldProvider, provider, clientName, clientEmitter); | ||
if (![...this._clientProviders.values(), this._defaultProvider].includes(oldProvider)) { | ||
(_f = oldProvider == null ? void 0 : oldProvider.onClose) == null ? void 0 : _f.call(oldProvider); | ||
} | ||
return this; | ||
} | ||
getProviderForClient(name) { | ||
var _a; | ||
if (!name) { | ||
return this._defaultProvider; | ||
} | ||
return (_a = this._clientProviders.get(name)) != null ? _a : this._defaultProvider; | ||
} | ||
getEventEmitterForClient(name) { | ||
const emitter = this._clientEvents.get(name); | ||
if (emitter) { | ||
return emitter; | ||
} | ||
const newEmitter = new OpenFeatureEventEmitter(() => this._logger); | ||
this._clientEvents.set(name, newEmitter); | ||
return newEmitter; | ||
} | ||
transferListeners(oldProvider, newProvider, clientName, clientEmitter) { | ||
var _a; | ||
(_a = oldProvider.events) == null ? void 0 : _a.removeAllHandlers(); | ||
Object.values(ProviderEvents).forEach( | ||
(eventType) => { | ||
var _a2; | ||
return (_a2 = newProvider.events) == null ? void 0 : _a2.addHandler(eventType, (details) => __async(this, null, function* () { | ||
clientEmitter.emit(eventType, __spreadProps(__spreadValues({}, details), { clientName })); | ||
this._events.emit(eventType, __spreadProps(__spreadValues({}, details), { clientName })); | ||
})); | ||
} | ||
); | ||
} | ||
close() { | ||
return __async(this, null, function* () { | ||
var _a, _b; | ||
try { | ||
yield (_b = (_a = this == null ? void 0 : this._defaultProvider) == null ? void 0 : _a.onClose) == null ? void 0 : _b.call(_a); | ||
} catch (err) { | ||
this.handleShutdownError(this._defaultProvider, err); | ||
} | ||
const providers = Array.from(this._clientProviders); | ||
yield Promise.all( | ||
providers.map((_0) => __async(this, [_0], function* ([, provider]) { | ||
var _a2; | ||
try { | ||
yield (_a2 = provider.onClose) == null ? void 0 : _a2.call(provider); | ||
} catch (err) { | ||
this.handleShutdownError(this._defaultProvider, err); | ||
} | ||
})) | ||
); | ||
}); | ||
} | ||
handleShutdownError(provider, err) { | ||
this._logger.error(`Error during shutdown of provider ${provider.metadata.name}: ${err}`); | ||
this._logger.error(err == null ? void 0 : err.stack); | ||
} | ||
setTransactionContextPropagator(transactionContextPropagator) { | ||
@@ -710,2 +917,5 @@ const baseMessage = "Invalid TransactionContextPropagator, will not be set: "; | ||
} | ||
get status() { | ||
return "NOT_READY" /* NOT_READY */; | ||
} | ||
resolveBooleanEvaluation(_, defaultValue) { | ||
@@ -732,18 +942,4 @@ return this.noOp(defaultValue); | ||
// src/types.ts | ||
var import_events = __toESM(require_events()); | ||
var ProviderEvents = /* @__PURE__ */ ((ProviderEvents2) => { | ||
ProviderEvents2["Ready"] = "PROVIDER_READY"; | ||
ProviderEvents2["Error"] = "PROVIDER_ERROR"; | ||
ProviderEvents2["ConfigurationChanged"] = "PROVIDER_CONFIGURATION_CHANGED"; | ||
ProviderEvents2["Stale"] = "PROVIDER_STALE"; | ||
return ProviderEvents2; | ||
})(ProviderEvents || {}); | ||
var ApiEvents = /* @__PURE__ */ ((ApiEvents2) => { | ||
ApiEvents2["ProviderChanged"] = "providerChanged"; | ||
return ApiEvents2; | ||
})(ApiEvents || {}); | ||
// src/open-feature.ts | ||
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/js.api"); | ||
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/web-sdk/api"); | ||
var _globalThis = globalThis; | ||
@@ -754,10 +950,7 @@ var OpenFeatureAPI = class extends OpenFeatureCommonAPI { | ||
super(); | ||
this._apiEvents = new import_events.EventEmitter(); | ||
this._providerReady = false; | ||
this._hooks = []; | ||
this._provider = NOOP_PROVIDER; | ||
this._defaultProvider = NOOP_PROVIDER; | ||
} | ||
/** | ||
* Gets a singleton instance of the OpenFeature API. | ||
* | ||
* @ignore | ||
@@ -775,10 +968,2 @@ * @returns {OpenFeatureAPI} OpenFeature API | ||
} | ||
/** | ||
* Get metadata about registered provider. | ||
* | ||
* @returns {ProviderMetadata} Provider Metadata | ||
*/ | ||
get providerMetadata() { | ||
return this._provider.metadata; | ||
} | ||
setLogger(logger) { | ||
@@ -804,38 +989,16 @@ this._logger = new SafeLogger(logger); | ||
this._context = context; | ||
yield (_b = (_a = this._provider) == null ? void 0 : _a.onContextChange) == null ? void 0 : _b.call(_a, oldContext, context); | ||
yield (_b = (_a = this._defaultProvider) == null ? void 0 : _a.onContextChange) == null ? void 0 : _b.call(_a, oldContext, context); | ||
}); | ||
} | ||
setProvider(provider) { | ||
var _a, _b, _c, _d, _e, _f, _g; | ||
if (this._provider !== provider) { | ||
const oldProvider = this._provider; | ||
this._provider = provider; | ||
this._providerReady = false; | ||
if (!this._provider.events) { | ||
this._provider.events = new import_events.EventEmitter(); | ||
} | ||
if (typeof ((_a = this._provider) == null ? void 0 : _a.initialize) === "function") { | ||
(_e = (_d = (_c = (_b = this._provider).initialize) == null ? void 0 : _c.call(_b, this._context)) == null ? void 0 : _d.then(() => { | ||
var _a2; | ||
this._providerReady = true; | ||
(_a2 = this._provider.events) == null ? void 0 : _a2.emit("PROVIDER_READY" /* Ready */); | ||
})) == null ? void 0 : _e.catch(() => { | ||
var _a2; | ||
(_a2 = this._provider.events) == null ? void 0 : _a2.emit("PROVIDER_ERROR" /* Error */); | ||
}); | ||
} else { | ||
this._providerReady = true; | ||
(_f = this._provider.events) == null ? void 0 : _f.emit("PROVIDER_READY" /* Ready */); | ||
} | ||
this._apiEvents.emit("providerChanged" /* ProviderChanged */); | ||
(_g = oldProvider == null ? void 0 : oldProvider.onClose) == null ? void 0 : _g.call(oldProvider); | ||
} | ||
return this; | ||
} | ||
close() { | ||
return __async(this, null, function* () { | ||
var _a, _b; | ||
yield (_b = (_a = this == null ? void 0 : this._provider) == null ? void 0 : _a.onClose) == null ? void 0 : _b.call(_a); | ||
}); | ||
} | ||
/** | ||
* 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} name The name of the client | ||
* @param {string} version The version of the client (only used for metadata) | ||
* @returns {Client} OpenFeature Client | ||
*/ | ||
getClient(name, version) { | ||
@@ -845,5 +1008,4 @@ return new OpenFeatureClient( | ||
// and so we don't have to make these public properties on the API class. | ||
() => this._provider, | ||
() => this._providerReady, | ||
() => this._apiEvents, | ||
() => this.getProviderForClient(name), | ||
() => this.getEventEmitterForClient(name), | ||
() => this._logger, | ||
@@ -858,23 +1020,29 @@ { name, version } | ||
var OpenFeatureClient = class { | ||
constructor(providerAccessor, providerReady, apiEvents, globalLogger, options) { | ||
constructor(providerAccessor, events, globalLogger, options) { | ||
this.providerAccessor = providerAccessor; | ||
this.providerReady = providerReady; | ||
this.events = events; | ||
this.globalLogger = globalLogger; | ||
this.options = options; | ||
this._hooks = []; | ||
this._handlerWrappers = []; | ||
this.metadata = { | ||
name: options.name, | ||
version: options.version | ||
} | ||
get metadata() { | ||
return { | ||
name: this.options.name, | ||
version: this.options.version, | ||
providerMetadata: this.providerAccessor().metadata | ||
}; | ||
this.attachListeners(); | ||
apiEvents().on("providerChanged" /* ProviderChanged */, () => { | ||
this.attachListeners(); | ||
}); | ||
} | ||
addHandler(eventType, handler) { | ||
this._handlerWrappers.push({ eventType, handler }); | ||
if (eventType === "PROVIDER_READY" /* Ready */ && this.providerReady()) { | ||
handler(); | ||
this.events().addHandler(eventType, handler); | ||
const providerReady = !this._provider.status || this._provider.status === "READY" /* READY */; | ||
if (eventType === "PROVIDER_READY" /* Ready */ && providerReady) { | ||
handler({ clientName: this.metadata.name }); | ||
} | ||
} | ||
removeHandler(notificationType, handler) { | ||
this.events().removeHandler(notificationType, handler); | ||
} | ||
getHandlers(eventType) { | ||
return this.events().getHandlers(eventType); | ||
} | ||
setLogger(logger) { | ||
@@ -899,9 +1067,3 @@ this._clientLogger = new SafeLogger(logger); | ||
getBooleanDetails(flagKey, defaultValue, options) { | ||
return this.evaluate( | ||
flagKey, | ||
this._provider.resolveBooleanEvaluation, | ||
defaultValue, | ||
"boolean", | ||
options | ||
); | ||
return this.evaluate(flagKey, this._provider.resolveBooleanEvaluation, defaultValue, "boolean", options); | ||
} | ||
@@ -941,2 +1103,3 @@ getStringValue(flagKey, defaultValue, options) { | ||
evaluate(flagKey, resolver, defaultValue, flagType, options = {}) { | ||
var _a; | ||
const allHooks = [ | ||
@@ -963,2 +1126,3 @@ ...OpenFeature.getHooks(), | ||
const evaluationDetails = __spreadProps(__spreadValues({}, resolution), { | ||
flagMetadata: Object.freeze((_a = resolution.flagMetadata) != null ? _a : {}), | ||
flagKey | ||
@@ -977,2 +1141,3 @@ }); | ||
reason: StandardResolutionReasons.ERROR, | ||
flagMetadata: Object.freeze({}), | ||
flagKey | ||
@@ -1032,11 +1197,3 @@ }; | ||
} | ||
attachListeners() { | ||
Object.values(ProviderEvents).forEach((eventType) => { | ||
var _a; | ||
return (_a = this._provider.events) == null ? void 0 : _a.on(eventType, () => { | ||
this._handlerWrappers.filter((wrapper) => wrapper.eventType === eventType).forEach((wrapper) => wrapper.handler()); | ||
}); | ||
}); | ||
} | ||
}; | ||
//# sourceMappingURL=index.js.map |
@@ -91,11 +91,11 @@ var __create = Object.create; | ||
}; | ||
function EventEmitter() { | ||
EventEmitter.init.call(this); | ||
function EventEmitter2() { | ||
EventEmitter2.init.call(this); | ||
} | ||
module.exports = EventEmitter; | ||
module.exports = EventEmitter2; | ||
module.exports.once = once; | ||
EventEmitter.EventEmitter = EventEmitter; | ||
EventEmitter.prototype._events = void 0; | ||
EventEmitter.prototype._eventsCount = 0; | ||
EventEmitter.prototype._maxListeners = void 0; | ||
EventEmitter2.EventEmitter = EventEmitter2; | ||
EventEmitter2.prototype._events = void 0; | ||
EventEmitter2.prototype._eventsCount = 0; | ||
EventEmitter2.prototype._maxListeners = void 0; | ||
var defaultMaxListeners = 10; | ||
@@ -107,3 +107,3 @@ function checkListener(listener) { | ||
} | ||
Object.defineProperty(EventEmitter, "defaultMaxListeners", { | ||
Object.defineProperty(EventEmitter2, "defaultMaxListeners", { | ||
enumerable: true, | ||
@@ -120,3 +120,3 @@ get: function() { | ||
}); | ||
EventEmitter.init = function() { | ||
EventEmitter2.init = function() { | ||
if (this._events === void 0 || this._events === Object.getPrototypeOf(this)._events) { | ||
@@ -128,3 +128,3 @@ this._events = /* @__PURE__ */ Object.create(null); | ||
}; | ||
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { | ||
EventEmitter2.prototype.setMaxListeners = function setMaxListeners(n) { | ||
if (typeof n !== "number" || n < 0 || NumberIsNaN(n)) { | ||
@@ -138,9 +138,9 @@ throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + "."); | ||
if (that._maxListeners === void 0) | ||
return EventEmitter.defaultMaxListeners; | ||
return EventEmitter2.defaultMaxListeners; | ||
return that._maxListeners; | ||
} | ||
EventEmitter.prototype.getMaxListeners = function getMaxListeners() { | ||
EventEmitter2.prototype.getMaxListeners = function getMaxListeners() { | ||
return _getMaxListeners(this); | ||
}; | ||
EventEmitter.prototype.emit = function emit(type) { | ||
EventEmitter2.prototype.emit = function emit(type) { | ||
var args = []; | ||
@@ -223,7 +223,7 @@ for (var i = 1; i < arguments.length; i++) | ||
} | ||
EventEmitter.prototype.addListener = function addListener(type, listener) { | ||
EventEmitter2.prototype.addListener = function addListener(type, listener) { | ||
return _addListener(this, type, listener, false); | ||
}; | ||
EventEmitter.prototype.on = EventEmitter.prototype.addListener; | ||
EventEmitter.prototype.prependListener = function prependListener(type, listener) { | ||
EventEmitter2.prototype.on = EventEmitter2.prototype.addListener; | ||
EventEmitter2.prototype.prependListener = function prependListener(type, listener) { | ||
return _addListener(this, type, listener, true); | ||
@@ -247,3 +247,3 @@ }; | ||
} | ||
EventEmitter.prototype.once = function once2(type, listener) { | ||
EventEmitter2.prototype.once = function once2(type, listener) { | ||
checkListener(listener); | ||
@@ -253,3 +253,3 @@ this.on(type, _onceWrap(this, type, listener)); | ||
}; | ||
EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) { | ||
EventEmitter2.prototype.prependOnceListener = function prependOnceListener(type, listener) { | ||
checkListener(listener); | ||
@@ -259,3 +259,3 @@ this.prependListener(type, _onceWrap(this, type, listener)); | ||
}; | ||
EventEmitter.prototype.removeListener = function removeListener(type, listener) { | ||
EventEmitter2.prototype.removeListener = function removeListener(type, listener) { | ||
var list, events, position, i, originalListener; | ||
@@ -300,4 +300,4 @@ checkListener(listener); | ||
}; | ||
EventEmitter.prototype.off = EventEmitter.prototype.removeListener; | ||
EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { | ||
EventEmitter2.prototype.off = EventEmitter2.prototype.removeListener; | ||
EventEmitter2.prototype.removeAllListeners = function removeAllListeners(type) { | ||
var listeners, events, i; | ||
@@ -354,9 +354,9 @@ events = this._events; | ||
} | ||
EventEmitter.prototype.listeners = function listeners(type) { | ||
EventEmitter2.prototype.listeners = function listeners(type) { | ||
return _listeners(this, type, true); | ||
}; | ||
EventEmitter.prototype.rawListeners = function rawListeners(type) { | ||
EventEmitter2.prototype.rawListeners = function rawListeners(type) { | ||
return _listeners(this, type, false); | ||
}; | ||
EventEmitter.listenerCount = function(emitter, type) { | ||
EventEmitter2.listenerCount = function(emitter, type) { | ||
if (typeof emitter.listenerCount === "function") { | ||
@@ -368,3 +368,3 @@ return emitter.listenerCount(type); | ||
}; | ||
EventEmitter.prototype.listenerCount = listenerCount; | ||
EventEmitter2.prototype.listenerCount = listenerCount; | ||
function listenerCount(type) { | ||
@@ -382,3 +382,3 @@ var events = this._events; | ||
} | ||
EventEmitter.prototype.eventNames = function eventNames() { | ||
EventEmitter2.prototype.eventNames = function eventNames() { | ||
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; | ||
@@ -464,3 +464,3 @@ }; | ||
/** | ||
* The resolved value was configured statically, or otherwise fell back to a pre-configured value. | ||
* The resolved value was configured statically, or otherwise fell back to a pre-configured value. | ||
*/ | ||
@@ -497,2 +497,8 @@ DEFAULT: "DEFAULT", | ||
})(ErrorCode || {}); | ||
var ProviderStatus = /* @__PURE__ */ ((ProviderStatus2) => { | ||
ProviderStatus2["NOT_READY"] = "NOT_READY"; | ||
ProviderStatus2["READY"] = "READY"; | ||
ProviderStatus2["ERROR"] = "ERROR"; | ||
return ProviderStatus2; | ||
})(ProviderStatus || {}); | ||
@@ -630,2 +636,72 @@ // ../shared/src/errors/open-feature-error-abstract.ts | ||
// ../shared/src/events.ts | ||
var import_events = __toESM(require_events()); | ||
var ProviderEvents = /* @__PURE__ */ ((ProviderEvents2) => { | ||
ProviderEvents2["Ready"] = "PROVIDER_READY"; | ||
ProviderEvents2["Error"] = "PROVIDER_ERROR"; | ||
ProviderEvents2["ConfigurationChanged"] = "PROVIDER_CONFIGURATION_CHANGED"; | ||
ProviderEvents2["Stale"] = "PROVIDER_STALE"; | ||
return ProviderEvents2; | ||
})(ProviderEvents || {}); | ||
var OpenFeatureEventEmitter = class { | ||
constructor(globalLogger) { | ||
this.globalLogger = globalLogger; | ||
this._handlers = /* @__PURE__ */ new WeakMap(); | ||
this.eventEmitter = new import_events.default({ captureRejections: true }); | ||
this.eventEmitter.on("error", (err) => { | ||
var _a; | ||
(_a = this._logger) == null ? void 0 : _a.error("Error running event handler:", err); | ||
}); | ||
} | ||
emit(eventType, context) { | ||
this.eventEmitter.emit(eventType, context); | ||
} | ||
addHandler(eventType, handler) { | ||
const asyncHandler = (context) => __async(this, null, function* () { | ||
yield handler(context); | ||
}); | ||
this._handlers.set(handler, asyncHandler); | ||
this.eventEmitter.on(eventType, asyncHandler); | ||
} | ||
removeHandler(eventType, handler) { | ||
const asyncHandler = this._handlers.get(handler); | ||
if (!asyncHandler) { | ||
return; | ||
} | ||
this.eventEmitter.removeListener(eventType, asyncHandler); | ||
} | ||
removeAllHandlers(eventType) { | ||
if (eventType) { | ||
this.eventEmitter.removeAllListeners(eventType); | ||
} else { | ||
this.eventEmitter.removeAllListeners(); | ||
} | ||
} | ||
getHandlers(eventType) { | ||
return this.eventEmitter.listeners(eventType); | ||
} | ||
setLogger(logger) { | ||
this._eventLogger = new SafeLogger(logger); | ||
return this; | ||
} | ||
get _logger() { | ||
var _a; | ||
return this._eventLogger || ((_a = this.globalLogger) == null ? void 0 : _a.call(this)); | ||
} | ||
}; | ||
// ../shared/src/type-guards.ts | ||
function isString(value) { | ||
return typeof value === "string"; | ||
} | ||
function stringOrUndefined(value) { | ||
return isString(value) ? value : void 0; | ||
} | ||
function isObject(value) { | ||
return typeof value === "object"; | ||
} | ||
function objectOrUndefined(value) { | ||
return isObject(value) ? value : void 0; | ||
} | ||
// ../shared/src/open-feature.ts | ||
@@ -637,6 +713,137 @@ var OpenFeatureCommonAPI = class { | ||
this._logger = new DefaultLogger(); | ||
this._events = new OpenFeatureEventEmitter(() => this._logger); | ||
this._clientProviders = /* @__PURE__ */ new Map(); | ||
this._clientEvents = /* @__PURE__ */ new Map(); | ||
} | ||
setLogger(logger) { | ||
this._logger = new SafeLogger(logger); | ||
return this; | ||
} | ||
/** | ||
* Get metadata about registered provider. | ||
* @returns {ProviderMetadata} Provider Metadata | ||
*/ | ||
get providerMetadata() { | ||
return this._defaultProvider.metadata; | ||
} | ||
getContext() { | ||
return this._context; | ||
} | ||
/** | ||
* Adds a handler for the given provider event type. | ||
* The handlers are called in the order they have been added. | ||
* When changing the provider, the currently attached handlers will listen to the events of the new provider. | ||
* @param {ProviderEvents} eventType The provider event type to listen to | ||
* @param {EventHandler} handler The handler to run on occurrence of the event type | ||
*/ | ||
addHandler(eventType, handler) { | ||
this._events.addHandler(eventType, handler); | ||
} | ||
/** | ||
* Removes a handler for the given provider event type. | ||
* @param {ProviderEvents} eventType The provider event type to remove the listener for | ||
* @param {EventHandler} handler The handler to remove for the provider event type | ||
*/ | ||
removeHandler(eventType, handler) { | ||
this._events.removeHandler(eventType, handler); | ||
} | ||
/** | ||
* Gets the current handlers for the given provider event type. | ||
* @param {ProviderEvents} eventType The provider event type to get the current handlers for | ||
* @returns {EventHandler[]} The handlers currently attached to the given provider event type | ||
*/ | ||
getHandlers(eventType) { | ||
return this._events.getHandlers(eventType); | ||
} | ||
setProvider(clientOrProvider, providerOrUndefined) { | ||
var _a, _b, _c, _d, _e, _f; | ||
const clientName = stringOrUndefined(clientOrProvider); | ||
const provider = (_a = objectOrUndefined(clientOrProvider)) != null ? _a : objectOrUndefined(providerOrUndefined); | ||
if (!provider) { | ||
return this; | ||
} | ||
const oldProvider = this.getProviderForClient(clientName); | ||
if (oldProvider === provider) { | ||
return this; | ||
} | ||
const clientEmitter = this.getEventEmitterForClient(clientName); | ||
if (typeof provider.initialize === "function") { | ||
(_d = (_c = (_b = provider.initialize) == null ? void 0 : _b.call(provider, this._context)) == null ? void 0 : _c.then(() => { | ||
var _a2; | ||
clientEmitter.emit("PROVIDER_READY" /* Ready */, { clientName }); | ||
(_a2 = this._events) == null ? void 0 : _a2.emit("PROVIDER_READY" /* Ready */, { clientName }); | ||
})) == null ? void 0 : _d.catch((error) => { | ||
var _a2; | ||
clientEmitter.emit("PROVIDER_ERROR" /* Error */, { clientName, message: error.message }); | ||
(_a2 = this._events) == null ? void 0 : _a2.emit("PROVIDER_ERROR" /* Error */, { clientName, message: error.message }); | ||
}); | ||
} else { | ||
clientEmitter.emit("PROVIDER_READY" /* Ready */, { clientName }); | ||
(_e = this._events) == null ? void 0 : _e.emit("PROVIDER_READY" /* Ready */, { clientName }); | ||
} | ||
if (clientName) { | ||
this._clientProviders.set(clientName, provider); | ||
} else { | ||
this._defaultProvider = provider; | ||
} | ||
this.transferListeners(oldProvider, provider, clientName, clientEmitter); | ||
if (![...this._clientProviders.values(), this._defaultProvider].includes(oldProvider)) { | ||
(_f = oldProvider == null ? void 0 : oldProvider.onClose) == null ? void 0 : _f.call(oldProvider); | ||
} | ||
return this; | ||
} | ||
getProviderForClient(name) { | ||
var _a; | ||
if (!name) { | ||
return this._defaultProvider; | ||
} | ||
return (_a = this._clientProviders.get(name)) != null ? _a : this._defaultProvider; | ||
} | ||
getEventEmitterForClient(name) { | ||
const emitter = this._clientEvents.get(name); | ||
if (emitter) { | ||
return emitter; | ||
} | ||
const newEmitter = new OpenFeatureEventEmitter(() => this._logger); | ||
this._clientEvents.set(name, newEmitter); | ||
return newEmitter; | ||
} | ||
transferListeners(oldProvider, newProvider, clientName, clientEmitter) { | ||
var _a; | ||
(_a = oldProvider.events) == null ? void 0 : _a.removeAllHandlers(); | ||
Object.values(ProviderEvents).forEach( | ||
(eventType) => { | ||
var _a2; | ||
return (_a2 = newProvider.events) == null ? void 0 : _a2.addHandler(eventType, (details) => __async(this, null, function* () { | ||
clientEmitter.emit(eventType, __spreadProps(__spreadValues({}, details), { clientName })); | ||
this._events.emit(eventType, __spreadProps(__spreadValues({}, details), { clientName })); | ||
})); | ||
} | ||
); | ||
} | ||
close() { | ||
return __async(this, null, function* () { | ||
var _a, _b; | ||
try { | ||
yield (_b = (_a = this == null ? void 0 : this._defaultProvider) == null ? void 0 : _a.onClose) == null ? void 0 : _b.call(_a); | ||
} catch (err) { | ||
this.handleShutdownError(this._defaultProvider, err); | ||
} | ||
const providers = Array.from(this._clientProviders); | ||
yield Promise.all( | ||
providers.map((_0) => __async(this, [_0], function* ([, provider]) { | ||
var _a2; | ||
try { | ||
yield (_a2 = provider.onClose) == null ? void 0 : _a2.call(provider); | ||
} catch (err) { | ||
this.handleShutdownError(this._defaultProvider, err); | ||
} | ||
})) | ||
); | ||
}); | ||
} | ||
handleShutdownError(provider, err) { | ||
this._logger.error(`Error during shutdown of provider ${provider.metadata.name}: ${err}`); | ||
this._logger.error(err == null ? void 0 : err.stack); | ||
} | ||
setTransactionContextPropagator(transactionContextPropagator) { | ||
@@ -676,2 +883,5 @@ const baseMessage = "Invalid TransactionContextPropagator, will not be set: "; | ||
} | ||
get status() { | ||
return "NOT_READY" /* NOT_READY */; | ||
} | ||
resolveBooleanEvaluation(_, defaultValue) { | ||
@@ -698,18 +908,4 @@ return this.noOp(defaultValue); | ||
// src/types.ts | ||
var import_events = __toESM(require_events()); | ||
var ProviderEvents = /* @__PURE__ */ ((ProviderEvents2) => { | ||
ProviderEvents2["Ready"] = "PROVIDER_READY"; | ||
ProviderEvents2["Error"] = "PROVIDER_ERROR"; | ||
ProviderEvents2["ConfigurationChanged"] = "PROVIDER_CONFIGURATION_CHANGED"; | ||
ProviderEvents2["Stale"] = "PROVIDER_STALE"; | ||
return ProviderEvents2; | ||
})(ProviderEvents || {}); | ||
var ApiEvents = /* @__PURE__ */ ((ApiEvents2) => { | ||
ApiEvents2["ProviderChanged"] = "providerChanged"; | ||
return ApiEvents2; | ||
})(ApiEvents || {}); | ||
// src/open-feature.ts | ||
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/js.api"); | ||
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/web-sdk/api"); | ||
var _globalThis = globalThis; | ||
@@ -720,10 +916,7 @@ var OpenFeatureAPI = class extends OpenFeatureCommonAPI { | ||
super(); | ||
this._apiEvents = new import_events.EventEmitter(); | ||
this._providerReady = false; | ||
this._hooks = []; | ||
this._provider = NOOP_PROVIDER; | ||
this._defaultProvider = NOOP_PROVIDER; | ||
} | ||
/** | ||
* Gets a singleton instance of the OpenFeature API. | ||
* | ||
* @ignore | ||
@@ -741,10 +934,2 @@ * @returns {OpenFeatureAPI} OpenFeature API | ||
} | ||
/** | ||
* Get metadata about registered provider. | ||
* | ||
* @returns {ProviderMetadata} Provider Metadata | ||
*/ | ||
get providerMetadata() { | ||
return this._provider.metadata; | ||
} | ||
setLogger(logger) { | ||
@@ -770,38 +955,16 @@ this._logger = new SafeLogger(logger); | ||
this._context = context; | ||
yield (_b = (_a = this._provider) == null ? void 0 : _a.onContextChange) == null ? void 0 : _b.call(_a, oldContext, context); | ||
yield (_b = (_a = this._defaultProvider) == null ? void 0 : _a.onContextChange) == null ? void 0 : _b.call(_a, oldContext, context); | ||
}); | ||
} | ||
setProvider(provider) { | ||
var _a, _b, _c, _d, _e, _f, _g; | ||
if (this._provider !== provider) { | ||
const oldProvider = this._provider; | ||
this._provider = provider; | ||
this._providerReady = false; | ||
if (!this._provider.events) { | ||
this._provider.events = new import_events.EventEmitter(); | ||
} | ||
if (typeof ((_a = this._provider) == null ? void 0 : _a.initialize) === "function") { | ||
(_e = (_d = (_c = (_b = this._provider).initialize) == null ? void 0 : _c.call(_b, this._context)) == null ? void 0 : _d.then(() => { | ||
var _a2; | ||
this._providerReady = true; | ||
(_a2 = this._provider.events) == null ? void 0 : _a2.emit("PROVIDER_READY" /* Ready */); | ||
})) == null ? void 0 : _e.catch(() => { | ||
var _a2; | ||
(_a2 = this._provider.events) == null ? void 0 : _a2.emit("PROVIDER_ERROR" /* Error */); | ||
}); | ||
} else { | ||
this._providerReady = true; | ||
(_f = this._provider.events) == null ? void 0 : _f.emit("PROVIDER_READY" /* Ready */); | ||
} | ||
this._apiEvents.emit("providerChanged" /* ProviderChanged */); | ||
(_g = oldProvider == null ? void 0 : oldProvider.onClose) == null ? void 0 : _g.call(oldProvider); | ||
} | ||
return this; | ||
} | ||
close() { | ||
return __async(this, null, function* () { | ||
var _a, _b; | ||
yield (_b = (_a = this == null ? void 0 : this._provider) == null ? void 0 : _a.onClose) == null ? void 0 : _b.call(_a); | ||
}); | ||
} | ||
/** | ||
* 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} name The name of the client | ||
* @param {string} version The version of the client (only used for metadata) | ||
* @returns {Client} OpenFeature Client | ||
*/ | ||
getClient(name, version) { | ||
@@ -811,5 +974,4 @@ return new OpenFeatureClient( | ||
// and so we don't have to make these public properties on the API class. | ||
() => this._provider, | ||
() => this._providerReady, | ||
() => this._apiEvents, | ||
() => this.getProviderForClient(name), | ||
() => this.getEventEmitterForClient(name), | ||
() => this._logger, | ||
@@ -824,23 +986,29 @@ { name, version } | ||
var OpenFeatureClient = class { | ||
constructor(providerAccessor, providerReady, apiEvents, globalLogger, options) { | ||
constructor(providerAccessor, events, globalLogger, options) { | ||
this.providerAccessor = providerAccessor; | ||
this.providerReady = providerReady; | ||
this.events = events; | ||
this.globalLogger = globalLogger; | ||
this.options = options; | ||
this._hooks = []; | ||
this._handlerWrappers = []; | ||
this.metadata = { | ||
name: options.name, | ||
version: options.version | ||
} | ||
get metadata() { | ||
return { | ||
name: this.options.name, | ||
version: this.options.version, | ||
providerMetadata: this.providerAccessor().metadata | ||
}; | ||
this.attachListeners(); | ||
apiEvents().on("providerChanged" /* ProviderChanged */, () => { | ||
this.attachListeners(); | ||
}); | ||
} | ||
addHandler(eventType, handler) { | ||
this._handlerWrappers.push({ eventType, handler }); | ||
if (eventType === "PROVIDER_READY" /* Ready */ && this.providerReady()) { | ||
handler(); | ||
this.events().addHandler(eventType, handler); | ||
const providerReady = !this._provider.status || this._provider.status === "READY" /* READY */; | ||
if (eventType === "PROVIDER_READY" /* Ready */ && providerReady) { | ||
handler({ clientName: this.metadata.name }); | ||
} | ||
} | ||
removeHandler(notificationType, handler) { | ||
this.events().removeHandler(notificationType, handler); | ||
} | ||
getHandlers(eventType) { | ||
return this.events().getHandlers(eventType); | ||
} | ||
setLogger(logger) { | ||
@@ -865,9 +1033,3 @@ this._clientLogger = new SafeLogger(logger); | ||
getBooleanDetails(flagKey, defaultValue, options) { | ||
return this.evaluate( | ||
flagKey, | ||
this._provider.resolveBooleanEvaluation, | ||
defaultValue, | ||
"boolean", | ||
options | ||
); | ||
return this.evaluate(flagKey, this._provider.resolveBooleanEvaluation, defaultValue, "boolean", options); | ||
} | ||
@@ -907,2 +1069,3 @@ getStringValue(flagKey, defaultValue, options) { | ||
evaluate(flagKey, resolver, defaultValue, flagType, options = {}) { | ||
var _a; | ||
const allHooks = [ | ||
@@ -929,2 +1092,3 @@ ...OpenFeature.getHooks(), | ||
const evaluationDetails = __spreadProps(__spreadValues({}, resolution), { | ||
flagMetadata: Object.freeze((_a = resolution.flagMetadata) != null ? _a : {}), | ||
flagKey | ||
@@ -943,2 +1107,3 @@ }); | ||
reason: StandardResolutionReasons.ERROR, | ||
flagMetadata: Object.freeze({}), | ||
flagKey | ||
@@ -998,14 +1163,4 @@ }; | ||
} | ||
attachListeners() { | ||
Object.values(ProviderEvents).forEach((eventType) => { | ||
var _a; | ||
return (_a = this._provider.events) == null ? void 0 : _a.on(eventType, () => { | ||
this._handlerWrappers.filter((wrapper) => wrapper.eventType === eventType).forEach((wrapper) => wrapper.handler()); | ||
}); | ||
}); | ||
} | ||
}; | ||
var export_OpenFeatureEventEmitter = import_events.EventEmitter; | ||
export { | ||
ApiEvents, | ||
DefaultLogger, | ||
@@ -1023,5 +1178,6 @@ ErrorCode, | ||
OpenFeatureError, | ||
export_OpenFeatureEventEmitter as OpenFeatureEventEmitter, | ||
OpenFeatureEventEmitter, | ||
ParseError, | ||
ProviderEvents, | ||
ProviderStatus, | ||
SafeLogger, | ||
@@ -1028,0 +1184,0 @@ StandardResolutionReasons, |
@@ -0,1 +1,65 @@ | ||
type EventMetadata = { | ||
[key: string]: string | boolean | number; | ||
}; | ||
type EventDetails = { | ||
clientName?: string; | ||
message?: string; | ||
flagsChanged?: string[]; | ||
metadata?: EventMetadata; | ||
}; | ||
type EventHandler = (eventDetails?: EventDetails) => Promise<unknown> | unknown; | ||
interface Eventing { | ||
/** | ||
* Adds a handler for the given provider event type. | ||
* The handlers are called in the order they have been added. | ||
* @param {ProviderEvents} eventType The provider event type to listen to | ||
* @param {EventHandler} handler The handler to run on occurrence of the event type | ||
*/ | ||
addHandler(eventType: ProviderEvents, handler: EventHandler): void; | ||
/** | ||
* Removes a handler for the given provider event type. | ||
* @param {ProviderEvents} eventType The provider event type to remove the listener for | ||
* @param {EventHandler} handler The handler to remove for the provider event type | ||
*/ | ||
removeHandler(eventType: ProviderEvents, handler: EventHandler): void; | ||
/** | ||
* Gets the current handlers for the given provider event type. | ||
* @param {ProviderEvents} eventType The provider event type to get the current handlers for | ||
* @returns {EventHandler[]} The handlers currently attached to the given provider event type | ||
*/ | ||
getHandlers(eventType: ProviderEvents): EventHandler[]; | ||
} | ||
declare enum ProviderEvents { | ||
/** | ||
* The provider is ready to evaluate flags. | ||
*/ | ||
Ready = "PROVIDER_READY", | ||
/** | ||
* The provider is in an error state. | ||
*/ | ||
Error = "PROVIDER_ERROR", | ||
/** | ||
* The flag configuration in the source-of-truth has changed. | ||
*/ | ||
ConfigurationChanged = "PROVIDER_CONFIGURATION_CHANGED", | ||
/** | ||
* The provider's cached state is no longer valid and may not be up-to-date with the source of truth. | ||
*/ | ||
Stale = "PROVIDER_STALE" | ||
} | ||
declare class OpenFeatureEventEmitter implements ManageLogger<OpenFeatureEventEmitter> { | ||
private readonly globalLogger?; | ||
private readonly _handlers; | ||
private readonly eventEmitter; | ||
private _eventLogger?; | ||
constructor(globalLogger?: (() => Logger) | undefined); | ||
emit(eventType: ProviderEvents, context?: EventDetails): void; | ||
addHandler(eventType: ProviderEvents, handler: EventHandler): void; | ||
removeHandler(eventType: ProviderEvents, handler: EventHandler): void; | ||
removeAllHandlers(eventType?: ProviderEvents): void; | ||
getHandlers(eventType: ProviderEvents): EventHandler[]; | ||
setLogger(logger: Logger): this; | ||
private get _logger(); | ||
} | ||
type PrimitiveValue = null | boolean | string | number; | ||
@@ -49,3 +113,3 @@ type JsonObject = { | ||
/** | ||
* The resolved value was configured statically, or otherwise fell back to a pre-configured value. | ||
* The resolved value was configured statically, or otherwise fell back to a pre-configured value. | ||
*/ | ||
@@ -103,5 +167,12 @@ readonly DEFAULT: "DEFAULT"; | ||
type ResolutionReason = keyof typeof StandardResolutionReasons | (string & Record<never, never>); | ||
/** | ||
* A structure which supports definition of arbitrary properties, with keys of type string, and values of type boolean, string, or number. | ||
* | ||
* This structure is populated by a provider for use by an Application Author (via the Evaluation API) or an Application Integrator (via hooks). | ||
*/ | ||
type FlagMetadata = Record<string, string | number | boolean>; | ||
type ResolutionDetails<U> = { | ||
value: U; | ||
variant?: string; | ||
flagMetadata?: FlagMetadata; | ||
reason?: ResolutionReason; | ||
@@ -113,2 +184,3 @@ errorCode?: ErrorCode; | ||
flagKey: string; | ||
flagMetadata: Readonly<FlagMetadata>; | ||
} & ResolutionDetails<T>; | ||
@@ -118,3 +190,2 @@ interface ManageContext<T> { | ||
* Access the evaluation context set on the receiver. | ||
* | ||
* @returns {EvaluationContext} Evaluation context | ||
@@ -126,3 +197,2 @@ */ | ||
* on this receiver. | ||
* | ||
* @template T The type of the receiver | ||
@@ -140,3 +210,2 @@ * @param {EvaluationContext} context Evaluation context | ||
* unless overridden in a particular client. | ||
* | ||
* @template T The type of the receiver | ||
@@ -154,2 +223,3 @@ * @param {Logger} logger The logger to be used | ||
readonly name?: string; | ||
readonly providerMetadata: ProviderMetadata; | ||
} | ||
@@ -185,3 +255,2 @@ interface ProviderMetadata extends Metadata { | ||
* transaction. | ||
* | ||
* @experimental | ||
@@ -201,3 +270,2 @@ * @template T The type of the receiver | ||
* context propagator. | ||
* | ||
* @experimental | ||
@@ -212,3 +280,2 @@ * @returns {TransactionContext} The current transaction context | ||
* Sets the transaction context using the registered transaction context propagator. | ||
* | ||
* @experimental | ||
@@ -222,4 +289,25 @@ * @template R The return value of the callback | ||
} | ||
declare enum ProviderStatus { | ||
NOT_READY = "NOT_READY", | ||
READY = "READY", | ||
ERROR = "ERROR" | ||
} | ||
interface CommonProvider { | ||
readonly metadata: ProviderMetadata; | ||
readonly status?: ProviderStatus; | ||
/** | ||
* An event emitter for ProviderEvents. | ||
* @see ProviderEvents | ||
*/ | ||
events?: OpenFeatureEventEmitter; | ||
onClose?(): Promise<void>; | ||
/** | ||
* A handler function used to setup the provider. | ||
* Called by the SDK after the provider is set. | ||
* When the returned promise resolves, the SDK fires the ProviderEvents.Ready event. | ||
* If the returned promise rejects, the SDK fires the ProviderEvents.Error event. | ||
* Use this function to perform any context-dependent setup within the provider. | ||
* @param context | ||
*/ | ||
initialize?(context?: EvaluationContext): Promise<void>; | ||
} | ||
@@ -285,79 +373,66 @@ | ||
declare abstract class OpenFeatureCommonAPI { | ||
declare abstract class OpenFeatureCommonAPI<P extends CommonProvider = CommonProvider> implements Eventing { | ||
protected _transactionContextPropagator: TransactionContextPropagator; | ||
protected _context: EvaluationContext; | ||
protected _logger: Logger; | ||
protected abstract _defaultProvider: P; | ||
private readonly _events; | ||
protected _clientProviders: Map<string, P>; | ||
protected _clientEvents: Map<string | undefined, OpenFeatureEventEmitter>; | ||
abstract clearHooks(): this; | ||
abstract setLogger(logger: Logger): this; | ||
setLogger(logger: Logger): this; | ||
/** | ||
* Get metadata about registered provider. | ||
* @returns {ProviderMetadata} Provider Metadata | ||
*/ | ||
get providerMetadata(): ProviderMetadata; | ||
getContext(): EvaluationContext; | ||
setTransactionContextPropagator(transactionContextPropagator: TransactionContextPropagator): OpenFeatureCommonAPI; | ||
setTransactionContext<R>(transactionContext: TransactionContext, callback: (...args: unknown[]) => R, ...args: unknown[]): void; | ||
getTransactionContext(): TransactionContext; | ||
} | ||
// Type definitions for events 3.0 | ||
// Project: https://github.com/Gozala/events | ||
// Definitions by: Yasunori Ohoka <https://github.com/yasupeke> | ||
// Shenwei Wang <https://github.com/weareoutman> | ||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped | ||
type Listener = (...args: any[]) => void; | ||
declare class EventEmitter { | ||
static listenerCount(emitter: EventEmitter, type: string | number): number; | ||
static defaultMaxListeners: number; | ||
eventNames(): Array<string | number>; | ||
setMaxListeners(n: number): this; | ||
getMaxListeners(): number; | ||
emit(type: string | number, ...args: any[]): boolean; | ||
addListener(type: string | number, listener: Listener): this; | ||
on(type: string | number, listener: Listener): this; | ||
once(type: string | number, listener: Listener): this; | ||
prependListener(type: string | number, listener: Listener): this; | ||
prependOnceListener(type: string | number, listener: Listener): this; | ||
removeListener(type: string | number, listener: Listener): this; | ||
off(type: string | number, listener: Listener): this; | ||
removeAllListeners(type?: string | number): this; | ||
listeners(type: string | number): Listener[]; | ||
listenerCount(type: string | number): number; | ||
rawListeners(type: string | number): Listener[]; | ||
} | ||
declare enum ProviderEvents { | ||
/** | ||
* The provider is ready to evaluate flags. | ||
* Adds a handler for the given provider event type. | ||
* The handlers are called in the order they have been added. | ||
* When changing the provider, the currently attached handlers will listen to the events of the new provider. | ||
* @param {ProviderEvents} eventType The provider event type to listen to | ||
* @param {EventHandler} handler The handler to run on occurrence of the event type | ||
*/ | ||
Ready = "PROVIDER_READY", | ||
addHandler(eventType: ProviderEvents, handler: EventHandler): void; | ||
/** | ||
* The provider is in an error state. | ||
* Removes a handler for the given provider event type. | ||
* @param {ProviderEvents} eventType The provider event type to remove the listener for | ||
* @param {EventHandler} handler The handler to remove for the provider event type | ||
*/ | ||
Error = "PROVIDER_ERROR", | ||
removeHandler(eventType: ProviderEvents, handler: EventHandler): void; | ||
/** | ||
* The flag configuration in the source-of-truth has changed. | ||
* Gets the current handlers for the given provider event type. | ||
* @param {ProviderEvents} eventType The provider event type to get the current handlers for | ||
* @returns {EventHandler[]} The handlers currently attached to the given provider event type | ||
*/ | ||
ConfigurationChanged = "PROVIDER_CONFIGURATION_CHANGED", | ||
getHandlers(eventType: ProviderEvents): EventHandler[]; | ||
/** | ||
* The provider's cached state is not longer valid and may not be up-to-date with the source of truth. | ||
* Sets the default provider for flag evaluations. | ||
* This provider will be used by unnamed clients and named clients to which no provider is bound. | ||
* Setting a provider supersedes the current provider used in new and existing clients without a name. | ||
* @template P | ||
* @param {P} provider The provider responsible for flag evaluations. | ||
* @returns {OpenFeatureCommonAPI} OpenFeature API | ||
*/ | ||
Stale = "PROVIDER_STALE" | ||
setProvider(provider: P): this; | ||
/** | ||
* Sets the provider that OpenFeature will use for flag evaluations of providers with the given name. | ||
* Setting a provider supersedes the current provider used in new and existing clients with that name. | ||
* @template P | ||
* @param {string} clientName The name to identify the client | ||
* @param {P} provider The provider responsible for flag evaluations. | ||
* @returns {this} OpenFeature API | ||
*/ | ||
setProvider(clientName: string, provider: P): this; | ||
protected getProviderForClient(name?: string): P; | ||
protected getEventEmitterForClient(name?: string): OpenFeatureEventEmitter; | ||
private transferListeners; | ||
close(): Promise<void>; | ||
private handleShutdownError; | ||
setTransactionContextPropagator(transactionContextPropagator: TransactionContextPropagator): OpenFeatureCommonAPI<P>; | ||
setTransactionContext<R>(transactionContext: TransactionContext, callback: (...args: unknown[]) => R, ...args: unknown[]): void; | ||
getTransactionContext(): TransactionContext; | ||
} | ||
interface EventData { | ||
flagKeysChanged?: string[]; | ||
changeMetadata?: { | ||
[key: string]: boolean | string; | ||
}; | ||
} | ||
declare enum ApiEvents { | ||
ProviderChanged = "providerChanged" | ||
} | ||
interface Eventing { | ||
addHandler(notificationType: string, handler: Handler): void; | ||
} | ||
type EventContext = { | ||
notificationType: string; | ||
[key: string]: unknown; | ||
}; | ||
type Handler = (eventContext?: EventContext) => void; | ||
type EventCallbackMessage = (eventContext: EventContext) => void; | ||
/** | ||
@@ -378,11 +453,4 @@ * Interface that providers must implement to resolve flag values for their particular | ||
/** | ||
* An event emitter for ProviderEvents. | ||
* | ||
* @see ProviderEvents | ||
*/ | ||
events?: EventEmitter; | ||
/** | ||
* A handler function to reconcile changes when the static context. | ||
* Called by the SDK when the context is changed. | ||
* | ||
* @param oldContext | ||
@@ -392,14 +460,3 @@ * @param newContext | ||
onContextChange?(oldContext: EvaluationContext, newContext: EvaluationContext): Promise<void>; | ||
onClose?(): Promise<void>; | ||
/** | ||
* A handler function used to setup the provider. | ||
* Called by the SDK after the provider is set. | ||
* When the returned promise resolves, the SDK fires the ProviderEvents.Ready event. | ||
* If the returned promise rejects, the SDK fires the ProviderEvents.Error event. | ||
* Use this function to perform any context-dependent setup within the provider. | ||
* | ||
* @param context | ||
*/ | ||
initialize?(context: EvaluationContext): Promise<void>; | ||
/** | ||
* Resolve a boolean flag and its evaluation details. | ||
@@ -425,3 +482,2 @@ */ | ||
* If an EvaluationContext is returned, it will be merged with the pre-existing EvaluationContext. | ||
* | ||
* @param hookContext | ||
@@ -433,3 +489,2 @@ * @param hookHints | ||
* Runs after flag values are successfully resolved from the provider. | ||
* | ||
* @param hookContext | ||
@@ -442,3 +497,2 @@ * @param evaluationDetails | ||
* Runs in the event of an unhandled error or promise rejection during flag resolution, or any attached hooks. | ||
* | ||
* @param hookContext | ||
@@ -452,3 +506,2 @@ * @param error | ||
* Errors thrown here are unhandled by the client and will surface in application code. | ||
* | ||
* @param hookContext | ||
@@ -466,3 +519,2 @@ * @param hookHints | ||
* Hooks registered on the client run with all evaluations on that client. | ||
* | ||
* @template T The type of the receiver | ||
@@ -475,3 +527,2 @@ * @param {Hook<FlagValue>[]} hooks A list of hooks that should always run | ||
* Access all the hooks that are registered on this receiver. | ||
* | ||
* @returns {Hook<FlagValue>[]} A list of the client hooks | ||
@@ -482,3 +533,2 @@ */ | ||
* Clears all the hooks that are registered on this receiver. | ||
* | ||
* @template T The type of the receiver | ||
@@ -496,3 +546,2 @@ * @returns {T} The receiver (this object) | ||
* Performs a flag evaluation that returns a boolean. | ||
* | ||
* @param {string} flagKey The flag key uniquely identifies a particular flag | ||
@@ -506,3 +555,2 @@ * @param {boolean} defaultValue The value returned if an error occurs | ||
* Performs a flag evaluation that a returns an evaluation details object. | ||
* | ||
* @param {string} flagKey The flag key uniquely identifies a particular flag | ||
@@ -516,3 +564,2 @@ * @param {boolean} defaultValue The value returned if an error occurs | ||
* Performs a flag evaluation that returns a string. | ||
* | ||
* @param {string} flagKey The flag key uniquely identifies a particular flag | ||
@@ -528,3 +575,2 @@ * @template {string} T A optional generic argument constraining the string | ||
* Performs a flag evaluation that a returns an evaluation details object. | ||
* | ||
* @param {string} flagKey The flag key uniquely identifies a particular flag | ||
@@ -540,3 +586,2 @@ * @template {string} T A optional generic argument constraining the string | ||
* Performs a flag evaluation that returns a number. | ||
* | ||
* @param {string} flagKey The flag key uniquely identifies a particular flag | ||
@@ -552,3 +597,2 @@ * @template {number} T A optional generic argument constraining the number | ||
* Performs a flag evaluation that a returns an evaluation details object. | ||
* | ||
* @param {string} flagKey The flag key uniquely identifies a particular flag | ||
@@ -564,3 +608,2 @@ * @template {number} T A optional generic argument constraining the number | ||
* Performs a flag evaluation that returns an object. | ||
* | ||
* @param {string} flagKey The flag key uniquely identifies a particular flag | ||
@@ -576,3 +619,2 @@ * @template {JsonValue} T A optional generic argument describing the structure | ||
* Performs a flag evaluation that a returns an evaluation details object. | ||
* | ||
* @param {string} flagKey The flag key uniquely identifies a particular flag | ||
@@ -596,3 +638,2 @@ * @template {JsonValue} T A optional generic argument describing the structure | ||
* to segment feature flag configuration. | ||
* | ||
* @param {string} name The name of the client | ||
@@ -607,3 +648,2 @@ * @param {string} version The version of the client | ||
* a provider supersedes the current provider used in new and existing clients. | ||
* | ||
* @param {Provider} provider The provider responsible for flag evaluations. | ||
@@ -621,10 +661,12 @@ * @returns {GlobalApi} OpenFeature API | ||
private readonly providerAccessor; | ||
private readonly providerReady; | ||
private readonly events; | ||
private readonly globalLogger; | ||
readonly metadata: ClientMetadata; | ||
private readonly options; | ||
private _hooks; | ||
private _clientLogger?; | ||
private _handlerWrappers; | ||
constructor(providerAccessor: () => Provider, providerReady: () => boolean, apiEvents: () => EventEmitter, globalLogger: () => Logger, options: OpenFeatureClientOptions); | ||
addHandler(eventType: ProviderEvents, handler: Handler): void; | ||
constructor(providerAccessor: () => Provider, events: () => OpenFeatureEventEmitter, globalLogger: () => Logger, options: OpenFeatureClientOptions); | ||
get metadata(): ClientMetadata; | ||
addHandler(eventType: ProviderEvents, handler: EventHandler): void; | ||
removeHandler(notificationType: ProviderEvents, handler: EventHandler): void; | ||
getHandlers(eventType: ProviderEvents): EventHandler[]; | ||
setLogger(logger: Logger): OpenFeatureClient; | ||
@@ -649,3 +691,2 @@ addHooks(...hooks: Hook<FlagValue>[]): OpenFeatureClient; | ||
private get _logger(); | ||
private attachListeners; | ||
} | ||
@@ -660,2 +701,3 @@ | ||
}; | ||
get status(): ProviderStatus; | ||
resolveBooleanEvaluation(_: string, defaultValue: boolean): ResolutionDetails<boolean>; | ||
@@ -669,11 +711,8 @@ resolveStringEvaluation(_: string, defaultValue: string): ResolutionDetails<string>; | ||
declare class OpenFeatureAPI extends OpenFeatureCommonAPI { | ||
private _apiEvents; | ||
private _providerReady; | ||
declare class OpenFeatureAPI extends OpenFeatureCommonAPI<Provider> { | ||
protected _hooks: Hook[]; | ||
protected _provider: Provider; | ||
protected _defaultProvider: Provider; | ||
private constructor(); | ||
/** | ||
* Gets a singleton instance of the OpenFeature API. | ||
* | ||
* @ignore | ||
@@ -683,8 +722,2 @@ * @returns {OpenFeatureAPI} OpenFeature API | ||
static getInstance(): OpenFeatureAPI; | ||
/** | ||
* Get metadata about registered provider. | ||
* | ||
* @returns {ProviderMetadata} Provider Metadata | ||
*/ | ||
get providerMetadata(): ProviderMetadata; | ||
setLogger(logger: Logger): this; | ||
@@ -695,4 +728,13 @@ addHooks(...hooks: Hook<FlagValue>[]): this; | ||
setContext(context: EvaluationContext): Promise<void>; | ||
setProvider(provider: Provider): OpenFeatureCommonAPI; | ||
close(): 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} name The name of the client | ||
* @param {string} version The version of the client (only used for metadata) | ||
* @returns {Client} OpenFeature Client | ||
*/ | ||
getClient(name?: string, version?: string): Client; | ||
@@ -702,3 +744,2 @@ } | ||
* A singleton instance of the OpenFeature API. | ||
* | ||
* @returns {OpenFeatureAPI} OpenFeature API | ||
@@ -708,2 +749,2 @@ */ | ||
export { ApiEvents, BeforeHookContext, Client, ClientMetadata, CommonProvider, DefaultLogger, ErrorCode, EvaluationContext, EvaluationContextValue, EvaluationDetails, EventCallbackMessage, EventContext, EventData, Eventing, Features, FlagEvaluationOptions, FlagNotFoundError, FlagValue, FlagValueType, GeneralError, GlobalApi, Handler, Hook, HookContext, HookHints, InvalidContextError, JsonArray, JsonObject, JsonValue, Logger, ManageContext, ManageLogger, ManageTransactionContextPropagator, NOOP_PROVIDER, NOOP_TRANSACTION_CONTEXT_PROPAGATOR, OpenFeature, OpenFeatureAPI, OpenFeatureClient, OpenFeatureCommonAPI, OpenFeatureError, EventEmitter as OpenFeatureEventEmitter, ParseError, PrimitiveValue, Provider, ProviderEvents, ProviderMetadata, ResolutionDetails, ResolutionReason, SafeLogger, StandardResolutionReasons, TargetingKeyMissingError, TransactionContext, TransactionContextPropagator, TypeMismatchError }; | ||
export { BeforeHookContext, Client, ClientMetadata, CommonProvider, DefaultLogger, ErrorCode, EvaluationContext, EvaluationContextValue, EvaluationDetails, EventDetails, EventHandler, EventMetadata, Eventing, Features, FlagEvaluationOptions, FlagMetadata, FlagNotFoundError, FlagValue, FlagValueType, GeneralError, GlobalApi, Hook, HookContext, HookHints, InvalidContextError, JsonArray, JsonObject, JsonValue, Logger, ManageContext, ManageLogger, ManageTransactionContextPropagator, NOOP_PROVIDER, NOOP_TRANSACTION_CONTEXT_PROPAGATOR, OpenFeature, OpenFeatureAPI, OpenFeatureClient, OpenFeatureCommonAPI, OpenFeatureError, OpenFeatureEventEmitter, ParseError, PrimitiveValue, Provider, ProviderEvents, ProviderMetadata, ProviderStatus, ResolutionDetails, ResolutionReason, SafeLogger, StandardResolutionReasons, TargetingKeyMissingError, TransactionContext, TransactionContextPropagator, TypeMismatchError }; |
{ | ||
"name": "@openfeature/web-sdk", | ||
"version": "0.3.2-experimental", | ||
"version": "0.3.3-experimental", | ||
"description": "OpenFeature SDK for Web", | ||
@@ -49,3 +49,3 @@ "main": "./dist/cjs/index.js", | ||
"devDependencies": { | ||
"@openfeature/shared": "0.0.3" | ||
"@openfeature/shared": "*" | ||
}, | ||
@@ -52,0 +52,0 @@ "typedoc": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
290400
2989