@openfeature/server-sdk
Advanced tools
Comparing version
@@ -30,34 +30,11 @@ "use strict"; | ||
OpenFeatureAPI: () => OpenFeatureAPI, | ||
OpenFeatureClient: () => OpenFeatureClient, | ||
OpenFeatureEventEmitter: () => OpenFeatureEventEmitter, | ||
ProviderEvents: () => import_core2.ServerProviderEvents, | ||
ProviderStatus: () => import_core3.ServerProviderStatus | ||
ProviderEvents: () => import_core6.ServerProviderEvents, | ||
ProviderStatus: () => import_core.ServerProviderStatus | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
// src/client/open-feature-client.ts | ||
var import_core7 = require("@openfeature/core"); | ||
// src/open-feature.ts | ||
var import_core6 = require("@openfeature/core"); | ||
// src/events/open-feature-event-emitter.ts | ||
// src/provider/provider.ts | ||
var import_core = require("@openfeature/core"); | ||
var import_node_events = require("events"); | ||
var OpenFeatureEventEmitter = class extends import_core.GenericEventEmitter { | ||
eventEmitter = new import_node_events.EventEmitter({ captureRejections: true }); | ||
constructor() { | ||
super(); | ||
this.eventEmitter.on("error", (err) => { | ||
this._logger?.error("Error running event handler:", err); | ||
}); | ||
} | ||
}; | ||
// src/events/events.ts | ||
var import_core2 = require("@openfeature/core"); | ||
// src/provider/provider.ts | ||
var import_core3 = require("@openfeature/core"); | ||
// src/provider/no-op-provider.ts | ||
@@ -91,7 +68,7 @@ var REASON_NO_OP = "No-op"; | ||
// src/provider/in-memory-provider/in-memory-provider.ts | ||
var import_core5 = require("@openfeature/core"); | ||
var import_core3 = require("@openfeature/core"); | ||
// src/provider/in-memory-provider/variant-not-found-error.ts | ||
var import_core4 = require("@openfeature/core"); | ||
var VariantFoundError = class _VariantFoundError extends import_core4.OpenFeatureError { | ||
var import_core2 = require("@openfeature/core"); | ||
var VariantFoundError = class _VariantFoundError extends import_core2.OpenFeatureError { | ||
code; | ||
@@ -102,3 +79,3 @@ constructor(message) { | ||
this.name = "VariantFoundError"; | ||
this.code = import_core4.ErrorCode.GENERAL; | ||
this.code = import_core2.ErrorCode.GENERAL; | ||
} | ||
@@ -125,3 +102,3 @@ }; | ||
this._flagConfiguration = { ...flagConfiguration }; | ||
this.events.emit(import_core2.ServerProviderEvents.ConfigurationChanged, { flagsChanged }); | ||
this.events.emit(import_core6.ServerProviderEvents.ConfigurationChanged, { flagsChanged }); | ||
} | ||
@@ -144,8 +121,8 @@ resolveBooleanEvaluation(flagKey, defaultValue, context, logger) { | ||
if (typeof resolutionResult?.value != typeof defaultValue) { | ||
throw new import_core5.TypeMismatchError(); | ||
throw new import_core3.TypeMismatchError(); | ||
} | ||
return resolutionResult; | ||
} catch (error) { | ||
if (!(error instanceof import_core5.OpenFeatureError)) { | ||
throw new import_core5.GeneralError(error?.message || "unknown error"); | ||
if (!(error instanceof import_core3.OpenFeatureError)) { | ||
throw new import_core3.GeneralError(error?.message || "unknown error"); | ||
} | ||
@@ -159,7 +136,7 @@ throw error; | ||
logger?.debug(message); | ||
throw new import_core5.FlagNotFoundError(message); | ||
throw new import_core3.FlagNotFoundError(message); | ||
} | ||
const flagSpec = this._flagConfiguration[flagKey]; | ||
if (flagSpec.disabled) { | ||
return { value: defaultValue, reason: import_core5.StandardResolutionReasons.DISABLED }; | ||
return { value: defaultValue, reason: import_core3.StandardResolutionReasons.DISABLED }; | ||
} | ||
@@ -177,3 +154,3 @@ const isContextEval = ctx && flagSpec?.contextEvaluator; | ||
...variant && { variant }, | ||
reason: isContextEval ? import_core5.StandardResolutionReasons.TARGETING_MATCH : import_core5.StandardResolutionReasons.STATIC | ||
reason: isContextEval ? import_core3.StandardResolutionReasons.TARGETING_MATCH : import_core3.StandardResolutionReasons.STATIC | ||
}; | ||
@@ -183,113 +160,7 @@ } | ||
// src/transaction-context/no-op-transaction-context-propagator.ts | ||
var NoopTransactionContextPropagator = class { | ||
getTransactionContext() { | ||
return {}; | ||
} | ||
setTransactionContext(_, callback, ...args) { | ||
callback(...args); | ||
} | ||
}; | ||
var NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator(); | ||
// src/transaction-context/async-local-storage-transaction-context-propagator.ts | ||
var import_async_hooks = require("async_hooks"); | ||
var AsyncLocalStorageTransactionContextPropagator = class { | ||
asyncLocalStorage = new import_async_hooks.AsyncLocalStorage(); | ||
getTransactionContext() { | ||
return this.asyncLocalStorage.getStore() ?? {}; | ||
} | ||
setTransactionContext(transactionContext, callback, ...args) { | ||
this.asyncLocalStorage.run(transactionContext, callback, ...args); | ||
} | ||
}; | ||
// src/open-feature.ts | ||
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/js-sdk/api"); | ||
var _globalThis = globalThis; | ||
var OpenFeatureAPI = class _OpenFeatureAPI extends import_core6.OpenFeatureCommonAPI { | ||
_statusEnumType = import_core3.ServerProviderStatus; | ||
_apiEmitter = new OpenFeatureEventEmitter(); | ||
_defaultProvider = new import_core6.ProviderWrapper(NOOP_PROVIDER, import_core3.ServerProviderStatus.NOT_READY, this._statusEnumType); | ||
_domainScopedProviders = /* @__PURE__ */ new Map(); | ||
_createEventEmitter = () => new OpenFeatureEventEmitter(); | ||
_transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR; | ||
constructor() { | ||
super("server"); | ||
} | ||
/** | ||
* 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) { | ||
if (!domain) { | ||
return this._defaultProvider.status; | ||
} | ||
return this._domainScopedProviders.get(domain)?.status ?? this._defaultProvider.status; | ||
} | ||
setContext(context) { | ||
this._context = context; | ||
return this; | ||
} | ||
getContext() { | ||
return this._context; | ||
} | ||
getClient(domainOrContext, versionOrContext, contextOrUndefined) { | ||
const domain = (0, import_core6.stringOrUndefined)(domainOrContext); | ||
const version = (0, import_core6.stringOrUndefined)(versionOrContext); | ||
const context = (0, import_core6.objectOrUndefined)(domainOrContext) ?? (0, import_core6.objectOrUndefined)(versionOrContext) ?? (0, import_core6.objectOrUndefined)(contextOrUndefined); | ||
return new OpenFeatureClient( | ||
() => this.getProviderForClient(domain), | ||
() => this.getProviderStatus(domain), | ||
() => this.buildAndCacheEventEmitterForClient(domain), | ||
() => this._logger, | ||
{ domain, version }, | ||
context | ||
); | ||
} | ||
/** | ||
* Clears all registered providers and resets the default provider. | ||
* @returns {Promise<void>} | ||
*/ | ||
clearProviders() { | ||
return super.clearProvidersAndSetDefault(NOOP_PROVIDER); | ||
} | ||
setTransactionContextPropagator(transactionContextPropagator) { | ||
const baseMessage = "Invalid TransactionContextPropagator, will not be set: "; | ||
if (typeof transactionContextPropagator?.getTransactionContext !== "function") { | ||
this._logger.error(`${baseMessage}: getTransactionContext is not a function.`); | ||
} else if (typeof transactionContextPropagator?.setTransactionContext !== "function") { | ||
this._logger.error(`${baseMessage}: setTransactionContext is not a function.`); | ||
} else { | ||
this._transactionContextPropagator = transactionContextPropagator; | ||
} | ||
return this; | ||
} | ||
setTransactionContext(transactionContext, callback, ...args) { | ||
this._transactionContextPropagator.setTransactionContext(transactionContext, callback, ...args); | ||
} | ||
getTransactionContext() { | ||
try { | ||
return this._transactionContextPropagator.getTransactionContext(); | ||
} catch (err) { | ||
const error = err; | ||
this._logger.error(`Error getting transaction context: ${error?.message}, returning empty context.`); | ||
this._logger.error(error?.stack); | ||
return {}; | ||
} | ||
} | ||
}; | ||
var OpenFeature = OpenFeatureAPI.getInstance(); | ||
var import_core7 = require("@openfeature/core"); | ||
// src/client/open-feature-client.ts | ||
// src/client/internal/open-feature-client.ts | ||
var import_core4 = require("@openfeature/core"); | ||
var OpenFeatureClient = class { | ||
@@ -321,3 +192,3 @@ constructor(providerAccessor, providerStatusAccessor, emitterAccessor, globalLogger, options, context = {}) { | ||
this.emitterAccessor().addHandler(eventType, handler); | ||
const shouldRunNow = (0, import_core7.statusMatchesEvent)(eventType, this._providerStatus); | ||
const shouldRunNow = (0, import_core4.statusMatchesEvent)(eventType, this._providerStatus); | ||
if (shouldRunNow) { | ||
@@ -342,3 +213,3 @@ try { | ||
setLogger(logger) { | ||
this._clientLogger = new import_core7.SafeLogger(logger); | ||
this._clientLogger = new import_core4.SafeLogger(logger); | ||
return this; | ||
@@ -436,6 +307,6 @@ } | ||
const frozenContext = await this.beforeHooks(allHooks, hookContext, options); | ||
if (this.providerStatus === import_core3.ServerProviderStatus.NOT_READY) { | ||
throw new import_core7.ProviderNotReadyError("provider has not yet initialized"); | ||
} else if (this.providerStatus === import_core3.ServerProviderStatus.FATAL) { | ||
throw new import_core7.ProviderFatalError("provider is in an irrecoverable error state"); | ||
if (this.providerStatus === import_core.ServerProviderStatus.NOT_READY) { | ||
throw new import_core4.ProviderNotReadyError("provider has not yet initialized"); | ||
} else if (this.providerStatus === import_core.ServerProviderStatus.FATAL) { | ||
throw new import_core4.ProviderFatalError("provider is in an irrecoverable error state"); | ||
} | ||
@@ -448,2 +319,5 @@ const resolution = await resolver.call(this._provider, flagKey, defaultValue, frozenContext, this._logger); | ||
}; | ||
if (evaluationDetails.errorCode) { | ||
throw (0, import_core4.instantiateErrorByErrorCode)(evaluationDetails.errorCode); | ||
} | ||
await this.afterHooks(allHooksReversed, hookContext, evaluationDetails, options); | ||
@@ -453,3 +327,3 @@ return evaluationDetails; | ||
const errorMessage = err?.message; | ||
const errorCode = err?.code || import_core7.ErrorCode.GENERAL; | ||
const errorCode = err?.code || import_core4.ErrorCode.GENERAL; | ||
await this.errorHooks(allHooksReversed, hookContext, err, options); | ||
@@ -460,3 +334,3 @@ return { | ||
value: defaultValue, | ||
reason: import_core7.StandardResolutionReasons.ERROR, | ||
reason: import_core4.StandardResolutionReasons.ERROR, | ||
flagMetadata: Object.freeze({}), | ||
@@ -521,2 +395,146 @@ flagKey | ||
// src/events/open-feature-event-emitter.ts | ||
var import_core5 = require("@openfeature/core"); | ||
var import_node_events = require("events"); | ||
var OpenFeatureEventEmitter = class extends import_core5.GenericEventEmitter { | ||
eventEmitter = new import_node_events.EventEmitter({ captureRejections: true }); | ||
constructor() { | ||
super(); | ||
this.eventEmitter.on("error", (err) => { | ||
this._logger?.error("Error running event handler:", err); | ||
}); | ||
} | ||
}; | ||
// src/events/events.ts | ||
var import_core6 = require("@openfeature/core"); | ||
// src/transaction-context/no-op-transaction-context-propagator.ts | ||
var NoopTransactionContextPropagator = class { | ||
getTransactionContext() { | ||
return {}; | ||
} | ||
setTransactionContext(_, callback, ...args) { | ||
callback(...args); | ||
} | ||
}; | ||
var NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator(); | ||
// src/transaction-context/async-local-storage-transaction-context-propagator.ts | ||
var import_async_hooks = require("async_hooks"); | ||
var AsyncLocalStorageTransactionContextPropagator = class { | ||
asyncLocalStorage = new import_async_hooks.AsyncLocalStorage(); | ||
getTransactionContext() { | ||
return this.asyncLocalStorage.getStore() ?? {}; | ||
} | ||
setTransactionContext(transactionContext, callback, ...args) { | ||
this.asyncLocalStorage.run(transactionContext, callback, ...args); | ||
} | ||
}; | ||
// src/open-feature.ts | ||
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/js-sdk/api"); | ||
var _globalThis = globalThis; | ||
var OpenFeatureAPI = class _OpenFeatureAPI extends import_core7.OpenFeatureCommonAPI { | ||
_statusEnumType = import_core.ServerProviderStatus; | ||
_apiEmitter = new OpenFeatureEventEmitter(); | ||
_defaultProvider = new import_core7.ProviderWrapper( | ||
NOOP_PROVIDER, | ||
import_core.ServerProviderStatus.NOT_READY, | ||
this._statusEnumType | ||
); | ||
_domainScopedProviders = /* @__PURE__ */ new Map(); | ||
_createEventEmitter = () => new OpenFeatureEventEmitter(); | ||
_transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR; | ||
constructor() { | ||
super("server"); | ||
} | ||
/** | ||
* 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) { | ||
if (!domain) { | ||
return this._defaultProvider.status; | ||
} | ||
return this._domainScopedProviders.get(domain)?.status ?? this._defaultProvider.status; | ||
} | ||
async setProviderAndWait(domainOrProvider, providerOrUndefined) { | ||
const domain = (0, import_core7.stringOrUndefined)(domainOrProvider); | ||
const provider = domain ? (0, import_core7.objectOrUndefined)(providerOrUndefined) : (0, import_core7.objectOrUndefined)(domainOrProvider); | ||
await this.setAwaitableProvider(domain, provider); | ||
} | ||
setProvider(clientOrProvider, providerOrUndefined) { | ||
const domain = (0, import_core7.stringOrUndefined)(clientOrProvider); | ||
const provider = domain ? (0, import_core7.objectOrUndefined)(providerOrUndefined) : (0, import_core7.objectOrUndefined)(clientOrProvider); | ||
const maybePromise = this.setAwaitableProvider(domain, provider); | ||
Promise.resolve(maybePromise).catch((err) => { | ||
this._logger.error("Error during provider initialization:", err); | ||
}); | ||
return this; | ||
} | ||
setContext(context) { | ||
this._context = context; | ||
return this; | ||
} | ||
getContext() { | ||
return this._context; | ||
} | ||
getClient(domainOrContext, versionOrContext, contextOrUndefined) { | ||
const domain = (0, import_core7.stringOrUndefined)(domainOrContext); | ||
const version = (0, import_core7.stringOrUndefined)(versionOrContext); | ||
const context = (0, import_core7.objectOrUndefined)(domainOrContext) ?? (0, import_core7.objectOrUndefined)(versionOrContext) ?? (0, import_core7.objectOrUndefined)(contextOrUndefined); | ||
return new OpenFeatureClient( | ||
() => this.getProviderForClient(domain), | ||
() => this.getProviderStatus(domain), | ||
() => this.buildAndCacheEventEmitterForClient(domain), | ||
() => this._logger, | ||
{ domain, version }, | ||
context | ||
); | ||
} | ||
/** | ||
* Clears all registered providers and resets the default provider. | ||
* @returns {Promise<void>} | ||
*/ | ||
clearProviders() { | ||
return super.clearProvidersAndSetDefault(NOOP_PROVIDER); | ||
} | ||
setTransactionContextPropagator(transactionContextPropagator) { | ||
const baseMessage = "Invalid TransactionContextPropagator, will not be set: "; | ||
if (typeof transactionContextPropagator?.getTransactionContext !== "function") { | ||
this._logger.error(`${baseMessage}: getTransactionContext is not a function.`); | ||
} else if (typeof transactionContextPropagator?.setTransactionContext !== "function") { | ||
this._logger.error(`${baseMessage}: setTransactionContext is not a function.`); | ||
} else { | ||
this._transactionContextPropagator = transactionContextPropagator; | ||
} | ||
return this; | ||
} | ||
setTransactionContext(transactionContext, callback, ...args) { | ||
this._transactionContextPropagator.setTransactionContext(transactionContext, callback, ...args); | ||
} | ||
getTransactionContext() { | ||
try { | ||
return this._transactionContextPropagator.getTransactionContext(); | ||
} catch (err) { | ||
const error = err; | ||
this._logger.error(`Error getting transaction context: ${error?.message}, returning empty context.`); | ||
this._logger.error(error?.stack); | ||
return {}; | ||
} | ||
} | ||
}; | ||
var OpenFeature = OpenFeatureAPI.getInstance(); | ||
// src/index.ts | ||
@@ -532,3 +550,2 @@ __reExport(src_exports, require("@openfeature/core"), module.exports); | ||
OpenFeatureAPI, | ||
OpenFeatureClient, | ||
OpenFeatureEventEmitter, | ||
@@ -535,0 +552,0 @@ ProviderEvents, |
@@ -1,35 +0,1 @@ | ||
// src/client/open-feature-client.ts | ||
import { | ||
ErrorCode as ErrorCode2, | ||
ProviderFatalError, | ||
ProviderNotReadyError, | ||
SafeLogger, | ||
StandardResolutionReasons as StandardResolutionReasons2, | ||
statusMatchesEvent | ||
} from "@openfeature/core"; | ||
// src/open-feature.ts | ||
import { | ||
OpenFeatureCommonAPI, | ||
ProviderWrapper, | ||
objectOrUndefined, | ||
stringOrUndefined | ||
} from "@openfeature/core"; | ||
// src/events/open-feature-event-emitter.ts | ||
import { GenericEventEmitter } from "@openfeature/core"; | ||
import { EventEmitter } from "events"; | ||
var OpenFeatureEventEmitter = class extends GenericEventEmitter { | ||
eventEmitter = new EventEmitter({ captureRejections: true }); | ||
constructor() { | ||
super(); | ||
this.eventEmitter.on("error", (err) => { | ||
this._logger?.error("Error running event handler:", err); | ||
}); | ||
} | ||
}; | ||
// src/events/events.ts | ||
import { ServerProviderEvents } from "@openfeature/core"; | ||
// src/provider/provider.ts | ||
@@ -158,113 +124,20 @@ import { ServerProviderStatus } from "@openfeature/core"; | ||
// src/transaction-context/no-op-transaction-context-propagator.ts | ||
var NoopTransactionContextPropagator = class { | ||
getTransactionContext() { | ||
return {}; | ||
} | ||
setTransactionContext(_, callback, ...args) { | ||
callback(...args); | ||
} | ||
}; | ||
var NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator(); | ||
// src/transaction-context/async-local-storage-transaction-context-propagator.ts | ||
import { AsyncLocalStorage } from "async_hooks"; | ||
var AsyncLocalStorageTransactionContextPropagator = class { | ||
asyncLocalStorage = new AsyncLocalStorage(); | ||
getTransactionContext() { | ||
return this.asyncLocalStorage.getStore() ?? {}; | ||
} | ||
setTransactionContext(transactionContext, callback, ...args) { | ||
this.asyncLocalStorage.run(transactionContext, callback, ...args); | ||
} | ||
}; | ||
// src/open-feature.ts | ||
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/js-sdk/api"); | ||
var _globalThis = globalThis; | ||
var OpenFeatureAPI = class _OpenFeatureAPI extends OpenFeatureCommonAPI { | ||
_statusEnumType = ServerProviderStatus; | ||
_apiEmitter = new OpenFeatureEventEmitter(); | ||
_defaultProvider = new ProviderWrapper(NOOP_PROVIDER, ServerProviderStatus.NOT_READY, this._statusEnumType); | ||
_domainScopedProviders = /* @__PURE__ */ new Map(); | ||
_createEventEmitter = () => new OpenFeatureEventEmitter(); | ||
_transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR; | ||
constructor() { | ||
super("server"); | ||
} | ||
/** | ||
* 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) { | ||
if (!domain) { | ||
return this._defaultProvider.status; | ||
} | ||
return this._domainScopedProviders.get(domain)?.status ?? this._defaultProvider.status; | ||
} | ||
setContext(context) { | ||
this._context = context; | ||
return this; | ||
} | ||
getContext() { | ||
return this._context; | ||
} | ||
getClient(domainOrContext, versionOrContext, contextOrUndefined) { | ||
const domain = stringOrUndefined(domainOrContext); | ||
const version = stringOrUndefined(versionOrContext); | ||
const context = objectOrUndefined(domainOrContext) ?? objectOrUndefined(versionOrContext) ?? objectOrUndefined(contextOrUndefined); | ||
return new OpenFeatureClient( | ||
() => this.getProviderForClient(domain), | ||
() => this.getProviderStatus(domain), | ||
() => this.buildAndCacheEventEmitterForClient(domain), | ||
() => this._logger, | ||
{ domain, version }, | ||
context | ||
); | ||
} | ||
/** | ||
* Clears all registered providers and resets the default provider. | ||
* @returns {Promise<void>} | ||
*/ | ||
clearProviders() { | ||
return super.clearProvidersAndSetDefault(NOOP_PROVIDER); | ||
} | ||
setTransactionContextPropagator(transactionContextPropagator) { | ||
const baseMessage = "Invalid TransactionContextPropagator, will not be set: "; | ||
if (typeof transactionContextPropagator?.getTransactionContext !== "function") { | ||
this._logger.error(`${baseMessage}: getTransactionContext is not a function.`); | ||
} else if (typeof transactionContextPropagator?.setTransactionContext !== "function") { | ||
this._logger.error(`${baseMessage}: setTransactionContext is not a function.`); | ||
} else { | ||
this._transactionContextPropagator = transactionContextPropagator; | ||
} | ||
return this; | ||
} | ||
setTransactionContext(transactionContext, callback, ...args) { | ||
this._transactionContextPropagator.setTransactionContext(transactionContext, callback, ...args); | ||
} | ||
getTransactionContext() { | ||
try { | ||
return this._transactionContextPropagator.getTransactionContext(); | ||
} catch (err) { | ||
const error = err; | ||
this._logger.error(`Error getting transaction context: ${error?.message}, returning empty context.`); | ||
this._logger.error(error?.stack); | ||
return {}; | ||
} | ||
} | ||
}; | ||
var OpenFeature = OpenFeatureAPI.getInstance(); | ||
import { | ||
OpenFeatureCommonAPI, | ||
ProviderWrapper, | ||
objectOrUndefined, | ||
stringOrUndefined | ||
} from "@openfeature/core"; | ||
// src/client/open-feature-client.ts | ||
// 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 { | ||
@@ -420,2 +293,5 @@ constructor(providerAccessor, providerStatusAccessor, emitterAccessor, globalLogger, options, context = {}) { | ||
}; | ||
if (evaluationDetails.errorCode) { | ||
throw instantiateErrorByErrorCode(evaluationDetails.errorCode); | ||
} | ||
await this.afterHooks(allHooksReversed, hookContext, evaluationDetails, options); | ||
@@ -491,2 +367,146 @@ return evaluationDetails; | ||
// src/events/open-feature-event-emitter.ts | ||
import { GenericEventEmitter } from "@openfeature/core"; | ||
import { EventEmitter } from "events"; | ||
var OpenFeatureEventEmitter = class extends GenericEventEmitter { | ||
eventEmitter = new EventEmitter({ captureRejections: true }); | ||
constructor() { | ||
super(); | ||
this.eventEmitter.on("error", (err) => { | ||
this._logger?.error("Error running event handler:", err); | ||
}); | ||
} | ||
}; | ||
// src/events/events.ts | ||
import { ServerProviderEvents } from "@openfeature/core"; | ||
// src/transaction-context/no-op-transaction-context-propagator.ts | ||
var NoopTransactionContextPropagator = class { | ||
getTransactionContext() { | ||
return {}; | ||
} | ||
setTransactionContext(_, callback, ...args) { | ||
callback(...args); | ||
} | ||
}; | ||
var NOOP_TRANSACTION_CONTEXT_PROPAGATOR = new NoopTransactionContextPropagator(); | ||
// src/transaction-context/async-local-storage-transaction-context-propagator.ts | ||
import { AsyncLocalStorage } from "async_hooks"; | ||
var AsyncLocalStorageTransactionContextPropagator = class { | ||
asyncLocalStorage = new AsyncLocalStorage(); | ||
getTransactionContext() { | ||
return this.asyncLocalStorage.getStore() ?? {}; | ||
} | ||
setTransactionContext(transactionContext, callback, ...args) { | ||
this.asyncLocalStorage.run(transactionContext, callback, ...args); | ||
} | ||
}; | ||
// src/open-feature.ts | ||
var GLOBAL_OPENFEATURE_API_KEY = Symbol.for("@openfeature/js-sdk/api"); | ||
var _globalThis = globalThis; | ||
var OpenFeatureAPI = class _OpenFeatureAPI extends OpenFeatureCommonAPI { | ||
_statusEnumType = ServerProviderStatus; | ||
_apiEmitter = new OpenFeatureEventEmitter(); | ||
_defaultProvider = new ProviderWrapper( | ||
NOOP_PROVIDER, | ||
ServerProviderStatus.NOT_READY, | ||
this._statusEnumType | ||
); | ||
_domainScopedProviders = /* @__PURE__ */ new Map(); | ||
_createEventEmitter = () => new OpenFeatureEventEmitter(); | ||
_transactionContextPropagator = NOOP_TRANSACTION_CONTEXT_PROPAGATOR; | ||
constructor() { | ||
super("server"); | ||
} | ||
/** | ||
* 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) { | ||
if (!domain) { | ||
return this._defaultProvider.status; | ||
} | ||
return this._domainScopedProviders.get(domain)?.status ?? this._defaultProvider.status; | ||
} | ||
async setProviderAndWait(domainOrProvider, providerOrUndefined) { | ||
const domain = stringOrUndefined(domainOrProvider); | ||
const provider = domain ? objectOrUndefined(providerOrUndefined) : objectOrUndefined(domainOrProvider); | ||
await this.setAwaitableProvider(domain, provider); | ||
} | ||
setProvider(clientOrProvider, providerOrUndefined) { | ||
const domain = stringOrUndefined(clientOrProvider); | ||
const provider = domain ? objectOrUndefined(providerOrUndefined) : objectOrUndefined(clientOrProvider); | ||
const maybePromise = this.setAwaitableProvider(domain, provider); | ||
Promise.resolve(maybePromise).catch((err) => { | ||
this._logger.error("Error during provider initialization:", err); | ||
}); | ||
return this; | ||
} | ||
setContext(context) { | ||
this._context = context; | ||
return this; | ||
} | ||
getContext() { | ||
return this._context; | ||
} | ||
getClient(domainOrContext, versionOrContext, contextOrUndefined) { | ||
const domain = stringOrUndefined(domainOrContext); | ||
const version = stringOrUndefined(versionOrContext); | ||
const context = objectOrUndefined(domainOrContext) ?? objectOrUndefined(versionOrContext) ?? objectOrUndefined(contextOrUndefined); | ||
return new OpenFeatureClient( | ||
() => this.getProviderForClient(domain), | ||
() => this.getProviderStatus(domain), | ||
() => this.buildAndCacheEventEmitterForClient(domain), | ||
() => this._logger, | ||
{ domain, version }, | ||
context | ||
); | ||
} | ||
/** | ||
* Clears all registered providers and resets the default provider. | ||
* @returns {Promise<void>} | ||
*/ | ||
clearProviders() { | ||
return super.clearProvidersAndSetDefault(NOOP_PROVIDER); | ||
} | ||
setTransactionContextPropagator(transactionContextPropagator) { | ||
const baseMessage = "Invalid TransactionContextPropagator, will not be set: "; | ||
if (typeof transactionContextPropagator?.getTransactionContext !== "function") { | ||
this._logger.error(`${baseMessage}: getTransactionContext is not a function.`); | ||
} else if (typeof transactionContextPropagator?.setTransactionContext !== "function") { | ||
this._logger.error(`${baseMessage}: setTransactionContext is not a function.`); | ||
} else { | ||
this._transactionContextPropagator = transactionContextPropagator; | ||
} | ||
return this; | ||
} | ||
setTransactionContext(transactionContext, callback, ...args) { | ||
this._transactionContextPropagator.setTransactionContext(transactionContext, callback, ...args); | ||
} | ||
getTransactionContext() { | ||
try { | ||
return this._transactionContextPropagator.getTransactionContext(); | ||
} catch (err) { | ||
const error = err; | ||
this._logger.error(`Error getting transaction context: ${error?.message}, returning empty context.`); | ||
this._logger.error(error?.stack); | ||
return {}; | ||
} | ||
} | ||
}; | ||
var OpenFeature = OpenFeatureAPI.getInstance(); | ||
// src/index.ts | ||
@@ -501,3 +521,2 @@ export * from "@openfeature/core"; | ||
OpenFeatureAPI, | ||
OpenFeatureClient, | ||
OpenFeatureEventEmitter, | ||
@@ -504,0 +523,0 @@ ServerProviderEvents as ProviderEvents, |
@@ -1,3 +0,2 @@ | ||
import * as _openfeature_core from '@openfeature/core'; | ||
import { BaseHook, FlagValue, EvaluationContext, HookHints, EvaluationDetails, JsonValue, CommonProvider, ServerProviderStatus, Logger, ResolutionDetails, GenericEventEmitter, ServerProviderEvents, EvaluationLifeCycle, ManageContext, ManageLogger, Eventing, ClientMetadata, EventHandler, OpenFeatureCommonAPI, ProviderWrapper } from '@openfeature/core'; | ||
import { BaseHook, FlagValue, EvaluationContext, HookHints, EvaluationDetails, JsonValue, CommonProvider, ServerProviderStatus, Logger, ResolutionDetails, GenericEventEmitter, ServerProviderEvents, EvaluationLifeCycle, ManageContext, ManageLogger, Eventing, ClientMetadata, OpenFeatureCommonAPI, ProviderWrapper } from '@openfeature/core'; | ||
export * from '@openfeature/core'; | ||
@@ -213,3 +212,3 @@ export { ServerProviderEvents as ProviderEvents, ServerProviderStatus as ProviderStatus } from '@openfeature/core'; | ||
declare class OpenFeatureEventEmitter extends GenericEventEmitter<ServerProviderEvents> { | ||
protected readonly eventEmitter: EventEmitter; | ||
protected readonly eventEmitter: EventEmitter<[never]>; | ||
constructor(); | ||
@@ -227,57 +226,2 @@ } | ||
/** | ||
* The InternalEventEmitter is not exported publicly and should only be used within the SDK. It extends the | ||
* OpenFeatureEventEmitter to include additional properties that can be included | ||
* in the event details. | ||
*/ | ||
declare abstract class InternalEventEmitter extends GenericEventEmitter<ServerProviderEvents> { | ||
} | ||
type OpenFeatureClientOptions = { | ||
/** | ||
* @deprecated Use `domain` instead. | ||
*/ | ||
name?: string; | ||
domain?: string; | ||
version?: string; | ||
}; | ||
declare class OpenFeatureClient implements Client, ManageContext<OpenFeatureClient> { | ||
private readonly providerAccessor; | ||
private readonly providerStatusAccessor; | ||
private readonly emitterAccessor; | ||
private readonly globalLogger; | ||
private readonly options; | ||
private _context; | ||
private _hooks; | ||
private _clientLogger?; | ||
constructor(providerAccessor: () => Provider, providerStatusAccessor: () => ServerProviderStatus, emitterAccessor: () => InternalEventEmitter, globalLogger: () => Logger, options: OpenFeatureClientOptions, context?: EvaluationContext); | ||
get metadata(): ClientMetadata; | ||
get providerStatus(): ServerProviderStatus; | ||
addHandler(eventType: ServerProviderEvents, handler: EventHandler): void; | ||
removeHandler(eventType: ServerProviderEvents, handler: EventHandler): void; | ||
getHandlers(eventType: ServerProviderEvents): EventHandler<ServerProviderEvents | _openfeature_core.AllProviderEvents>[]; | ||
setLogger(logger: Logger): OpenFeatureClient; | ||
setContext(context: EvaluationContext): OpenFeatureClient; | ||
getContext(): EvaluationContext; | ||
addHooks(...hooks: Hook[]): OpenFeatureClient; | ||
getHooks(): Hook[]; | ||
clearHooks(): OpenFeatureClient; | ||
getBooleanValue(flagKey: string, defaultValue: boolean, context?: EvaluationContext, options?: FlagEvaluationOptions): Promise<boolean>; | ||
getBooleanDetails(flagKey: string, defaultValue: boolean, context?: EvaluationContext, options?: FlagEvaluationOptions): Promise<EvaluationDetails<boolean>>; | ||
getStringValue<T extends string = string>(flagKey: string, defaultValue: T, context?: EvaluationContext, options?: FlagEvaluationOptions): Promise<T>; | ||
getStringDetails<T extends string = string>(flagKey: string, defaultValue: T, context?: EvaluationContext, options?: FlagEvaluationOptions): Promise<EvaluationDetails<T>>; | ||
getNumberValue<T extends number = number>(flagKey: string, defaultValue: T, context?: EvaluationContext, options?: FlagEvaluationOptions): Promise<T>; | ||
getNumberDetails<T extends number = number>(flagKey: string, defaultValue: T, context?: EvaluationContext, options?: FlagEvaluationOptions): Promise<EvaluationDetails<T>>; | ||
getObjectValue<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, context?: EvaluationContext, options?: FlagEvaluationOptions): Promise<T>; | ||
getObjectDetails<T extends JsonValue = JsonValue>(flagKey: string, defaultValue: T, context?: EvaluationContext, options?: FlagEvaluationOptions): Promise<EvaluationDetails<T>>; | ||
private evaluate; | ||
private beforeHooks; | ||
private afterHooks; | ||
private errorHooks; | ||
private finallyHooks; | ||
private get _provider(); | ||
private get _providerStatus(); | ||
private get _logger(); | ||
} | ||
/** | ||
* Transaction context is a mechanism for adding transaction specific context that | ||
@@ -364,2 +308,37 @@ * is merged with evaluation context prior to flag evaluation. Examples of potential | ||
private getProviderStatus; | ||
/** | ||
* Sets the default provider for flag evaluations and returns a promise that resolves when the provider is ready. | ||
* This provider will be used by domainless clients and clients associated with domains to which no provider is bound. | ||
* Setting a provider supersedes the current provider used in new and existing unbound clients. | ||
* @param {Provider} provider The provider responsible for flag evaluations. | ||
* @returns {Promise<void>} | ||
* @throws Uncaught exceptions thrown by the provider during initialization. | ||
*/ | ||
setProviderAndWait(provider: Provider): Promise<void>; | ||
/** | ||
* Sets the provider that OpenFeature will use for flag evaluations on clients bound to the same domain. | ||
* A promise is returned that resolves when the provider is ready. | ||
* Setting a provider supersedes the current provider used in new and existing clients bound to the same domain. | ||
* @param {string} domain The name to identify the client | ||
* @param {Provider} provider The provider responsible for flag evaluations. | ||
* @returns {Promise<void>} | ||
* @throws Uncaught exceptions thrown by the provider during initialization. | ||
*/ | ||
setProviderAndWait(domain: string, provider: Provider): Promise<void>; | ||
/** | ||
* Sets the default provider for flag evaluations. | ||
* This provider will be used by domainless clients and clients associated with domains to which no provider is bound. | ||
* Setting a provider supersedes the current provider used in new and existing unbound clients. | ||
* @param {Provider} provider The provider responsible for flag evaluations. | ||
* @returns {this} OpenFeature API | ||
*/ | ||
setProvider(provider: Provider): this; | ||
/** | ||
* Sets the provider for flag evaluations of providers with the given name. | ||
* Setting a provider supersedes the current provider used in new and existing clients bound to the same domain. | ||
* @param {string} domain The name to identify the client | ||
* @param {Provider} provider The provider responsible for flag evaluations. | ||
* @returns {this} OpenFeature API | ||
*/ | ||
setProvider(domain: string, provider: Provider): this; | ||
setContext(context: EvaluationContext): this; | ||
@@ -417,2 +396,2 @@ getContext(): EvaluationContext; | ||
export { AsyncLocalStorageTransactionContextPropagator, Client, Features, FlagEvaluationOptions, Hook, InMemoryProvider, ManageTransactionContextPropagator, NOOP_PROVIDER, NOOP_TRANSACTION_CONTEXT_PROPAGATOR, OpenFeature, OpenFeatureAPI, OpenFeatureClient, OpenFeatureEventEmitter, Provider, TransactionContext, TransactionContextPropagator }; | ||
export { AsyncLocalStorageTransactionContextPropagator, Client, Features, FlagEvaluationOptions, Hook, InMemoryProvider, ManageTransactionContextPropagator, NOOP_PROVIDER, NOOP_TRANSACTION_CONTEXT_PROPAGATOR, OpenFeature, OpenFeatureAPI, OpenFeatureEventEmitter, Provider, TransactionContext, TransactionContextPropagator }; |
{ | ||
"name": "@openfeature/server-sdk", | ||
"version": "1.13.5", | ||
"version": "1.14.0", | ||
"description": "OpenFeature SDK for JavaScript", | ||
@@ -48,10 +48,10 @@ "main": "./dist/cjs/index.js", | ||
"engines": { | ||
"node": ">=16" | ||
"node": ">=18" | ||
}, | ||
"peerDependencies": { | ||
"@openfeature/core": "1.1.0" | ||
"@openfeature/core": "1.2.0" | ||
}, | ||
"devDependencies": { | ||
"@openfeature/core": "1.1.0" | ||
"@openfeature/core": "1.2.0" | ||
} | ||
} |
@@ -19,4 +19,4 @@ <!-- markdownlint-disable MD033 --> | ||
<!-- x-release-please-start-version --> | ||
<a href="https://github.com/open-feature/js-sdk/releases/tag/server-sdk-v1.13.5"> | ||
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.13.5&color=blue&style=for-the-badge" /> | ||
<a href="https://github.com/open-feature/js-sdk/releases/tag/server-sdk-v1.14.0"> | ||
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.14.0&color=blue&style=for-the-badge" /> | ||
</a> | ||
@@ -48,3 +48,3 @@ <!-- x-release-please-end --> | ||
- Node.js version 16+ | ||
- Node.js version 18+ | ||
@@ -59,2 +59,5 @@ ### Install | ||
> [!TIP] | ||
> This SDK is designed to run in Node.JS. If you're interested in browser support, check out the [Web SDK](https://openfeature.dev/docs/reference/technologies/client/web/). | ||
#### yarn | ||
@@ -164,2 +167,5 @@ | ||
Context is merged by the SDK before a flag evaluation occurs. | ||
The merge order is defined [here](https://openfeature.dev/specification/sections/evaluation-context#requirement-323) in the OpenFeature specification. | ||
### Hooks | ||
@@ -166,0 +172,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
178432
5.48%1417
1.36%384
1.59%