@launchdarkly/js-server-sdk-common
Version:
LaunchDarkly Server SDK for JavaScript - common code
517 lines • 29.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable class-methods-use-this */
const js_sdk_common_1 = require("@launchdarkly/js-sdk-common");
const api_1 = require("./api");
const BigSegmentsManager_1 = require("./BigSegmentsManager");
const createStreamListeners_1 = require("./data_sources/createStreamListeners");
const DataSourceUpdates_1 = require("./data_sources/DataSourceUpdates");
const PollingProcessor_1 = require("./data_sources/PollingProcessor");
const Requestor_1 = require("./data_sources/Requestor");
const StreamingProcessor_1 = require("./data_sources/StreamingProcessor");
const createDiagnosticsInitConfig_1 = require("./diagnostics/createDiagnosticsInitConfig");
const collection_1 = require("./evaluation/collection");
const EvalResult_1 = require("./evaluation/EvalResult");
const Evaluator_1 = require("./evaluation/Evaluator");
const ContextDeduplicator_1 = require("./events/ContextDeduplicator");
const EventFactory_1 = require("./events/EventFactory");
const isExperiment_1 = require("./events/isExperiment");
const FlagsStateBuilder_1 = require("./FlagsStateBuilder");
const HookRunner_1 = require("./hooks/HookRunner");
const MigrationOpEventConversion_1 = require("./MigrationOpEventConversion");
const MigrationOpTracker_1 = require("./MigrationOpTracker");
const Configuration_1 = require("./options/Configuration");
const VersionedDataKinds_1 = require("./store/VersionedDataKinds");
const { ClientMessages, ErrorKinds, NullEventProcessor } = js_sdk_common_1.internal;
var InitState;
(function (InitState) {
InitState[InitState["Initializing"] = 0] = "Initializing";
InitState[InitState["Initialized"] = 1] = "Initialized";
InitState[InitState["Failed"] = 2] = "Failed";
})(InitState || (InitState = {}));
const HIGH_TIMEOUT_THRESHOLD = 60;
const BOOL_VARIATION_METHOD_NAME = 'LDClient.boolVariation';
const NUMBER_VARIATION_METHOD_NAME = 'LDClient.numberVariation';
const STRING_VARIATION_METHOD_NAME = 'LDClient.stringVariation';
const JSON_VARIATION_METHOD_NAME = 'LDClient.jsonVariation';
const VARIATION_METHOD_NAME = 'LDClient.variation';
const MIGRATION_VARIATION_METHOD_NAME = 'LDClient.migrationVariation';
const BOOL_VARIATION_DETAIL_METHOD_NAME = 'LDClient.boolVariationDetail';
const NUMBER_VARIATION_DETAIL_METHOD_NAME = 'LDClient.numberVariationDetail';
const STRING_VARIATION_DETAIL_METHOD_NAME = 'LDClient.stringVariationDetail';
const JSON_VARIATION_DETAIL_METHOD_NAME = 'LDClient.jsonVariationDetail';
const VARIATION_METHOD_DETAIL_NAME = 'LDClient.variationDetail';
/**
* @ignore
*/
class LDClientImpl {
get logger() {
return this._logger;
}
constructor(_sdkKey, _platform, options, callbacks, internalOptions) {
var _a, _b, _c, _d, _e;
this._sdkKey = _sdkKey;
this._platform = _platform;
this._initState = InitState.Initializing;
this._eventFactoryDefault = new EventFactory_1.default(false);
this._eventFactoryWithReasons = new EventFactory_1.default(true);
this._onError = callbacks.onError;
this._onFailed = callbacks.onFailed;
this._onReady = callbacks.onReady;
const { onUpdate, hasEventListeners } = callbacks;
const config = new Configuration_1.default(options, internalOptions);
this._hookRunner = new HookRunner_1.default(config.logger, config.hooks || []);
if (!_sdkKey && !config.offline) {
throw new Error('You must configure the client with an SDK key');
}
this._config = config;
this._logger = config.logger;
const baseHeaders = (0, js_sdk_common_1.defaultHeaders)(_sdkKey, _platform.info, config.tags);
const clientContext = new js_sdk_common_1.ClientContext(_sdkKey, config, _platform);
const featureStore = config.featureStoreFactory(clientContext);
const dataSourceUpdates = new DataSourceUpdates_1.default(featureStore, hasEventListeners, onUpdate);
if (config.sendEvents && !config.offline && !config.diagnosticOptOut) {
this._diagnosticsManager = new js_sdk_common_1.internal.DiagnosticsManager(_sdkKey, _platform, (0, createDiagnosticsInitConfig_1.default)(config, _platform, featureStore));
}
if (!config.sendEvents || config.offline) {
this._eventProcessor = new NullEventProcessor();
}
else {
this._eventProcessor = new js_sdk_common_1.internal.EventProcessor(config, clientContext, baseHeaders, new ContextDeduplicator_1.default(config), this._diagnosticsManager);
}
this._featureStore = featureStore;
const manager = new BigSegmentsManager_1.default((_b = (_a = config.bigSegments) === null || _a === void 0 ? void 0 : _a.store) === null || _b === void 0 ? void 0 : _b.call(_a, clientContext), (_c = config.bigSegments) !== null && _c !== void 0 ? _c : {}, config.logger, this._platform.crypto);
this._bigSegmentsManager = manager;
this.bigSegmentStatusProviderInternal = manager.statusProvider;
const queries = {
getFlag(key, cb) {
featureStore.get(VersionedDataKinds_1.default.Features, key, (item) => cb(item));
},
getSegment(key, cb) {
featureStore.get(VersionedDataKinds_1.default.Segments, key, (item) => cb(item));
},
getBigSegmentsMembership(userKey) {
return manager.getUserMembership(userKey);
},
};
this._evaluator = new Evaluator_1.default(this._platform, queries);
const listeners = (0, createStreamListeners_1.createStreamListeners)(dataSourceUpdates, this._logger, {
put: () => this._initSuccess(),
});
const makeDefaultProcessor = () => config.stream
? new StreamingProcessor_1.default(clientContext, '/all', [], listeners, baseHeaders, this._diagnosticsManager, (e) => this._dataSourceErrorHandler(e), this._config.streamInitialReconnectDelay)
: new PollingProcessor_1.default(config, new Requestor_1.default(config, this._platform.requests, baseHeaders), dataSourceUpdates, () => this._initSuccess(), (e) => this._dataSourceErrorHandler(e));
if (!(config.offline || config.useLdd)) {
this._updateProcessor =
(_e = (_d = config.updateProcessorFactory) === null || _d === void 0 ? void 0 : _d.call(config, clientContext, dataSourceUpdates, () => this._initSuccess(), (e) => this._dataSourceErrorHandler(e))) !== null && _e !== void 0 ? _e : makeDefaultProcessor();
}
if (this._updateProcessor) {
this._updateProcessor.start();
}
else {
// Deferring the start callback should allow client construction to complete before we start
// emitting events. Allowing the client an opportunity to register events.
setTimeout(() => this._initSuccess(), 0);
}
}
initialized() {
return this._initState === InitState.Initialized;
}
waitForInitialization(options) {
// An initialization promise is only created if someone is going to use that promise.
// If we always created an initialization promise, and there was no call waitForInitialization
// by the time the promise was rejected, then that would result in an unhandled promise
// rejection.
var _a, _b;
// If there is no update processor, then there is functionally no initialization
// so it is fine not to wait.
if ((options === null || options === void 0 ? void 0 : options.timeout) === undefined && this._updateProcessor !== undefined) {
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn('The waitForInitialization function was called without a timeout specified.' +
' In a future version a default timeout will be applied.');
}
if ((options === null || options === void 0 ? void 0 : options.timeout) !== undefined &&
(options === null || options === void 0 ? void 0 : options.timeout) > HIGH_TIMEOUT_THRESHOLD &&
this._updateProcessor !== undefined) {
(_b = this._logger) === null || _b === void 0 ? void 0 : _b.warn('The waitForInitialization function was called with a timeout greater than ' +
`${HIGH_TIMEOUT_THRESHOLD} seconds. We recommend a timeout of less than ` +
`${HIGH_TIMEOUT_THRESHOLD} seconds.`);
}
// Initialization promise was created by a previous call to waitForInitialization.
if (this._initializedPromise) {
// This promise may already be resolved/rejected, but it doesn't hurt to wrap it in a timeout.
return this._clientWithTimeout(this._initializedPromise, options === null || options === void 0 ? void 0 : options.timeout, this._logger);
}
// Initialization completed before waitForInitialization was called, so we have completed
// and there was no promise. So we make a resolved promise and return it.
if (this._initState === InitState.Initialized) {
this._initializedPromise = Promise.resolve(this);
// Already initialized, no need to timeout.
return this._initializedPromise;
}
// Initialization failed before waitForInitialization was called, so we have completed
// and there was no promise. So we make a rejected promise and return it.
if (this._initState === InitState.Failed) {
// Already failed, no need to timeout.
this._initializedPromise = Promise.reject(this._rejectionReason);
return this._initializedPromise;
}
if (!this._initializedPromise) {
this._initializedPromise = new Promise((resolve, reject) => {
this._initResolve = resolve;
this._initReject = reject;
});
}
return this._clientWithTimeout(this._initializedPromise, options === null || options === void 0 ? void 0 : options.timeout, this._logger);
}
variation(key, context, defaultValue, callback) {
return this._hookRunner
.withEvaluationSeries(key, context, defaultValue, VARIATION_METHOD_NAME, () => new Promise((resolve) => {
this._evaluateIfPossible(key, context, defaultValue, this._eventFactoryDefault, (res) => {
resolve(res.detail);
});
}))
.then((detail) => {
callback === null || callback === void 0 ? void 0 : callback(null, detail.value);
return detail.value;
});
}
variationDetail(key, context, defaultValue, callback) {
return this._hookRunner.withEvaluationSeries(key, context, defaultValue, VARIATION_METHOD_DETAIL_NAME, () => new Promise((resolve) => {
this._evaluateIfPossible(key, context, defaultValue, this._eventFactoryWithReasons, (res) => {
resolve(res.detail);
callback === null || callback === void 0 ? void 0 : callback(null, res.detail);
});
}));
}
_typedEval(key, context, defaultValue, eventFactory, methodName, typeChecker) {
return this._hookRunner.withEvaluationSeries(key, context, defaultValue, methodName, () => new Promise((resolve) => {
this._evaluateIfPossible(key, context, defaultValue, eventFactory, (res) => {
const typedRes = {
value: res.detail.value,
reason: res.detail.reason,
variationIndex: res.detail.variationIndex,
};
resolve(typedRes);
}, typeChecker);
}));
}
async boolVariation(key, context, defaultValue) {
return (await this._typedEval(key, context, defaultValue, this._eventFactoryDefault, BOOL_VARIATION_METHOD_NAME, (value) => [js_sdk_common_1.TypeValidators.Boolean.is(value), js_sdk_common_1.TypeValidators.Boolean.getType()])).value;
}
async numberVariation(key, context, defaultValue) {
return (await this._typedEval(key, context, defaultValue, this._eventFactoryDefault, NUMBER_VARIATION_METHOD_NAME, (value) => [js_sdk_common_1.TypeValidators.Number.is(value), js_sdk_common_1.TypeValidators.Number.getType()])).value;
}
async stringVariation(key, context, defaultValue) {
return (await this._typedEval(key, context, defaultValue, this._eventFactoryDefault, STRING_VARIATION_METHOD_NAME, (value) => [js_sdk_common_1.TypeValidators.String.is(value), js_sdk_common_1.TypeValidators.String.getType()])).value;
}
jsonVariation(key, context, defaultValue) {
return this._hookRunner
.withEvaluationSeries(key, context, defaultValue, JSON_VARIATION_METHOD_NAME, () => new Promise((resolve) => {
this._evaluateIfPossible(key, context, defaultValue, this._eventFactoryDefault, (res) => {
resolve(res.detail);
});
}))
.then((detail) => detail.value);
}
boolVariationDetail(key, context, defaultValue) {
return this._typedEval(key, context, defaultValue, this._eventFactoryWithReasons, BOOL_VARIATION_DETAIL_METHOD_NAME, (value) => [js_sdk_common_1.TypeValidators.Boolean.is(value), js_sdk_common_1.TypeValidators.Boolean.getType()]);
}
numberVariationDetail(key, context, defaultValue) {
return this._typedEval(key, context, defaultValue, this._eventFactoryWithReasons, NUMBER_VARIATION_DETAIL_METHOD_NAME, (value) => [js_sdk_common_1.TypeValidators.Number.is(value), js_sdk_common_1.TypeValidators.Number.getType()]);
}
stringVariationDetail(key, context, defaultValue) {
return this._typedEval(key, context, defaultValue, this._eventFactoryWithReasons, STRING_VARIATION_DETAIL_METHOD_NAME, (value) => [js_sdk_common_1.TypeValidators.String.is(value), js_sdk_common_1.TypeValidators.String.getType()]);
}
jsonVariationDetail(key, context, defaultValue) {
return this._hookRunner.withEvaluationSeries(key, context, defaultValue, JSON_VARIATION_DETAIL_METHOD_NAME, () => new Promise((resolve) => {
this._evaluateIfPossible(key, context, defaultValue, this._eventFactoryWithReasons, (res) => {
resolve(res.detail);
});
}));
}
async _migrationVariationInternal(key, context, defaultValue) {
var _a;
const res = await new Promise((resolve) => {
this._evaluateIfPossible(key, context, defaultValue, this._eventFactoryWithReasons, ({ detail }, flag) => {
if (!(0, api_1.IsMigrationStage)(detail.value)) {
const error = new Error(`Unrecognized MigrationState for "${key}"; returning default value.`);
this._onError(error);
const reason = {
kind: 'ERROR',
errorKind: ErrorKinds.WrongType,
};
resolve({
detail: {
value: defaultValue,
reason,
},
flag,
});
return;
}
resolve({ detail, flag });
});
});
const { detail, flag } = res;
const checkRatio = (_a = flag === null || flag === void 0 ? void 0 : flag.migration) === null || _a === void 0 ? void 0 : _a.checkRatio;
const samplingRatio = flag === null || flag === void 0 ? void 0 : flag.samplingRatio;
return {
detail,
migration: {
value: detail.value,
tracker: new MigrationOpTracker_1.default(key, context, defaultValue, detail.value, detail.reason, checkRatio,
// Can be null for compatibility reasons.
detail.variationIndex === null ? undefined : detail.variationIndex, flag === null || flag === void 0 ? void 0 : flag.version, samplingRatio, this._logger),
},
};
}
async migrationVariation(key, context, defaultValue) {
const res = await this._hookRunner.withEvaluationSeriesExtraDetail(key, context, defaultValue, MIGRATION_VARIATION_METHOD_NAME, () => this._migrationVariationInternal(key, context, defaultValue));
return res.migration;
}
allFlagsState(context, options, callback) {
var _a, _b, _c;
if (this._config.offline) {
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.info('allFlagsState() called in offline mode. Returning empty state.');
const allFlagState = new FlagsStateBuilder_1.default(false, false).build();
callback === null || callback === void 0 ? void 0 : callback(null, allFlagState);
return Promise.resolve(allFlagState);
}
const evalContext = js_sdk_common_1.Context.fromLDContext(context);
if (!evalContext.valid) {
(_b = this._logger) === null || _b === void 0 ? void 0 : _b.info(`${(_c = evalContext.message) !== null && _c !== void 0 ? _c : 'Invalid context.'}. Returning empty state.`);
return Promise.resolve(new FlagsStateBuilder_1.default(false, false).build());
}
return new Promise((resolve) => {
const doEval = (valid) => this._featureStore.all(VersionedDataKinds_1.default.Features, (allFlags) => {
const builder = new FlagsStateBuilder_1.default(valid, !!(options === null || options === void 0 ? void 0 : options.withReasons));
const clientOnly = !!(options === null || options === void 0 ? void 0 : options.clientSideOnly);
const detailsOnlyIfTracked = !!(options === null || options === void 0 ? void 0 : options.detailsOnlyForTrackedFlags);
(0, collection_1.allAsync)(Object.values(allFlags), (storeItem, iterCb) => {
var _a;
const flag = storeItem;
if (clientOnly && !((_a = flag.clientSideAvailability) === null || _a === void 0 ? void 0 : _a.usingEnvironmentId)) {
iterCb(true);
return;
}
this._evaluator.evaluateCb(flag, evalContext, (res) => {
var _a;
if (res.isError) {
this._onError(new Error(`Error for feature flag "${flag.key}" while evaluating all flags: ${res.message}`));
}
const requireExperimentData = (0, isExperiment_1.default)(flag, res.detail.reason);
builder.addFlag(flag, res.detail.value, (_a = res.detail.variationIndex) !== null && _a !== void 0 ? _a : undefined, res.detail.reason, flag.trackEvents || requireExperimentData, requireExperimentData, detailsOnlyIfTracked, res.prerequisites);
iterCb(true);
});
}, () => {
const res = builder.build();
callback === null || callback === void 0 ? void 0 : callback(null, res);
resolve(res);
});
});
if (!this.initialized()) {
this._featureStore.initialized((storeInitialized) => {
var _a, _b;
let valid = true;
if (storeInitialized) {
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn('Called allFlagsState before client initialization; using last known' +
' values from data store');
}
else {
(_b = this._logger) === null || _b === void 0 ? void 0 : _b.warn('Called allFlagsState before client initialization. Data store not available; ' +
'returning empty state');
valid = false;
}
doEval(valid);
});
}
else {
doEval(true);
}
});
}
secureModeHash(context) {
const checkedContext = js_sdk_common_1.Context.fromLDContext(context);
const key = checkedContext.valid ? checkedContext.canonicalKey : undefined;
if (!this._platform.crypto.createHmac) {
// This represents an error in platform implementation.
throw new Error('Platform must implement createHmac');
}
const hmac = this._platform.crypto.createHmac('sha256', this._sdkKey);
if (key === undefined) {
throw new js_sdk_common_1.LDClientError('Could not generate secure mode hash for invalid context');
}
hmac.update(key);
return hmac.digest('hex');
}
close() {
var _a;
this._eventProcessor.close();
(_a = this._updateProcessor) === null || _a === void 0 ? void 0 : _a.close();
this._featureStore.close();
this._bigSegmentsManager.close();
}
isOffline() {
return this._config.offline;
}
track(key, context, data, metricValue) {
var _a, _b;
const checkedContext = js_sdk_common_1.Context.fromLDContext(context);
if (!checkedContext.valid) {
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn(ClientMessages.MissingContextKeyNoEvent);
return;
}
// 0 is valid, so do not truthy check the metric value
if (metricValue !== undefined && !js_sdk_common_1.TypeValidators.Number.is(metricValue)) {
(_b = this._logger) === null || _b === void 0 ? void 0 : _b.warn(ClientMessages.invalidMetricValue(typeof metricValue));
}
this._eventProcessor.sendEvent(this._eventFactoryDefault.customEvent(key, checkedContext, data, metricValue));
}
trackMigration(event) {
const converted = (0, MigrationOpEventConversion_1.default)(event);
if (!converted) {
return;
}
this._eventProcessor.sendEvent(converted);
}
identify(context) {
var _a;
const checkedContext = js_sdk_common_1.Context.fromLDContext(context);
if (!checkedContext.valid) {
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn(ClientMessages.MissingContextKeyNoEvent);
return;
}
this._eventProcessor.sendEvent(this._eventFactoryDefault.identifyEvent(checkedContext));
}
async flush(callback) {
try {
await this._eventProcessor.flush();
}
catch (err) {
return callback === null || callback === void 0 ? void 0 : callback(err, false);
}
return callback === null || callback === void 0 ? void 0 : callback(null, true);
}
addHook(hook) {
this._hookRunner.addHook(hook);
}
_variationInternal(flagKey, context, defaultValue, eventFactory, cb, typeChecker) {
var _a, _b;
if (this._config.offline) {
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.info('Variation called in offline mode. Returning default value.');
cb(EvalResult_1.default.forError(ErrorKinds.ClientNotReady, undefined, defaultValue));
return;
}
const evalContext = js_sdk_common_1.Context.fromLDContext(context);
if (!evalContext.valid) {
this._onError(new js_sdk_common_1.LDClientError(`${(_b = evalContext.message) !== null && _b !== void 0 ? _b : 'Context not valid;'} returning default value.`));
cb(EvalResult_1.default.forError(ErrorKinds.UserNotSpecified, undefined, defaultValue));
return;
}
this._featureStore.get(VersionedDataKinds_1.default.Features, flagKey, (item) => {
const flag = item;
if (!flag) {
const error = new js_sdk_common_1.LDClientError(`Unknown feature flag "${flagKey}"; returning default value`);
this._onError(error);
const result = EvalResult_1.default.forError(ErrorKinds.FlagNotFound, undefined, defaultValue);
this._eventProcessor.sendEvent(this._eventFactoryDefault.unknownFlagEvent(flagKey, defaultValue, evalContext));
cb(result);
return;
}
this._evaluator.evaluateCb(flag, evalContext, (evalRes) => {
var _a;
if (evalRes.detail.variationIndex === undefined ||
evalRes.detail.variationIndex === null) {
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug('Result value is null in variation');
evalRes.setDefault(defaultValue);
}
if (typeChecker) {
const [matched, type] = typeChecker(evalRes.detail.value);
if (!matched) {
const errorRes = EvalResult_1.default.forError(ErrorKinds.WrongType, `Did not receive expected type (${type}) evaluating feature flag "${flagKey}"`, defaultValue);
this._sendEvalEvent(errorRes, eventFactory, flag, evalContext, defaultValue);
cb(errorRes, flag);
return;
}
}
this._sendEvalEvent(evalRes, eventFactory, flag, evalContext, defaultValue);
cb(evalRes, flag);
}, eventFactory);
});
}
_sendEvalEvent(evalRes, eventFactory, flag, evalContext, defaultValue) {
var _a;
(_a = evalRes.events) === null || _a === void 0 ? void 0 : _a.forEach((event) => {
this._eventProcessor.sendEvent(Object.assign({}, event));
});
this._eventProcessor.sendEvent(eventFactory.evalEventServer(flag, evalContext, evalRes.detail, defaultValue, undefined));
}
_evaluateIfPossible(flagKey, context, defaultValue, eventFactory, cb, typeChecker) {
if (!this.initialized()) {
this._featureStore.initialized((storeInitialized) => {
var _a, _b;
if (storeInitialized) {
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.warn('Variation called before LaunchDarkly client initialization completed' +
" (did you wait for the 'ready' event?) - using last known values from feature store");
this._variationInternal(flagKey, context, defaultValue, eventFactory, cb, typeChecker);
return;
}
(_b = this._logger) === null || _b === void 0 ? void 0 : _b.warn('Variation called before LaunchDarkly client initialization completed (did you wait for the' +
"'ready' event?) - using default value");
cb(EvalResult_1.default.forError(ErrorKinds.ClientNotReady, undefined, defaultValue));
});
return;
}
this._variationInternal(flagKey, context, defaultValue, eventFactory, cb, typeChecker);
}
_dataSourceErrorHandler(e) {
var _a;
const error = e.code === 401 ? new Error('Authentication failed. Double check your SDK key.') : e;
this._onError(error);
this._onFailed(error);
if (!this.initialized()) {
this._initState = InitState.Failed;
this._rejectionReason = error;
(_a = this._initReject) === null || _a === void 0 ? void 0 : _a.call(this, error);
}
}
_initSuccess() {
var _a;
if (!this.initialized()) {
this._initState = InitState.Initialized;
(_a = this._initResolve) === null || _a === void 0 ? void 0 : _a.call(this, this);
this._onReady();
}
}
/**
* Apply a timeout promise to a base promise. This is for use with waitForInitialization.
* Currently it returns a LDClient. In the future it should return a status.
*
* The client isn't always the expected type of the consumer. It returns an LDClient interface
* which is less capable than, for example, the node client interface.
*
* @param basePromise The promise to race against a timeout.
* @param timeout The timeout in seconds.
* @param logger A logger to log when the timeout expires.
* @returns
*/
_clientWithTimeout(basePromise, timeout, logger) {
if (timeout) {
const cancelableTimeout = (0, js_sdk_common_1.cancelableTimedPromise)(timeout, 'waitForInitialization');
return Promise.race([
basePromise.then(() => this),
cancelableTimeout.promise.then(() => this),
])
.catch((reason) => {
if (reason instanceof js_sdk_common_1.LDTimeoutError) {
logger === null || logger === void 0 ? void 0 : logger.error(reason.message);
}
throw reason;
})
.finally(() => cancelableTimeout.cancel());
}
return basePromise;
}
}
exports.default = LDClientImpl;
//# sourceMappingURL=LDClientImpl.js.map