UNPKG

configcat-common

Version:

ConfigCat is a configuration as a service that lets you manage your features and configurations without actually deploying new code.

670 lines (669 loc) 35.8 kB
import { __assign, __awaiter, __generator } from "tslib"; import { AutoPollConfigService } from "./AutoPollConfigService"; import { AutoPollOptions, LazyLoadOptions, ManualPollOptions, PollingMode } from "./ConfigCatClientOptions"; import { ClientCacheState, RefreshResult } from "./ConfigServiceBase"; import { OverrideBehaviour } from "./FlagOverrides"; import { LazyLoadConfigService } from "./LazyLoadConfigService"; import { ManualPollConfigService } from "./ManualPollConfigService"; import { getWeakRefStub, isWeakRefAvailable } from "./Polyfills"; import { RolloutEvaluator, checkSettingsAvailable, evaluate, evaluateAll, evaluationDetailsFromDefaultValue, getTimestampAsDate, handleInvalidReturnValue, isAllowedValue } from "./RolloutEvaluator"; import { errorToString, isArray, throwError } from "./Utils"; var ConfigCatClientCache = /** @class */ (function () { function ConfigCatClientCache() { this.instances = {}; } ConfigCatClientCache.prototype.getOrCreate = function (options, configCatKernel) { var instance; var cachedInstance = this.instances[options.sdkKey]; if (cachedInstance) { var weakRef = cachedInstance[0]; instance = weakRef.deref(); if (instance) { return [instance, true]; } } var token = {}; instance = new ConfigCatClient(options, configCatKernel, token); var weakRefCtor = isWeakRefAvailable() ? WeakRef : getWeakRefStub(); this.instances[options.sdkKey] = [new weakRefCtor(instance), token]; return [instance, false]; }; ConfigCatClientCache.prototype.remove = function (sdkKey, cacheToken) { var cachedInstance = this.instances[sdkKey]; if (cachedInstance) { var weakRef = cachedInstance[0], token = cachedInstance[1]; var instanceIsAvailable = !!weakRef.deref(); if (!instanceIsAvailable || token === cacheToken) { delete this.instances[sdkKey]; return instanceIsAvailable; } } return false; }; ConfigCatClientCache.prototype.clear = function () { var removedInstances = []; for (var _i = 0, _a = Object.entries(this.instances); _i < _a.length; _i++) { var _b = _a[_i], sdkKey = _b[0], weakRef = _b[1][0]; var instance = weakRef.deref(); if (instance) { removedInstances.push(instance); } delete this.instances[sdkKey]; } return removedInstances; }; return ConfigCatClientCache; }()); export { ConfigCatClientCache }; var clientInstanceCache = new ConfigCatClientCache(); var ConfigCatClient = /** @class */ (function () { function ConfigCatClient(options, configCatKernel, cacheToken) { var _a; this.cacheToken = cacheToken; /** @inheritdoc */ this.addListener = this.on; /** @inheritdoc */ this.off = this.removeListener; if (!options) { throw new Error("Invalid 'options' value"); } this.options = options; this.options.logger.debug("Initializing ConfigCatClient. Options: " + JSON.stringify(this.options)); if (!configCatKernel) { throw new Error("Invalid 'configCatKernel' value"); } if (!configCatKernel.configFetcher) { throw new Error("Invalid 'configCatKernel.configFetcher' value"); } // To avoid possible memory leaks, the components of the client should not hold a strong reference to the hooks object (see also SafeHooksWrapper). this.hooks = options.yieldHooks(); if (options.defaultUser) { this.setDefaultUser(options.defaultUser); } this.evaluator = new RolloutEvaluator(options.logger); if (((_a = options.flagOverrides) === null || _a === void 0 ? void 0 : _a.behaviour) !== OverrideBehaviour.LocalOnly) { this.configService = options instanceof AutoPollOptions ? new AutoPollConfigService(configCatKernel.configFetcher, options) : options instanceof ManualPollOptions ? new ManualPollConfigService(configCatKernel.configFetcher, options) : options instanceof LazyLoadOptions ? new LazyLoadConfigService(configCatKernel.configFetcher, options) : throwError(new Error("Invalid 'options' value")); } else { this.hooks.emit("clientReady", ClientCacheState.HasLocalOverrideFlagDataOnly); } this.suppressFinalize = registerForFinalization(this, { sdkKey: options.sdkKey, cacheToken: cacheToken, configService: this.configService, logger: options.logger }); } Object.defineProperty(ConfigCatClient, "instanceCache", { get: function () { return clientInstanceCache; }, enumerable: false, configurable: true }); ConfigCatClient.get = function (sdkKey, pollingMode, options, configCatKernel) { var _a; var invalidSdkKeyError = "Invalid 'sdkKey' value"; if (!sdkKey) { throw new Error(invalidSdkKeyError); } var optionsClass = pollingMode === PollingMode.AutoPoll ? AutoPollOptions : pollingMode === PollingMode.ManualPoll ? ManualPollOptions : pollingMode === PollingMode.LazyLoad ? LazyLoadOptions : throwError(new Error("Invalid 'pollingMode' value")); var actualOptions = new optionsClass(sdkKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.defaultCacheFactory, configCatKernel.eventEmitterFactory); if (((_a = actualOptions.flagOverrides) === null || _a === void 0 ? void 0 : _a.behaviour) !== OverrideBehaviour.LocalOnly && !isValidSdkKey(sdkKey, actualOptions.baseUrlOverriden)) { throw new Error(invalidSdkKeyError); } var _b = clientInstanceCache.getOrCreate(actualOptions, configCatKernel), instance = _b[0], instanceAlreadyCreated = _b[1]; if (instanceAlreadyCreated && options) { actualOptions.logger.clientIsAlreadyCreated(sdkKey); } return instance; }; ConfigCatClient.finalize = function (data) { // Safeguard against situations where user forgets to dispose of the client instance. var _a; (_a = data.logger) === null || _a === void 0 ? void 0 : _a.debug("finalize() called"); if (data.cacheToken) { clientInstanceCache.remove(data.sdkKey, data.cacheToken); } ConfigCatClient.close(data.configService, data.logger); }; ConfigCatClient.close = function (configService, logger, hooks) { logger === null || logger === void 0 ? void 0 : logger.debug("close() called"); hooks === null || hooks === void 0 ? void 0 : hooks.tryDisconnect(); configService === null || configService === void 0 ? void 0 : configService.dispose(); }; ConfigCatClient.prototype.dispose = function () { var options = this.options; options.logger.debug("dispose() called"); if (this.cacheToken) { clientInstanceCache.remove(options.sdkKey, this.cacheToken); } ConfigCatClient.close(this.configService, options.logger, this.hooks); this.suppressFinalize(); }; ConfigCatClient.disposeAll = function () { var removedInstances = clientInstanceCache.clear(); var errors; for (var _i = 0, removedInstances_1 = removedInstances; _i < removedInstances_1.length; _i++) { var instance = removedInstances_1[_i]; try { ConfigCatClient.close(instance.configService, instance.options.logger, instance.hooks); instance.suppressFinalize(); } catch (err) { errors !== null && errors !== void 0 ? errors : (errors = []); errors.push(err); } } if (errors) { throw typeof AggregateError !== "undefined" ? new AggregateError(errors) : errors.pop(); } }; ConfigCatClient.prototype.getValueAsync = function (key, defaultValue, user) { return __awaiter(this, void 0, void 0, function () { var value, evaluationDetails, remoteConfig, settings, err_1; var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: this.options.logger.debug("getValueAsync() called."); validateKey(key); ensureAllowedDefaultValue(defaultValue); remoteConfig = null; user !== null && user !== void 0 ? user : (user = this.defaultUser); _b.label = 1; case 1: _b.trys.push([1, 3, , 4]); settings = void 0; return [4 /*yield*/, this.getSettingsAsync()]; case 2: _a = _b.sent(), settings = _a[0], remoteConfig = _a[1]; evaluationDetails = evaluate(this.evaluator, settings, key, defaultValue, user, remoteConfig, this.options.logger); value = evaluationDetails.value; return [3 /*break*/, 4]; case 3: err_1 = _b.sent(); this.options.logger.settingEvaluationErrorSingle("getValueAsync", key, "defaultValue", defaultValue, err_1); evaluationDetails = evaluationDetailsFromDefaultValue(key, defaultValue, getTimestampAsDate(remoteConfig), user, errorToString(err_1), err_1); value = defaultValue; return [3 /*break*/, 4]; case 4: this.hooks.emit("flagEvaluated", evaluationDetails); return [2 /*return*/, value]; } }); }); }; ConfigCatClient.prototype.getValueDetailsAsync = function (key, defaultValue, user) { return __awaiter(this, void 0, void 0, function () { var evaluationDetails, remoteConfig, settings, err_2; var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: this.options.logger.debug("getValueDetailsAsync() called."); validateKey(key); ensureAllowedDefaultValue(defaultValue); remoteConfig = null; user !== null && user !== void 0 ? user : (user = this.defaultUser); _b.label = 1; case 1: _b.trys.push([1, 3, , 4]); settings = void 0; return [4 /*yield*/, this.getSettingsAsync()]; case 2: _a = _b.sent(), settings = _a[0], remoteConfig = _a[1]; evaluationDetails = evaluate(this.evaluator, settings, key, defaultValue, user, remoteConfig, this.options.logger); return [3 /*break*/, 4]; case 3: err_2 = _b.sent(); this.options.logger.settingEvaluationErrorSingle("getValueDetailsAsync", key, "defaultValue", defaultValue, err_2); evaluationDetails = evaluationDetailsFromDefaultValue(key, defaultValue, getTimestampAsDate(remoteConfig), user, errorToString(err_2), err_2); return [3 /*break*/, 4]; case 4: this.hooks.emit("flagEvaluated", evaluationDetails); return [2 /*return*/, evaluationDetails]; } }); }); }; ConfigCatClient.prototype.getAllKeysAsync = function () { return __awaiter(this, void 0, void 0, function () { var defaultReturnValue, settings, err_3; return __generator(this, function (_a) { switch (_a.label) { case 0: this.options.logger.debug("getAllKeysAsync() called."); defaultReturnValue = "empty array"; _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, this.getSettingsAsync()]; case 2: settings = (_a.sent())[0]; if (!checkSettingsAvailable(settings, this.options.logger, defaultReturnValue)) { return [2 /*return*/, []]; } return [2 /*return*/, Object.keys(settings)]; case 3: err_3 = _a.sent(); this.options.logger.settingEvaluationError("getAllKeysAsync", defaultReturnValue, err_3); return [2 /*return*/, []]; case 4: return [2 /*return*/]; } }); }); }; ConfigCatClient.prototype.getAllValuesAsync = function (user) { return __awaiter(this, void 0, void 0, function () { var defaultReturnValue, result, evaluationDetailsArray, evaluationErrors, _a, settings, remoteConfig, err_4, _i, evaluationDetailsArray_1, evaluationDetail; var _b; return __generator(this, function (_c) { switch (_c.label) { case 0: this.options.logger.debug("getAllValuesAsync() called."); defaultReturnValue = "empty array"; user !== null && user !== void 0 ? user : (user = this.defaultUser); _c.label = 1; case 1: _c.trys.push([1, 3, , 4]); return [4 /*yield*/, this.getSettingsAsync()]; case 2: _a = _c.sent(), settings = _a[0], remoteConfig = _a[1]; _b = evaluateAll(this.evaluator, settings, user, remoteConfig, this.options.logger, defaultReturnValue), evaluationDetailsArray = _b[0], evaluationErrors = _b[1]; result = evaluationDetailsArray.map(function (details) { return new SettingKeyValue(details.key, details.value); }); return [3 /*break*/, 4]; case 3: err_4 = _c.sent(); this.options.logger.settingEvaluationError("getAllValuesAsync", defaultReturnValue, err_4); return [2 /*return*/, []]; case 4: if (evaluationErrors === null || evaluationErrors === void 0 ? void 0 : evaluationErrors.length) { this.options.logger.settingEvaluationError("getAllValuesAsync", "evaluation result", typeof AggregateError !== "undefined" ? new AggregateError(evaluationErrors) : evaluationErrors.pop()); } for (_i = 0, evaluationDetailsArray_1 = evaluationDetailsArray; _i < evaluationDetailsArray_1.length; _i++) { evaluationDetail = evaluationDetailsArray_1[_i]; this.hooks.emit("flagEvaluated", evaluationDetail); } return [2 /*return*/, result]; } }); }); }; ConfigCatClient.prototype.getAllValueDetailsAsync = function (user) { return __awaiter(this, void 0, void 0, function () { var defaultReturnValue, evaluationDetailsArray, evaluationErrors, _a, settings, remoteConfig, err_5, _i, evaluationDetailsArray_2, evaluationDetail; var _b; return __generator(this, function (_c) { switch (_c.label) { case 0: this.options.logger.debug("getAllValueDetailsAsync() called."); defaultReturnValue = "empty array"; user !== null && user !== void 0 ? user : (user = this.defaultUser); _c.label = 1; case 1: _c.trys.push([1, 3, , 4]); return [4 /*yield*/, this.getSettingsAsync()]; case 2: _a = _c.sent(), settings = _a[0], remoteConfig = _a[1]; _b = evaluateAll(this.evaluator, settings, user, remoteConfig, this.options.logger, defaultReturnValue), evaluationDetailsArray = _b[0], evaluationErrors = _b[1]; return [3 /*break*/, 4]; case 3: err_5 = _c.sent(); this.options.logger.settingEvaluationError("getAllValueDetailsAsync", defaultReturnValue, err_5); return [2 /*return*/, []]; case 4: if (evaluationErrors === null || evaluationErrors === void 0 ? void 0 : evaluationErrors.length) { this.options.logger.settingEvaluationError("getAllValueDetailsAsync", "evaluation result", typeof AggregateError !== "undefined" ? new AggregateError(evaluationErrors) : evaluationErrors.pop()); } for (_i = 0, evaluationDetailsArray_2 = evaluationDetailsArray; _i < evaluationDetailsArray_2.length; _i++) { evaluationDetail = evaluationDetailsArray_2[_i]; this.hooks.emit("flagEvaluated", evaluationDetail); } return [2 /*return*/, evaluationDetailsArray]; } }); }); }; ConfigCatClient.prototype.getKeyAndValueAsync = function (variationId) { return __awaiter(this, void 0, void 0, function () { var defaultReturnValue, settings, _i, _a, _b, settingKey, setting, targetingRules, i, then, j, percentageOption, percentageOptions, i, percentageOption, err_6; return __generator(this, function (_c) { switch (_c.label) { case 0: this.options.logger.debug("getKeyAndValueAsync() called."); defaultReturnValue = "null"; _c.label = 1; case 1: _c.trys.push([1, 3, , 4]); return [4 /*yield*/, this.getSettingsAsync()]; case 2: settings = (_c.sent())[0]; if (!checkSettingsAvailable(settings, this.options.logger, defaultReturnValue)) { return [2 /*return*/, null]; } for (_i = 0, _a = Object.entries(settings); _i < _a.length; _i++) { _b = _a[_i], settingKey = _b[0], setting = _b[1]; if (variationId === setting.variationId) { return [2 /*return*/, new SettingKeyValue(settingKey, ensureAllowedValue(setting.value))]; } targetingRules = settings[settingKey].targetingRules; if (targetingRules && targetingRules.length > 0) { for (i = 0; i < targetingRules.length; i++) { then = targetingRules[i].then; if (isArray(then)) { for (j = 0; j < then.length; j++) { percentageOption = then[j]; if (variationId === percentageOption.variationId) { return [2 /*return*/, new SettingKeyValue(settingKey, ensureAllowedValue(percentageOption.value))]; } } } else if (variationId === then.variationId) { return [2 /*return*/, new SettingKeyValue(settingKey, ensureAllowedValue(then.value))]; } } } percentageOptions = settings[settingKey].percentageOptions; if (percentageOptions && percentageOptions.length > 0) { for (i = 0; i < percentageOptions.length; i++) { percentageOption = percentageOptions[i]; if (variationId === percentageOption.variationId) { return [2 /*return*/, new SettingKeyValue(settingKey, ensureAllowedValue(percentageOption.value))]; } } } } this.options.logger.settingForVariationIdIsNotPresent(variationId); return [3 /*break*/, 4]; case 3: err_6 = _c.sent(); this.options.logger.settingEvaluationError("getKeyAndValueAsync", defaultReturnValue, err_6); return [3 /*break*/, 4]; case 4: return [2 /*return*/, null]; } }); }); }; ConfigCatClient.prototype.forceRefreshAsync = function () { return __awaiter(this, void 0, void 0, function () { var result, err_7; return __generator(this, function (_a) { switch (_a.label) { case 0: this.options.logger.debug("forceRefreshAsync() called."); if (!this.configService) return [3 /*break*/, 5]; _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, this.configService.refreshConfigAsync()]; case 2: result = (_a.sent())[0]; return [2 /*return*/, result]; case 3: err_7 = _a.sent(); this.options.logger.forceRefreshError("forceRefreshAsync", err_7); return [2 /*return*/, RefreshResult.failure(errorToString(err_7), err_7)]; case 4: return [3 /*break*/, 6]; case 5: return [2 /*return*/, RefreshResult.failure("Client is configured to use the LocalOnly override behavior, which prevents making HTTP requests.")]; case 6: return [2 /*return*/]; } }); }); }; ConfigCatClient.prototype.setDefaultUser = function (defaultUser) { this.defaultUser = defaultUser; }; ConfigCatClient.prototype.clearDefaultUser = function () { this.defaultUser = void 0; }; Object.defineProperty(ConfigCatClient.prototype, "isOffline", { get: function () { var _a, _b; return (_b = (_a = this.configService) === null || _a === void 0 ? void 0 : _a.isOffline) !== null && _b !== void 0 ? _b : true; }, enumerable: false, configurable: true }); ConfigCatClient.prototype.setOnline = function () { if (this.configService) { this.configService.setOnline(); } else { this.options.logger.configServiceMethodHasNoEffectDueToOverrideBehavior(OverrideBehaviour[OverrideBehaviour.LocalOnly], "setOnline"); } }; ConfigCatClient.prototype.setOffline = function () { var _a; (_a = this.configService) === null || _a === void 0 ? void 0 : _a.setOffline(); }; ConfigCatClient.prototype.waitForReady = function () { var configService = this.configService; return configService ? configService.readyPromise : Promise.resolve(ClientCacheState.HasLocalOverrideFlagDataOnly); }; ConfigCatClient.prototype.snapshot = function () { var _a, _b, _c; var _this = this; var _d; var getRemoteConfig = function () { var config = _this.options.cache.getInMemory(); var settings = !config.isEmpty ? config.config.settings : null; return [settings, config]; }; var remoteSettings; var remoteConfig; var flagOverrides = (_d = this.options) === null || _d === void 0 ? void 0 : _d.flagOverrides; if (flagOverrides) { var localSettings = flagOverrides.dataSource.getOverridesSync(); switch (flagOverrides.behaviour) { case OverrideBehaviour.LocalOnly: return new Snapshot(localSettings, null, this); case OverrideBehaviour.LocalOverRemote: _a = getRemoteConfig(), remoteSettings = _a[0], remoteConfig = _a[1]; return new Snapshot(__assign(__assign({}, (remoteSettings !== null && remoteSettings !== void 0 ? remoteSettings : {})), localSettings), remoteConfig, this); case OverrideBehaviour.RemoteOverLocal: _b = getRemoteConfig(), remoteSettings = _b[0], remoteConfig = _b[1]; return new Snapshot(__assign(__assign({}, localSettings), (remoteSettings !== null && remoteSettings !== void 0 ? remoteSettings : {})), remoteConfig, this); } } _c = getRemoteConfig(), remoteSettings = _c[0], remoteConfig = _c[1]; return new Snapshot(remoteSettings, remoteConfig, this); }; ConfigCatClient.prototype.getSettingsAsync = function () { var _a; return __awaiter(this, void 0, void 0, function () { var getRemoteConfigAsync, flagOverrides, remoteSettings, remoteConfig, localSettings, _b; var _c, _d; var _this = this; return __generator(this, function (_e) { switch (_e.label) { case 0: this.options.logger.debug("getSettingsAsync() called."); getRemoteConfigAsync = function () { return __awaiter(_this, void 0, void 0, function () { var config, settings; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.configService.getConfig()]; case 1: config = _a.sent(); settings = !config.isEmpty ? config.config.settings : null; return [2 /*return*/, [settings, config]]; } }); }); }; flagOverrides = (_a = this.options) === null || _a === void 0 ? void 0 : _a.flagOverrides; if (!flagOverrides) return [3 /*break*/, 7]; remoteSettings = void 0; remoteConfig = void 0; return [4 /*yield*/, flagOverrides.dataSource.getOverrides()]; case 1: localSettings = _e.sent(); _b = flagOverrides.behaviour; switch (_b) { case OverrideBehaviour.LocalOnly: return [3 /*break*/, 2]; case OverrideBehaviour.LocalOverRemote: return [3 /*break*/, 3]; case OverrideBehaviour.RemoteOverLocal: return [3 /*break*/, 5]; } return [3 /*break*/, 7]; case 2: return [2 /*return*/, [localSettings, null]]; case 3: return [4 /*yield*/, getRemoteConfigAsync()]; case 4: _c = _e.sent(), remoteSettings = _c[0], remoteConfig = _c[1]; return [2 /*return*/, [__assign(__assign({}, (remoteSettings !== null && remoteSettings !== void 0 ? remoteSettings : {})), localSettings), remoteConfig]]; case 5: return [4 /*yield*/, getRemoteConfigAsync()]; case 6: _d = _e.sent(), remoteSettings = _d[0], remoteConfig = _d[1]; return [2 /*return*/, [__assign(__assign({}, localSettings), (remoteSettings !== null && remoteSettings !== void 0 ? remoteSettings : {})), remoteConfig]]; case 7: return [4 /*yield*/, getRemoteConfigAsync()]; case 8: return [2 /*return*/, _e.sent()]; } }); }); }; /** @inheritdoc */ ConfigCatClient.prototype.on = function (eventName, listener) { this.hooks.on(eventName, listener); return this; }; /** @inheritdoc */ ConfigCatClient.prototype.once = function (eventName, listener) { this.hooks.once(eventName, listener); return this; }; /** @inheritdoc */ ConfigCatClient.prototype.removeListener = function (eventName, listener) { this.hooks.removeListener(eventName, listener); return this; }; /** @inheritdoc */ ConfigCatClient.prototype.removeAllListeners = function (eventName) { this.hooks.removeAllListeners(eventName); return this; }; /** @inheritdoc */ ConfigCatClient.prototype.listeners = function (eventName) { return this.hooks.listeners(eventName); }; /** @inheritdoc */ ConfigCatClient.prototype.listenerCount = function (eventName) { return this.hooks.listenerCount(eventName); }; /** @inheritdoc */ ConfigCatClient.prototype.eventNames = function () { return this.hooks.eventNames(); }; return ConfigCatClient; }()); export { ConfigCatClient }; var Snapshot = /** @class */ (function () { function Snapshot(mergedSettings, remoteConfig, client) { this.mergedSettings = mergedSettings; this.remoteConfig = remoteConfig; this.defaultUser = client["defaultUser"]; this.evaluator = client["evaluator"]; this.options = client["options"]; this.cacheState = remoteConfig ? client["configService"].getCacheState(remoteConfig) : ClientCacheState.HasLocalOverrideFlagDataOnly; } Object.defineProperty(Snapshot.prototype, "fetchedConfig", { get: function () { var config = this.remoteConfig; return config && !config.isEmpty ? config.config : null; }, enumerable: false, configurable: true }); Snapshot.prototype.getAllKeys = function () { return this.mergedSettings ? Object.keys(this.mergedSettings) : []; }; Snapshot.prototype.getValue = function (key, defaultValue, user) { this.options.logger.debug("Snapshot.getValue() called."); validateKey(key); ensureAllowedDefaultValue(defaultValue); var value, evaluationDetails; user !== null && user !== void 0 ? user : (user = this.defaultUser); try { evaluationDetails = evaluate(this.evaluator, this.mergedSettings, key, defaultValue, user, this.remoteConfig, this.options.logger); value = evaluationDetails.value; } catch (err) { this.options.logger.settingEvaluationErrorSingle("Snapshot.getValue", key, "defaultValue", defaultValue, err); evaluationDetails = evaluationDetailsFromDefaultValue(key, defaultValue, getTimestampAsDate(this.remoteConfig), user, errorToString(err), err); value = defaultValue; } this.options.hooks.emit("flagEvaluated", evaluationDetails); return value; }; Snapshot.prototype.getValueDetails = function (key, defaultValue, user) { this.options.logger.debug("Snapshot.getValueDetails() called."); validateKey(key); ensureAllowedDefaultValue(defaultValue); var evaluationDetails; user !== null && user !== void 0 ? user : (user = this.defaultUser); try { evaluationDetails = evaluate(this.evaluator, this.mergedSettings, key, defaultValue, user, this.remoteConfig, this.options.logger); } catch (err) { this.options.logger.settingEvaluationErrorSingle("Snapshot.getValueDetails", key, "defaultValue", defaultValue, err); evaluationDetails = evaluationDetailsFromDefaultValue(key, defaultValue, getTimestampAsDate(this.remoteConfig), user, errorToString(err), err); } this.options.hooks.emit("flagEvaluated", evaluationDetails); return evaluationDetails; }; return Snapshot; }()); /** Setting key-value pair. */ var SettingKeyValue = /** @class */ (function () { function SettingKeyValue(settingKey, settingValue) { this.settingKey = settingKey; this.settingValue = settingValue; } return SettingKeyValue; }()); export { SettingKeyValue }; function isValidSdkKey(sdkKey, customBaseUrl) { var proxyPrefix = "configcat-proxy/"; // NOTE: String.prototype.startsWith was introduced after ES5. We'd rather work around it instead of polyfilling it. if (customBaseUrl && sdkKey.length > proxyPrefix.length && sdkKey.lastIndexOf(proxyPrefix, 0) === 0) { return true; } var components = sdkKey.split("/"); var keyLength = 22; switch (components.length) { case 2: return components[0].length === keyLength && components[1].length === keyLength; case 3: return components[0] === "configcat-sdk-1" && components[1].length === keyLength && components[2].length === keyLength; default: return false; } } function validateKey(key) { if (!key) { throw new Error("Invalid 'key' value"); } } function ensureAllowedDefaultValue(value) { if (value != null && !isAllowedValue(value)) { throw new TypeError("The default value must be boolean, number, string, null or undefined."); } } function ensureAllowedValue(value) { return isAllowedValue(value) ? value : handleInvalidReturnValue(value); } var registerForFinalization = function (client, data) { // Use FinalizationRegistry (finalization callbacks) if the runtime provides that feature. if (typeof FinalizationRegistry !== "undefined") { var finalizationRegistry_1 = new FinalizationRegistry(function (data) { return ConfigCatClient["finalize"](data); }); registerForFinalization = function (client, data) { var unregisterToken = {}; finalizationRegistry_1.register(client, data, unregisterToken); return function () { return finalizationRegistry_1.unregister(unregisterToken); }; }; } // If FinalizationRegistry is unavailable, we can't really track finalization. // (Although we could implement something which resembles finalization callbacks using a weak map + a timer, // since ConfigCatClientCache also needs to keep (weak) references to the created client instances, // this hypothetical approach wouldn't work without a complete WeakRef polyfill, // which is kind of impossible (for more details, see Polyfills.ts). else { registerForFinalization = function () { return function () { }; }; } return registerForFinalization(client, data); };