Socket
Socket
Sign inDemoInstall

configcat-common

Package Overview
Dependencies
Maintainers
4
Versions
83
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

configcat-common - npm Package Compare versions

Comparing version 6.0.1 to 7.0.0

DEPENDENCIES.md

28

lib/AutoPollConfigService.d.ts
import { AutoPollOptions } from "./ConfigCatClientOptions";
import { IConfigService, ConfigServiceBase } from "./ConfigServiceBase";
import { IConfigFetcher } from "./index";
import type { IConfigFetcher } from "./ConfigFetcher";
import { ConfigServiceBase, IConfigService, RefreshResult } from "./ConfigServiceBase";
import { ProjectConfig } from "./ProjectConfig";
export declare class AutoPollConfigService extends ConfigServiceBase implements IConfigService {
private maxInitWaitTimeStamp;
private configChanged;
private timerId;
private autoPollConfig;
private disposed;
constructor(configFetcher: IConfigFetcher, autoPollConfig: AutoPollOptions);
export declare class AutoPollConfigService extends ConfigServiceBase<AutoPollOptions> implements IConfigService {
private initialized;
private initialization;
private signalInitialization;
private timerId?;
constructor(configFetcher: IConfigFetcher, options: AutoPollOptions);
private waitForInitializationAsync;
getConfig(): Promise<ProjectConfig | null>;
refreshConfigAsync(): Promise<ProjectConfig | null>;
refreshConfigAsync(): Promise<[RefreshResult, ProjectConfig | null]>;
dispose(): void;
private refreshLogic;
protected onConfigUpdated(newConfig: ProjectConfig): void;
protected onConfigChanged(newConfig: ProjectConfig): void;
protected setOnlineCore(): void;
protected setOfflineCore(): void;
private startRefreshWorker;
private stopRefreshWorker;
private refreshWorkerLogic;
private tryReadFromCache;
private sleep;
}
//# sourceMappingURL=AutoPollConfigService.d.ts.map
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AutoPollConfigService = void 0;
var tslib_1 = require("tslib");
var ConfigServiceBase_1 = require("./ConfigServiceBase");
var ProjectConfig_1 = require("./ProjectConfig");
var Utils_1 = require("./Utils");
var AutoPollConfigService = /** @class */ (function (_super) {
__extends(AutoPollConfigService, _super);
function AutoPollConfigService(configFetcher, autoPollConfig) {
var _this = _super.call(this, configFetcher, autoPollConfig) || this;
_this.disposed = false;
_this.configChanged = autoPollConfig.configChanged;
_this.autoPollConfig = autoPollConfig;
_this.startRefreshWorker(autoPollConfig.pollIntervalSeconds * 1000);
_this.maxInitWaitTimeStamp = new Date().getTime() + (autoPollConfig.maxInitWaitTimeSeconds * 1000);
tslib_1.__extends(AutoPollConfigService, _super);
function AutoPollConfigService(configFetcher, options) {
var _this = _super.call(this, configFetcher, options) || this;
_this.signalInitialization = (void 0); // the initial value is only for keeping the TS compiler happy
if (options.maxInitWaitTimeSeconds > 0) {
_this.initialized = false;
// This promise will be resolved when
// 1. the cache contains a valid config at startup (see startRefreshWorker) or
// 2. config.json is downloaded the first time (see onConfigUpdated) or
// 3. maxInitWaitTimeSeconds has passed (see the setTimeout call below).
_this.initialization = new Promise(function (resolve) { return _this.signalInitialization = function () {
_this.initialized = true;
resolve();
}; });
_this.initialization.then(function () { return !_this.disposed && options.hooks.emit("clientReady"); });
setTimeout(function () { return _this.signalInitialization(); }, options.maxInitWaitTimeSeconds * 1000);
}
else {
_this.initialized = true;
_this.initialization = Promise.resolve();
options.hooks.emit("clientReady");
}
if (!options.offline) {
_this.startRefreshWorker(options.pollIntervalSeconds * 1000);
}
return _this;
}
AutoPollConfigService.prototype.waitForInitializationAsync = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var cancelDelay, result;
var _this = this;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, Promise.race([
(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.initialization];
case 1:
_a.sent();
return [2 /*return*/, true];
}
}); }); })(),
(0, Utils_1.delay)(this.options.maxInitWaitTimeSeconds * 1000, function (cancel) { return cancelDelay = cancel; })
])];
case 1:
result = _a.sent();
cancelDelay();
return [2 /*return*/, !!result];
}
});
});
};
AutoPollConfigService.prototype.getConfig = function () {
return __awaiter(this, void 0, void 0, function () {
var p;
return __generator(this, function (_a) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
function logSuccess(logger) {
logger.debug("AutoPollConfigService.getConfig() - returning value from cache.");
}
var cacheConfig;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
this.autoPollConfig.logger.debug("AutoPollConfigService.getConfig() called.");
return [4 /*yield*/, this.tryReadFromCache(0)];
this.options.logger.debug("AutoPollConfigService.getConfig() called.");
cacheConfig = null;
if (!(!this.isOffline && !this.initialized)) return [3 /*break*/, 3];
return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 1:
p = _a.sent();
if (!p) {
this.autoPollConfig.logger.debug("AutoPollConfigService.getConfig() - cache is empty, refreshing the cache.");
return [2 /*return*/, this.refreshLogic(true)];
cacheConfig = _a.sent();
if (!ProjectConfig_1.ProjectConfig.isExpired(cacheConfig, this.options.pollIntervalSeconds * 1000)) {
logSuccess(this.options.logger);
return [2 /*return*/, cacheConfig];
}
this.options.logger.debug("AutoPollConfigService.getConfig() - cache is empty or expired, waiting for initialization.");
return [4 /*yield*/, this.waitForInitializationAsync()];
case 2:
_a.sent();
_a.label = 3;
case 3: return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 4:
cacheConfig = _a.sent();
if (!ProjectConfig_1.ProjectConfig.isExpired(cacheConfig, this.options.pollIntervalSeconds * 1000)) {
logSuccess(this.options.logger);
}
else {
this.autoPollConfig.logger.debug("AutoPollConfigService.getConfig() - returning value from cache.");
return [2 /*return*/, new Promise(function (resolve) { return resolve(p); })];
this.options.logger.debug("AutoPollConfigService.getConfig() - cache is empty or expired.");
}
return [2 /*return*/];
return [2 /*return*/, cacheConfig];
}

@@ -92,92 +100,83 @@ });

AutoPollConfigService.prototype.refreshConfigAsync = function () {
this.autoPollConfig.logger.debug("AutoPollConfigService.refreshConfigAsync() called.");
return this.refreshLogic(true);
this.options.logger.debug("AutoPollConfigService.refreshConfigAsync() called.");
return _super.prototype.refreshConfigAsync.call(this);
};
AutoPollConfigService.prototype.dispose = function () {
this.autoPollConfig.logger.debug("AutoPollConfigService.dispose() called.");
this.disposed = true;
this.options.logger.debug("AutoPollConfigService.dispose() called.");
_super.prototype.dispose.call(this);
if (this.timerId) {
this.autoPollConfig.logger.debug("AutoPollConfigService.dispose() - clearing setTimeout.");
clearTimeout(this.timerId);
this.stopRefreshWorker();
}
};
AutoPollConfigService.prototype.refreshLogic = function (forceUpdateCache) {
var _this = this;
this.autoPollConfig.logger.debug("AutoPollConfigService.refreshLogic() - called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var cachedConfig, newConfig, weDontHaveCachedYetButHaveNew, weHaveBothButTheyDiffers;
return __generator(this, function (_a) {
AutoPollConfigService.prototype.onConfigUpdated = function (newConfig) {
_super.prototype.onConfigUpdated.call(this, newConfig);
this.signalInitialization();
};
AutoPollConfigService.prototype.onConfigChanged = function (newConfig) {
_super.prototype.onConfigChanged.call(this, newConfig);
this.options.configChanged();
};
AutoPollConfigService.prototype.setOnlineCore = function () {
this.startRefreshWorker(this.options.pollIntervalSeconds * 1000);
};
AutoPollConfigService.prototype.setOfflineCore = function () {
this.stopRefreshWorker();
};
AutoPollConfigService.prototype.startRefreshWorker = function (delayMs) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var latestConfig;
var _this = this;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.baseConfig.cache.get(this.baseConfig.getCacheKey())];
case 0:
this.options.logger.debug("AutoPollConfigService.startRefreshWorker() called.");
return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 1:
cachedConfig = _a.sent();
return [4 /*yield*/, this.refreshLogicBaseAsync(cachedConfig, forceUpdateCache)];
latestConfig = _a.sent();
if (!ProjectConfig_1.ProjectConfig.isExpired(latestConfig, this.options.pollIntervalSeconds * 1000)) return [3 /*break*/, 4];
if (!!this.isOfflineExactly) return [3 /*break*/, 3];
return [4 /*yield*/, this.refreshConfigCoreAsync(latestConfig)];
case 2:
newConfig = _a.sent();
weDontHaveCachedYetButHaveNew = !cachedConfig && newConfig;
weHaveBothButTheyDiffers = cachedConfig && newConfig && !ProjectConfig_1.ProjectConfig.equals(cachedConfig, newConfig);
this.autoPollConfig.logger.debug("AutoPollConfigService.refreshLogic() - weDontHaveCachedYetButHaveNew: ." + weDontHaveCachedYetButHaveNew + ". weHaveBothButTheyDiffers: " + weHaveBothButTheyDiffers + ".");
if (weDontHaveCachedYetButHaveNew || weHaveBothButTheyDiffers) {
this.configChanged();
}
resolve(newConfig);
_a.sent();
_a.label = 3;
case 3: return [3 /*break*/, 5];
case 4:
this.signalInitialization();
_a.label = 5;
case 5:
this.options.logger.debug("AutoPollConfigService.startRefreshWorker() - calling refreshWorkerLogic()'s setTimeout.");
this.timerId = setTimeout(function (d) { return _this.refreshWorkerLogic(d); }, delayMs, delayMs);
return [2 /*return*/];
}
});
}); });
};
AutoPollConfigService.prototype.startRefreshWorker = function (delay) {
var _this = this;
this.autoPollConfig.logger.debug("AutoPollConfigService.startRefreshWorker() called.");
this.refreshLogic(true).then(function (_) {
_this.autoPollConfig.logger.debug("AutoPollConfigService.startRefreshWorker() - calling refreshWorkerLogic()'s setTimeout.");
setTimeout(function () { return _this.refreshWorkerLogic(delay); }, delay);
});
};
AutoPollConfigService.prototype.refreshWorkerLogic = function (delay) {
var _this = this;
if (this.disposed) {
this.autoPollConfig.logger.debug("AutoPollConfigService.refreshWorkerLogic() - called on a disposed client.");
return;
}
this.autoPollConfig.logger.debug("AutoPollConfigService.refreshWorkerLogic() - called.");
this.refreshLogic(false).then(function (_) {
_this.autoPollConfig.logger.debug("AutoPollConfigService.refreshWorkerLogic() - calling refreshWorkerLogic()'s setTimeout.");
_this.timerId = setTimeout(function () {
_this.refreshWorkerLogic(delay);
}, delay);
});
AutoPollConfigService.prototype.stopRefreshWorker = function () {
this.options.logger.debug("AutoPollConfigService.stopRefreshWorker() - clearing setTimeout.");
clearTimeout(this.timerId);
};
AutoPollConfigService.prototype.tryReadFromCache = function (tries) {
return __awaiter(this, void 0, void 0, function () {
var p, diff, delay;
return __generator(this, function (_a) {
AutoPollConfigService.prototype.refreshWorkerLogic = function (delayMs) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var latestConfig;
var _this = this;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
this.autoPollConfig.logger.debug("AutoPollConfigService.tryReadFromCache() - called. Tries: " + tries + ".");
return [4 /*yield*/, this.baseConfig.cache.get(this.baseConfig.getCacheKey())];
if (this.disposed) {
this.options.logger.debug("AutoPollConfigService.refreshWorkerLogic() - called on a disposed client.");
return [2 /*return*/];
}
this.options.logger.debug("AutoPollConfigService.refreshWorkerLogic() - called.");
if (!!this.isOffline) return [3 /*break*/, 3];
return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 1:
p = _a.sent();
if (!(this.maxInitWaitTimeStamp > new Date().getTime()
&& (
// Wait for maxInitWaitTimeStamp in case the cache is empty
!p
// Wait for maxInitWaitTimeStamp in case of an expired cache (if its timestamp is older than the pollIntervalSeconds)
|| p.Timestamp < new Date().getTime() - this.autoPollConfig.pollIntervalSeconds * 1000))) return [3 /*break*/, 3];
if (!p) {
this.autoPollConfig.logger.debug("AutoPollConfigService.tryReadFromCache() - waiting for maxInitWaitTimeStamp because cache is empty.");
}
else {
this.autoPollConfig.logger.debug("AutoPollConfigService.tryReadFromCache() - waiting for maxInitWaitTimeStamp because cache is expired.");
}
diff = this.maxInitWaitTimeStamp - new Date().getTime();
delay = 30 + (tries * tries * 20);
return [4 /*yield*/, this.sleep(Math.min(diff, delay))];
latestConfig = _a.sent();
return [4 /*yield*/, this.refreshConfigCoreAsync(latestConfig)];
case 2:
_a.sent();
tries++;
return [2 /*return*/, this.tryReadFromCache(tries)];
_a.label = 3;
case 3:
this.autoPollConfig.logger.debug("AutoPollConfigService.tryReadFromCache() - returning value from cache.");
return [2 /*return*/, new Promise(function (resolve) { return resolve(p); })];
this.options.logger.debug("AutoPollConfigService.refreshWorkerLogic() - calling refreshWorkerLogic()'s setTimeout.");
this.timerId = setTimeout(function (d) { return _this.refreshWorkerLogic(d); }, delayMs, delayMs);
return [2 /*return*/];
}

@@ -187,7 +186,4 @@ });

};
AutoPollConfigService.prototype.sleep = function (ms) {
return new Promise(function (resolve) { return setTimeout(resolve, ms); });
};
return AutoPollConfigService;
}(ConfigServiceBase_1.ConfigServiceBase));
exports.AutoPollConfigService = AutoPollConfigService;
import { ProjectConfig } from "./ProjectConfig";
import { ICache } from "./index";
export interface ICache {
set(key: string, config: ProjectConfig): Promise<void> | void;
get(key: string): Promise<ProjectConfig | null> | ProjectConfig | null;
}
export declare class InMemoryCache implements ICache {

@@ -8,4 +11,4 @@ cache: {

set(key: string, config: ProjectConfig): void;
get(key: string): ProjectConfig;
get(key: string): ProjectConfig | null;
}
//# sourceMappingURL=Cache.d.ts.map

@@ -12,3 +12,4 @@ "use strict";

InMemoryCache.prototype.get = function (key) {
return this.cache[key];
var _a;
return (_a = this.cache[key]) !== null && _a !== void 0 ? _a : null;
};

@@ -15,0 +16,0 @@ return InMemoryCache;

@@ -1,26 +0,52 @@

import { IConfigCatKernel } from "./index";
import { AutoPollOptions, ManualPollOptions, LazyLoadOptions } from "./ConfigCatClientOptions";
import { User } from "./RolloutEvaluator";
export interface IConfigCatClient {
import type { ICache } from "./Cache";
import { ConfigCatClientOptions, OptionsForPollingMode, PollingMode } from "./ConfigCatClientOptions";
import type { IConfigFetcher } from "./ConfigFetcher";
import { RefreshResult } from "./ConfigServiceBase";
import type { IEventEmitter } from "./EventEmitter";
import type { HookEvents, IProvidesHooks } from "./Hooks";
import { IEvaluationDetails, SettingTypeOf, SettingValue, User, VariationIdTypeOf, VariationIdValue } from "./RolloutEvaluator";
export interface IConfigCatClient extends IProvidesHooks {
/** Returns the value of a feature flag or setting based on it's key
* @deprecated This method is obsolete and will be removed from the public API in a future major version. Please use the getValueAsync() method instead.
*/
getValue<T extends SettingValue>(key: string, defaultValue: T, callback: (value: SettingTypeOf<T>) => void, user?: User): void;
/** Returns the value of a feature flag or setting based on it's key */
getValue(key: string, defaultValue: any, callback: (value: any) => void, user?: User): void;
/** Returns the value of a feature flag or setting based on it's key */
getValueAsync(key: string, defaultValue: any, user?: User): Promise<any>;
getValueAsync<T extends SettingValue>(key: string, defaultValue: T, user?: User): Promise<SettingTypeOf<T>>;
/** Returns the value along with evaluation details of a feature flag or setting based on it's key
* @deprecated This method is obsolete and will be removed from the public API in a future major version. Please use the getValueDetailsAsync() method instead.
*/
getValueDetails<T extends SettingValue>(key: string, defaultValue: T, callback: (evaluationDetails: IEvaluationDetails<SettingTypeOf<T>>) => void, user?: User): void;
/** Returns the value along with evaluation details of a feature flag or setting based on it's key */
getValueDetailsAsync<T extends SettingValue>(key: string, defaultValue: T, user?: User): Promise<IEvaluationDetails<SettingTypeOf<T>>>;
/** Downloads the latest feature flag and configuration values
* @deprecated This method is obsolete and will be removed from the public API in a future major version. Please use the forceRefreshAsync() method instead.
*/
forceRefresh(callback: (result: RefreshResult) => void): void;
/** Downloads the latest feature flag and configuration values */
forceRefresh(callback: () => void): void;
/** Downloads the latest feature flag and configuration values */
forceRefreshAsync(): Promise<any>;
/** Gets a list of keys for all your feature flags and settings */
forceRefreshAsync(): Promise<RefreshResult>;
/** Gets a list of keys for all your feature flags and settings
* @deprecated This method is obsolete and will be removed from the public API in a future major version. Please use the getAllKeysAsync() method instead.
*/
getAllKeys(callback: (value: string[]) => void): void;
/** Gets a list of keys for all your feature flags and settings */
getAllKeysAsync(): Promise<string[]>;
/** Returns the Variation ID (analytics) of a feature flag or setting based on it's key */
getVariationId(key: string, defaultVariationId: any, callback: (variationId: string) => void, user?: User): void;
/** Returns the Variation ID (analytics) of a feature flag or setting based on it's key */
getVariationIdAsync(key: string, defaultVariationId: any, user?: User): Promise<string>;
/** Returns the Variation IDs (analytics) of all feature flags or settings */
/** Returns the Variation ID (analytics) of a feature flag or setting based on it's key
* @deprecated This method is obsolete and will be removed from the public API in a future major version. Please use the getValueDetails() method instead.
*/
getVariationId<T extends VariationIdValue>(key: string, defaultVariationId: T, callback: (variationId: VariationIdTypeOf<T>) => void, user?: User): void;
/** Returns the Variation ID (analytics) of a feature flag or setting based on it's key
* @deprecated This method is obsolete and will be removed from the public API in a future major version. Please use the getValueDetailsAsync() method instead.
*/
getVariationIdAsync<T extends VariationIdValue>(key: string, defaultVariationId: T, user?: User): Promise<VariationIdTypeOf<T>>;
/** Returns the Variation IDs (analytics) of all feature flags or settings
* @deprecated This method is obsolete and will be removed from the public API in a future major version. Please use the getAllValueDetails() method instead.
*/
getAllVariationIds(callback: (variationIds: string[]) => void, user?: User): void;
/** Returns the Variation IDs (analytics) of all feature flags or settings */
/** Returns the Variation IDs (analytics) of all feature flags or settings
* @deprecated This method is obsolete and will be removed from the public API in a future major version. Please use the getAllValueDetailsAsync() method instead.
*/
getAllVariationIdsAsync(user?: User): Promise<string[]>;
/** Returns the key of a setting and it's value identified by the given Variation ID (analytics) */
/** Returns the key of a setting and it's value identified by the given Variation ID (analytics)
* @deprecated This method is obsolete and will be removed from the public API in a future major version. Please use the getKeyAndValueAsync() method instead.
*/
getKeyAndValue(variationId: string, callback: (settingkeyAndValue: SettingKeyValue | null) => void): void;

@@ -31,6 +57,14 @@ /** Returns the key of a setting and it's value identified by the given Variation ID (analytics) */

dispose(): void;
/** Returns the values of all feature flags or settings */
/** Returns the values of all feature flags or settings
* @deprecated This method is obsolete and will be removed from the public API in a future major version. Please use the getAllValuesAsync() method instead.
*/
getAllValues(callback: (result: SettingKeyValue[]) => void, user?: User): void;
/** Returns the values of all feature flags or settings */
getAllValuesAsync(user?: User): Promise<SettingKeyValue[]>;
/** Returns the values along with evaluation details of all feature flags or settings
* @deprecated This method is obsolete and will be removed from the public API in a future major version. Please use the getAllValueDetailsAsync() method instead.
*/
getAllValueDetails(callback: (result: IEvaluationDetails[]) => void, user?: User): void;
/** Returns the values along with evaluation details of all feature flags or settings */
getAllValueDetailsAsync(user?: User): Promise<IEvaluationDetails[]>;
/** Sets the default user for feature flag evaluations.

@@ -41,4 +75,27 @@ * In case the getValue function isn't called with a UserObject, this default user will be used instead. */

clearDefaultUser(): void;
/** True when the client is configured not to initiate HTTP requests, otherwise false. */
get isOffline(): boolean;
/** Configures the client to allow HTTP requests. */
setOnline(): void;
/** Configures the client to not initiate HTTP requests and work only from its cache. */
setOffline(): void;
}
export interface IConfigCatKernel {
configFetcher: IConfigFetcher;
/**
* Default ICache implementation.
*/
cache?: ICache;
sdkType: string;
sdkVersion: string;
eventEmitterFactory?: () => IEventEmitter;
}
export declare class ConfigCatClientCache {
private instances;
getOrCreate(options: ConfigCatClientOptions, configCatKernel: IConfigCatKernel): [ConfigCatClient, boolean];
remove(sdkKey: string, cacheToken: object): boolean;
clear(): ConfigCatClient[];
}
export declare class ConfigCatClient implements IConfigCatClient {
private cacheToken?;
private configService?;

@@ -48,12 +105,20 @@ private evaluator;

private defaultUser?;
constructor(options: AutoPollOptions | ManualPollOptions | LazyLoadOptions, configCatKernel: IConfigCatKernel);
private suppressFinalize;
private static get instanceCache();
static get<TMode extends PollingMode>(sdkKey: string, pollingMode: TMode, options: OptionsForPollingMode<TMode> | undefined | null, configCatKernel: IConfigCatKernel): IConfigCatClient;
constructor(options: ConfigCatClientOptions, configCatKernel: IConfigCatKernel, cacheToken?: object | undefined);
private static finalize;
private static close;
dispose(): void;
getValue(key: string, defaultValue: any, callback: (value: any) => void, user?: User): void;
getValueAsync(key: string, defaultValue: any, user?: User): Promise<any>;
forceRefresh(callback: () => void): void;
forceRefreshAsync(): Promise<void>;
static disposeAll(): void;
getValue<T extends SettingValue>(key: string, defaultValue: T, callback: (value: SettingTypeOf<T>) => void, user?: User): void;
getValueAsync<T extends SettingValue>(key: string, defaultValue: T, user?: User): Promise<SettingTypeOf<T>>;
getValueDetails<T extends SettingValue>(key: string, defaultValue: T, callback: (evaluationDetails: IEvaluationDetails<SettingTypeOf<T>>) => void, user?: User): void;
getValueDetailsAsync<T extends SettingValue>(key: string, defaultValue: T, user?: User): Promise<IEvaluationDetails<SettingTypeOf<T>>>;
forceRefresh(callback: (result: RefreshResult) => void): void;
forceRefreshAsync(): Promise<RefreshResult>;
getAllKeys(callback: (value: string[]) => void): void;
getAllKeysAsync(): Promise<string[]>;
getVariationId(key: string, defaultVariationId: any, callback: (variationId: string) => void, user?: User): void;
getVariationIdAsync(key: string, defaultVariationId: any, user?: User): Promise<string>;
getVariationId<T extends VariationIdValue>(key: string, defaultVariationId: T, callback: (variationId: VariationIdTypeOf<T>) => void, user?: User): void;
getVariationIdAsync<T extends VariationIdValue>(key: string, defaultVariationId: T, user?: User): Promise<VariationIdTypeOf<T>>;
getAllVariationIds(callback: (variationIds: string[]) => void, user?: User): void;

@@ -65,10 +130,34 @@ getAllVariationIdsAsync(user?: User): Promise<string[]>;

getAllValuesAsync(user?: User): Promise<SettingKeyValue[]>;
getAllValueDetails(callback: (result: IEvaluationDetails[]) => void, user?: User): void;
getAllValueDetailsAsync(user?: User): Promise<IEvaluationDetails[]>;
setDefaultUser(defaultUser: User): void;
clearDefaultUser(): void;
get isOffline(): boolean;
setOnline(): void;
setOffline(): void;
private getSettingsAsync;
/** @inheritdoc */
addListener: <TEventName extends keyof HookEvents>(eventName: TEventName, listener: (...args: HookEvents[TEventName]) => void) => this;
/** @inheritdoc */
on<TEventName extends keyof HookEvents>(eventName: TEventName, listener: (...args: HookEvents[TEventName]) => void): this;
/** @inheritdoc */
once<TEventName extends keyof HookEvents>(eventName: TEventName, listener: (...args: HookEvents[TEventName]) => void): this;
/** @inheritdoc */
removeListener<TEventName extends keyof HookEvents>(eventName: TEventName, listener: (...args: HookEvents[TEventName]) => void): this;
/** @inheritdoc */
off: <TEventName extends keyof HookEvents>(eventName: TEventName, listener: (...args: HookEvents[TEventName]) => void) => this;
/** @inheritdoc */
removeAllListeners(eventName?: keyof HookEvents): this;
/** @inheritdoc */
listeners(eventName: keyof HookEvents): Function[];
/** @inheritdoc */
listenerCount(eventName: keyof HookEvents): number;
/** @inheritdoc */
eventNames(): Array<keyof HookEvents>;
}
export declare class SettingKeyValue {
export declare class SettingKeyValue<TValue = SettingValue> {
settingKey: string;
settingValue: any;
settingValue: TValue;
constructor(settingKey: string, settingValue: TValue);
}
//# sourceMappingURL=ConfigCatClient.d.ts.map
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SettingKeyValue = exports.ConfigCatClient = void 0;
exports.SettingKeyValue = exports.ConfigCatClient = exports.ConfigCatClientCache = void 0;
var tslib_1 = require("tslib");
var AutoPollConfigService_1 = require("./AutoPollConfigService");
var ConfigCatClientOptions_1 = require("./ConfigCatClientOptions");
var AutoPollConfigService_1 = require("./AutoPollConfigService");
var ConfigServiceBase_1 = require("./ConfigServiceBase");
var FlagOverrides_1 = require("./FlagOverrides");
var LazyLoadConfigService_1 = require("./LazyLoadConfigService");
var ManualPollService_1 = require("./ManualPollService");
var ManualPollConfigService_1 = require("./ManualPollConfigService");
var ProjectConfig_1 = require("./ProjectConfig");
var RolloutEvaluator_1 = require("./RolloutEvaluator");
var ProjectConfig_1 = require("./ProjectConfig");
var FlagOverrides_1 = require("./FlagOverrides");
var Utils_1 = require("./Utils");
var ConfigCatClientCache = /** @class */ (function () {
function ConfigCatClientCache() {
this.instances = {};
}
ConfigCatClientCache.prototype.getOrCreate = function (options, configCatKernel) {
var instance;
var cachedInstance = this.instances[options.apiKey];
if (cachedInstance) {
var weakRef = cachedInstance[0];
instance = weakRef.deref();
if (instance) {
return [instance, true];
}
}
var token = {};
instance = new ConfigCatClient(options, configCatKernel, token);
this.instances[options.apiKey] = [new WeakRef(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;
}());
exports.ConfigCatClientCache = ConfigCatClientCache;
var clientInstanceCache = new ConfigCatClientCache();
var ConfigCatClient = /** @class */ (function () {
function ConfigCatClient(options, configCatKernel) {
function ConfigCatClient(options, configCatKernel, cacheToken) {
var _a;
this.cacheToken = cacheToken;
/** @inheritdoc */
this.addListener = this.on;
/** @inheritdoc */
this.off = this.removeListener;
if (!options) {

@@ -73,189 +80,317 @@ throw new Error("Invalid 'options' value");

}
if (options === null || options === void 0 ? void 0 : options.defaultUser) {
if (options.defaultUser) {
this.setDefaultUser(options.defaultUser);
}
this.evaluator = new RolloutEvaluator_1.RolloutEvaluator(options.logger);
if (((_a = options === null || options === void 0 ? void 0 : options.flagOverrides) === null || _a === void 0 ? void 0 : _a.behaviour) != FlagOverrides_1.OverrideBehaviour.LocalOnly) {
if (options && options instanceof ConfigCatClientOptions_1.LazyLoadOptions) {
this.configService = new LazyLoadConfigService_1.LazyLoadConfigService(configCatKernel.configFetcher, options);
}
else if (options && options instanceof ConfigCatClientOptions_1.ManualPollOptions) {
this.configService = new ManualPollService_1.ManualPollService(configCatKernel.configFetcher, options);
}
else if (options && options instanceof ConfigCatClientOptions_1.AutoPollOptions) {
this.configService = new AutoPollConfigService_1.AutoPollConfigService(configCatKernel.configFetcher, options);
}
else {
throw new Error("Invalid 'options' value");
}
if (((_a = options.flagOverrides) === null || _a === void 0 ? void 0 : _a.behaviour) != FlagOverrides_1.OverrideBehaviour.LocalOnly) {
var configServiceClass = options instanceof ConfigCatClientOptions_1.AutoPollOptions ? AutoPollConfigService_1.AutoPollConfigService :
options instanceof ConfigCatClientOptions_1.ManualPollOptions ? ManualPollConfigService_1.ManualPollConfigService :
options instanceof ConfigCatClientOptions_1.LazyLoadOptions ? LazyLoadConfigService_1.LazyLoadConfigService :
(function () { throw new Error("Invalid 'options' value"); })();
this.configService = new configServiceClass(configCatKernel.configFetcher, options);
}
else {
this.options.hooks.emit("clientReady");
}
this.suppressFinalize = registerForFinalization(this, { sdkKey: options.apiKey, 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) {
if (!sdkKey) {
throw new Error("Invalid 'sdkKey' value");
}
var optionsClass = pollingMode === ConfigCatClientOptions_1.PollingMode.AutoPoll ? ConfigCatClientOptions_1.AutoPollOptions :
pollingMode === ConfigCatClientOptions_1.PollingMode.ManualPoll ? ConfigCatClientOptions_1.ManualPollOptions :
pollingMode === ConfigCatClientOptions_1.PollingMode.LazyLoad ? ConfigCatClientOptions_1.LazyLoadOptions :
(function () { throw new Error("Invalid 'pollingMode' value"); })();
var actualOptions = new optionsClass(sdkKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache, configCatKernel.eventEmitterFactory);
var _a = clientInstanceCache.getOrCreate(actualOptions, configCatKernel), instance = _a[0], instanceAlreadyCreated = _a[1];
if (instanceAlreadyCreated && options) {
actualOptions.logger.warn("Client for SDK key '".concat(sdkKey, "' is already created and will be reused; configuration action is being ignored."));
}
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 () {
this.options.logger.debug("dispose() called");
if (this.configService instanceof AutoPollConfigService_1.AutoPollConfigService) {
this.options.logger.debug("Disposing AutoPollConfigService");
this.configService.dispose();
var options = this.options;
options.logger.debug("dispose() called");
if (this.cacheToken) {
clientInstanceCache.remove(options.apiKey, this.cacheToken);
}
ConfigCatClient.close(this.configService, options.logger, options.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.options.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.getValue = function (key, defaultValue, callback, user) {
this.options.logger.debug("getValue() called.");
this.getValueAsync(key, defaultValue, user).then(function (value) {
callback(value);
});
this.getValueAsync(key, defaultValue, user).then(callback);
};
ConfigCatClient.prototype.getValueAsync = function (key, defaultValue, user) {
var _this = this;
this.options.logger.debug("getValueAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var settings, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getSettingsAsync()];
return tslib_1.__awaiter(this, void 0, void 0, function () {
var value, evaluationDetails, remoteConfig, settings, err_1;
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
this.options.logger.debug("getValueAsync() called.");
remoteConfig = null;
user !== null && user !== void 0 ? user : (user = this.defaultUser);
_b.label = 1;
case 1:
settings = _a.sent();
if (!settings) {
this.options.logger.error("config.json is not present. Returning default value: '" + defaultValue + "'.");
resolve(defaultValue);
return [2 /*return*/];
}
result = this.evaluator.Evaluate(settings, key, defaultValue, user !== null && user !== void 0 ? user : this.defaultUser).Value;
resolve(result);
return [2 /*return*/];
_b.trys.push([1, 3, , 4]);
(0, RolloutEvaluator_1.ensureAllowedDefaultValue)(defaultValue);
settings = void 0;
return [4 /*yield*/, this.getSettingsAsync()];
case 2:
_a = _b.sent(), settings = _a[0], remoteConfig = _a[1];
evaluationDetails = (0, RolloutEvaluator_1.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.error("Error occurred in getValueAsync().", err_1);
evaluationDetails = (0, RolloutEvaluator_1.evaluationDetailsFromDefaultValue)(key, defaultValue, (0, Utils_1.getTimestampAsDate)(remoteConfig), user, (0, Utils_1.errorToString)(err_1), err_1);
value = defaultValue;
return [3 /*break*/, 4];
case 4:
this.options.hooks.emit("flagEvaluated", evaluationDetails);
return [2 /*return*/, value];
}
});
}); });
});
};
ConfigCatClient.prototype.getValueDetails = function (key, defaultValue, callback, user) {
this.options.logger.debug("getValueDetails() called.");
this.getValueDetailsAsync(key, defaultValue, user).then(callback);
};
ConfigCatClient.prototype.getValueDetailsAsync = function (key, defaultValue, user) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var evaluationDetails, remoteConfig, settings, err_2;
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
this.options.logger.debug("getValueDetailsAsync() called.");
remoteConfig = null;
user !== null && user !== void 0 ? user : (user = this.defaultUser);
_b.label = 1;
case 1:
_b.trys.push([1, 3, , 4]);
(0, RolloutEvaluator_1.ensureAllowedDefaultValue)(defaultValue);
settings = void 0;
return [4 /*yield*/, this.getSettingsAsync()];
case 2:
_a = _b.sent(), settings = _a[0], remoteConfig = _a[1];
evaluationDetails = (0, RolloutEvaluator_1.evaluate)(this.evaluator, settings, key, defaultValue, user, remoteConfig, this.options.logger);
return [3 /*break*/, 4];
case 3:
err_2 = _b.sent();
this.options.logger.error("Error occurred in getValueDetailsAsync().", err_2);
evaluationDetails = (0, RolloutEvaluator_1.evaluationDetailsFromDefaultValue)(key, defaultValue, (0, Utils_1.getTimestampAsDate)(remoteConfig), user, (0, Utils_1.errorToString)(err_2), err_2);
return [3 /*break*/, 4];
case 4:
this.options.hooks.emit("flagEvaluated", evaluationDetails);
return [2 /*return*/, evaluationDetails];
}
});
});
};
ConfigCatClient.prototype.forceRefresh = function (callback) {
this.options.logger.debug("forceRefresh() called.");
this.forceRefreshAsync().then(function () {
callback();
});
this.forceRefreshAsync().then(callback);
};
ConfigCatClient.prototype.forceRefreshAsync = function () {
var _this = this;
this.options.logger.debug("forceRefreshAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, ((_a = this.configService) === null || _a === void 0 ? void 0 : _a.refreshConfigAsync())];
return tslib_1.__awaiter(this, void 0, void 0, function () {
var result, err_3;
return tslib_1.__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:
_b.sent();
resolve();
return [2 /*return*/];
_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_3 = _a.sent();
this.options.logger.error("Error occurred in forceRefreshAsync().", err_3);
return [2 /*return*/, ConfigServiceBase_1.RefreshResult.failure((0, Utils_1.errorToString)(err_3), err_3)];
case 4: return [3 /*break*/, 6];
case 5: return [2 /*return*/, ConfigServiceBase_1.RefreshResult.failure("Client is configured to use the LocalOnly override behavior, which prevents making HTTP requests.")];
case 6: return [2 /*return*/];
}
});
}); });
});
};
ConfigCatClient.prototype.getAllKeys = function (callback) {
this.options.logger.debug("getAllKeys() called.");
this.getAllKeysAsync().then(function (value) {
callback(value);
});
this.getAllKeysAsync().then(callback);
};
ConfigCatClient.prototype.getAllKeysAsync = function () {
var _this = this;
this.options.logger.debug("getAllKeysAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var settings;
return __generator(this, function (_a) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var settings, err_4;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getSettingsAsync()];
case 0:
this.options.logger.debug("getAllKeysAsync() called.");
_a.label = 1;
case 1:
settings = _a.sent();
if (!settings) {
this.options.logger.error("config.json is not present, returning empty array");
resolve([]);
return [2 /*return*/];
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.getSettingsAsync()];
case 2:
settings = (_a.sent())[0];
if (!(0, RolloutEvaluator_1.checkSettingsAvailable)(settings, this.options.logger, ", returning empty array")) {
return [2 /*return*/, []];
}
resolve(Object.keys(settings));
return [2 /*return*/];
return [2 /*return*/, Object.keys(settings)];
case 3:
err_4 = _a.sent();
this.options.logger.error("Error occurred in getAllKeysAsync().", err_4);
return [2 /*return*/, []];
case 4: return [2 /*return*/];
}
});
}); });
});
};
ConfigCatClient.prototype.getVariationId = function (key, defaultVariationId, callback, user) {
this.options.logger.debug("getVariationId() called.");
this.getVariationIdAsync(key, defaultVariationId, user).then(function (variationId) {
callback(variationId);
});
this.getVariationIdAsync(key, defaultVariationId, user).then(callback);
};
ConfigCatClient.prototype.getVariationIdAsync = function (key, defaultVariationId, user) {
var _this = this;
this.options.logger.debug("getVariationIdAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var settings, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getSettingsAsync()];
return tslib_1.__awaiter(this, void 0, void 0, function () {
var variationId, evaluationDetails, remoteConfig, settings, err_5;
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
this.options.logger.debug("getVariationIdAsync() called.");
remoteConfig = null;
user !== null && user !== void 0 ? user : (user = this.defaultUser);
_b.label = 1;
case 1:
settings = _a.sent();
if (!settings) {
this.options.logger.error("config.json is not present. Returning default variationId: '" + defaultVariationId + "'.");
resolve(defaultVariationId);
return [2 /*return*/];
}
result = this.evaluator.Evaluate(settings, key, null, user !== null && user !== void 0 ? user : this.defaultUser, defaultVariationId).VariationId;
resolve(result);
return [2 /*return*/];
_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 = (0, RolloutEvaluator_1.evaluateVariationId)(this.evaluator, settings, key, defaultVariationId, user, remoteConfig, this.options.logger);
variationId = evaluationDetails.variationId;
return [3 /*break*/, 4];
case 3:
err_5 = _b.sent();
this.options.logger.error("Error occurred in getVariationIdAsync().", err_5);
evaluationDetails = (0, RolloutEvaluator_1.evaluationDetailsFromDefaultVariationId)(key, defaultVariationId, (0, Utils_1.getTimestampAsDate)(remoteConfig), user, (0, Utils_1.errorToString)(err_5), err_5);
variationId = defaultVariationId;
return [3 /*break*/, 4];
case 4:
this.options.hooks.emit("flagEvaluated", evaluationDetails);
return [2 /*return*/, variationId];
}
});
}); });
});
};
ConfigCatClient.prototype.getAllVariationIds = function (callback, user) {
this.options.logger.debug("getAllVariationIds() called.");
this.getAllVariationIdsAsync(user).then(function (variationIds) {
callback(variationIds);
});
this.getAllVariationIdsAsync(user).then(callback);
};
ConfigCatClient.prototype.getAllVariationIdsAsync = function (user) {
var _this = this;
this.options.logger.debug("getAllVariationIdsAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var keys, promises, variationIds;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getAllKeysAsync()];
return tslib_1.__awaiter(this, void 0, void 0, function () {
var result, evaluationDetailsArray, _a, settings, remoteConfig, errors, err_6, _i, evaluationDetailsArray_1, evaluationDetail;
var _b;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
this.options.logger.debug("getAllVariationIdsAsync() called.");
user !== null && user !== void 0 ? user : (user = this.defaultUser);
_c.label = 1;
case 1:
keys = _a.sent();
if (keys.length === 0) {
resolve([]);
return [2 /*return*/];
_c.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.getSettingsAsync()];
case 2:
_a = _c.sent(), settings = _a[0], remoteConfig = _a[1];
errors = void 0;
_b = (0, RolloutEvaluator_1.evaluateAllVariationIds)(this.evaluator, settings, user, remoteConfig, this.options.logger), evaluationDetailsArray = _b[0], errors = _b[1];
if (errors === null || errors === void 0 ? void 0 : errors.length) {
throw typeof AggregateError !== "undefined" ? new AggregateError(errors) : errors.pop();
}
promises = keys.map(function (key) { return _this.getVariationIdAsync(key, null, user); });
return [4 /*yield*/, Promise.all(promises)];
case 2:
variationIds = _a.sent();
resolve(variationIds);
return [2 /*return*/];
result = evaluationDetailsArray.filter(function (details) { return details !== null && details !== void 0; }).map(function (details) { return details.variationId; });
return [3 /*break*/, 4];
case 3:
err_6 = _c.sent();
this.options.logger.error("Error occurred in getAllVariationIdsAsync().", err_6);
evaluationDetailsArray !== null && evaluationDetailsArray !== void 0 ? evaluationDetailsArray : (evaluationDetailsArray = []);
result = [];
return [3 /*break*/, 4];
case 4:
for (_i = 0, evaluationDetailsArray_1 = evaluationDetailsArray; _i < evaluationDetailsArray_1.length; _i++) {
evaluationDetail = evaluationDetailsArray_1[_i];
this.options.hooks.emit("flagEvaluated", evaluationDetail);
}
return [2 /*return*/, result];
}
});
}); });
});
};
ConfigCatClient.prototype.getKeyAndValue = function (variationId, callback) {
this.options.logger.debug("getKeyAndValue() called.");
this.getKeyAndValueAsync(variationId).then(function (settingKeyAndValue) {
callback(settingKeyAndValue);
});
this.getKeyAndValueAsync(variationId).then(callback);
};
ConfigCatClient.prototype.getKeyAndValueAsync = function (variationId) {
var _this = this;
this.options.logger.debug("getKeyAndValueAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var settings, settingKey, rolloutRules, i, rolloutRule, percentageItems, i, percentageItem;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getSettingsAsync()];
return tslib_1.__awaiter(this, void 0, void 0, function () {
var settings, _i, _a, _b, settingKey, setting, rolloutRules, i, rolloutRule, percentageItems, i, percentageItem, err_7;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
this.options.logger.debug("getKeyAndValueAsync() called.");
_c.label = 1;
case 1:
settings = _a.sent();
if (!settings) {
this.options.logger.error("config.json is not present, returning empty array");
resolve(null);
return [2 /*return*/];
_c.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.getSettingsAsync()];
case 2:
settings = (_c.sent())[0];
if (!(0, RolloutEvaluator_1.checkSettingsAvailable)(settings, this.options.logger, ", returning null")) {
return [2 /*return*/, null];
}
for (settingKey in settings) {
if (variationId === settings[settingKey].variationId) {
resolve({ settingKey: settingKey, settingValue: settings[settingKey].value });
return [2 /*return*/];
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, setting.value)];
}

@@ -267,4 +402,3 @@ rolloutRules = settings[settingKey].rolloutRules;

if (variationId === rolloutRule.variationId) {
resolve({ settingKey: settingKey, settingValue: rolloutRule.value });
return [2 /*return*/];
return [2 /*return*/, new SettingKeyValue(settingKey, rolloutRule.value)];
}

@@ -278,4 +412,3 @@ }

if (variationId === percentageItem.variationId) {
resolve({ settingKey: settingKey, settingValue: percentageItem.value });
return [2 /*return*/];
return [2 /*return*/, new SettingKeyValue(settingKey, percentageItem.value)];
}

@@ -286,44 +419,94 @@ }

this.options.logger.error("Could not find the setting for the given variation ID: " + variationId);
resolve(null);
return [2 /*return*/];
return [3 /*break*/, 4];
case 3:
err_7 = _c.sent();
this.options.logger.error("Error occurred in getKeyAndValueAsync().", err_7);
return [3 /*break*/, 4];
case 4: return [2 /*return*/, null];
}
});
}); });
});
};
ConfigCatClient.prototype.getAllValues = function (callback, user) {
this.options.logger.debug("getAllValues() called.");
this.getAllValuesAsync(user).then(function (value) {
callback(value);
});
this.getAllValuesAsync(user).then(callback);
};
ConfigCatClient.prototype.getAllValuesAsync = function (user) {
var _this = this;
this.options.logger.debug("getAllValuesAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var settings, keys, result;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getSettingsAsync()];
return tslib_1.__awaiter(this, void 0, void 0, function () {
var result, evaluationDetailsArray, _a, settings, remoteConfig, errors, err_8, _i, evaluationDetailsArray_2, evaluationDetail;
var _b;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
this.options.logger.debug("getAllValuesAsync() called.");
user !== null && user !== void 0 ? user : (user = this.defaultUser);
_c.label = 1;
case 1:
settings = _a.sent();
if (!settings) {
this.options.logger.error("config.json is not present, returning empty array");
resolve([]);
return [2 /*return*/];
_c.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.getSettingsAsync()];
case 2:
_a = _c.sent(), settings = _a[0], remoteConfig = _a[1];
errors = void 0;
_b = (0, RolloutEvaluator_1.evaluateAll)(this.evaluator, settings, user, remoteConfig, this.options.logger), evaluationDetailsArray = _b[0], errors = _b[1];
if (errors === null || errors === void 0 ? void 0 : errors.length) {
throw typeof AggregateError !== "undefined" ? new AggregateError(errors) : errors.pop();
}
keys = Object.keys(settings);
result = evaluationDetailsArray.map(function (details) { return new SettingKeyValue(details.key, details.value); });
return [3 /*break*/, 4];
case 3:
err_8 = _c.sent();
this.options.logger.error("Error occurred in getAllValuesAsync().", err_8);
evaluationDetailsArray !== null && evaluationDetailsArray !== void 0 ? evaluationDetailsArray : (evaluationDetailsArray = []);
result = [];
keys.forEach(function (key) {
result.push({
settingKey: key,
settingValue: _this.evaluator.Evaluate(settings, key, undefined, user !== null && user !== void 0 ? user : _this.defaultUser).Value
});
});
resolve(result);
return [2 /*return*/];
return [3 /*break*/, 4];
case 4:
for (_i = 0, evaluationDetailsArray_2 = evaluationDetailsArray; _i < evaluationDetailsArray_2.length; _i++) {
evaluationDetail = evaluationDetailsArray_2[_i];
this.options.hooks.emit("flagEvaluated", evaluationDetail);
}
return [2 /*return*/, result];
}
});
}); });
});
};
ConfigCatClient.prototype.getAllValueDetails = function (callback, user) {
this.options.logger.debug("getAllValueDetails() called.");
this.getAllValueDetailsAsync(user).then(callback);
};
ConfigCatClient.prototype.getAllValueDetailsAsync = function (user) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var evaluationDetailsArray, _a, settings, remoteConfig, errors, err_9, _i, evaluationDetailsArray_3, evaluationDetail;
var _b;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
this.options.logger.debug("getAllValueDetailsAsync() called.");
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];
errors = void 0;
_b = (0, RolloutEvaluator_1.evaluateAll)(this.evaluator, settings, user, remoteConfig, this.options.logger), evaluationDetailsArray = _b[0], errors = _b[1];
if (errors === null || errors === void 0 ? void 0 : errors.length) {
throw typeof AggregateError !== "undefined" ? new AggregateError(errors) : errors.pop();
}
return [3 /*break*/, 4];
case 3:
err_9 = _c.sent();
this.options.logger.error("Error occurred in getAllValueDetailsAsync().", err_9);
evaluationDetailsArray !== null && evaluationDetailsArray !== void 0 ? evaluationDetailsArray : (evaluationDetailsArray = []);
return [3 /*break*/, 4];
case 4:
for (_i = 0, evaluationDetailsArray_3 = evaluationDetailsArray; _i < evaluationDetailsArray_3.length; _i++) {
evaluationDetail = evaluationDetailsArray_3[_i];
this.options.hooks.emit("flagEvaluated", evaluationDetail);
}
return [2 /*return*/, evaluationDetailsArray];
}
});
});
};
ConfigCatClient.prototype.setDefaultUser = function (defaultUser) {

@@ -333,47 +516,109 @@ this.defaultUser = defaultUser;

ConfigCatClient.prototype.clearDefaultUser = function () {
this.defaultUser = undefined;
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.warn("Client is configured to use the LocalOnly override behavior, thus SetOnline() has no effect.");
}
};
ConfigCatClient.prototype.setOffline = function () {
var _a;
(_a = this.configService) === null || _a === void 0 ? void 0 : _a.setOffline();
};
ConfigCatClient.prototype.getSettingsAsync = function () {
var _this = this;
this.options.logger.debug("getSettingsAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var localSettings, remoteConfig, remoteSettings, config;
var _a, _b, _c;
return __generator(this, function (_d) {
switch (_d.label) {
var _a;
return tslib_1.__awaiter(this, void 0, void 0, function () {
var getRemoteConfigAsync, flagOverrides, remoteSettings, remoteConfig, localSettings, _b;
var _c, _d;
var _this = this;
return tslib_1.__generator(this, function (_e) {
switch (_e.label) {
case 0:
if (!((_a = this.options) === null || _a === void 0 ? void 0 : _a.flagOverrides)) return [3 /*break*/, 3];
return [4 /*yield*/, this.options.flagOverrides.dataSource.getOverrides()];
this.options.logger.debug("getSettingsAsync() called.");
getRemoteConfigAsync = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var config, json, settings;
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, ((_a = this.configService) === null || _a === void 0 ? void 0 : _a.getConfig())];
case 1:
config = _b.sent();
json = config === null || config === void 0 ? void 0 : config.ConfigJSON;
settings = (json === null || json === void 0 ? void 0 : json[ProjectConfig_1.ConfigFile.FeatureFlags]) ? (0, Utils_1.getSettingsFromConfig)(json) : null;
return [2 /*return*/, [settings, config !== null && config !== void 0 ? config : null]];
}
});
}); };
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 = _d.sent();
if (this.options.flagOverrides.behaviour == FlagOverrides_1.OverrideBehaviour.LocalOnly) {
resolve(localSettings);
return [2 /*return*/];
localSettings = _e.sent();
_b = flagOverrides.behaviour;
switch (_b) {
case FlagOverrides_1.OverrideBehaviour.LocalOnly: return [3 /*break*/, 2];
case FlagOverrides_1.OverrideBehaviour.LocalOverRemote: return [3 /*break*/, 3];
case FlagOverrides_1.OverrideBehaviour.RemoteOverLocal: return [3 /*break*/, 5];
}
return [4 /*yield*/, ((_b = this.configService) === null || _b === void 0 ? void 0 : _b.getConfig())];
case 2:
remoteConfig = _d.sent();
remoteSettings = (0, Utils_1.getSettingsFromConfig)(remoteConfig === null || remoteConfig === void 0 ? void 0 : remoteConfig.ConfigJSON);
if (this.options.flagOverrides.behaviour == FlagOverrides_1.OverrideBehaviour.LocalOverRemote) {
resolve(__assign(__assign({}, remoteSettings), localSettings));
return [2 /*return*/];
}
else if (this.options.flagOverrides.behaviour == FlagOverrides_1.OverrideBehaviour.RemoteOverLocal) {
resolve(__assign(__assign({}, localSettings), remoteSettings));
return [2 /*return*/];
}
_d.label = 3;
case 3: return [4 /*yield*/, ((_c = this.configService) === null || _c === void 0 ? void 0 : _c.getConfig())];
return [3 /*break*/, 7];
case 2: return [2 /*return*/, [localSettings, null]];
case 3: return [4 /*yield*/, getRemoteConfigAsync()];
case 4:
config = _d.sent();
if (!config || !config.ConfigJSON || !config.ConfigJSON[ProjectConfig_1.ConfigFile.FeatureFlags]) {
resolve(null);
return [2 /*return*/];
}
resolve((0, Utils_1.getSettingsFromConfig)(config.ConfigJSON));
return [2 /*return*/];
_c = _e.sent(), remoteSettings = _c[0], remoteConfig = _c[1];
return [2 /*return*/, [tslib_1.__assign(tslib_1.__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*/, [tslib_1.__assign(tslib_1.__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.options.hooks.on(eventName, listener);
return this;
};
/** @inheritdoc */
ConfigCatClient.prototype.once = function (eventName, listener) {
this.options.hooks.once(eventName, listener);
return this;
};
/** @inheritdoc */
ConfigCatClient.prototype.removeListener = function (eventName, listener) {
this.options.hooks.removeListener(eventName, listener);
return this;
};
/** @inheritdoc */
ConfigCatClient.prototype.removeAllListeners = function (eventName) {
this.options.hooks.removeAllListeners(eventName);
return this;
};
/** @inheritdoc */
ConfigCatClient.prototype.listeners = function (eventName) {
return this.options.hooks.listeners(eventName);
};
/** @inheritdoc */
ConfigCatClient.prototype.listenerCount = function (eventName) {
return this.options.hooks.listenerCount(eventName);
};
/** @inheritdoc */
ConfigCatClient.prototype.eventNames = function () {
return this.options.hooks.eventNames();
};
return ConfigCatClient;

@@ -383,3 +628,5 @@ }());

var SettingKeyValue = /** @class */ (function () {
function SettingKeyValue() {
function SettingKeyValue(settingKey, settingValue) {
this.settingKey = settingKey;
this.settingValue = settingValue;
}

@@ -389,1 +636,22 @@ return SettingKeyValue;

exports.SettingKeyValue = SettingKeyValue;
;
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);
};

@@ -1,3 +0,12 @@

import { IConfigCatLogger, IAutoPollOptions, ILazyLoadingOptions, IManualPollOptions, ICache, User } from "./index";
import { ICache } from "./Cache";
import { IConfigCatLogger, LoggerWrapper } from "./ConfigCatLogger";
import type { IEventEmitter } from "./EventEmitter";
import { FlagOverrides } from "./FlagOverrides";
import { Hooks, IProvidesHooks } from "./Hooks";
import { User } from "./RolloutEvaluator";
export declare enum PollingMode {
AutoPoll = 0,
LazyLoad = 1,
ManualPoll = 2
}
/** Control the location of the config.json files containing your feature flags and settings within the ConfigCat CDN. */

@@ -29,6 +38,23 @@ export declare enum DataGovernance {

defaultUser?: User | null;
/**
* Indicates whether the client should be initialized to offline mode or not. Defaults to false.
*/
offline?: boolean | null;
/** Provides an opportunity to add listeners to client hooks (events) at client initalization time. */
setupHooks?: (hooks: IProvidesHooks) => void;
}
export interface IAutoPollOptions extends IOptions {
pollIntervalSeconds?: number;
maxInitWaitTimeSeconds?: number;
configChanged?: () => void;
}
export interface IManualPollOptions extends IOptions {
}
export interface ILazyLoadingOptions extends IOptions {
cacheTimeToLiveSeconds?: number;
}
export type OptionsForPollingMode<TMode extends PollingMode> = TMode extends PollingMode.AutoPoll ? IAutoPollOptions : TMode extends PollingMode.ManualPoll ? IManualPollOptions : TMode extends PollingMode.LazyLoad ? ILazyLoadingOptions : never;
export declare abstract class OptionsBase implements IOptions {
private configFileName;
logger: IConfigCatLogger;
logger: LoggerWrapper;
apiKey: string;

@@ -43,4 +69,6 @@ clientVersion: string;

flagOverrides?: FlagOverrides;
defaultUser?: User | null;
constructor(apiKey: string, clientVersion: string, options?: IOptions | null, defaultCache?: ICache | null);
defaultUser?: User;
offline: boolean;
hooks: Hooks;
constructor(apiKey: string, clientVersion: string, options?: IOptions | null, defaultCache?: ICache | null, eventEmitterFactory?: (() => IEventEmitter) | null);
getUrl(): string;

@@ -52,10 +80,12 @@ getCacheKey(): string;

pollIntervalSeconds: number;
/** You can subscribe to configuration changes with this callback. */
/** You can subscribe to configuration changes with this callback.
* @deprecated This property is obsolete and will be removed from the public API in a future major version. Please use the 'options.setupHooks = hooks => hooks.on("configChanged", ...)' format instead.
*/
configChanged: () => void;
/** Maximum waiting time between the client initialization and the first config acquisition in seconds. */
maxInitWaitTimeSeconds: number;
constructor(apiKey: string, sdkType: string, sdkVersion: string, options?: IAutoPollOptions | null, defaultCache?: ICache | null);
constructor(apiKey: string, sdkType: string, sdkVersion: string, options?: IAutoPollOptions | null, defaultCache?: ICache | null, eventEmitterFactory?: (() => IEventEmitter) | null);
}
export declare class ManualPollOptions extends OptionsBase implements IManualPollOptions {
constructor(apiKey: string, sdkType: string, sdkVersion: string, options?: IManualPollOptions | null, defaultCache?: ICache | null);
constructor(apiKey: string, sdkType: string, sdkVersion: string, options?: IManualPollOptions | null, defaultCache?: ICache | null, eventEmitterFactory?: (() => IEventEmitter) | null);
}

@@ -65,4 +95,5 @@ export declare class LazyLoadOptions extends OptionsBase implements ILazyLoadingOptions {

cacheTimeToLiveSeconds: number;
constructor(apiKey: string, sdkType: string, sdkVersion: string, options?: ILazyLoadingOptions | null, defaultCache?: ICache | null);
constructor(apiKey: string, sdkType: string, sdkVersion: string, options?: ILazyLoadingOptions | null, defaultCache?: ICache | null, eventEmitterFactory?: (() => IEventEmitter) | null);
}
export type ConfigCatClientOptions = AutoPollOptions | ManualPollOptions | LazyLoadOptions;
//# sourceMappingURL=ConfigCatClientOptions.d.ts.map
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.LazyLoadOptions = exports.ManualPollOptions = exports.AutoPollOptions = exports.OptionsBase = exports.DataGovernance = void 0;
exports.LazyLoadOptions = exports.ManualPollOptions = exports.AutoPollOptions = exports.OptionsBase = exports.DataGovernance = exports.PollingMode = void 0;
var tslib_1 = require("tslib");
var Cache_1 = require("./Cache");
var ConfigCatLogger_1 = require("./ConfigCatLogger");
var index_1 = require("./index");
var Cache_1 = require("./Cache");
var DefaultEventEmitter_1 = require("./DefaultEventEmitter");
var Hooks_1 = require("./Hooks");
var PollingMode;
(function (PollingMode) {
PollingMode[PollingMode["AutoPoll"] = 0] = "AutoPoll";
PollingMode[PollingMode["LazyLoad"] = 1] = "LazyLoad";
PollingMode[PollingMode["ManualPoll"] = 2] = "ManualPoll";
})(PollingMode = exports.PollingMode || (exports.PollingMode = {}));
/** Control the location of the config.json files containing your feature flags and settings within the ConfigCat CDN. */

@@ -31,9 +24,9 @@ var DataGovernance;

var OptionsBase = /** @class */ (function () {
function OptionsBase(apiKey, clientVersion, options, defaultCache) {
var _a;
function OptionsBase(apiKey, clientVersion, options, defaultCache, eventEmitterFactory) {
var _a, _b, _c;
this.configFileName = "config_v5";
this.logger = new ConfigCatLogger_1.ConfigCatConsoleLogger(index_1.LogLevel.Warn);
this.requestTimeoutMs = 30000;
this.baseUrlOverriden = false;
this.proxy = "";
this.offline = false;
if (!apiKey) {

@@ -57,6 +50,7 @@ throw new Error("Invalid 'apiKey' value");

}
var eventEmitter = (_b = eventEmitterFactory === null || eventEmitterFactory === void 0 ? void 0 : eventEmitterFactory()) !== null && _b !== void 0 ? _b : new DefaultEventEmitter_1.DefaultEventEmitter();
this.hooks = new Hooks_1.Hooks(eventEmitter);
var logger;
if (options) {
if (options.logger) {
this.logger = options.logger;
}
logger = options.logger;
if (options.requestTimeoutMs) {

@@ -84,3 +78,8 @@ if (options.requestTimeoutMs < 0) {

}
if (options.offline) {
this.offline = options.offline;
}
(_c = options.setupHooks) === null || _c === void 0 ? void 0 : _c.call(options, this.hooks);
}
this.logger = new ConfigCatLogger_1.LoggerWrapper(logger !== null && logger !== void 0 ? logger : new ConfigCatLogger_1.ConfigCatConsoleLogger(), this.hooks);
}

@@ -97,8 +96,10 @@ OptionsBase.prototype.getUrl = function () {

var AutoPollOptions = /** @class */ (function (_super) {
__extends(AutoPollOptions, _super);
function AutoPollOptions(apiKey, sdkType, sdkVersion, options, defaultCache) {
var _this = _super.call(this, apiKey, sdkType + "/a-" + sdkVersion, options, defaultCache) || this;
tslib_1.__extends(AutoPollOptions, _super);
function AutoPollOptions(apiKey, sdkType, sdkVersion, options, defaultCache, eventEmitterFactory) {
var _this = _super.call(this, apiKey, sdkType + "/a-" + sdkVersion, options, defaultCache, eventEmitterFactory) || this;
/** The client's poll interval in seconds. Default: 60 seconds. */
_this.pollIntervalSeconds = 60;
/** You can subscribe to configuration changes with this callback. */
/** You can subscribe to configuration changes with this callback.
* @deprecated This property is obsolete and will be removed from the public API in a future major version. Please use the 'options.setupHooks = hooks => hooks.on("configChanged", ...)' format instead.
*/
_this.configChanged = function () { };

@@ -108,3 +109,3 @@ /** Maximum waiting time between the client initialization and the first config acquisition in seconds. */

if (options) {
if (options.pollIntervalSeconds !== undefined && options.pollIntervalSeconds !== null) {
if (options.pollIntervalSeconds !== void 0 && options.pollIntervalSeconds !== null) {
_this.pollIntervalSeconds = options.pollIntervalSeconds;

@@ -115,10 +116,10 @@ }

}
if (options.maxInitWaitTimeSeconds !== undefined && options.maxInitWaitTimeSeconds !== null) {
if (options.maxInitWaitTimeSeconds !== void 0 && options.maxInitWaitTimeSeconds !== null) {
_this.maxInitWaitTimeSeconds = options.maxInitWaitTimeSeconds;
}
}
if (_this.pollIntervalSeconds < 1) {
if (!(_this.pollIntervalSeconds >= 1 && (typeof _this.pollIntervalSeconds === 'number'))) {
throw new Error("Invalid 'pollIntervalSeconds' value");
}
if (_this.maxInitWaitTimeSeconds < 0) {
if (!(_this.maxInitWaitTimeSeconds >= 0 && (typeof _this.maxInitWaitTimeSeconds === 'number'))) {
throw new Error("Invalid 'maxInitWaitTimeSeconds' value");

@@ -132,5 +133,5 @@ }

var ManualPollOptions = /** @class */ (function (_super) {
__extends(ManualPollOptions, _super);
function ManualPollOptions(apiKey, sdkType, sdkVersion, options, defaultCache) {
return _super.call(this, apiKey, sdkType + "/m-" + sdkVersion, options, defaultCache) || this;
tslib_1.__extends(ManualPollOptions, _super);
function ManualPollOptions(apiKey, sdkType, sdkVersion, options, defaultCache, eventEmitterFactory) {
return _super.call(this, apiKey, sdkType + "/m-" + sdkVersion, options, defaultCache, eventEmitterFactory) || this;
}

@@ -141,5 +142,5 @@ return ManualPollOptions;

var LazyLoadOptions = /** @class */ (function (_super) {
__extends(LazyLoadOptions, _super);
function LazyLoadOptions(apiKey, sdkType, sdkVersion, options, defaultCache) {
var _this = _super.call(this, apiKey, sdkType + "/l-" + sdkVersion, options, defaultCache) || this;
tslib_1.__extends(LazyLoadOptions, _super);
function LazyLoadOptions(apiKey, sdkType, sdkVersion, options, defaultCache, eventEmitterFactory) {
var _this = _super.call(this, apiKey, sdkType + "/l-" + sdkVersion, options, defaultCache, eventEmitterFactory) || this;
/** The cache TTL. */

@@ -146,0 +147,0 @@ _this.cacheTimeToLiveSeconds = 60;

@@ -1,19 +0,50 @@

import { IConfigCatLogger, LogLevel } from "./index";
import { Hooks } from "./Hooks";
export declare enum LogLevel {
Debug = 4,
Info = 3,
Warn = 2,
Error = 1,
Off = -1
}
export interface IConfigCatLogger {
readonly level?: LogLevel;
debug(message: string): void;
/**
* @deprecated Use `debug(message: string)` method instead of this
*/
log(message: string): void;
info(message: string): void;
warn(message: string): void;
error(message: string): void;
}
export declare class LoggerWrapper implements IConfigCatLogger {
private logger;
private hooks?;
get level(): LogLevel;
constructor(logger: IConfigCatLogger, hooks?: Hooks | undefined);
log(message: string): void;
debug(message: string): void;
info(message: string): void;
warn(message: string): void;
error(message: string, err?: any): void;
private isLogLevelEnabled;
}
export declare class ConfigCatConsoleLogger implements IConfigCatLogger {
level: LogLevel;
SOURCE: string;
level: LogLevel;
/**
* Create an instance of ConfigCatConsoleLogger
*/
constructor(logLevel: LogLevel);
/**
* @deprecated Use `debug(message: string)` method instead of this
*/
constructor(level?: LogLevel);
/** @inheritdoc */
log(message: string): void;
/** @inheritdoc */
debug(message: string): void;
/** @inheritdoc */
info(message: string): void;
/** @inheritdoc */
warn(message: string): void;
/** @inheritdoc */
error(message: string): void;
isLogLevelEnabled(logLevel: LogLevel): boolean;
}
//# sourceMappingURL=ConfigCatLogger.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigCatConsoleLogger = void 0;
var index_1 = require("./index");
exports.ConfigCatConsoleLogger = exports.LoggerWrapper = exports.LogLevel = void 0;
var Utils_1 = require("./Utils");
var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["Debug"] = 4] = "Debug";
LogLevel[LogLevel["Info"] = 3] = "Info";
LogLevel[LogLevel["Warn"] = 2] = "Warn";
LogLevel[LogLevel["Error"] = 1] = "Error";
LogLevel[LogLevel["Off"] = -1] = "Off";
})(LogLevel = exports.LogLevel || (exports.LogLevel = {}));
var LoggerWrapper = /** @class */ (function () {
function LoggerWrapper(logger, hooks) {
this.logger = logger;
this.hooks = hooks;
}
Object.defineProperty(LoggerWrapper.prototype, "level", {
get: function () { var _a; return (_a = this.logger.level) !== null && _a !== void 0 ? _a : LogLevel.Warn; },
enumerable: false,
configurable: true
});
LoggerWrapper.prototype.log = function (message) {
this.info(message);
};
LoggerWrapper.prototype.debug = function (message) {
if (this.isLogLevelEnabled(LogLevel.Debug)) {
this.logger.debug(message);
}
};
LoggerWrapper.prototype.info = function (message) {
if (this.isLogLevelEnabled(LogLevel.Info)) {
this.logger.info(message);
}
};
LoggerWrapper.prototype.warn = function (message) {
if (this.isLogLevelEnabled(LogLevel.Warn)) {
this.logger.warn(message);
}
};
LoggerWrapper.prototype.error = function (message, err) {
var _a;
if (this.isLogLevelEnabled(LogLevel.Error)) {
var logMessage = err
? message + '\n' + (0, Utils_1.errorToString)(err, true)
: message;
this.logger.error(logMessage);
}
(_a = this.hooks) === null || _a === void 0 ? void 0 : _a.emit("clientError", message, err);
};
LoggerWrapper.prototype.isLogLevelEnabled = function (logLevel) {
return this.level >= logLevel;
};
return LoggerWrapper;
}());
exports.LoggerWrapper = LoggerWrapper;
var ConfigCatConsoleLogger = /** @class */ (function () {

@@ -9,40 +61,29 @@ /**

*/
function ConfigCatConsoleLogger(logLevel) {
function ConfigCatConsoleLogger(level) {
if (level === void 0) { level = LogLevel.Warn; }
this.level = level;
this.SOURCE = "ConfigCat";
this.level = index_1.LogLevel.Warn;
if (logLevel) {
this.level = logLevel;
}
}
/**
* @deprecated Use `debug(message: string)` method instead of this
*/
/** @inheritdoc */
ConfigCatConsoleLogger.prototype.log = function (message) {
this.info(message);
};
/** @inheritdoc */
ConfigCatConsoleLogger.prototype.debug = function (message) {
if (this.isLogLevelEnabled(index_1.LogLevel.Debug)) {
console.info(this.SOURCE + " - DEBUG - " + message);
}
console.info(this.SOURCE + " - DEBUG - " + message);
};
/** @inheritdoc */
ConfigCatConsoleLogger.prototype.info = function (message) {
if (this.isLogLevelEnabled(index_1.LogLevel.Info)) {
console.info(this.SOURCE + " - INFO - " + message);
}
console.info(this.SOURCE + " - INFO - " + message);
};
/** @inheritdoc */
ConfigCatConsoleLogger.prototype.warn = function (message) {
if (this.isLogLevelEnabled(index_1.LogLevel.Warn)) {
console.warn(this.SOURCE + " - WARN - " + message);
}
console.warn(this.SOURCE + " - WARN - " + message);
};
/** @inheritdoc */
ConfigCatConsoleLogger.prototype.error = function (message) {
if (this.isLogLevelEnabled(index_1.LogLevel.Error)) {
console.error(this.SOURCE + " - ERROR - " + message);
}
console.error(this.SOURCE + " - ERROR - " + message);
};
ConfigCatConsoleLogger.prototype.isLogLevelEnabled = function (logLevel) {
return this.level >= logLevel;
};
return ConfigCatConsoleLogger;
}());
exports.ConfigCatConsoleLogger = ConfigCatConsoleLogger;

@@ -1,17 +0,53 @@

import { IConfigFetcher } from "./index";
import { OptionsBase } from "./ConfigCatClientOptions";
import { FetchResult, IConfigFetcher } from "./ConfigFetcher";
import { ProjectConfig } from "./ProjectConfig";
export declare class RefreshResult {
errorMessage: string | null;
errorException?: any;
constructor(errorMessage: string | null, errorException?: any);
get isSuccess(): boolean;
static from(fetchResult: FetchResult): RefreshResult;
static success(): RefreshResult;
static failure(errorMessage: string, errorException?: any): RefreshResult;
}
export interface IConfigService {
getConfig(): Promise<ProjectConfig | null>;
refreshConfigAsync(): Promise<ProjectConfig | null>;
refreshConfigAsync(): Promise<[RefreshResult, ProjectConfig | null]>;
get isOffline(): boolean;
setOnline(): void;
setOffline(): void;
dispose(): void;
}
export declare abstract class ConfigServiceBase {
declare enum ConfigServiceStatus {
Online = 0,
Offline = 1,
Disposed = 2
}
export declare abstract class ConfigServiceBase<TOptions extends OptionsBase> {
protected configFetcher: IConfigFetcher;
protected baseConfig: OptionsBase;
private fetchLogicCallbacks;
constructor(configFetcher: IConfigFetcher, baseConfig: OptionsBase);
protected refreshLogicBaseAsync(lastProjectConfig: ProjectConfig | null, forceUpdateCache?: boolean): Promise<ProjectConfig | null>;
private fetchLogic;
private fetchLogicInternal;
protected options: TOptions;
private status;
private pendingFetch;
constructor(configFetcher: IConfigFetcher, options: TOptions);
dispose(): void;
protected get disposed(): boolean;
abstract getConfig(): Promise<ProjectConfig | null>;
refreshConfigAsync(): Promise<[RefreshResult, ProjectConfig | null]>;
protected refreshConfigCoreAsync(latestConfig: ProjectConfig | null): Promise<[FetchResult, ProjectConfig | null]>;
protected onConfigUpdated(newConfig: ProjectConfig): void;
protected onConfigChanged(newConfig: ProjectConfig): void;
private fetchAsync;
private fetchLogicAsync;
private fetchRequestAsync;
protected get isOfflineExactly(): boolean;
get isOffline(): boolean;
protected setOnlineCore(): void;
setOnline(): void;
protected setOfflineCore(): void;
setOffline(): void;
logStatusChange(status: ConfigServiceStatus): void;
logOfflineModeWarning(): void;
logDisposedWarning(methodName: string): void;
}
export {};
//# sourceMappingURL=ConfigServiceBase.d.ts.map
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigServiceBase = void 0;
var index_1 = require("./index");
exports.ConfigServiceBase = exports.RefreshResult = void 0;
var tslib_1 = require("tslib");
var ConfigFetcher_1 = require("./ConfigFetcher");
var ProjectConfig_1 = require("./ProjectConfig");
var RefreshResult = /** @class */ (function () {
function RefreshResult(errorMessage, errorException) {
this.errorMessage = errorMessage;
this.errorException = errorException;
}
Object.defineProperty(RefreshResult.prototype, "isSuccess", {
get: function () { return this.errorMessage === null; },
enumerable: false,
configurable: true
});
RefreshResult.from = function (fetchResult) {
return fetchResult.status !== ConfigFetcher_1.FetchStatus.Errored
? RefreshResult.success()
: RefreshResult.failure(fetchResult.errorMessage, fetchResult.errorException);
};
RefreshResult.success = function () {
return new RefreshResult(null);
};
RefreshResult.failure = function (errorMessage, errorException) {
return new RefreshResult(errorMessage, errorException);
};
return RefreshResult;
}());
exports.RefreshResult = RefreshResult;
var ConfigServiceStatus;
(function (ConfigServiceStatus) {
ConfigServiceStatus[ConfigServiceStatus["Online"] = 0] = "Online";
ConfigServiceStatus[ConfigServiceStatus["Offline"] = 1] = "Offline";
ConfigServiceStatus[ConfigServiceStatus["Disposed"] = 2] = "Disposed";
})(ConfigServiceStatus || (ConfigServiceStatus = {}));
var ConfigServiceBase = /** @class */ (function () {
function ConfigServiceBase(configFetcher, baseConfig) {
this.fetchLogicCallbacks = [];
function ConfigServiceBase(configFetcher, options) {
this.pendingFetch = null;
this.configFetcher = configFetcher;
this.baseConfig = baseConfig;
this.options = options;
this.status = options.offline ? ConfigServiceStatus.Offline : ConfigServiceStatus.Online;
}
ConfigServiceBase.prototype.refreshLogicBaseAsync = function (lastProjectConfig, forceUpdateCache) {
var _this = this;
if (forceUpdateCache === void 0) { forceUpdateCache = true; }
this.baseConfig.logger.debug("ConfigServiceBase.refreshLogicBaseAsync() - called.");
return new Promise(function (resolve) {
var _a;
_this.fetchLogic(_this.baseConfig, (_a = lastProjectConfig === null || lastProjectConfig === void 0 ? void 0 : lastProjectConfig.HttpETag) !== null && _a !== void 0 ? _a : null, 0, function (newConfig) { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(newConfig && newConfig.ConfigJSON)) return [3 /*break*/, 2];
this.baseConfig.logger.debug("ConfigServiceBase.refreshLogicBaseAsync() - fetchLogic() success, returning config.");
return [4 /*yield*/, this.baseConfig.cache.set(this.baseConfig.getCacheKey(), newConfig)];
case 1:
_a.sent();
resolve(newConfig);
return [3 /*break*/, 5];
case 2:
if (!(forceUpdateCache && lastProjectConfig && lastProjectConfig.ConfigJSON)) return [3 /*break*/, 4];
this.baseConfig.logger.debug("ConfigServiceBase.refreshLogicBaseAsync() - fetchLogic() didn't return a config, setting the cache with last config with new timestamp, returning last config.");
lastProjectConfig.Timestamp = new Date().getTime();
return [4 /*yield*/, this.baseConfig.cache.set(this.baseConfig.getCacheKey(), lastProjectConfig)];
case 3:
_a.sent();
resolve(lastProjectConfig);
return [3 /*break*/, 5];
case 4:
this.baseConfig.logger.debug("ConfigServiceBase.refreshLogicBaseAsync() - fetchLogic() didn't return a config, returing last config.");
resolve(lastProjectConfig);
_a.label = 5;
case 5: return [2 /*return*/];
}
});
}); });
ConfigServiceBase.prototype.dispose = function () {
this.status = ConfigServiceStatus.Disposed;
};
Object.defineProperty(ConfigServiceBase.prototype, "disposed", {
get: function () { return this.status === ConfigServiceStatus.Disposed; },
enumerable: false,
configurable: true
});
ConfigServiceBase.prototype.refreshConfigAsync = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var latestConfig, _a, fetchResult, config;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 1:
latestConfig = _b.sent();
if (!!this.isOffline) return [3 /*break*/, 3];
return [4 /*yield*/, this.refreshConfigCoreAsync(latestConfig)];
case 2:
_a = _b.sent(), fetchResult = _a[0], config = _a[1];
return [2 /*return*/, [RefreshResult.from(fetchResult), config]];
case 3:
this.logOfflineModeWarning();
return [2 /*return*/, [RefreshResult.failure("Client is in offline mode, it can't initiate HTTP calls."), latestConfig]];
}
});
});
};
ConfigServiceBase.prototype.fetchLogic = function (options, lastEtag, retries, callback) {
var _this = this;
this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic() - called.");
var calledBaseUrl = this.baseConfig.baseUrl;
this.fetchLogicInternal(this.baseConfig, lastEtag, retries, function (result) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): result.status: " + (result === null || result === void 0 ? void 0 : result.status));
if (!result || result.status != index_1.FetchStatus.Fetched || ProjectConfig_1.ProjectConfig.compareEtags(lastEtag !== null && lastEtag !== void 0 ? lastEtag : '', result.eTag)) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): result.status != FetchStatus.Fetched or etags are the same. Returning null.");
callback(null);
return;
}
if (!result.responseBody) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): no response body. Returning null.");
callback(null);
return;
}
var newConfig = new ProjectConfig_1.ProjectConfig(new Date().getTime(), result.responseBody, result.eTag);
var preferences = newConfig.ConfigJSON[ProjectConfig_1.ConfigFile.Preferences];
if (!preferences) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): preferences is empty. Returning newConfig.");
callback(newConfig);
return;
}
var baseUrl = preferences[ProjectConfig_1.Preferences.BaseUrl];
// If the base_url is the same as the last called one, just return the response.
if (!baseUrl || baseUrl == calledBaseUrl) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): baseUrl OK. Returning newConfig.");
callback(newConfig);
return;
}
var redirect = preferences[ProjectConfig_1.Preferences.Redirect];
// If the base_url is overridden, and the redirect parameter is not 2 (force),
// the SDK should not redirect the calls and it just have to return the response.
if (options.baseUrlOverriden && redirect !== 2) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): options.baseUrlOverriden && redirect !== 2.");
callback(newConfig);
return;
}
options.baseUrl = baseUrl;
if (redirect === 0) {
callback(newConfig);
return;
}
if (redirect === 1) {
options.logger.warn("Your dataGovernance parameter at ConfigCatClient initialization is not in sync " +
"with your preferences on the ConfigCat Dashboard: " +
"https://app.configcat.com/organization/data-governance. " +
"Only Organization Admins can access this preference.");
}
if (retries >= 2) {
options.logger.error("Redirect loop during config.json fetch. Please contact support@configcat.com.");
callback(newConfig);
return;
}
_this.fetchLogic(options, lastEtag, ++retries, callback);
return;
ConfigServiceBase.prototype.refreshConfigCoreAsync = function (latestConfig) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, fetchResult, newConfig, configContentHasChanged;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.fetchAsync(latestConfig)];
case 1:
_a = _b.sent(), fetchResult = _a[0], newConfig = _a[1];
configContentHasChanged = !ProjectConfig_1.ProjectConfig.equals(latestConfig, newConfig);
if (!(newConfig && (configContentHasChanged || newConfig.Timestamp > latestConfig.Timestamp))) return [3 /*break*/, 3];
return [4 /*yield*/, this.options.cache.set(this.options.getCacheKey(), newConfig)];
case 2:
_b.sent();
this.onConfigUpdated(newConfig);
if (configContentHasChanged) {
this.onConfigChanged(newConfig);
}
return [2 /*return*/, [fetchResult, newConfig]];
case 3: return [2 /*return*/, [fetchResult, latestConfig]];
}
});
});
};
ConfigServiceBase.prototype.fetchLogicInternal = function (options, lastEtag, retries, callback) {
ConfigServiceBase.prototype.onConfigUpdated = function (newConfig) { };
ConfigServiceBase.prototype.onConfigChanged = function (newConfig) {
this.options.logger.debug("config changed");
this.options.hooks.emit("configChanged", newConfig);
};
ConfigServiceBase.prototype.fetchAsync = function (lastConfig) {
var _this = this;
this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): called.");
if (retries === 0) { // Only lock on the top-level calls, not on the recursive calls (config.json redirections).
this.fetchLogicCallbacks.push(callback);
if (this.fetchLogicCallbacks.length > 1) {
// The first fetchLogic call is already in progress.
this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): The first fetchLogic call is already in progress. this.fetchLogicCallbacks.length = " + this.fetchLogicCallbacks.length);
return;
}
this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): Calling fetchLogic");
this.configFetcher.fetchLogic(options, lastEtag, function (newProjectConfig) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): fetchLogic() success, calling callbacks. this.fetchLogicCallbacks.length = " + _this.fetchLogicCallbacks.length);
while (_this.fetchLogicCallbacks.length) {
var thisCallback = _this.fetchLogicCallbacks.pop();
if (thisCallback) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): fetchLogic() success, calling callback.");
thisCallback(newProjectConfig);
}
var _a;
return (_a = this.pendingFetch) !== null && _a !== void 0 ? _a : (this.pendingFetch = (function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, , 2, 3]);
return [4 /*yield*/, this.fetchLogicAsync(lastConfig)];
case 1: return [2 /*return*/, _a.sent()];
case 2:
this.pendingFetch = null;
return [7 /*endfinally*/];
case 3: return [2 /*return*/];
}
});
}); })());
};
ConfigServiceBase.prototype.fetchLogicAsync = function (lastConfig) {
var _a;
return tslib_1.__awaiter(this, void 0, void 0, function () {
var options, errorMessage, _b, response, configJson, err_1, errorMessage_1;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
options = this.options;
options.logger.debug("ConfigServiceBase.fetchLogicAsync() - called.");
_c.label = 1;
case 1:
_c.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.fetchRequestAsync((_a = lastConfig === null || lastConfig === void 0 ? void 0 : lastConfig.HttpETag) !== null && _a !== void 0 ? _a : null)];
case 2:
_b = _c.sent(), response = _b[0], configJson = _b[1];
switch (response.statusCode) {
case 200: // OK
if (!configJson) {
errorMessage = "Fetch was successful but HTTP response was invalid";
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): ".concat(errorMessage.charAt(0).toLowerCase()).concat(errorMessage.slice(1), ". Returning null."));
return [2 /*return*/, [ConfigFetcher_1.FetchResult.error(errorMessage), null]];
}
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): fetch was successful. Returning new config.");
return [2 /*return*/, [ConfigFetcher_1.FetchResult.success(response.body, response.eTag), new ProjectConfig_1.ProjectConfig(new Date().getTime(), configJson, response.eTag)]];
case 304: // Not Modified
if (!lastConfig) {
errorMessage = "HTTP response ".concat(response.statusCode, " ").concat(response.reasonPhrase, " was received when no config is cached locally");
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): ".concat(errorMessage.charAt(0).toLowerCase()).concat(errorMessage.slice(1), ". Returning null."));
return [2 /*return*/, [ConfigFetcher_1.FetchResult.error(errorMessage), null]];
}
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): content was not modified. Returning last config with updated timestamp.");
return [2 /*return*/, [ConfigFetcher_1.FetchResult.notModified(), new ProjectConfig_1.ProjectConfig(new Date().getTime(), lastConfig.ConfigJSON, lastConfig.HttpETag)]];
case 403: // Forbidden
case 404: // Not Found
errorMessage = "Double-check your SDK Key at https://app.configcat.com/sdkkey";
options.logger.error(errorMessage);
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): fetch was unsuccessful. Returning last config (if any) with updated timestamp.");
return [2 /*return*/, [ConfigFetcher_1.FetchResult.error(errorMessage), lastConfig ? new ProjectConfig_1.ProjectConfig(new Date().getTime(), lastConfig.ConfigJSON, lastConfig.HttpETag) : null]];
default:
errorMessage = "Unexpected HTTP response was received: ".concat(response.statusCode, " ").concat(response.reasonPhrase);
options.logger.error(errorMessage);
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): fetch was unsuccessful. Returning null.");
return [2 /*return*/, [ConfigFetcher_1.FetchResult.error(errorMessage), null]];
}
return [3 /*break*/, 4];
case 3:
err_1 = _c.sent();
errorMessage_1 = err_1 instanceof ConfigFetcher_1.FetchError
? err_1.message
: "Unexpected error occurred during fetching.";
options.logger.error(errorMessage_1, err_1);
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): fetch was unsuccessful. Returning null.");
return [2 /*return*/, [ConfigFetcher_1.FetchResult.error(errorMessage_1, err_1), null]];
case 4: return [2 /*return*/];
}
});
});
};
ConfigServiceBase.prototype.fetchRequestAsync = function (lastETag, maxRetryCount) {
if (maxRetryCount === void 0) { maxRetryCount = 2; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var options, retryNumber, response, configJSON, preferences, baseUrl, redirect;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
options = this.options;
options.logger.debug("ConfigServiceBase.fetchRequestAsync() - called.");
retryNumber = 0;
_a.label = 1;
case 1:
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): calling fetchLogic()".concat(retryNumber > 0 ? ", retry ".concat(retryNumber, "/").concat(maxRetryCount) : ""));
return [4 /*yield*/, this.configFetcher.fetchLogic(options, lastETag)];
case 2:
response = _a.sent();
if (response.statusCode !== 200) {
return [2 /*return*/, [response]];
}
if (!response.body) {
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): no response body.");
return [2 /*return*/, [response]];
}
configJSON = void 0;
try {
configJSON = JSON.parse(response.body);
}
catch (_b) {
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): invalid response body.");
return [2 /*return*/, [response]];
}
preferences = configJSON[ProjectConfig_1.ConfigFile.Preferences];
if (!preferences) {
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): preferences is empty.");
return [2 /*return*/, [response, configJSON]];
}
baseUrl = preferences[ProjectConfig_1.Preferences.BaseUrl];
// If the base_url is the same as the last called one, just return the response.
if (!baseUrl || baseUrl == options.baseUrl) {
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): baseUrl OK.");
return [2 /*return*/, [response, configJSON]];
}
redirect = preferences[ProjectConfig_1.Preferences.Redirect];
// If the base_url is overridden, and the redirect parameter is not 2 (force),
// the SDK should not redirect the calls and it just have to return the response.
if (options.baseUrlOverriden && redirect !== 2) {
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): options.baseUrlOverriden && redirect !== 2.");
return [2 /*return*/, [response, configJSON]];
}
options.baseUrl = baseUrl;
if (redirect === 0) {
return [2 /*return*/, [response, configJSON]];
}
if (redirect === 1) {
options.logger.warn("Your dataGovernance parameter at ConfigCatClient initialization is not in sync " +
"with your preferences on the ConfigCat Dashboard: " +
"https://app.configcat.com/organization/data-governance. " +
"Only Organization Admins can access this preference.");
}
if (retryNumber >= maxRetryCount) {
options.logger.error("Redirect loop during config.json fetch. Please contact support@configcat.com.");
return [2 /*return*/, [response, configJSON]];
}
_a.label = 3;
case 3:
retryNumber++;
return [3 /*break*/, 1];
case 4: return [2 /*return*/];
}
});
});
};
Object.defineProperty(ConfigServiceBase.prototype, "isOfflineExactly", {
get: function () {
return this.status === ConfigServiceStatus.Offline;
},
enumerable: false,
configurable: true
});
Object.defineProperty(ConfigServiceBase.prototype, "isOffline", {
get: function () {
return this.status !== ConfigServiceStatus.Online;
},
enumerable: false,
configurable: true
});
ConfigServiceBase.prototype.setOnlineCore = function () { };
ConfigServiceBase.prototype.setOnline = function () {
if (this.status === ConfigServiceStatus.Offline) {
this.setOnlineCore();
this.status = ConfigServiceStatus.Online;
this.logStatusChange(this.status);
}
else {
// Recursive calls should call the fetchLogic as is.
this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): calling fetchLogic(), recursive call. retries = " + retries);
this.configFetcher.fetchLogic(options, lastEtag, callback);
else if (this.disposed) {
this.logDisposedWarning("setOnline");
}
};
ConfigServiceBase.prototype.setOfflineCore = function () { };
ConfigServiceBase.prototype.setOffline = function () {
if (this.status == ConfigServiceStatus.Online) {
this.setOfflineCore();
this.status = ConfigServiceStatus.Offline;
this.logStatusChange(this.status);
}
else if (this.disposed) {
this.logDisposedWarning("setOnline");
}
};
ConfigServiceBase.prototype.logStatusChange = function (status) {
var _a;
this.options.logger.debug("Switched to ".concat((_a = ConfigServiceStatus[status]) === null || _a === void 0 ? void 0 : _a.toUpperCase(), " mode."));
};
ConfigServiceBase.prototype.logOfflineModeWarning = function () {
this.options.logger.warn("Client is in offline mode, it can't initiate HTTP calls.");
};
ConfigServiceBase.prototype.logDisposedWarning = function (methodName) {
this.options.logger.warn("Client has already been disposed, thus ".concat(methodName, "() has no effect."));
};
return ConfigServiceBase;
}());
exports.ConfigServiceBase = ConfigServiceBase;

@@ -1,84 +0,92 @@

var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
import { __awaiter, __extends, __generator } from "tslib";
import { ConfigServiceBase } from "./ConfigServiceBase";
import { ProjectConfig } from "./ProjectConfig";
import { delay } from "./Utils";
var AutoPollConfigService = /** @class */ (function (_super) {
__extends(AutoPollConfigService, _super);
function AutoPollConfigService(configFetcher, autoPollConfig) {
var _this = _super.call(this, configFetcher, autoPollConfig) || this;
_this.disposed = false;
_this.configChanged = autoPollConfig.configChanged;
_this.autoPollConfig = autoPollConfig;
_this.startRefreshWorker(autoPollConfig.pollIntervalSeconds * 1000);
_this.maxInitWaitTimeStamp = new Date().getTime() + (autoPollConfig.maxInitWaitTimeSeconds * 1000);
function AutoPollConfigService(configFetcher, options) {
var _this = _super.call(this, configFetcher, options) || this;
_this.signalInitialization = (void 0); // the initial value is only for keeping the TS compiler happy
if (options.maxInitWaitTimeSeconds > 0) {
_this.initialized = false;
// This promise will be resolved when
// 1. the cache contains a valid config at startup (see startRefreshWorker) or
// 2. config.json is downloaded the first time (see onConfigUpdated) or
// 3. maxInitWaitTimeSeconds has passed (see the setTimeout call below).
_this.initialization = new Promise(function (resolve) { return _this.signalInitialization = function () {
_this.initialized = true;
resolve();
}; });
_this.initialization.then(function () { return !_this.disposed && options.hooks.emit("clientReady"); });
setTimeout(function () { return _this.signalInitialization(); }, options.maxInitWaitTimeSeconds * 1000);
}
else {
_this.initialized = true;
_this.initialization = Promise.resolve();
options.hooks.emit("clientReady");
}
if (!options.offline) {
_this.startRefreshWorker(options.pollIntervalSeconds * 1000);
}
return _this;
}
AutoPollConfigService.prototype.waitForInitializationAsync = function () {
return __awaiter(this, void 0, void 0, function () {
var cancelDelay, result;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, Promise.race([
(function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.initialization];
case 1:
_a.sent();
return [2 /*return*/, true];
}
}); }); })(),
delay(this.options.maxInitWaitTimeSeconds * 1000, function (cancel) { return cancelDelay = cancel; })
])];
case 1:
result = _a.sent();
cancelDelay();
return [2 /*return*/, !!result];
}
});
});
};
AutoPollConfigService.prototype.getConfig = function () {
return __awaiter(this, void 0, void 0, function () {
var p;
function logSuccess(logger) {
logger.debug("AutoPollConfigService.getConfig() - returning value from cache.");
}
var cacheConfig;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.autoPollConfig.logger.debug("AutoPollConfigService.getConfig() called.");
return [4 /*yield*/, this.tryReadFromCache(0)];
this.options.logger.debug("AutoPollConfigService.getConfig() called.");
cacheConfig = null;
if (!(!this.isOffline && !this.initialized)) return [3 /*break*/, 3];
return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 1:
p = _a.sent();
if (!p) {
this.autoPollConfig.logger.debug("AutoPollConfigService.getConfig() - cache is empty, refreshing the cache.");
return [2 /*return*/, this.refreshLogic(true)];
cacheConfig = _a.sent();
if (!ProjectConfig.isExpired(cacheConfig, this.options.pollIntervalSeconds * 1000)) {
logSuccess(this.options.logger);
return [2 /*return*/, cacheConfig];
}
this.options.logger.debug("AutoPollConfigService.getConfig() - cache is empty or expired, waiting for initialization.");
return [4 /*yield*/, this.waitForInitializationAsync()];
case 2:
_a.sent();
_a.label = 3;
case 3: return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 4:
cacheConfig = _a.sent();
if (!ProjectConfig.isExpired(cacheConfig, this.options.pollIntervalSeconds * 1000)) {
logSuccess(this.options.logger);
}
else {
this.autoPollConfig.logger.debug("AutoPollConfigService.getConfig() - returning value from cache.");
return [2 /*return*/, new Promise(function (resolve) { return resolve(p); })];
this.options.logger.debug("AutoPollConfigService.getConfig() - cache is empty or expired.");
}
return [2 /*return*/];
return [2 /*return*/, cacheConfig];
}

@@ -89,92 +97,83 @@ });

AutoPollConfigService.prototype.refreshConfigAsync = function () {
this.autoPollConfig.logger.debug("AutoPollConfigService.refreshConfigAsync() called.");
return this.refreshLogic(true);
this.options.logger.debug("AutoPollConfigService.refreshConfigAsync() called.");
return _super.prototype.refreshConfigAsync.call(this);
};
AutoPollConfigService.prototype.dispose = function () {
this.autoPollConfig.logger.debug("AutoPollConfigService.dispose() called.");
this.disposed = true;
this.options.logger.debug("AutoPollConfigService.dispose() called.");
_super.prototype.dispose.call(this);
if (this.timerId) {
this.autoPollConfig.logger.debug("AutoPollConfigService.dispose() - clearing setTimeout.");
clearTimeout(this.timerId);
this.stopRefreshWorker();
}
};
AutoPollConfigService.prototype.refreshLogic = function (forceUpdateCache) {
var _this = this;
this.autoPollConfig.logger.debug("AutoPollConfigService.refreshLogic() - called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var cachedConfig, newConfig, weDontHaveCachedYetButHaveNew, weHaveBothButTheyDiffers;
AutoPollConfigService.prototype.onConfigUpdated = function (newConfig) {
_super.prototype.onConfigUpdated.call(this, newConfig);
this.signalInitialization();
};
AutoPollConfigService.prototype.onConfigChanged = function (newConfig) {
_super.prototype.onConfigChanged.call(this, newConfig);
this.options.configChanged();
};
AutoPollConfigService.prototype.setOnlineCore = function () {
this.startRefreshWorker(this.options.pollIntervalSeconds * 1000);
};
AutoPollConfigService.prototype.setOfflineCore = function () {
this.stopRefreshWorker();
};
AutoPollConfigService.prototype.startRefreshWorker = function (delayMs) {
return __awaiter(this, void 0, void 0, function () {
var latestConfig;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.baseConfig.cache.get(this.baseConfig.getCacheKey())];
case 0:
this.options.logger.debug("AutoPollConfigService.startRefreshWorker() called.");
return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 1:
cachedConfig = _a.sent();
return [4 /*yield*/, this.refreshLogicBaseAsync(cachedConfig, forceUpdateCache)];
latestConfig = _a.sent();
if (!ProjectConfig.isExpired(latestConfig, this.options.pollIntervalSeconds * 1000)) return [3 /*break*/, 4];
if (!!this.isOfflineExactly) return [3 /*break*/, 3];
return [4 /*yield*/, this.refreshConfigCoreAsync(latestConfig)];
case 2:
newConfig = _a.sent();
weDontHaveCachedYetButHaveNew = !cachedConfig && newConfig;
weHaveBothButTheyDiffers = cachedConfig && newConfig && !ProjectConfig.equals(cachedConfig, newConfig);
this.autoPollConfig.logger.debug("AutoPollConfigService.refreshLogic() - weDontHaveCachedYetButHaveNew: ." + weDontHaveCachedYetButHaveNew + ". weHaveBothButTheyDiffers: " + weHaveBothButTheyDiffers + ".");
if (weDontHaveCachedYetButHaveNew || weHaveBothButTheyDiffers) {
this.configChanged();
}
resolve(newConfig);
_a.sent();
_a.label = 3;
case 3: return [3 /*break*/, 5];
case 4:
this.signalInitialization();
_a.label = 5;
case 5:
this.options.logger.debug("AutoPollConfigService.startRefreshWorker() - calling refreshWorkerLogic()'s setTimeout.");
this.timerId = setTimeout(function (d) { return _this.refreshWorkerLogic(d); }, delayMs, delayMs);
return [2 /*return*/];
}
});
}); });
};
AutoPollConfigService.prototype.startRefreshWorker = function (delay) {
var _this = this;
this.autoPollConfig.logger.debug("AutoPollConfigService.startRefreshWorker() called.");
this.refreshLogic(true).then(function (_) {
_this.autoPollConfig.logger.debug("AutoPollConfigService.startRefreshWorker() - calling refreshWorkerLogic()'s setTimeout.");
setTimeout(function () { return _this.refreshWorkerLogic(delay); }, delay);
});
};
AutoPollConfigService.prototype.refreshWorkerLogic = function (delay) {
var _this = this;
if (this.disposed) {
this.autoPollConfig.logger.debug("AutoPollConfigService.refreshWorkerLogic() - called on a disposed client.");
return;
}
this.autoPollConfig.logger.debug("AutoPollConfigService.refreshWorkerLogic() - called.");
this.refreshLogic(false).then(function (_) {
_this.autoPollConfig.logger.debug("AutoPollConfigService.refreshWorkerLogic() - calling refreshWorkerLogic()'s setTimeout.");
_this.timerId = setTimeout(function () {
_this.refreshWorkerLogic(delay);
}, delay);
});
AutoPollConfigService.prototype.stopRefreshWorker = function () {
this.options.logger.debug("AutoPollConfigService.stopRefreshWorker() - clearing setTimeout.");
clearTimeout(this.timerId);
};
AutoPollConfigService.prototype.tryReadFromCache = function (tries) {
AutoPollConfigService.prototype.refreshWorkerLogic = function (delayMs) {
return __awaiter(this, void 0, void 0, function () {
var p, diff, delay;
var latestConfig;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.autoPollConfig.logger.debug("AutoPollConfigService.tryReadFromCache() - called. Tries: " + tries + ".");
return [4 /*yield*/, this.baseConfig.cache.get(this.baseConfig.getCacheKey())];
if (this.disposed) {
this.options.logger.debug("AutoPollConfigService.refreshWorkerLogic() - called on a disposed client.");
return [2 /*return*/];
}
this.options.logger.debug("AutoPollConfigService.refreshWorkerLogic() - called.");
if (!!this.isOffline) return [3 /*break*/, 3];
return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 1:
p = _a.sent();
if (!(this.maxInitWaitTimeStamp > new Date().getTime()
&& (
// Wait for maxInitWaitTimeStamp in case the cache is empty
!p
// Wait for maxInitWaitTimeStamp in case of an expired cache (if its timestamp is older than the pollIntervalSeconds)
|| p.Timestamp < new Date().getTime() - this.autoPollConfig.pollIntervalSeconds * 1000))) return [3 /*break*/, 3];
if (!p) {
this.autoPollConfig.logger.debug("AutoPollConfigService.tryReadFromCache() - waiting for maxInitWaitTimeStamp because cache is empty.");
}
else {
this.autoPollConfig.logger.debug("AutoPollConfigService.tryReadFromCache() - waiting for maxInitWaitTimeStamp because cache is expired.");
}
diff = this.maxInitWaitTimeStamp - new Date().getTime();
delay = 30 + (tries * tries * 20);
return [4 /*yield*/, this.sleep(Math.min(diff, delay))];
latestConfig = _a.sent();
return [4 /*yield*/, this.refreshConfigCoreAsync(latestConfig)];
case 2:
_a.sent();
tries++;
return [2 /*return*/, this.tryReadFromCache(tries)];
_a.label = 3;
case 3:
this.autoPollConfig.logger.debug("AutoPollConfigService.tryReadFromCache() - returning value from cache.");
return [2 /*return*/, new Promise(function (resolve) { return resolve(p); })];
this.options.logger.debug("AutoPollConfigService.refreshWorkerLogic() - calling refreshWorkerLogic()'s setTimeout.");
this.timerId = setTimeout(function (d) { return _this.refreshWorkerLogic(d); }, delayMs, delayMs);
return [2 /*return*/];
}

@@ -184,7 +183,4 @@ });

};
AutoPollConfigService.prototype.sleep = function (ms) {
return new Promise(function (resolve) { return setTimeout(resolve, ms); });
};
return AutoPollConfigService;
}(ConfigServiceBase));
export { AutoPollConfigService };

@@ -9,3 +9,4 @@ var InMemoryCache = /** @class */ (function () {

InMemoryCache.prototype.get = function (key) {
return this.cache[key];
var _a;
return (_a = this.cache[key]) !== null && _a !== void 0 ? _a : null;
};

@@ -12,0 +13,0 @@ return InMemoryCache;

@@ -1,59 +0,66 @@

var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
import { __assign, __awaiter, __generator } from "tslib";
import { AutoPollConfigService } from "./AutoPollConfigService";
import { AutoPollOptions, LazyLoadOptions, ManualPollOptions, PollingMode } from "./ConfigCatClientOptions";
import { RefreshResult } from "./ConfigServiceBase";
import { OverrideBehaviour } from "./FlagOverrides";
import { LazyLoadConfigService } from "./LazyLoadConfigService";
import { ManualPollConfigService } from "./ManualPollConfigService";
import { ConfigFile } from "./ProjectConfig";
import { checkSettingsAvailable, ensureAllowedDefaultValue, evaluate, evaluateAll, evaluateAllVariationIds, evaluateVariationId, evaluationDetailsFromDefaultValue, evaluationDetailsFromDefaultVariationId, RolloutEvaluator } from "./RolloutEvaluator";
import { errorToString, getSettingsFromConfig, getTimestampAsDate } from "./Utils";
var ConfigCatClientCache = /** @class */ (function () {
function ConfigCatClientCache() {
this.instances = {};
}
ConfigCatClientCache.prototype.getOrCreate = function (options, configCatKernel) {
var instance;
var cachedInstance = this.instances[options.apiKey];
if (cachedInstance) {
var weakRef = cachedInstance[0];
instance = weakRef.deref();
if (instance) {
return [instance, true];
}
}
return t;
var token = {};
instance = new ConfigCatClient(options, configCatKernel, token);
this.instances[options.apiKey] = [new WeakRef(instance), token];
return [instance, false];
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
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;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
import { AutoPollOptions, ManualPollOptions, LazyLoadOptions } from "./ConfigCatClientOptions";
import { AutoPollConfigService } from "./AutoPollConfigService";
import { LazyLoadConfigService } from "./LazyLoadConfigService";
import { ManualPollService } from "./ManualPollService";
import { RolloutEvaluator } from "./RolloutEvaluator";
import { ConfigFile } from "./ProjectConfig";
import { OverrideBehaviour } from "./FlagOverrides";
import { getSettingsFromConfig } from "./Utils";
}
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) {
function ConfigCatClient(options, configCatKernel, cacheToken) {
var _a;
this.cacheToken = cacheToken;
/** @inheritdoc */
this.addListener = this.on;
/** @inheritdoc */
this.off = this.removeListener;
if (!options) {

@@ -70,189 +77,317 @@ throw new Error("Invalid 'options' value");

}
if (options === null || options === void 0 ? void 0 : options.defaultUser) {
if (options.defaultUser) {
this.setDefaultUser(options.defaultUser);
}
this.evaluator = new RolloutEvaluator(options.logger);
if (((_a = options === null || options === void 0 ? void 0 : options.flagOverrides) === null || _a === void 0 ? void 0 : _a.behaviour) != OverrideBehaviour.LocalOnly) {
if (options && options instanceof LazyLoadOptions) {
this.configService = new LazyLoadConfigService(configCatKernel.configFetcher, options);
}
else if (options && options instanceof ManualPollOptions) {
this.configService = new ManualPollService(configCatKernel.configFetcher, options);
}
else if (options && options instanceof AutoPollOptions) {
this.configService = new AutoPollConfigService(configCatKernel.configFetcher, options);
}
else {
throw new Error("Invalid 'options' value");
}
if (((_a = options.flagOverrides) === null || _a === void 0 ? void 0 : _a.behaviour) != OverrideBehaviour.LocalOnly) {
var configServiceClass = options instanceof AutoPollOptions ? AutoPollConfigService :
options instanceof ManualPollOptions ? ManualPollConfigService :
options instanceof LazyLoadOptions ? LazyLoadConfigService :
(function () { throw new Error("Invalid 'options' value"); })();
this.configService = new configServiceClass(configCatKernel.configFetcher, options);
}
else {
this.options.hooks.emit("clientReady");
}
this.suppressFinalize = registerForFinalization(this, { sdkKey: options.apiKey, 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) {
if (!sdkKey) {
throw new Error("Invalid 'sdkKey' value");
}
var optionsClass = pollingMode === PollingMode.AutoPoll ? AutoPollOptions :
pollingMode === PollingMode.ManualPoll ? ManualPollOptions :
pollingMode === PollingMode.LazyLoad ? LazyLoadOptions :
(function () { throw new Error("Invalid 'pollingMode' value"); })();
var actualOptions = new optionsClass(sdkKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache, configCatKernel.eventEmitterFactory);
var _a = clientInstanceCache.getOrCreate(actualOptions, configCatKernel), instance = _a[0], instanceAlreadyCreated = _a[1];
if (instanceAlreadyCreated && options) {
actualOptions.logger.warn("Client for SDK key '".concat(sdkKey, "' is already created and will be reused; configuration action is being ignored."));
}
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 () {
this.options.logger.debug("dispose() called");
if (this.configService instanceof AutoPollConfigService) {
this.options.logger.debug("Disposing AutoPollConfigService");
this.configService.dispose();
var options = this.options;
options.logger.debug("dispose() called");
if (this.cacheToken) {
clientInstanceCache.remove(options.apiKey, this.cacheToken);
}
ConfigCatClient.close(this.configService, options.logger, options.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.options.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.getValue = function (key, defaultValue, callback, user) {
this.options.logger.debug("getValue() called.");
this.getValueAsync(key, defaultValue, user).then(function (value) {
callback(value);
});
this.getValueAsync(key, defaultValue, user).then(callback);
};
ConfigCatClient.prototype.getValueAsync = function (key, defaultValue, user) {
var _this = this;
this.options.logger.debug("getValueAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var settings, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getSettingsAsync()];
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.");
remoteConfig = null;
user !== null && user !== void 0 ? user : (user = this.defaultUser);
_b.label = 1;
case 1:
settings = _a.sent();
if (!settings) {
this.options.logger.error("config.json is not present. Returning default value: '" + defaultValue + "'.");
resolve(defaultValue);
return [2 /*return*/];
}
result = this.evaluator.Evaluate(settings, key, defaultValue, user !== null && user !== void 0 ? user : this.defaultUser).Value;
resolve(result);
return [2 /*return*/];
_b.trys.push([1, 3, , 4]);
ensureAllowedDefaultValue(defaultValue);
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.error("Error occurred in getValueAsync().", err_1);
evaluationDetails = evaluationDetailsFromDefaultValue(key, defaultValue, getTimestampAsDate(remoteConfig), user, errorToString(err_1), err_1);
value = defaultValue;
return [3 /*break*/, 4];
case 4:
this.options.hooks.emit("flagEvaluated", evaluationDetails);
return [2 /*return*/, value];
}
});
}); });
};
ConfigCatClient.prototype.forceRefresh = function (callback) {
this.options.logger.debug("forceRefresh() called.");
this.forceRefreshAsync().then(function () {
callback();
});
};
ConfigCatClient.prototype.forceRefreshAsync = function () {
var _this = this;
this.options.logger.debug("forceRefreshAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
ConfigCatClient.prototype.getValueDetails = function (key, defaultValue, callback, user) {
this.options.logger.debug("getValueDetails() called.");
this.getValueDetailsAsync(key, defaultValue, user).then(callback);
};
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: return [4 /*yield*/, ((_a = this.configService) === null || _a === void 0 ? void 0 : _a.refreshConfigAsync())];
case 0:
this.options.logger.debug("getValueDetailsAsync() called.");
remoteConfig = null;
user !== null && user !== void 0 ? user : (user = this.defaultUser);
_b.label = 1;
case 1:
_b.sent();
resolve();
return [2 /*return*/];
_b.trys.push([1, 3, , 4]);
ensureAllowedDefaultValue(defaultValue);
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.error("Error occurred in getValueDetailsAsync().", err_2);
evaluationDetails = evaluationDetailsFromDefaultValue(key, defaultValue, getTimestampAsDate(remoteConfig), user, errorToString(err_2), err_2);
return [3 /*break*/, 4];
case 4:
this.options.hooks.emit("flagEvaluated", evaluationDetails);
return [2 /*return*/, evaluationDetails];
}
});
}); });
});
};
ConfigCatClient.prototype.forceRefresh = function (callback) {
this.options.logger.debug("forceRefresh() called.");
this.forceRefreshAsync().then(callback);
};
ConfigCatClient.prototype.forceRefreshAsync = function () {
return __awaiter(this, void 0, void 0, function () {
var result, err_3;
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_3 = _a.sent();
this.options.logger.error("Error occurred in forceRefreshAsync().", err_3);
return [2 /*return*/, RefreshResult.failure(errorToString(err_3), err_3)];
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.getAllKeys = function (callback) {
this.options.logger.debug("getAllKeys() called.");
this.getAllKeysAsync().then(function (value) {
callback(value);
});
this.getAllKeysAsync().then(callback);
};
ConfigCatClient.prototype.getAllKeysAsync = function () {
var _this = this;
this.options.logger.debug("getAllKeysAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var settings;
return __awaiter(this, void 0, void 0, function () {
var settings, err_4;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getSettingsAsync()];
case 0:
this.options.logger.debug("getAllKeysAsync() called.");
_a.label = 1;
case 1:
settings = _a.sent();
if (!settings) {
this.options.logger.error("config.json is not present, returning empty array");
resolve([]);
return [2 /*return*/];
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.getSettingsAsync()];
case 2:
settings = (_a.sent())[0];
if (!checkSettingsAvailable(settings, this.options.logger, ", returning empty array")) {
return [2 /*return*/, []];
}
resolve(Object.keys(settings));
return [2 /*return*/];
return [2 /*return*/, Object.keys(settings)];
case 3:
err_4 = _a.sent();
this.options.logger.error("Error occurred in getAllKeysAsync().", err_4);
return [2 /*return*/, []];
case 4: return [2 /*return*/];
}
});
}); });
});
};
ConfigCatClient.prototype.getVariationId = function (key, defaultVariationId, callback, user) {
this.options.logger.debug("getVariationId() called.");
this.getVariationIdAsync(key, defaultVariationId, user).then(function (variationId) {
callback(variationId);
});
this.getVariationIdAsync(key, defaultVariationId, user).then(callback);
};
ConfigCatClient.prototype.getVariationIdAsync = function (key, defaultVariationId, user) {
var _this = this;
this.options.logger.debug("getVariationIdAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var settings, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getSettingsAsync()];
return __awaiter(this, void 0, void 0, function () {
var variationId, evaluationDetails, remoteConfig, settings, err_5;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
this.options.logger.debug("getVariationIdAsync() called.");
remoteConfig = null;
user !== null && user !== void 0 ? user : (user = this.defaultUser);
_b.label = 1;
case 1:
settings = _a.sent();
if (!settings) {
this.options.logger.error("config.json is not present. Returning default variationId: '" + defaultVariationId + "'.");
resolve(defaultVariationId);
return [2 /*return*/];
}
result = this.evaluator.Evaluate(settings, key, null, user !== null && user !== void 0 ? user : this.defaultUser, defaultVariationId).VariationId;
resolve(result);
return [2 /*return*/];
_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 = evaluateVariationId(this.evaluator, settings, key, defaultVariationId, user, remoteConfig, this.options.logger);
variationId = evaluationDetails.variationId;
return [3 /*break*/, 4];
case 3:
err_5 = _b.sent();
this.options.logger.error("Error occurred in getVariationIdAsync().", err_5);
evaluationDetails = evaluationDetailsFromDefaultVariationId(key, defaultVariationId, getTimestampAsDate(remoteConfig), user, errorToString(err_5), err_5);
variationId = defaultVariationId;
return [3 /*break*/, 4];
case 4:
this.options.hooks.emit("flagEvaluated", evaluationDetails);
return [2 /*return*/, variationId];
}
});
}); });
});
};
ConfigCatClient.prototype.getAllVariationIds = function (callback, user) {
this.options.logger.debug("getAllVariationIds() called.");
this.getAllVariationIdsAsync(user).then(function (variationIds) {
callback(variationIds);
});
this.getAllVariationIdsAsync(user).then(callback);
};
ConfigCatClient.prototype.getAllVariationIdsAsync = function (user) {
var _this = this;
this.options.logger.debug("getAllVariationIdsAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var keys, promises, variationIds;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getAllKeysAsync()];
return __awaiter(this, void 0, void 0, function () {
var result, evaluationDetailsArray, _a, settings, remoteConfig, errors, err_6, _i, evaluationDetailsArray_1, evaluationDetail;
var _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
this.options.logger.debug("getAllVariationIdsAsync() called.");
user !== null && user !== void 0 ? user : (user = this.defaultUser);
_c.label = 1;
case 1:
keys = _a.sent();
if (keys.length === 0) {
resolve([]);
return [2 /*return*/];
_c.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.getSettingsAsync()];
case 2:
_a = _c.sent(), settings = _a[0], remoteConfig = _a[1];
errors = void 0;
_b = evaluateAllVariationIds(this.evaluator, settings, user, remoteConfig, this.options.logger), evaluationDetailsArray = _b[0], errors = _b[1];
if (errors === null || errors === void 0 ? void 0 : errors.length) {
throw typeof AggregateError !== "undefined" ? new AggregateError(errors) : errors.pop();
}
promises = keys.map(function (key) { return _this.getVariationIdAsync(key, null, user); });
return [4 /*yield*/, Promise.all(promises)];
case 2:
variationIds = _a.sent();
resolve(variationIds);
return [2 /*return*/];
result = evaluationDetailsArray.filter(function (details) { return details !== null && details !== void 0; }).map(function (details) { return details.variationId; });
return [3 /*break*/, 4];
case 3:
err_6 = _c.sent();
this.options.logger.error("Error occurred in getAllVariationIdsAsync().", err_6);
evaluationDetailsArray !== null && evaluationDetailsArray !== void 0 ? evaluationDetailsArray : (evaluationDetailsArray = []);
result = [];
return [3 /*break*/, 4];
case 4:
for (_i = 0, evaluationDetailsArray_1 = evaluationDetailsArray; _i < evaluationDetailsArray_1.length; _i++) {
evaluationDetail = evaluationDetailsArray_1[_i];
this.options.hooks.emit("flagEvaluated", evaluationDetail);
}
return [2 /*return*/, result];
}
});
}); });
});
};
ConfigCatClient.prototype.getKeyAndValue = function (variationId, callback) {
this.options.logger.debug("getKeyAndValue() called.");
this.getKeyAndValueAsync(variationId).then(function (settingKeyAndValue) {
callback(settingKeyAndValue);
});
this.getKeyAndValueAsync(variationId).then(callback);
};
ConfigCatClient.prototype.getKeyAndValueAsync = function (variationId) {
var _this = this;
this.options.logger.debug("getKeyAndValueAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var settings, settingKey, rolloutRules, i, rolloutRule, percentageItems, i, percentageItem;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getSettingsAsync()];
return __awaiter(this, void 0, void 0, function () {
var settings, _i, _a, _b, settingKey, setting, rolloutRules, i, rolloutRule, percentageItems, i, percentageItem, err_7;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
this.options.logger.debug("getKeyAndValueAsync() called.");
_c.label = 1;
case 1:
settings = _a.sent();
if (!settings) {
this.options.logger.error("config.json is not present, returning empty array");
resolve(null);
return [2 /*return*/];
_c.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.getSettingsAsync()];
case 2:
settings = (_c.sent())[0];
if (!checkSettingsAvailable(settings, this.options.logger, ", returning null")) {
return [2 /*return*/, null];
}
for (settingKey in settings) {
if (variationId === settings[settingKey].variationId) {
resolve({ settingKey: settingKey, settingValue: settings[settingKey].value });
return [2 /*return*/];
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, setting.value)];
}

@@ -264,4 +399,3 @@ rolloutRules = settings[settingKey].rolloutRules;

if (variationId === rolloutRule.variationId) {
resolve({ settingKey: settingKey, settingValue: rolloutRule.value });
return [2 /*return*/];
return [2 /*return*/, new SettingKeyValue(settingKey, rolloutRule.value)];
}

@@ -275,4 +409,3 @@ }

if (variationId === percentageItem.variationId) {
resolve({ settingKey: settingKey, settingValue: percentageItem.value });
return [2 /*return*/];
return [2 /*return*/, new SettingKeyValue(settingKey, percentageItem.value)];
}

@@ -283,44 +416,94 @@ }

this.options.logger.error("Could not find the setting for the given variation ID: " + variationId);
resolve(null);
return [2 /*return*/];
return [3 /*break*/, 4];
case 3:
err_7 = _c.sent();
this.options.logger.error("Error occurred in getKeyAndValueAsync().", err_7);
return [3 /*break*/, 4];
case 4: return [2 /*return*/, null];
}
});
}); });
});
};
ConfigCatClient.prototype.getAllValues = function (callback, user) {
this.options.logger.debug("getAllValues() called.");
this.getAllValuesAsync(user).then(function (value) {
callback(value);
});
this.getAllValuesAsync(user).then(callback);
};
ConfigCatClient.prototype.getAllValuesAsync = function (user) {
var _this = this;
this.options.logger.debug("getAllValuesAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var settings, keys, result;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getSettingsAsync()];
return __awaiter(this, void 0, void 0, function () {
var result, evaluationDetailsArray, _a, settings, remoteConfig, errors, err_8, _i, evaluationDetailsArray_2, evaluationDetail;
var _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
this.options.logger.debug("getAllValuesAsync() called.");
user !== null && user !== void 0 ? user : (user = this.defaultUser);
_c.label = 1;
case 1:
settings = _a.sent();
if (!settings) {
this.options.logger.error("config.json is not present, returning empty array");
resolve([]);
return [2 /*return*/];
_c.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.getSettingsAsync()];
case 2:
_a = _c.sent(), settings = _a[0], remoteConfig = _a[1];
errors = void 0;
_b = evaluateAll(this.evaluator, settings, user, remoteConfig, this.options.logger), evaluationDetailsArray = _b[0], errors = _b[1];
if (errors === null || errors === void 0 ? void 0 : errors.length) {
throw typeof AggregateError !== "undefined" ? new AggregateError(errors) : errors.pop();
}
keys = Object.keys(settings);
result = evaluationDetailsArray.map(function (details) { return new SettingKeyValue(details.key, details.value); });
return [3 /*break*/, 4];
case 3:
err_8 = _c.sent();
this.options.logger.error("Error occurred in getAllValuesAsync().", err_8);
evaluationDetailsArray !== null && evaluationDetailsArray !== void 0 ? evaluationDetailsArray : (evaluationDetailsArray = []);
result = [];
keys.forEach(function (key) {
result.push({
settingKey: key,
settingValue: _this.evaluator.Evaluate(settings, key, undefined, user !== null && user !== void 0 ? user : _this.defaultUser).Value
});
});
resolve(result);
return [2 /*return*/];
return [3 /*break*/, 4];
case 4:
for (_i = 0, evaluationDetailsArray_2 = evaluationDetailsArray; _i < evaluationDetailsArray_2.length; _i++) {
evaluationDetail = evaluationDetailsArray_2[_i];
this.options.hooks.emit("flagEvaluated", evaluationDetail);
}
return [2 /*return*/, result];
}
});
}); });
});
};
ConfigCatClient.prototype.getAllValueDetails = function (callback, user) {
this.options.logger.debug("getAllValueDetails() called.");
this.getAllValueDetailsAsync(user).then(callback);
};
ConfigCatClient.prototype.getAllValueDetailsAsync = function (user) {
return __awaiter(this, void 0, void 0, function () {
var evaluationDetailsArray, _a, settings, remoteConfig, errors, err_9, _i, evaluationDetailsArray_3, evaluationDetail;
var _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
this.options.logger.debug("getAllValueDetailsAsync() called.");
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];
errors = void 0;
_b = evaluateAll(this.evaluator, settings, user, remoteConfig, this.options.logger), evaluationDetailsArray = _b[0], errors = _b[1];
if (errors === null || errors === void 0 ? void 0 : errors.length) {
throw typeof AggregateError !== "undefined" ? new AggregateError(errors) : errors.pop();
}
return [3 /*break*/, 4];
case 3:
err_9 = _c.sent();
this.options.logger.error("Error occurred in getAllValueDetailsAsync().", err_9);
evaluationDetailsArray !== null && evaluationDetailsArray !== void 0 ? evaluationDetailsArray : (evaluationDetailsArray = []);
return [3 /*break*/, 4];
case 4:
for (_i = 0, evaluationDetailsArray_3 = evaluationDetailsArray; _i < evaluationDetailsArray_3.length; _i++) {
evaluationDetail = evaluationDetailsArray_3[_i];
this.options.hooks.emit("flagEvaluated", evaluationDetail);
}
return [2 /*return*/, evaluationDetailsArray];
}
});
});
};
ConfigCatClient.prototype.setDefaultUser = function (defaultUser) {

@@ -330,47 +513,109 @@ this.defaultUser = defaultUser;

ConfigCatClient.prototype.clearDefaultUser = function () {
this.defaultUser = undefined;
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.warn("Client is configured to use the LocalOnly override behavior, thus SetOnline() has no effect.");
}
};
ConfigCatClient.prototype.setOffline = function () {
var _a;
(_a = this.configService) === null || _a === void 0 ? void 0 : _a.setOffline();
};
ConfigCatClient.prototype.getSettingsAsync = function () {
var _this = this;
this.options.logger.debug("getSettingsAsync() called.");
return new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var localSettings, remoteConfig, remoteSettings, config;
var _a, _b, _c;
return __generator(this, function (_d) {
switch (_d.label) {
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:
if (!((_a = this.options) === null || _a === void 0 ? void 0 : _a.flagOverrides)) return [3 /*break*/, 3];
return [4 /*yield*/, this.options.flagOverrides.dataSource.getOverrides()];
this.options.logger.debug("getSettingsAsync() called.");
getRemoteConfigAsync = function () { return __awaiter(_this, void 0, void 0, function () {
var config, json, settings;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, ((_a = this.configService) === null || _a === void 0 ? void 0 : _a.getConfig())];
case 1:
config = _b.sent();
json = config === null || config === void 0 ? void 0 : config.ConfigJSON;
settings = (json === null || json === void 0 ? void 0 : json[ConfigFile.FeatureFlags]) ? getSettingsFromConfig(json) : null;
return [2 /*return*/, [settings, config !== null && config !== void 0 ? config : null]];
}
});
}); };
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 = _d.sent();
if (this.options.flagOverrides.behaviour == OverrideBehaviour.LocalOnly) {
resolve(localSettings);
return [2 /*return*/];
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 [4 /*yield*/, ((_b = this.configService) === null || _b === void 0 ? void 0 : _b.getConfig())];
case 2:
remoteConfig = _d.sent();
remoteSettings = getSettingsFromConfig(remoteConfig === null || remoteConfig === void 0 ? void 0 : remoteConfig.ConfigJSON);
if (this.options.flagOverrides.behaviour == OverrideBehaviour.LocalOverRemote) {
resolve(__assign(__assign({}, remoteSettings), localSettings));
return [2 /*return*/];
}
else if (this.options.flagOverrides.behaviour == OverrideBehaviour.RemoteOverLocal) {
resolve(__assign(__assign({}, localSettings), remoteSettings));
return [2 /*return*/];
}
_d.label = 3;
case 3: return [4 /*yield*/, ((_c = this.configService) === null || _c === void 0 ? void 0 : _c.getConfig())];
return [3 /*break*/, 7];
case 2: return [2 /*return*/, [localSettings, null]];
case 3: return [4 /*yield*/, getRemoteConfigAsync()];
case 4:
config = _d.sent();
if (!config || !config.ConfigJSON || !config.ConfigJSON[ConfigFile.FeatureFlags]) {
resolve(null);
return [2 /*return*/];
}
resolve(getSettingsFromConfig(config.ConfigJSON));
return [2 /*return*/];
_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.options.hooks.on(eventName, listener);
return this;
};
/** @inheritdoc */
ConfigCatClient.prototype.once = function (eventName, listener) {
this.options.hooks.once(eventName, listener);
return this;
};
/** @inheritdoc */
ConfigCatClient.prototype.removeListener = function (eventName, listener) {
this.options.hooks.removeListener(eventName, listener);
return this;
};
/** @inheritdoc */
ConfigCatClient.prototype.removeAllListeners = function (eventName) {
this.options.hooks.removeAllListeners(eventName);
return this;
};
/** @inheritdoc */
ConfigCatClient.prototype.listeners = function (eventName) {
return this.options.hooks.listeners(eventName);
};
/** @inheritdoc */
ConfigCatClient.prototype.listenerCount = function (eventName) {
return this.options.hooks.listenerCount(eventName);
};
/** @inheritdoc */
ConfigCatClient.prototype.eventNames = function () {
return this.options.hooks.eventNames();
};
return ConfigCatClient;

@@ -380,3 +625,5 @@ }());

var SettingKeyValue = /** @class */ (function () {
function SettingKeyValue() {
function SettingKeyValue(settingKey, settingValue) {
this.settingKey = settingKey;
this.settingValue = settingValue;
}

@@ -386,1 +633,22 @@ return SettingKeyValue;

export { SettingKeyValue };
;
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);
};

@@ -1,19 +0,12 @@

var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import { ConfigCatConsoleLogger } from "./ConfigCatLogger";
import { LogLevel } from "./index";
import { __extends } from "tslib";
import { InMemoryCache } from "./Cache";
import { ConfigCatConsoleLogger, LoggerWrapper } from "./ConfigCatLogger";
import { DefaultEventEmitter } from "./DefaultEventEmitter";
import { Hooks } from "./Hooks";
export var PollingMode;
(function (PollingMode) {
PollingMode[PollingMode["AutoPoll"] = 0] = "AutoPoll";
PollingMode[PollingMode["LazyLoad"] = 1] = "LazyLoad";
PollingMode[PollingMode["ManualPoll"] = 2] = "ManualPoll";
})(PollingMode || (PollingMode = {}));
/** Control the location of the config.json files containing your feature flags and settings within the ConfigCat CDN. */

@@ -28,9 +21,9 @@ export var DataGovernance;

var OptionsBase = /** @class */ (function () {
function OptionsBase(apiKey, clientVersion, options, defaultCache) {
var _a;
function OptionsBase(apiKey, clientVersion, options, defaultCache, eventEmitterFactory) {
var _a, _b, _c;
this.configFileName = "config_v5";
this.logger = new ConfigCatConsoleLogger(LogLevel.Warn);
this.requestTimeoutMs = 30000;
this.baseUrlOverriden = false;
this.proxy = "";
this.offline = false;
if (!apiKey) {

@@ -54,6 +47,7 @@ throw new Error("Invalid 'apiKey' value");

}
var eventEmitter = (_b = eventEmitterFactory === null || eventEmitterFactory === void 0 ? void 0 : eventEmitterFactory()) !== null && _b !== void 0 ? _b : new DefaultEventEmitter();
this.hooks = new Hooks(eventEmitter);
var logger;
if (options) {
if (options.logger) {
this.logger = options.logger;
}
logger = options.logger;
if (options.requestTimeoutMs) {

@@ -81,3 +75,8 @@ if (options.requestTimeoutMs < 0) {

}
if (options.offline) {
this.offline = options.offline;
}
(_c = options.setupHooks) === null || _c === void 0 ? void 0 : _c.call(options, this.hooks);
}
this.logger = new LoggerWrapper(logger !== null && logger !== void 0 ? logger : new ConfigCatConsoleLogger(), this.hooks);
}

@@ -95,7 +94,9 @@ OptionsBase.prototype.getUrl = function () {

__extends(AutoPollOptions, _super);
function AutoPollOptions(apiKey, sdkType, sdkVersion, options, defaultCache) {
var _this = _super.call(this, apiKey, sdkType + "/a-" + sdkVersion, options, defaultCache) || this;
function AutoPollOptions(apiKey, sdkType, sdkVersion, options, defaultCache, eventEmitterFactory) {
var _this = _super.call(this, apiKey, sdkType + "/a-" + sdkVersion, options, defaultCache, eventEmitterFactory) || this;
/** The client's poll interval in seconds. Default: 60 seconds. */
_this.pollIntervalSeconds = 60;
/** You can subscribe to configuration changes with this callback. */
/** You can subscribe to configuration changes with this callback.
* @deprecated This property is obsolete and will be removed from the public API in a future major version. Please use the 'options.setupHooks = hooks => hooks.on("configChanged", ...)' format instead.
*/
_this.configChanged = function () { };

@@ -105,3 +106,3 @@ /** Maximum waiting time between the client initialization and the first config acquisition in seconds. */

if (options) {
if (options.pollIntervalSeconds !== undefined && options.pollIntervalSeconds !== null) {
if (options.pollIntervalSeconds !== void 0 && options.pollIntervalSeconds !== null) {
_this.pollIntervalSeconds = options.pollIntervalSeconds;

@@ -112,10 +113,10 @@ }

}
if (options.maxInitWaitTimeSeconds !== undefined && options.maxInitWaitTimeSeconds !== null) {
if (options.maxInitWaitTimeSeconds !== void 0 && options.maxInitWaitTimeSeconds !== null) {
_this.maxInitWaitTimeSeconds = options.maxInitWaitTimeSeconds;
}
}
if (_this.pollIntervalSeconds < 1) {
if (!(_this.pollIntervalSeconds >= 1 && (typeof _this.pollIntervalSeconds === 'number'))) {
throw new Error("Invalid 'pollIntervalSeconds' value");
}
if (_this.maxInitWaitTimeSeconds < 0) {
if (!(_this.maxInitWaitTimeSeconds >= 0 && (typeof _this.maxInitWaitTimeSeconds === 'number'))) {
throw new Error("Invalid 'maxInitWaitTimeSeconds' value");

@@ -130,4 +131,4 @@ }

__extends(ManualPollOptions, _super);
function ManualPollOptions(apiKey, sdkType, sdkVersion, options, defaultCache) {
return _super.call(this, apiKey, sdkType + "/m-" + sdkVersion, options, defaultCache) || this;
function ManualPollOptions(apiKey, sdkType, sdkVersion, options, defaultCache, eventEmitterFactory) {
return _super.call(this, apiKey, sdkType + "/m-" + sdkVersion, options, defaultCache, eventEmitterFactory) || this;
}

@@ -139,4 +140,4 @@ return ManualPollOptions;

__extends(LazyLoadOptions, _super);
function LazyLoadOptions(apiKey, sdkType, sdkVersion, options, defaultCache) {
var _this = _super.call(this, apiKey, sdkType + "/l-" + sdkVersion, options, defaultCache) || this;
function LazyLoadOptions(apiKey, sdkType, sdkVersion, options, defaultCache, eventEmitterFactory) {
var _this = _super.call(this, apiKey, sdkType + "/l-" + sdkVersion, options, defaultCache, eventEmitterFactory) || this;
/** The cache TTL. */

@@ -143,0 +144,0 @@ _this.cacheTimeToLiveSeconds = 60;

@@ -1,2 +0,54 @@

import { LogLevel } from "./index";
import { errorToString } from "./Utils";
export var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["Debug"] = 4] = "Debug";
LogLevel[LogLevel["Info"] = 3] = "Info";
LogLevel[LogLevel["Warn"] = 2] = "Warn";
LogLevel[LogLevel["Error"] = 1] = "Error";
LogLevel[LogLevel["Off"] = -1] = "Off";
})(LogLevel || (LogLevel = {}));
var LoggerWrapper = /** @class */ (function () {
function LoggerWrapper(logger, hooks) {
this.logger = logger;
this.hooks = hooks;
}
Object.defineProperty(LoggerWrapper.prototype, "level", {
get: function () { var _a; return (_a = this.logger.level) !== null && _a !== void 0 ? _a : LogLevel.Warn; },
enumerable: false,
configurable: true
});
LoggerWrapper.prototype.log = function (message) {
this.info(message);
};
LoggerWrapper.prototype.debug = function (message) {
if (this.isLogLevelEnabled(LogLevel.Debug)) {
this.logger.debug(message);
}
};
LoggerWrapper.prototype.info = function (message) {
if (this.isLogLevelEnabled(LogLevel.Info)) {
this.logger.info(message);
}
};
LoggerWrapper.prototype.warn = function (message) {
if (this.isLogLevelEnabled(LogLevel.Warn)) {
this.logger.warn(message);
}
};
LoggerWrapper.prototype.error = function (message, err) {
var _a;
if (this.isLogLevelEnabled(LogLevel.Error)) {
var logMessage = err
? message + '\n' + errorToString(err, true)
: message;
this.logger.error(logMessage);
}
(_a = this.hooks) === null || _a === void 0 ? void 0 : _a.emit("clientError", message, err);
};
LoggerWrapper.prototype.isLogLevelEnabled = function (logLevel) {
return this.level >= logLevel;
};
return LoggerWrapper;
}());
export { LoggerWrapper };
var ConfigCatConsoleLogger = /** @class */ (function () {

@@ -6,40 +58,29 @@ /**

*/
function ConfigCatConsoleLogger(logLevel) {
function ConfigCatConsoleLogger(level) {
if (level === void 0) { level = LogLevel.Warn; }
this.level = level;
this.SOURCE = "ConfigCat";
this.level = LogLevel.Warn;
if (logLevel) {
this.level = logLevel;
}
}
/**
* @deprecated Use `debug(message: string)` method instead of this
*/
/** @inheritdoc */
ConfigCatConsoleLogger.prototype.log = function (message) {
this.info(message);
};
/** @inheritdoc */
ConfigCatConsoleLogger.prototype.debug = function (message) {
if (this.isLogLevelEnabled(LogLevel.Debug)) {
console.info(this.SOURCE + " - DEBUG - " + message);
}
console.info(this.SOURCE + " - DEBUG - " + message);
};
/** @inheritdoc */
ConfigCatConsoleLogger.prototype.info = function (message) {
if (this.isLogLevelEnabled(LogLevel.Info)) {
console.info(this.SOURCE + " - INFO - " + message);
}
console.info(this.SOURCE + " - INFO - " + message);
};
/** @inheritdoc */
ConfigCatConsoleLogger.prototype.warn = function (message) {
if (this.isLogLevelEnabled(LogLevel.Warn)) {
console.warn(this.SOURCE + " - WARN - " + message);
}
console.warn(this.SOURCE + " - WARN - " + message);
};
/** @inheritdoc */
ConfigCatConsoleLogger.prototype.error = function (message) {
if (this.isLogLevelEnabled(LogLevel.Error)) {
console.error(this.SOURCE + " - ERROR - " + message);
}
console.error(this.SOURCE + " - ERROR - " + message);
};
ConfigCatConsoleLogger.prototype.isLogLevelEnabled = function (logLevel) {
return this.level >= logLevel;
};
return ConfigCatConsoleLogger;
}());
export { ConfigCatConsoleLogger };

@@ -1,169 +0,293 @@

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
import { __awaiter, __generator } from "tslib";
import { FetchError, FetchResult, FetchStatus } from "./ConfigFetcher";
import { ConfigFile, Preferences, ProjectConfig } from "./ProjectConfig";
var RefreshResult = /** @class */ (function () {
function RefreshResult(errorMessage, errorException) {
this.errorMessage = errorMessage;
this.errorException = errorException;
}
Object.defineProperty(RefreshResult.prototype, "isSuccess", {
get: function () { return this.errorMessage === null; },
enumerable: false,
configurable: true
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
import { FetchStatus } from "./index";
import { ConfigFile, Preferences, ProjectConfig } from "./ProjectConfig";
RefreshResult.from = function (fetchResult) {
return fetchResult.status !== FetchStatus.Errored
? RefreshResult.success()
: RefreshResult.failure(fetchResult.errorMessage, fetchResult.errorException);
};
RefreshResult.success = function () {
return new RefreshResult(null);
};
RefreshResult.failure = function (errorMessage, errorException) {
return new RefreshResult(errorMessage, errorException);
};
return RefreshResult;
}());
export { RefreshResult };
var ConfigServiceStatus;
(function (ConfigServiceStatus) {
ConfigServiceStatus[ConfigServiceStatus["Online"] = 0] = "Online";
ConfigServiceStatus[ConfigServiceStatus["Offline"] = 1] = "Offline";
ConfigServiceStatus[ConfigServiceStatus["Disposed"] = 2] = "Disposed";
})(ConfigServiceStatus || (ConfigServiceStatus = {}));
var ConfigServiceBase = /** @class */ (function () {
function ConfigServiceBase(configFetcher, baseConfig) {
this.fetchLogicCallbacks = [];
function ConfigServiceBase(configFetcher, options) {
this.pendingFetch = null;
this.configFetcher = configFetcher;
this.baseConfig = baseConfig;
this.options = options;
this.status = options.offline ? ConfigServiceStatus.Offline : ConfigServiceStatus.Online;
}
ConfigServiceBase.prototype.refreshLogicBaseAsync = function (lastProjectConfig, forceUpdateCache) {
var _this = this;
if (forceUpdateCache === void 0) { forceUpdateCache = true; }
this.baseConfig.logger.debug("ConfigServiceBase.refreshLogicBaseAsync() - called.");
return new Promise(function (resolve) {
var _a;
_this.fetchLogic(_this.baseConfig, (_a = lastProjectConfig === null || lastProjectConfig === void 0 ? void 0 : lastProjectConfig.HttpETag) !== null && _a !== void 0 ? _a : null, 0, function (newConfig) { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(newConfig && newConfig.ConfigJSON)) return [3 /*break*/, 2];
this.baseConfig.logger.debug("ConfigServiceBase.refreshLogicBaseAsync() - fetchLogic() success, returning config.");
return [4 /*yield*/, this.baseConfig.cache.set(this.baseConfig.getCacheKey(), newConfig)];
case 1:
_a.sent();
resolve(newConfig);
return [3 /*break*/, 5];
case 2:
if (!(forceUpdateCache && lastProjectConfig && lastProjectConfig.ConfigJSON)) return [3 /*break*/, 4];
this.baseConfig.logger.debug("ConfigServiceBase.refreshLogicBaseAsync() - fetchLogic() didn't return a config, setting the cache with last config with new timestamp, returning last config.");
lastProjectConfig.Timestamp = new Date().getTime();
return [4 /*yield*/, this.baseConfig.cache.set(this.baseConfig.getCacheKey(), lastProjectConfig)];
case 3:
_a.sent();
resolve(lastProjectConfig);
return [3 /*break*/, 5];
case 4:
this.baseConfig.logger.debug("ConfigServiceBase.refreshLogicBaseAsync() - fetchLogic() didn't return a config, returing last config.");
resolve(lastProjectConfig);
_a.label = 5;
case 5: return [2 /*return*/];
}
});
}); });
ConfigServiceBase.prototype.dispose = function () {
this.status = ConfigServiceStatus.Disposed;
};
Object.defineProperty(ConfigServiceBase.prototype, "disposed", {
get: function () { return this.status === ConfigServiceStatus.Disposed; },
enumerable: false,
configurable: true
});
ConfigServiceBase.prototype.refreshConfigAsync = function () {
return __awaiter(this, void 0, void 0, function () {
var latestConfig, _a, fetchResult, config;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 1:
latestConfig = _b.sent();
if (!!this.isOffline) return [3 /*break*/, 3];
return [4 /*yield*/, this.refreshConfigCoreAsync(latestConfig)];
case 2:
_a = _b.sent(), fetchResult = _a[0], config = _a[1];
return [2 /*return*/, [RefreshResult.from(fetchResult), config]];
case 3:
this.logOfflineModeWarning();
return [2 /*return*/, [RefreshResult.failure("Client is in offline mode, it can't initiate HTTP calls."), latestConfig]];
}
});
});
};
ConfigServiceBase.prototype.fetchLogic = function (options, lastEtag, retries, callback) {
var _this = this;
this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic() - called.");
var calledBaseUrl = this.baseConfig.baseUrl;
this.fetchLogicInternal(this.baseConfig, lastEtag, retries, function (result) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): result.status: " + (result === null || result === void 0 ? void 0 : result.status));
if (!result || result.status != FetchStatus.Fetched || ProjectConfig.compareEtags(lastEtag !== null && lastEtag !== void 0 ? lastEtag : '', result.eTag)) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): result.status != FetchStatus.Fetched or etags are the same. Returning null.");
callback(null);
return;
}
if (!result.responseBody) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): no response body. Returning null.");
callback(null);
return;
}
var newConfig = new ProjectConfig(new Date().getTime(), result.responseBody, result.eTag);
var preferences = newConfig.ConfigJSON[ConfigFile.Preferences];
if (!preferences) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): preferences is empty. Returning newConfig.");
callback(newConfig);
return;
}
var baseUrl = preferences[Preferences.BaseUrl];
// If the base_url is the same as the last called one, just return the response.
if (!baseUrl || baseUrl == calledBaseUrl) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): baseUrl OK. Returning newConfig.");
callback(newConfig);
return;
}
var redirect = preferences[Preferences.Redirect];
// If the base_url is overridden, and the redirect parameter is not 2 (force),
// the SDK should not redirect the calls and it just have to return the response.
if (options.baseUrlOverriden && redirect !== 2) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogic(): options.baseUrlOverriden && redirect !== 2.");
callback(newConfig);
return;
}
options.baseUrl = baseUrl;
if (redirect === 0) {
callback(newConfig);
return;
}
if (redirect === 1) {
options.logger.warn("Your dataGovernance parameter at ConfigCatClient initialization is not in sync " +
"with your preferences on the ConfigCat Dashboard: " +
"https://app.configcat.com/organization/data-governance. " +
"Only Organization Admins can access this preference.");
}
if (retries >= 2) {
options.logger.error("Redirect loop during config.json fetch. Please contact support@configcat.com.");
callback(newConfig);
return;
}
_this.fetchLogic(options, lastEtag, ++retries, callback);
return;
ConfigServiceBase.prototype.refreshConfigCoreAsync = function (latestConfig) {
return __awaiter(this, void 0, void 0, function () {
var _a, fetchResult, newConfig, configContentHasChanged;
return __generator(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.fetchAsync(latestConfig)];
case 1:
_a = _b.sent(), fetchResult = _a[0], newConfig = _a[1];
configContentHasChanged = !ProjectConfig.equals(latestConfig, newConfig);
if (!(newConfig && (configContentHasChanged || newConfig.Timestamp > latestConfig.Timestamp))) return [3 /*break*/, 3];
return [4 /*yield*/, this.options.cache.set(this.options.getCacheKey(), newConfig)];
case 2:
_b.sent();
this.onConfigUpdated(newConfig);
if (configContentHasChanged) {
this.onConfigChanged(newConfig);
}
return [2 /*return*/, [fetchResult, newConfig]];
case 3: return [2 /*return*/, [fetchResult, latestConfig]];
}
});
});
};
ConfigServiceBase.prototype.fetchLogicInternal = function (options, lastEtag, retries, callback) {
ConfigServiceBase.prototype.onConfigUpdated = function (newConfig) { };
ConfigServiceBase.prototype.onConfigChanged = function (newConfig) {
this.options.logger.debug("config changed");
this.options.hooks.emit("configChanged", newConfig);
};
ConfigServiceBase.prototype.fetchAsync = function (lastConfig) {
var _this = this;
this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): called.");
if (retries === 0) { // Only lock on the top-level calls, not on the recursive calls (config.json redirections).
this.fetchLogicCallbacks.push(callback);
if (this.fetchLogicCallbacks.length > 1) {
// The first fetchLogic call is already in progress.
this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): The first fetchLogic call is already in progress. this.fetchLogicCallbacks.length = " + this.fetchLogicCallbacks.length);
return;
}
this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): Calling fetchLogic");
this.configFetcher.fetchLogic(options, lastEtag, function (newProjectConfig) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): fetchLogic() success, calling callbacks. this.fetchLogicCallbacks.length = " + _this.fetchLogicCallbacks.length);
while (_this.fetchLogicCallbacks.length) {
var thisCallback = _this.fetchLogicCallbacks.pop();
if (thisCallback) {
_this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): fetchLogic() success, calling callback.");
thisCallback(newProjectConfig);
}
var _a;
return (_a = this.pendingFetch) !== null && _a !== void 0 ? _a : (this.pendingFetch = (function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, , 2, 3]);
return [4 /*yield*/, this.fetchLogicAsync(lastConfig)];
case 1: return [2 /*return*/, _a.sent()];
case 2:
this.pendingFetch = null;
return [7 /*endfinally*/];
case 3: return [2 /*return*/];
}
});
}); })());
};
ConfigServiceBase.prototype.fetchLogicAsync = function (lastConfig) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var options, errorMessage, _b, response, configJson, err_1, errorMessage_1;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
options = this.options;
options.logger.debug("ConfigServiceBase.fetchLogicAsync() - called.");
_c.label = 1;
case 1:
_c.trys.push([1, 3, , 4]);
return [4 /*yield*/, this.fetchRequestAsync((_a = lastConfig === null || lastConfig === void 0 ? void 0 : lastConfig.HttpETag) !== null && _a !== void 0 ? _a : null)];
case 2:
_b = _c.sent(), response = _b[0], configJson = _b[1];
switch (response.statusCode) {
case 200: // OK
if (!configJson) {
errorMessage = "Fetch was successful but HTTP response was invalid";
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): ".concat(errorMessage.charAt(0).toLowerCase()).concat(errorMessage.slice(1), ". Returning null."));
return [2 /*return*/, [FetchResult.error(errorMessage), null]];
}
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): fetch was successful. Returning new config.");
return [2 /*return*/, [FetchResult.success(response.body, response.eTag), new ProjectConfig(new Date().getTime(), configJson, response.eTag)]];
case 304: // Not Modified
if (!lastConfig) {
errorMessage = "HTTP response ".concat(response.statusCode, " ").concat(response.reasonPhrase, " was received when no config is cached locally");
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): ".concat(errorMessage.charAt(0).toLowerCase()).concat(errorMessage.slice(1), ". Returning null."));
return [2 /*return*/, [FetchResult.error(errorMessage), null]];
}
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): content was not modified. Returning last config with updated timestamp.");
return [2 /*return*/, [FetchResult.notModified(), new ProjectConfig(new Date().getTime(), lastConfig.ConfigJSON, lastConfig.HttpETag)]];
case 403: // Forbidden
case 404: // Not Found
errorMessage = "Double-check your SDK Key at https://app.configcat.com/sdkkey";
options.logger.error(errorMessage);
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): fetch was unsuccessful. Returning last config (if any) with updated timestamp.");
return [2 /*return*/, [FetchResult.error(errorMessage), lastConfig ? new ProjectConfig(new Date().getTime(), lastConfig.ConfigJSON, lastConfig.HttpETag) : null]];
default:
errorMessage = "Unexpected HTTP response was received: ".concat(response.statusCode, " ").concat(response.reasonPhrase);
options.logger.error(errorMessage);
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): fetch was unsuccessful. Returning null.");
return [2 /*return*/, [FetchResult.error(errorMessage), null]];
}
return [3 /*break*/, 4];
case 3:
err_1 = _c.sent();
errorMessage_1 = err_1 instanceof FetchError
? err_1.message
: "Unexpected error occurred during fetching.";
options.logger.error(errorMessage_1, err_1);
options.logger.debug("ConfigServiceBase.fetchLogicAsync(): fetch was unsuccessful. Returning null.");
return [2 /*return*/, [FetchResult.error(errorMessage_1, err_1), null]];
case 4: return [2 /*return*/];
}
});
});
};
ConfigServiceBase.prototype.fetchRequestAsync = function (lastETag, maxRetryCount) {
if (maxRetryCount === void 0) { maxRetryCount = 2; }
return __awaiter(this, void 0, void 0, function () {
var options, retryNumber, response, configJSON, preferences, baseUrl, redirect;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
options = this.options;
options.logger.debug("ConfigServiceBase.fetchRequestAsync() - called.");
retryNumber = 0;
_a.label = 1;
case 1:
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): calling fetchLogic()".concat(retryNumber > 0 ? ", retry ".concat(retryNumber, "/").concat(maxRetryCount) : ""));
return [4 /*yield*/, this.configFetcher.fetchLogic(options, lastETag)];
case 2:
response = _a.sent();
if (response.statusCode !== 200) {
return [2 /*return*/, [response]];
}
if (!response.body) {
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): no response body.");
return [2 /*return*/, [response]];
}
configJSON = void 0;
try {
configJSON = JSON.parse(response.body);
}
catch (_b) {
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): invalid response body.");
return [2 /*return*/, [response]];
}
preferences = configJSON[ConfigFile.Preferences];
if (!preferences) {
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): preferences is empty.");
return [2 /*return*/, [response, configJSON]];
}
baseUrl = preferences[Preferences.BaseUrl];
// If the base_url is the same as the last called one, just return the response.
if (!baseUrl || baseUrl == options.baseUrl) {
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): baseUrl OK.");
return [2 /*return*/, [response, configJSON]];
}
redirect = preferences[Preferences.Redirect];
// If the base_url is overridden, and the redirect parameter is not 2 (force),
// the SDK should not redirect the calls and it just have to return the response.
if (options.baseUrlOverriden && redirect !== 2) {
options.logger.debug("ConfigServiceBase.fetchRequestAsync(): options.baseUrlOverriden && redirect !== 2.");
return [2 /*return*/, [response, configJSON]];
}
options.baseUrl = baseUrl;
if (redirect === 0) {
return [2 /*return*/, [response, configJSON]];
}
if (redirect === 1) {
options.logger.warn("Your dataGovernance parameter at ConfigCatClient initialization is not in sync " +
"with your preferences on the ConfigCat Dashboard: " +
"https://app.configcat.com/organization/data-governance. " +
"Only Organization Admins can access this preference.");
}
if (retryNumber >= maxRetryCount) {
options.logger.error("Redirect loop during config.json fetch. Please contact support@configcat.com.");
return [2 /*return*/, [response, configJSON]];
}
_a.label = 3;
case 3:
retryNumber++;
return [3 /*break*/, 1];
case 4: return [2 /*return*/];
}
});
});
};
Object.defineProperty(ConfigServiceBase.prototype, "isOfflineExactly", {
get: function () {
return this.status === ConfigServiceStatus.Offline;
},
enumerable: false,
configurable: true
});
Object.defineProperty(ConfigServiceBase.prototype, "isOffline", {
get: function () {
return this.status !== ConfigServiceStatus.Online;
},
enumerable: false,
configurable: true
});
ConfigServiceBase.prototype.setOnlineCore = function () { };
ConfigServiceBase.prototype.setOnline = function () {
if (this.status === ConfigServiceStatus.Offline) {
this.setOnlineCore();
this.status = ConfigServiceStatus.Online;
this.logStatusChange(this.status);
}
else {
// Recursive calls should call the fetchLogic as is.
this.baseConfig.logger.debug("ConfigServiceBase.fetchLogicInternal(): calling fetchLogic(), recursive call. retries = " + retries);
this.configFetcher.fetchLogic(options, lastEtag, callback);
else if (this.disposed) {
this.logDisposedWarning("setOnline");
}
};
ConfigServiceBase.prototype.setOfflineCore = function () { };
ConfigServiceBase.prototype.setOffline = function () {
if (this.status == ConfigServiceStatus.Online) {
this.setOfflineCore();
this.status = ConfigServiceStatus.Offline;
this.logStatusChange(this.status);
}
else if (this.disposed) {
this.logDisposedWarning("setOnline");
}
};
ConfigServiceBase.prototype.logStatusChange = function (status) {
var _a;
this.options.logger.debug("Switched to ".concat((_a = ConfigServiceStatus[status]) === null || _a === void 0 ? void 0 : _a.toUpperCase(), " mode."));
};
ConfigServiceBase.prototype.logOfflineModeWarning = function () {
this.options.logger.warn("Client is in offline mode, it can't initiate HTTP calls.");
};
ConfigServiceBase.prototype.logDisposedWarning = function (methodName) {
this.options.logger.warn("Client has already been disposed, thus ".concat(methodName, "() has no effect."));
};
return ConfigServiceBase;
}());
export { ConfigServiceBase };
import { ConfigCatClient } from "./ConfigCatClient";
import { AutoPollOptions, ManualPollOptions, LazyLoadOptions } from "./ConfigCatClientOptions";
import { ConfigCatConsoleLogger } from "./ConfigCatLogger";
import { AutoPollOptions, LazyLoadOptions, ManualPollOptions, PollingMode } from "./ConfigCatClientOptions";
import { ConfigCatConsoleLogger, LogLevel } from "./ConfigCatLogger";
import { setupPolyfills } from "./Polyfills";
setupPolyfills();
/**
* Returns an instance of ConfigCatClient for the specified SDK Key.
* @remarks This method returns a single, shared instance per each distinct SDK Key.
* That is, a new client object is created only when there is none available for the specified SDK Key.
* Otherwise, the already created instance is returned (in which case the 'pollingMode', 'options' and 'configCatKernel' arguments are ignored).
* So, please keep in mind that when you make multiple calls to this method using the same SDK Key, you may end up with multiple references to the same client object.
* @param sdkKey SDK Key (a.k.a ApiKey) to access configuration
* @param pollingMode The polling mode to use
* @param options Options for the specified polling mode
*/
export function getClient(sdkKey, pollingMode, options, configCatKernel) {
return ConfigCatClient.get(sdkKey, pollingMode, options, configCatKernel);
}
/**
* Disposes all existing ConfigCatClient instances.
*/
export function disposeAllClients() {
ConfigCatClient.disposeAll();
}
/**
* Create an instance of ConfigCatClient and setup AutoPoll mode
* @param {string} apiKey - ApiKey to access your configuration.
* @param config - Configuration for autoPoll mode
* @deprecated This function is obsolete and will be removed from the public API in a future major version. To obtain a ConfigCatClient instance with auto polling for a specific SDK Key, please use the 'getClient(sdkKey, PollingMode.AutoPoll, options, ...)' format.
*/
export function createClientWithAutoPoll(apiKey, configCatKernel, options) {
return new ConfigCatClient(new AutoPollOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache), configCatKernel);
return new ConfigCatClient(new AutoPollOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache, configCatKernel.eventEmitterFactory), configCatKernel);
}

@@ -18,5 +38,6 @@ /**

* @param config - Configuration for manualPoll mode
* @deprecated This function is obsolete and will be removed from the public API in a future major version. To obtain a ConfigCatClient instance with manual polling for a specific SDK Key, please use the 'getClient(sdkKey, PollingMode.ManualPoll, options, ...)' format.
*/
export function createClientWithManualPoll(apiKey, configCatKernel, options) {
return new ConfigCatClient(new ManualPollOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache), configCatKernel);
return new ConfigCatClient(new ManualPollOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache, configCatKernel.eventEmitterFactory), configCatKernel);
}

@@ -27,9 +48,10 @@ /**

* @param config - Configuration for lazyLoad mode
* @deprecated This function is obsolete and will be removed from the public API in a future major version. To obtain a ConfigCatClient instance with lazy loading for a specific SDK Key, please use the 'getClient(sdkKey, PollingMode.LazyLoad, options, ...)' format.
*/
export function createClientWithLazyLoad(apiKey, configCatKernel, options) {
return new ConfigCatClient(new LazyLoadOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache), configCatKernel);
return new ConfigCatClient(new LazyLoadOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache, configCatKernel.eventEmitterFactory), configCatKernel);
}
/**
* Create an instance of ConfigCatConsoleLogger
* @param {LogLevel} logLevel - Specifies message's filtering to output for the CofigCatConsoleLogger.
* @param {LogLevel} logLevel - Specifies message's filtering to output for the ConfigCatConsoleLogger.
*/

@@ -39,37 +61,15 @@ export function createConsoleLogger(logLevel) {

}
export var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["Debug"] = 4] = "Debug";
LogLevel[LogLevel["Info"] = 3] = "Info";
LogLevel[LogLevel["Warn"] = 2] = "Warn";
LogLevel[LogLevel["Error"] = 1] = "Error";
LogLevel[LogLevel["Off"] = -1] = "Off";
})(LogLevel || (LogLevel = {}));
export var FetchStatus;
(function (FetchStatus) {
FetchStatus[FetchStatus["Fetched"] = 0] = "Fetched";
FetchStatus[FetchStatus["NotModified"] = 1] = "NotModified";
FetchStatus[FetchStatus["Errored"] = 2] = "Errored";
})(FetchStatus || (FetchStatus = {}));
var FetchResult = /** @class */ (function () {
function FetchResult(status, responseBody, eTag) {
this.status = status;
this.responseBody = responseBody;
this.eTag = eTag;
}
FetchResult.success = function (responseBody, eTag) {
return new FetchResult(FetchStatus.Fetched, responseBody, eTag);
};
FetchResult.notModified = function () {
return new FetchResult(FetchStatus.NotModified, "");
};
FetchResult.error = function () {
return new FetchResult(FetchStatus.Errored, "");
};
return FetchResult;
}());
export { FetchResult };
export { ProjectConfig } from "./ProjectConfig";
export { OptionsBase, DataGovernance } from "./ConfigCatClientOptions";
export { FetchStatus, FetchResult, FetchError } from './ConfigFetcher';
export { OptionsBase } from "./ConfigCatClientOptions";
export { InMemoryCache } from "./Cache";
/* Public types for end users */
// List types here which are part of the public API of platform-specific SDKs, thus, should be exposed to end users.
// These exports should be re-exported in the entry module of each platform-specific SDK!
export { PollingMode };
export { DataGovernance } from "./ConfigCatClientOptions";
export { LogLevel };
export { ProjectConfig, RolloutRule, RolloutPercentageItem, Setting } from "./ProjectConfig";
export { SettingKeyValue } from "./ConfigCatClient";
export { User } from "./RolloutEvaluator";
export { FlagOverrides, MapOverrideDataSource, OverrideBehaviour } from "./FlagOverrides";
export { RefreshResult } from "./ConfigServiceBase";

@@ -1,58 +0,10 @@

var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
import { __awaiter, __extends, __generator } from "tslib";
import { ConfigServiceBase } from "./ConfigServiceBase";
import { ProjectConfig } from "./ProjectConfig";
var LazyLoadConfigService = /** @class */ (function (_super) {
__extends(LazyLoadConfigService, _super);
function LazyLoadConfigService(configFetcher, config) {
var _this = _super.call(this, configFetcher, config) || this;
_this.cacheTimeToLiveSeconds = config.cacheTimeToLiveSeconds;
function LazyLoadConfigService(configFetcher, options) {
var _this = _super.call(this, configFetcher, options) || this;
_this.cacheTimeToLiveSeconds = options.cacheTimeToLiveSeconds;
options.hooks.emit("clientReady");
return _this;

@@ -62,19 +14,29 @@ }

return __awaiter(this, void 0, void 0, function () {
var p;
return __generator(this, function (_a) {
switch (_a.label) {
function logExpired(logger, appendix) {
if (appendix === void 0) { appendix = ""; }
logger.debug("LazyLoadConfigService.getConfig(): cache is empty or expired".concat(appendix, "."));
}
var config;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
this.baseConfig.logger.debug("LazyLoadConfigService.getConfig() called.");
return [4 /*yield*/, this.baseConfig.cache.get(this.baseConfig.getCacheKey())];
this.options.logger.debug("LazyLoadConfigService.getConfig() called.");
return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 1:
p = _a.sent();
if (p && p.Timestamp + (this.cacheTimeToLiveSeconds * 1000) > new Date().getTime()) {
this.baseConfig.logger.debug("LazyLoadConfigService.getConfig(): cache is valid, returning from cache.");
return [2 /*return*/, p];
}
else {
this.baseConfig.logger.debug("LazyLoadConfigService.getConfig(): cache is empty or expired, calling refreshLogicBaseAsync().");
return [2 /*return*/, this.refreshLogicBaseAsync(p)];
}
return [2 /*return*/];
config = _b.sent();
if (!ProjectConfig.isExpired(config, this.cacheTimeToLiveSeconds * 1000)) return [3 /*break*/, 5];
if (!!this.isOffline) return [3 /*break*/, 3];
logExpired(this.options.logger, ", calling refreshConfigCoreAsync()");
return [4 /*yield*/, this.refreshConfigCoreAsync(config)];
case 2:
_a = _b.sent(), config = _a[1];
return [3 /*break*/, 4];
case 3:
logExpired(this.options.logger);
_b.label = 4;
case 4: return [2 /*return*/, config];
case 5:
this.options.logger.debug("LazyLoadConfigService.getConfig(): cache is valid, returning from cache.");
return [2 /*return*/, config];
}

@@ -86,12 +48,5 @@ });

return __awaiter(this, void 0, void 0, function () {
var p;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.baseConfig.logger.debug("LazyLoadConfigService.refreshConfigAsync() called.");
return [4 /*yield*/, this.baseConfig.cache.get(this.baseConfig.getCacheKey())];
case 1:
p = _a.sent();
return [2 /*return*/, this.refreshLogicBaseAsync(p)];
}
this.options.logger.debug("LazyLoadConfigService.refreshConfigAsync() called.");
return [2 /*return*/, _super.prototype.refreshConfigAsync.call(this)];
});

@@ -98,0 +53,0 @@ });

export function setupPolyfills() {
if (!Object.fromEntries) {
Object.fromEntries = function (entries) {
if (!entries || !entries[Symbol.iterator]) {
throw new Error('Object.fromEntries() requires a single iterable argument');
}
var obj = {};
for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
var _a = entries_1[_i], key = _a[0], value = _a[1];
obj[key] = value;
}
return obj;
};
// Object.values
if (typeof Object.values === "undefined") {
Object.values = ObjectValuesPolyfill;
}
// Object.entries
if (typeof Object.entries === "undefined") {
Object.entries = ObjectEntriesPolyfill;
}
// Object.fromEntries
if (typeof Object.fromEntries === "undefined") {
Object.fromEntries = ObjectFromEntriesPolyfill;
}
// WeakRef
if (typeof WeakRef === "undefined") {
// There's no way to correctly polyfill WeakRef (https://stackoverflow.com/a/69971312/8656352),
// so we just polyfill its API (which means falling back on strong references in this case).
WeakRef = getWeakRefFallback();
}
}
export function ObjectValuesPolyfill(o) {
var result = [];
for (var _i = 0, _a = Object.keys(o); _i < _a.length; _i++) {
var key = _a[_i];
result.push(o[key]);
}
return result;
}
export function ObjectEntriesPolyfill(o) {
var result = [];
for (var _i = 0, _a = Object.keys(o); _i < _a.length; _i++) {
var key = _a[_i];
result.push([key, o[key]]);
}
return result;
}
export function ObjectFromEntriesPolyfill(entries) {
var _a;
var result = {};
if (Array.isArray(entries)) {
for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
var _b = entries_1[_i], key = _b[0], value = _b[1];
result[key] = value;
}
}
else if (typeof Symbol !== "undefined" && (entries === null || entries === void 0 ? void 0 : entries[Symbol.iterator])) {
var iterator = entries[Symbol.iterator]();
var element = void 0, done = void 0;
while ((_a = iterator.next(), element = _a.value, done = _a.done, !done)) {
var key = element[0], value = element[1];
result[key] = value;
}
}
else {
throw new Error('Object.fromEntries() requires a single iterable argument');
}
return result;
}
export function getWeakRefFallback() {
var WeakRef = function (target) {
this.target = target;
};
WeakRef.prototype.deref = function () {
return this.target;
};
WeakRef.isFallback = true;
return WeakRef;
}
export var isWeakRefAvailable = function () { return typeof WeakRef === "function" && !WeakRef.hasOwnProperty("isFallback"); };

@@ -0,5 +1,10 @@

// NOTE: No instance methods should be added to this class!
// Flawed ICache implementations may erase the prototype information (when serialization is involved),
// which would lead to "... is not a function" errors in the case of instance methods.
// (As a matter of fact, this type should have been defined as an interface to prevent such complications but
// we can't really change this any more because this would be a too dangerous breaking change at this point.)
var ProjectConfig = /** @class */ (function () {
function ProjectConfig(timeStamp, jsonConfig, httpETag) {
this.Timestamp = timeStamp;
this.ConfigJSON = JSON.parse(jsonConfig);
this.ConfigJSON = typeof jsonConfig === "string" ? JSON.parse(jsonConfig) : jsonConfig;
this.HttpETag = httpETag;

@@ -11,5 +16,14 @@ }

ProjectConfig.equals = function (projectConfig1, projectConfig2) {
if (!projectConfig1 || !projectConfig2)
if (!projectConfig1) {
// If both configs are null, we consider them equal.
return !projectConfig2;
}
if (!projectConfig2) {
return false;
return this.compareEtags(projectConfig1.HttpETag, projectConfig2.HttpETag);
}
// When both ETags are available, we don't need to check the JSON content
// (because of how HTTP ETags work - see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag).
return !!projectConfig1.HttpETag && !!projectConfig2.HttpETag
? this.compareEtags(projectConfig1.HttpETag, projectConfig2.HttpETag)
: JSON.stringify(projectConfig1.ConfigJSON) === JSON.stringify(projectConfig2.ConfigJSON);
};

@@ -28,2 +42,5 @@ ProjectConfig.compareEtags = function (etag1, etag2) {

};
ProjectConfig.isExpired = function (projectConfig, expirationMs) {
return !projectConfig || projectConfig.Timestamp + expirationMs < new Date().getTime();
};
return ProjectConfig;

@@ -30,0 +47,0 @@ }());

@@ -0,4 +1,5 @@

import { RolloutPercentageItem, RolloutRule } from "./ProjectConfig";
import * as semver from "./Semver";
import { sha1 } from "./Sha1";
import * as semver from "./Semver";
import { isUndefined } from "./Utils";
import { errorToString, getTimestampAsDate, isUndefined } from "./Utils";
/** Object for variation evaluation */

@@ -21,11 +22,4 @@ var User = /** @class */ (function () {

}
RolloutEvaluator.prototype.Evaluate = function (settings, key, defaultValue, user, defaultVariationId) {
RolloutEvaluator.prototype.Evaluate = function (setting, key, defaultValue, user, remoteConfig) {
this.logger.debug("RolloutEvaluator.Evaluate() called.");
if (!settings[key]) {
var s = "Evaluating getValue('" + key + "') failed. Returning default value: '" + defaultValue + "'.";
s += " Here are the available keys: {" + Object.keys(settings).join() + "}.";
this.logger.error(s);
return { Value: defaultValue, VariationId: defaultVariationId };
}
var featureFlag = settings[key];
var eLog = new EvaluateLogger();

@@ -35,39 +29,44 @@ eLog.User = user;

eLog.ReturnValue = defaultValue;
var result = new EvaluateResult();
result.EvaluateLog = eLog;
if (user) {
result = this.EvaluateRules(featureFlag.rolloutRules, user, eLog);
if (result.ValueAndVariationId == null) {
result.ValueAndVariationId = this.EvaluateVariations(featureFlag.rolloutPercentageItems, key, user);
if (result.ValueAndVariationId) {
result.EvaluateLog.ReturnValue = result.ValueAndVariationId.Value;
var result;
try {
if (user) {
// evaluate comparison-based rules
result = this.EvaluateRules(setting.rolloutRules, user, eLog);
if (result !== null) {
eLog.ReturnValue = result.value;
return evaluationDetailsFromEvaluateResult(key, result, getTimestampAsDate(remoteConfig), user);
}
if (featureFlag.rolloutPercentageItems.length > 0) {
result.EvaluateLog.OpAppendLine("Evaluating % options => " + (result.ValueAndVariationId == null ? "user not targeted" : "user targeted"));
// evaluate percentage-based rules
result = this.EvaluatePercentageRules(setting.rolloutPercentageItems, key, user);
if (setting.rolloutPercentageItems && setting.rolloutPercentageItems.length > 0) {
eLog.OpAppendLine("Evaluating % options => " + (!result ? "user not targeted" : "user targeted"));
}
if (result !== null) {
eLog.ReturnValue = result.value;
return evaluationDetailsFromEvaluateResult(key, result, getTimestampAsDate(remoteConfig), user);
}
}
}
else {
if ((featureFlag.rolloutRules && featureFlag.rolloutRules.length > 0) ||
(featureFlag.rolloutPercentageItems && featureFlag.rolloutPercentageItems.length > 0)) {
var s = "Evaluating getValue('" + key + "'). ";
s += "UserObject missing! You should pass a UserObject to getValue(), in order to make targeting work properly. ";
s += "Read more: https://configcat.com/docs/advanced/user-object";
this.logger.warn(s);
else {
if ((setting.rolloutRules && setting.rolloutRules.length > 0) ||
(setting.rolloutPercentageItems && setting.rolloutPercentageItems.length > 0)) {
var s = "Evaluating getValue('" + key + "'). ";
s += "UserObject missing! You should pass a UserObject to getValue(), in order to make targeting work properly. ";
s += "Read more: https://configcat.com/docs/advanced/user-object";
this.logger.warn(s);
}
}
}
if (result.ValueAndVariationId == null) {
result.ValueAndVariationId = {
Value: featureFlag.value,
VariationId: featureFlag.variationId,
// regular evaluate
result = {
value: setting.value,
variationId: setting.variationId
};
result.EvaluateLog.ReturnValue = result.ValueAndVariationId.Value;
eLog.ReturnValue = result.value;
return evaluationDetailsFromEvaluateResult(key, result, getTimestampAsDate(remoteConfig), user);
}
this.logger.info(result.EvaluateLog.GetLog());
return result.ValueAndVariationId;
finally {
this.logger.info(eLog.GetLog());
}
};
RolloutEvaluator.prototype.EvaluateRules = function (rolloutRules, user, eLog) {
this.logger.debug("RolloutEvaluator.EvaluateRules() called.");
var result = new EvaluateResult();
result.ValueAndVariationId = null;
if (rolloutRules && rolloutRules.length > 0) {

@@ -85,2 +84,7 @@ var _loop_1 = function (i) {

}
var result = {
value: rule.value,
variationId: rule.variationId,
matchedRule: rule
};
switch (comparator) {

@@ -93,8 +97,2 @@ case 0: // is one of

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -114,8 +112,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -129,8 +121,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -144,8 +130,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -164,8 +144,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -184,8 +158,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -201,8 +169,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -222,8 +184,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -245,9 +201,8 @@ }

}
result.EvaluateLog = eLog;
return result;
return null;
};
RolloutEvaluator.prototype.EvaluateVariations = function (rolloutPercentageItems, key, user) {
RolloutEvaluator.prototype.EvaluatePercentageRules = function (rolloutPercentageItems, key, user) {
this.logger.debug("RolloutEvaluator.EvaluateVariations() called.");
if (rolloutPercentageItems && rolloutPercentageItems.length > 0) {
var hashCandidate = key + ((user.identifier === null || user.identifier === undefined) ? '' : user.identifier);
var hashCandidate = key + ((user.identifier === null || user.identifier === void 0) ? '' : user.identifier);
var hashValue = sha1(hashCandidate).substring(0, 7);

@@ -257,8 +212,9 @@ var hashScale = parseInt(hashValue, 16) % 100;

for (var i = 0; i < rolloutPercentageItems.length; i++) {
var variation = rolloutPercentageItems[i];
bucket += +variation.percentage;
var percentageRule = rolloutPercentageItems[i];
bucket += +percentageRule.percentage;
if (hashScale < bucket) {
return {
Value: variation.value,
VariationId: variation.variationId
value: percentageRule.value,
variationId: percentageRule.variationId,
matchedRule: percentageRule
};

@@ -420,12 +376,2 @@ }

export { RolloutEvaluator };
var ValueAndVariationId = /** @class */ (function () {
function ValueAndVariationId() {
}
return ValueAndVariationId;
}());
var EvaluateResult = /** @class */ (function () {
function EvaluateResult() {
}
return EvaluateResult;
}());
var EvaluateLogger = /** @class */ (function () {

@@ -446,1 +392,121 @@ function EvaluateLogger() {

}());
/* Helper functions */
function evaluationDetailsFromEvaluateResult(key, evaluateResult, fetchTime, user) {
return {
key: key,
value: evaluateResult.value,
variationId: evaluateResult.variationId,
fetchTime: fetchTime,
user: user,
isDefaultValue: false,
matchedEvaluationRule: evaluateResult.matchedRule instanceof RolloutRule ? evaluateResult.matchedRule : void 0,
matchedEvaluationPercentageRule: evaluateResult.matchedRule instanceof RolloutPercentageItem ? evaluateResult.matchedRule : void 0,
};
}
export function evaluationDetailsFromDefaultValue(key, defaultValue, fetchTime, user, errorMessage, errorException) {
return {
key: key,
value: defaultValue,
fetchTime: fetchTime,
user: user,
isDefaultValue: true,
errorMessage: errorMessage,
errorException: errorException
};
}
export function evaluationDetailsFromDefaultVariationId(key, defaultVariationId, fetchTime, user, errorMessage, errorException) {
return {
key: key,
value: null,
variationId: defaultVariationId,
fetchTime: fetchTime,
user: user,
isDefaultValue: true,
errorMessage: errorMessage,
errorException: errorException
};
}
export function evaluate(evaluator, settings, key, defaultValue, user, remoteConfig, logger) {
var errorMessage;
if (!settings) {
errorMessage = "config.json is not present. Returning default value: '".concat(defaultValue, "'.");
logger.error(errorMessage);
return evaluationDetailsFromDefaultValue(key, defaultValue, getTimestampAsDate(remoteConfig), user, errorMessage);
}
var setting = settings[key];
if (!setting) {
errorMessage = "Evaluating '".concat(key, "' failed (key was not found in config.json). Returning default value: '").concat(defaultValue, "'. These are the available keys: ").concat(keysToString(settings), ".");
logger.error(errorMessage);
return evaluationDetailsFromDefaultValue(key, defaultValue, getTimestampAsDate(remoteConfig), user, errorMessage);
}
ensureAllowedDefaultValue(defaultValue);
var evaluationDetails = evaluator.Evaluate(setting, key, defaultValue, user, remoteConfig);
if (defaultValue !== null && defaultValue !== void 0 && typeof defaultValue !== typeof evaluationDetails.value) {
throw new Error("The type of a setting must match the type of the given default value.\nThe setting's type was ".concat(typeof defaultValue, ", the given default value's type was ").concat(typeof evaluationDetails.value, ".\nPlease pass a corresponding default value type."));
}
return evaluationDetails;
}
export function evaluateVariationId(evaluator, settings, key, defaultVariationId, user, remoteConfig, logger) {
var errorMessage;
if (!settings) {
errorMessage = "config.json is not present. Returning default variationId: '".concat(defaultVariationId, "'.");
logger.error(errorMessage);
return evaluationDetailsFromDefaultVariationId(key, defaultVariationId, getTimestampAsDate(remoteConfig), user, errorMessage);
}
var setting = settings[key];
if (!setting) {
errorMessage = "Evaluating '".concat(key, "' failed (key was not found in config.json). Returning default variationId: '").concat(defaultVariationId, "'. These are the available keys: ").concat(keysToString(settings), ".");
logger.error(errorMessage);
return evaluationDetailsFromDefaultVariationId(key, defaultVariationId, getTimestampAsDate(remoteConfig), user, errorMessage);
}
return evaluator.Evaluate(setting, key, null, user, remoteConfig, defaultVariationId);
}
function evaluateAllCore(evaluator, settings, user, remoteConfig, logger, getDetailsForError) {
var errors;
if (!checkSettingsAvailable(settings, logger, ", returning empty array")) {
return [[], errors];
}
var evaluationDetailsArray = [];
var index = 0;
for (var _i = 0, _a = Object.entries(settings); _i < _a.length; _i++) {
var _b = _a[_i], key = _b[0], setting = _b[1];
var evaluationDetails = void 0;
try {
evaluationDetails = evaluator.Evaluate(setting, key, null, user, remoteConfig);
}
catch (err) {
errors !== null && errors !== void 0 ? errors : (errors = []);
errors.push(err);
evaluationDetails = getDetailsForError(key, getTimestampAsDate(remoteConfig), user, err);
}
evaluationDetailsArray[index++] = evaluationDetails;
}
return [evaluationDetailsArray, errors];
}
export function evaluateAll(evaluator, settings, user, remoteConfig, logger) {
return evaluateAllCore(evaluator, settings, user, remoteConfig, logger, function (key, fetchTime, user, err) { return evaluationDetailsFromDefaultValue(key, null, fetchTime, user, errorToString(err), err); });
}
export function evaluateAllVariationIds(evaluator, settings, user, remoteConfig, logger) {
return evaluateAllCore(evaluator, settings, user, remoteConfig, logger, function (key, fetchTime, user, err) { return evaluationDetailsFromDefaultVariationId(key, null, fetchTime, user, errorToString(err), err); });
}
export function checkSettingsAvailable(settings, logger, appendix) {
if (appendix === void 0) { appendix = ""; }
if (!settings) {
logger.error("config.json is not present".concat(appendix));
return false;
}
return true;
}
export function ensureAllowedDefaultValue(value) {
if (value === null || value === void 0) {
return;
}
var type = typeof value;
if (type === "boolean" || type === "number" || type === "string") {
return;
}
throw new Error("The default value must be boolean, number, string, null or undefined.");
}
function keysToString(settings) {
return Object.keys(settings).join();
}

@@ -30,3 +30,3 @@ var numeric = /^[0-9]+$/;

src[index] = value;
re[index] = new RegExp(value, undefined);
re[index] = new RegExp(value);
};

@@ -164,9 +164,9 @@ createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*');

var b = other.prerelease[i];
if (a === undefined && b === undefined) {
if (a === void 0 && b === void 0) {
return 0;
}
else if (b === undefined) {
else if (b === void 0) {
return 1;
}
else if (a === undefined) {
else if (a === void 0) {
return -1;

@@ -190,9 +190,9 @@ }

var b = other.build[i];
if (a === undefined && b === undefined) {
if (a === void 0 && b === void 0) {
return 0;
}
else if (b === undefined) {
else if (b === void 0) {
return 1;
}
else if (a === undefined) {
else if (a === void 0) {
return -1;

@@ -199,0 +199,0 @@ }

import { ConfigFile, Setting } from "./ProjectConfig";
export var isUndefined = function (comp) { return comp === undefined; };
export var isUndefined = function (comp) { return comp === void 0; };
export function delay(delayMs, obtainCancel) {
var timerId;
var promise = new Promise(function (resolve) { return timerId = setTimeout(resolve, delayMs); });
obtainCancel === null || obtainCancel === void 0 ? void 0 : obtainCancel(function () { return clearTimeout(timerId); });
return promise;
}
;
export function getSettingsFromConfig(json) {
if (!json) {
return {};
}
return Object.fromEntries(Object.entries(json[ConfigFile.FeatureFlags]).map(function (_a) {

@@ -12,1 +16,10 @@ var key = _a[0], value = _a[1];

}
export function getTimestampAsDate(projectConfig) {
return projectConfig ? new Date(projectConfig.Timestamp) : void 0;
}
export function errorToString(err, includeStackTrace) {
if (includeStackTrace === void 0) { includeStackTrace = false; }
return err instanceof Error
? includeStackTrace && err.stack ? err.stack : err.toString()
: err + "";
}

@@ -1,8 +0,24 @@

import { IConfigCatClient } from "./ConfigCatClient";
import { IOptions, OptionsBase } from "./ConfigCatClientOptions";
import { ProjectConfig } from "./ProjectConfig";
import { IConfigCatClient, IConfigCatKernel } from "./ConfigCatClient";
import { IAutoPollOptions, ILazyLoadingOptions, IManualPollOptions, OptionsForPollingMode, PollingMode } from "./ConfigCatClientOptions";
import { IConfigCatLogger, LogLevel } from "./ConfigCatLogger";
/**
* Returns an instance of ConfigCatClient for the specified SDK Key.
* @remarks This method returns a single, shared instance per each distinct SDK Key.
* That is, a new client object is created only when there is none available for the specified SDK Key.
* Otherwise, the already created instance is returned (in which case the 'pollingMode', 'options' and 'configCatKernel' arguments are ignored).
* So, please keep in mind that when you make multiple calls to this method using the same SDK Key, you may end up with multiple references to the same client object.
* @param sdkKey SDK Key (a.k.a ApiKey) to access configuration
* @param pollingMode The polling mode to use
* @param options Options for the specified polling mode
*/
export declare function getClient<TMode extends PollingMode>(sdkKey: string, pollingMode: TMode, options: OptionsForPollingMode<TMode> | undefined | null, configCatKernel: IConfigCatKernel): IConfigCatClient;
/**
* Disposes all existing ConfigCatClient instances.
*/
export declare function disposeAllClients(): void;
/**
* Create an instance of ConfigCatClient and setup AutoPoll mode
* @param {string} apiKey - ApiKey to access your configuration.
* @param config - Configuration for autoPoll mode
* @deprecated This function is obsolete and will be removed from the public API in a future major version. To obtain a ConfigCatClient instance with auto polling for a specific SDK Key, please use the 'getClient(sdkKey, PollingMode.AutoPoll, options, ...)' format.
*/

@@ -14,2 +30,3 @@ export declare function createClientWithAutoPoll(apiKey: string, configCatKernel: IConfigCatKernel, options?: IAutoPollOptions): IConfigCatClient;

* @param config - Configuration for manualPoll mode
* @deprecated This function is obsolete and will be removed from the public API in a future major version. To obtain a ConfigCatClient instance with manual polling for a specific SDK Key, please use the 'getClient(sdkKey, PollingMode.ManualPoll, options, ...)' format.
*/

@@ -21,2 +38,3 @@ export declare function createClientWithManualPoll(apiKey: string, configCatKernel: IConfigCatKernel, options?: IManualPollOptions): IConfigCatClient;

* @param config - Configuration for lazyLoad mode
* @deprecated This function is obsolete and will be removed from the public API in a future major version. To obtain a ConfigCatClient instance with lazy loading for a specific SDK Key, please use the 'getClient(sdkKey, PollingMode.LazyLoad, options, ...)' format.
*/

@@ -26,68 +44,27 @@ export declare function createClientWithLazyLoad(apiKey: string, configCatKernel: IConfigCatKernel, options?: ILazyLoadingOptions): IConfigCatClient;

* Create an instance of ConfigCatConsoleLogger
* @param {LogLevel} logLevel - Specifies message's filtering to output for the CofigCatConsoleLogger.
* @param {LogLevel} logLevel - Specifies message's filtering to output for the ConfigCatConsoleLogger.
*/
export declare function createConsoleLogger(logLevel: LogLevel): IConfigCatLogger;
export interface IAutoPollOptions extends IOptions {
pollIntervalSeconds?: number;
maxInitWaitTimeSeconds?: number;
configChanged?: () => void;
}
export interface IManualPollOptions extends IOptions {
}
export interface ILazyLoadingOptions extends IOptions {
cacheTimeToLiveSeconds?: number;
}
export interface IConfigCatLogger {
debug(message: string): void;
/**
* @deprecated Use `debug(message: string)` method instead of this
*/
log(message: string): void;
info(message: string): void;
warn(message: string): void;
error(message: string): void;
}
export declare enum LogLevel {
Debug = 4,
Info = 3,
Warn = 2,
Error = 1,
Off = -1
}
export interface IConfigCatKernel {
configFetcher: IConfigFetcher;
/**
* Default ICache implementation.
*/
cache?: ICache;
sdkType: string;
sdkVersion: string;
}
export declare enum FetchStatus {
Fetched = 0,
NotModified = 1,
Errored = 2
}
export declare class FetchResult {
status: FetchStatus;
responseBody: string;
eTag?: string;
constructor(status: FetchStatus, responseBody: string, eTag?: string);
static success(responseBody: string, eTag: string): FetchResult;
static notModified(): FetchResult;
static error(): FetchResult;
}
export interface IConfigFetcher {
fetchLogic(options: OptionsBase, lastEtag: string | null, callback: (result: FetchResult) => void): void;
}
export interface ICache {
set(key: string, config: ProjectConfig): Promise<void> | void;
get(key: string): Promise<ProjectConfig | null> | ProjectConfig | null;
}
export { ProjectConfig } from "./ProjectConfig";
export type { IConfigCatClient } from "./ConfigCatClient";
export { OptionsBase, DataGovernance } from "./ConfigCatClientOptions";
export type { IConfigCatKernel };
export type { IConfigFetcher, IFetchResponse, FetchErrorCauses } from './ConfigFetcher';
export { FetchStatus, FetchResult, FetchError } from './ConfigFetcher';
export { OptionsBase } from "./ConfigCatClientOptions";
export { InMemoryCache } from "./Cache";
export type { IEventProvider, IEventEmitter } from "./EventEmitter";
export { PollingMode };
export type { IOptions } from "./ConfigCatClientOptions";
export type { IAutoPollOptions, IManualPollOptions, ILazyLoadingOptions };
export { DataGovernance } from "./ConfigCatClientOptions";
export type { IConfigCatLogger };
export { LogLevel };
export type { ICache } from './Cache';
export { ProjectConfig, RolloutRule, RolloutPercentageItem, Setting } from "./ProjectConfig";
export type { IConfigCatClient };
export { SettingKeyValue } from "./ConfigCatClient";
export type { IEvaluationDetails, SettingTypeOf, SettingValue, VariationIdTypeOf, VariationIdValue } from "./RolloutEvaluator";
export { User } from "./RolloutEvaluator";
export type { IOverrideDataSource } from "./FlagOverrides";
export { FlagOverrides, MapOverrideDataSource, OverrideBehaviour } from "./FlagOverrides";
export { RefreshResult } from "./ConfigServiceBase";
export type { IProvidesHooks, HookEvents } from "./Hooks";
//# sourceMappingURL=index.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OverrideBehaviour = exports.MapOverrideDataSource = exports.FlagOverrides = exports.User = exports.DataGovernance = exports.OptionsBase = exports.ProjectConfig = exports.FetchResult = exports.FetchStatus = exports.LogLevel = exports.createConsoleLogger = exports.createClientWithLazyLoad = exports.createClientWithManualPoll = exports.createClientWithAutoPoll = void 0;
exports.RefreshResult = exports.OverrideBehaviour = exports.MapOverrideDataSource = exports.FlagOverrides = exports.User = exports.SettingKeyValue = exports.Setting = exports.RolloutPercentageItem = exports.RolloutRule = exports.ProjectConfig = exports.LogLevel = exports.DataGovernance = exports.PollingMode = exports.InMemoryCache = exports.OptionsBase = exports.FetchError = exports.FetchResult = exports.FetchStatus = exports.createConsoleLogger = exports.createClientWithLazyLoad = exports.createClientWithManualPoll = exports.createClientWithAutoPoll = exports.disposeAllClients = exports.getClient = void 0;
var ConfigCatClient_1 = require("./ConfigCatClient");
var ConfigCatClientOptions_1 = require("./ConfigCatClientOptions");
Object.defineProperty(exports, "PollingMode", { enumerable: true, get: function () { return ConfigCatClientOptions_1.PollingMode; } });
var ConfigCatLogger_1 = require("./ConfigCatLogger");
Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return ConfigCatLogger_1.LogLevel; } });
var Polyfills_1 = require("./Polyfills");
(0, Polyfills_1.setupPolyfills)();
/**
* Returns an instance of ConfigCatClient for the specified SDK Key.
* @remarks This method returns a single, shared instance per each distinct SDK Key.
* That is, a new client object is created only when there is none available for the specified SDK Key.
* Otherwise, the already created instance is returned (in which case the 'pollingMode', 'options' and 'configCatKernel' arguments are ignored).
* So, please keep in mind that when you make multiple calls to this method using the same SDK Key, you may end up with multiple references to the same client object.
* @param sdkKey SDK Key (a.k.a ApiKey) to access configuration
* @param pollingMode The polling mode to use
* @param options Options for the specified polling mode
*/
function getClient(sdkKey, pollingMode, options, configCatKernel) {
return ConfigCatClient_1.ConfigCatClient.get(sdkKey, pollingMode, options, configCatKernel);
}
exports.getClient = getClient;
/**
* Disposes all existing ConfigCatClient instances.
*/
function disposeAllClients() {
ConfigCatClient_1.ConfigCatClient.disposeAll();
}
exports.disposeAllClients = disposeAllClients;
/**
* Create an instance of ConfigCatClient and setup AutoPoll mode
* @param {string} apiKey - ApiKey to access your configuration.
* @param config - Configuration for autoPoll mode
* @deprecated This function is obsolete and will be removed from the public API in a future major version. To obtain a ConfigCatClient instance with auto polling for a specific SDK Key, please use the 'getClient(sdkKey, PollingMode.AutoPoll, options, ...)' format.
*/
function createClientWithAutoPoll(apiKey, configCatKernel, options) {
return new ConfigCatClient_1.ConfigCatClient(new ConfigCatClientOptions_1.AutoPollOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache), configCatKernel);
return new ConfigCatClient_1.ConfigCatClient(new ConfigCatClientOptions_1.AutoPollOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache, configCatKernel.eventEmitterFactory), configCatKernel);
}

@@ -22,5 +46,6 @@ exports.createClientWithAutoPoll = createClientWithAutoPoll;

* @param config - Configuration for manualPoll mode
* @deprecated This function is obsolete and will be removed from the public API in a future major version. To obtain a ConfigCatClient instance with manual polling for a specific SDK Key, please use the 'getClient(sdkKey, PollingMode.ManualPoll, options, ...)' format.
*/
function createClientWithManualPoll(apiKey, configCatKernel, options) {
return new ConfigCatClient_1.ConfigCatClient(new ConfigCatClientOptions_1.ManualPollOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache), configCatKernel);
return new ConfigCatClient_1.ConfigCatClient(new ConfigCatClientOptions_1.ManualPollOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache, configCatKernel.eventEmitterFactory), configCatKernel);
}

@@ -32,5 +57,6 @@ exports.createClientWithManualPoll = createClientWithManualPoll;

* @param config - Configuration for lazyLoad mode
* @deprecated This function is obsolete and will be removed from the public API in a future major version. To obtain a ConfigCatClient instance with lazy loading for a specific SDK Key, please use the 'getClient(sdkKey, PollingMode.LazyLoad, options, ...)' format.
*/
function createClientWithLazyLoad(apiKey, configCatKernel, options) {
return new ConfigCatClient_1.ConfigCatClient(new ConfigCatClientOptions_1.LazyLoadOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache), configCatKernel);
return new ConfigCatClient_1.ConfigCatClient(new ConfigCatClientOptions_1.LazyLoadOptions(apiKey, configCatKernel.sdkType, configCatKernel.sdkVersion, options, configCatKernel.cache, configCatKernel.eventEmitterFactory), configCatKernel);
}

@@ -40,3 +66,3 @@ exports.createClientWithLazyLoad = createClientWithLazyLoad;

* Create an instance of ConfigCatConsoleLogger
* @param {LogLevel} logLevel - Specifies message's filtering to output for the CofigCatConsoleLogger.
* @param {LogLevel} logLevel - Specifies message's filtering to output for the ConfigCatConsoleLogger.
*/

@@ -47,39 +73,19 @@ function createConsoleLogger(logLevel) {

exports.createConsoleLogger = createConsoleLogger;
var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["Debug"] = 4] = "Debug";
LogLevel[LogLevel["Info"] = 3] = "Info";
LogLevel[LogLevel["Warn"] = 2] = "Warn";
LogLevel[LogLevel["Error"] = 1] = "Error";
LogLevel[LogLevel["Off"] = -1] = "Off";
})(LogLevel = exports.LogLevel || (exports.LogLevel = {}));
var FetchStatus;
(function (FetchStatus) {
FetchStatus[FetchStatus["Fetched"] = 0] = "Fetched";
FetchStatus[FetchStatus["NotModified"] = 1] = "NotModified";
FetchStatus[FetchStatus["Errored"] = 2] = "Errored";
})(FetchStatus = exports.FetchStatus || (exports.FetchStatus = {}));
var FetchResult = /** @class */ (function () {
function FetchResult(status, responseBody, eTag) {
this.status = status;
this.responseBody = responseBody;
this.eTag = eTag;
}
FetchResult.success = function (responseBody, eTag) {
return new FetchResult(FetchStatus.Fetched, responseBody, eTag);
};
FetchResult.notModified = function () {
return new FetchResult(FetchStatus.NotModified, "");
};
FetchResult.error = function () {
return new FetchResult(FetchStatus.Errored, "");
};
return FetchResult;
}());
exports.FetchResult = FetchResult;
var ConfigFetcher_1 = require("./ConfigFetcher");
Object.defineProperty(exports, "FetchStatus", { enumerable: true, get: function () { return ConfigFetcher_1.FetchStatus; } });
Object.defineProperty(exports, "FetchResult", { enumerable: true, get: function () { return ConfigFetcher_1.FetchResult; } });
Object.defineProperty(exports, "FetchError", { enumerable: true, get: function () { return ConfigFetcher_1.FetchError; } });
var ConfigCatClientOptions_2 = require("./ConfigCatClientOptions");
Object.defineProperty(exports, "OptionsBase", { enumerable: true, get: function () { return ConfigCatClientOptions_2.OptionsBase; } });
var Cache_1 = require("./Cache");
Object.defineProperty(exports, "InMemoryCache", { enumerable: true, get: function () { return Cache_1.InMemoryCache; } });
var ConfigCatClientOptions_3 = require("./ConfigCatClientOptions");
Object.defineProperty(exports, "DataGovernance", { enumerable: true, get: function () { return ConfigCatClientOptions_3.DataGovernance; } });
var ProjectConfig_1 = require("./ProjectConfig");
Object.defineProperty(exports, "ProjectConfig", { enumerable: true, get: function () { return ProjectConfig_1.ProjectConfig; } });
var ConfigCatClientOptions_2 = require("./ConfigCatClientOptions");
Object.defineProperty(exports, "OptionsBase", { enumerable: true, get: function () { return ConfigCatClientOptions_2.OptionsBase; } });
Object.defineProperty(exports, "DataGovernance", { enumerable: true, get: function () { return ConfigCatClientOptions_2.DataGovernance; } });
Object.defineProperty(exports, "RolloutRule", { enumerable: true, get: function () { return ProjectConfig_1.RolloutRule; } });
Object.defineProperty(exports, "RolloutPercentageItem", { enumerable: true, get: function () { return ProjectConfig_1.RolloutPercentageItem; } });
Object.defineProperty(exports, "Setting", { enumerable: true, get: function () { return ProjectConfig_1.Setting; } });
var ConfigCatClient_2 = require("./ConfigCatClient");
Object.defineProperty(exports, "SettingKeyValue", { enumerable: true, get: function () { return ConfigCatClient_2.SettingKeyValue; } });
var RolloutEvaluator_1 = require("./RolloutEvaluator");

@@ -91,1 +97,3 @@ Object.defineProperty(exports, "User", { enumerable: true, get: function () { return RolloutEvaluator_1.User; } });

Object.defineProperty(exports, "OverrideBehaviour", { enumerable: true, get: function () { return FlagOverrides_1.OverrideBehaviour; } });
var ConfigServiceBase_1 = require("./ConfigServiceBase");
Object.defineProperty(exports, "RefreshResult", { enumerable: true, get: function () { return ConfigServiceBase_1.RefreshResult; } });

@@ -1,11 +0,11 @@

import { IConfigService, ConfigServiceBase } from "./ConfigServiceBase";
import { LazyLoadOptions } from "./ConfigCatClientOptions";
import { IConfigFetcher } from "./index";
import type { IConfigFetcher } from "./ConfigFetcher";
import { ConfigServiceBase, IConfigService, RefreshResult } from "./ConfigServiceBase";
import { ProjectConfig } from "./ProjectConfig";
export declare class LazyLoadConfigService extends ConfigServiceBase implements IConfigService {
export declare class LazyLoadConfigService extends ConfigServiceBase<LazyLoadOptions> implements IConfigService {
private cacheTimeToLiveSeconds;
constructor(configFetcher: IConfigFetcher, config: LazyLoadOptions);
constructor(configFetcher: IConfigFetcher, options: LazyLoadOptions);
getConfig(): Promise<ProjectConfig | null>;
refreshConfigAsync(): Promise<ProjectConfig | null>;
refreshConfigAsync(): Promise<[RefreshResult, ProjectConfig | null]>;
}
//# sourceMappingURL=LazyLoadConfigService.d.ts.map
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.LazyLoadConfigService = void 0;
var tslib_1 = require("tslib");
var ConfigServiceBase_1 = require("./ConfigServiceBase");
var ProjectConfig_1 = require("./ProjectConfig");
var LazyLoadConfigService = /** @class */ (function (_super) {
__extends(LazyLoadConfigService, _super);
function LazyLoadConfigService(configFetcher, config) {
var _this = _super.call(this, configFetcher, config) || this;
_this.cacheTimeToLiveSeconds = config.cacheTimeToLiveSeconds;
tslib_1.__extends(LazyLoadConfigService, _super);
function LazyLoadConfigService(configFetcher, options) {
var _this = _super.call(this, configFetcher, options) || this;
_this.cacheTimeToLiveSeconds = options.cacheTimeToLiveSeconds;
options.hooks.emit("clientReady");
return _this;
}
LazyLoadConfigService.prototype.getConfig = function () {
return __awaiter(this, void 0, void 0, function () {
var p;
return __generator(this, function (_a) {
switch (_a.label) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
function logExpired(logger, appendix) {
if (appendix === void 0) { appendix = ""; }
logger.debug("LazyLoadConfigService.getConfig(): cache is empty or expired".concat(appendix, "."));
}
var config;
var _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
this.baseConfig.logger.debug("LazyLoadConfigService.getConfig() called.");
return [4 /*yield*/, this.baseConfig.cache.get(this.baseConfig.getCacheKey())];
this.options.logger.debug("LazyLoadConfigService.getConfig() called.");
return [4 /*yield*/, this.options.cache.get(this.options.getCacheKey())];
case 1:
p = _a.sent();
if (p && p.Timestamp + (this.cacheTimeToLiveSeconds * 1000) > new Date().getTime()) {
this.baseConfig.logger.debug("LazyLoadConfigService.getConfig(): cache is valid, returning from cache.");
return [2 /*return*/, p];
}
else {
this.baseConfig.logger.debug("LazyLoadConfigService.getConfig(): cache is empty or expired, calling refreshLogicBaseAsync().");
return [2 /*return*/, this.refreshLogicBaseAsync(p)];
}
return [2 /*return*/];
config = _b.sent();
if (!ProjectConfig_1.ProjectConfig.isExpired(config, this.cacheTimeToLiveSeconds * 1000)) return [3 /*break*/, 5];
if (!!this.isOffline) return [3 /*break*/, 3];
logExpired(this.options.logger, ", calling refreshConfigCoreAsync()");
return [4 /*yield*/, this.refreshConfigCoreAsync(config)];
case 2:
_a = _b.sent(), config = _a[1];
return [3 /*break*/, 4];
case 3:
logExpired(this.options.logger);
_b.label = 4;
case 4: return [2 /*return*/, config];
case 5:
this.options.logger.debug("LazyLoadConfigService.getConfig(): cache is valid, returning from cache.");
return [2 /*return*/, config];
}

@@ -87,13 +49,6 @@ });

LazyLoadConfigService.prototype.refreshConfigAsync = function () {
return __awaiter(this, void 0, void 0, function () {
var p;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.baseConfig.logger.debug("LazyLoadConfigService.refreshConfigAsync() called.");
return [4 /*yield*/, this.baseConfig.cache.get(this.baseConfig.getCacheKey())];
case 1:
p = _a.sent();
return [2 /*return*/, this.refreshLogicBaseAsync(p)];
}
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
this.options.logger.debug("LazyLoadConfigService.refreshConfigAsync() called.");
return [2 /*return*/, _super.prototype.refreshConfigAsync.call(this)];
});

@@ -100,0 +55,0 @@ });

export declare function setupPolyfills(): void;
export declare function ObjectValuesPolyfill<T>(o: {
[s: string]: T;
} | ArrayLike<T>): T[];
export declare function ObjectEntriesPolyfill<T>(o: {
[s: string]: T;
} | ArrayLike<T>): [string, T][];
export declare function ObjectFromEntriesPolyfill<T>(entries: Iterable<readonly [PropertyKey, T]>): {
[k: PropertyKey]: T;
};
export declare function getWeakRefFallback<T extends object>(): WeakRefConstructor;
export declare const isWeakRefAvailable: () => boolean;
//# sourceMappingURL=Polyfills.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.setupPolyfills = void 0;
exports.isWeakRefAvailable = exports.getWeakRefFallback = exports.ObjectFromEntriesPolyfill = exports.ObjectEntriesPolyfill = exports.ObjectValuesPolyfill = exports.setupPolyfills = void 0;
function setupPolyfills() {
if (!Object.fromEntries) {
Object.fromEntries = function (entries) {
if (!entries || !entries[Symbol.iterator]) {
throw new Error('Object.fromEntries() requires a single iterable argument');
}
var obj = {};
for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
var _a = entries_1[_i], key = _a[0], value = _a[1];
obj[key] = value;
}
return obj;
};
// Object.values
if (typeof Object.values === "undefined") {
Object.values = ObjectValuesPolyfill;
}
// Object.entries
if (typeof Object.entries === "undefined") {
Object.entries = ObjectEntriesPolyfill;
}
// Object.fromEntries
if (typeof Object.fromEntries === "undefined") {
Object.fromEntries = ObjectFromEntriesPolyfill;
}
// WeakRef
if (typeof WeakRef === "undefined") {
// There's no way to correctly polyfill WeakRef (https://stackoverflow.com/a/69971312/8656352),
// so we just polyfill its API (which means falling back on strong references in this case).
WeakRef = getWeakRefFallback();
}
}
exports.setupPolyfills = setupPolyfills;
function ObjectValuesPolyfill(o) {
var result = [];
for (var _i = 0, _a = Object.keys(o); _i < _a.length; _i++) {
var key = _a[_i];
result.push(o[key]);
}
return result;
}
exports.ObjectValuesPolyfill = ObjectValuesPolyfill;
function ObjectEntriesPolyfill(o) {
var result = [];
for (var _i = 0, _a = Object.keys(o); _i < _a.length; _i++) {
var key = _a[_i];
result.push([key, o[key]]);
}
return result;
}
exports.ObjectEntriesPolyfill = ObjectEntriesPolyfill;
function ObjectFromEntriesPolyfill(entries) {
var _a;
var result = {};
if (Array.isArray(entries)) {
for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
var _b = entries_1[_i], key = _b[0], value = _b[1];
result[key] = value;
}
}
else if (typeof Symbol !== "undefined" && (entries === null || entries === void 0 ? void 0 : entries[Symbol.iterator])) {
var iterator = entries[Symbol.iterator]();
var element = void 0, done = void 0;
while ((_a = iterator.next(), element = _a.value, done = _a.done, !done)) {
var key = element[0], value = element[1];
result[key] = value;
}
}
else {
throw new Error('Object.fromEntries() requires a single iterable argument');
}
return result;
}
exports.ObjectFromEntriesPolyfill = ObjectFromEntriesPolyfill;
function getWeakRefFallback() {
var WeakRef = function (target) {
this.target = target;
};
WeakRef.prototype.deref = function () {
return this.target;
};
WeakRef.isFallback = true;
return WeakRef;
}
exports.getWeakRefFallback = getWeakRefFallback;
var isWeakRefAvailable = function () { return typeof WeakRef === "function" && !WeakRef.hasOwnProperty("isFallback"); };
exports.isWeakRefAvailable = isWeakRefAvailable;

@@ -6,5 +6,5 @@ export declare class ProjectConfig {

ConfigJSON: any;
/** Timestamp in milliseconds */
/** Timestamp of last successful download (regardless of whether the config has changed or not) in milliseconds */
Timestamp: number;
constructor(timeStamp: number, jsonConfig: string, httpETag?: string);
constructor(timeStamp: number, jsonConfig: string | object, httpETag?: string);
/**

@@ -16,2 +16,3 @@ * Determines whether the specified ProjectConfig instances are considered equal.

private static ensureStrictEtag;
static isExpired(projectConfig: ProjectConfig | null, expirationMs: number): boolean;
}

@@ -18,0 +19,0 @@ export declare class ConfigFile {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RolloutPercentageItem = exports.RolloutRule = exports.Setting = exports.Preferences = exports.ConfigFile = exports.ProjectConfig = void 0;
// NOTE: No instance methods should be added to this class!
// Flawed ICache implementations may erase the prototype information (when serialization is involved),
// which would lead to "... is not a function" errors in the case of instance methods.
// (As a matter of fact, this type should have been defined as an interface to prevent such complications but
// we can't really change this any more because this would be a too dangerous breaking change at this point.)
var ProjectConfig = /** @class */ (function () {
function ProjectConfig(timeStamp, jsonConfig, httpETag) {
this.Timestamp = timeStamp;
this.ConfigJSON = JSON.parse(jsonConfig);
this.ConfigJSON = typeof jsonConfig === "string" ? JSON.parse(jsonConfig) : jsonConfig;
this.HttpETag = httpETag;

@@ -14,5 +19,14 @@ }

ProjectConfig.equals = function (projectConfig1, projectConfig2) {
if (!projectConfig1 || !projectConfig2)
if (!projectConfig1) {
// If both configs are null, we consider them equal.
return !projectConfig2;
}
if (!projectConfig2) {
return false;
return this.compareEtags(projectConfig1.HttpETag, projectConfig2.HttpETag);
}
// When both ETags are available, we don't need to check the JSON content
// (because of how HTTP ETags work - see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag).
return !!projectConfig1.HttpETag && !!projectConfig2.HttpETag
? this.compareEtags(projectConfig1.HttpETag, projectConfig2.HttpETag)
: JSON.stringify(projectConfig1.ConfigJSON) === JSON.stringify(projectConfig2.ConfigJSON);
};

@@ -31,2 +45,5 @@ ProjectConfig.compareEtags = function (etag1, etag2) {

};
ProjectConfig.isExpired = function (projectConfig, expirationMs) {
return !projectConfig || projectConfig.Timestamp + expirationMs < new Date().getTime();
};
return ProjectConfig;

@@ -33,0 +50,0 @@ }());

@@ -1,8 +0,32 @@

import { IConfigCatLogger } from "./index";
import { Setting } from "./ProjectConfig";
import { LoggerWrapper } from "./ConfigCatLogger";
import { ProjectConfig, RolloutPercentageItem, RolloutRule, Setting } from "./ProjectConfig";
export type SettingValue = boolean | number | string | null | undefined;
export type SettingTypeOf<T> = T extends boolean ? boolean : T extends number ? number : T extends string ? string : T extends null ? boolean | number | string | null : T extends undefined ? boolean | number | string | undefined : any;
export type VariationIdValue = string | null | undefined;
export type VariationIdTypeOf<T> = T extends string ? string : T extends null ? string | null : T extends undefined ? string | undefined : any;
export interface IRolloutEvaluator {
Evaluate(settings: {
[name: string]: Setting;
}, key: string, defaultValue: any, user?: User, defaultVariationId?: any): ValueAndVariationId;
Evaluate(setting: Setting, key: string, defaultValue: SettingValue, user: User | undefined, remoteConfig: ProjectConfig | null, defaultVariationId?: VariationIdValue): IEvaluationDetails;
}
export interface IEvaluationDetails<TValue = SettingValue> {
/** Key of the feature or setting flag. */
key: string;
/** Evaluated value of the feature or setting flag. */
value: TValue;
/** Variation ID of the feature or setting flag (if available). */
variationId?: VariationIdValue;
/** Time of last successful download of config.json (if there has been a successful download already). */
fetchTime?: Date;
/** The User object used for the evaluation (if available). */
user?: User;
/** Indicates whether the default value passed to IConfigCatClient.getValue or IConfigCatClient.getValueAsync is used as the result of the evaluation. */
isDefaultValue: boolean;
/** Error message in case evaluation failed. */
errorMessage?: string;
/** The exception object related to the error in case evaluation failed (if any). */
errorException?: any;
/** The comparison-based targeting rule which was used to select the evaluated value (if any). */
matchedEvaluationRule?: RolloutRule;
/** The percentage-based targeting rule which was used to select the evaluated value (if any). */
matchedEvaluationPercentageRule?: RolloutPercentageItem;
}
/** Object for variation evaluation */

@@ -26,8 +50,6 @@ export declare class User {

private logger;
constructor(logger: IConfigCatLogger);
Evaluate(settings: {
[name: string]: Setting;
}, key: string, defaultValue: any, user?: User, defaultVariationId?: any): ValueAndVariationId;
constructor(logger: LoggerWrapper);
Evaluate(setting: Setting, key: string, defaultValue: SettingValue, user: User | undefined, remoteConfig: ProjectConfig | null): IEvaluationDetails;
private EvaluateRules;
private EvaluateVariations;
private EvaluatePercentageRules;
private EvaluateNumber;

@@ -38,7 +60,22 @@ private EvaluateSemver;

}
declare class ValueAndVariationId {
Value: any;
VariationId: any;
}
export {};
export declare function evaluationDetailsFromDefaultValue<T extends SettingValue>(key: string, defaultValue: T, fetchTime?: Date, user?: User, errorMessage?: string, errorException?: any): IEvaluationDetails<SettingTypeOf<T>>;
export declare function evaluationDetailsFromDefaultVariationId(key: string, defaultVariationId: VariationIdValue, fetchTime?: Date, user?: User, errorMessage?: string, errorException?: any): IEvaluationDetails;
export declare function evaluate<T extends SettingValue>(evaluator: IRolloutEvaluator, settings: {
[name: string]: Setting;
} | null, key: string, defaultValue: T, user: User | undefined, remoteConfig: ProjectConfig | null, logger: LoggerWrapper): IEvaluationDetails<SettingTypeOf<T>>;
export declare function evaluateVariationId(evaluator: IRolloutEvaluator, settings: {
[name: string]: Setting;
} | null, key: string, defaultVariationId: VariationIdValue, user: User | undefined, remoteConfig: ProjectConfig | null, logger: LoggerWrapper): IEvaluationDetails;
export declare function evaluateAll(evaluator: IRolloutEvaluator, settings: {
[name: string]: Setting;
} | null, user: User | undefined, remoteConfig: ProjectConfig | null, logger: LoggerWrapper): [IEvaluationDetails[], any[] | undefined];
export declare function evaluateAllVariationIds(evaluator: IRolloutEvaluator, settings: {
[name: string]: Setting;
} | null, user: User | undefined, remoteConfig: ProjectConfig | null, logger: LoggerWrapper): [IEvaluationDetails[], any[] | undefined];
export declare function checkSettingsAvailable(settings: {
[name: string]: Setting;
} | null, logger: LoggerWrapper, appendix?: string): settings is {
[name: string]: Setting;
};
export declare function ensureAllowedDefaultValue(value: SettingValue): void;
//# sourceMappingURL=RolloutEvaluator.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RolloutEvaluator = exports.User = void 0;
exports.ensureAllowedDefaultValue = exports.checkSettingsAvailable = exports.evaluateAllVariationIds = exports.evaluateAll = exports.evaluateVariationId = exports.evaluate = exports.evaluationDetailsFromDefaultVariationId = exports.evaluationDetailsFromDefaultValue = exports.RolloutEvaluator = exports.User = void 0;
var ProjectConfig_1 = require("./ProjectConfig");
var semver = require("./Semver");
var Sha1_1 = require("./Sha1");
var semver = require("./Semver");
var Utils_1 = require("./Utils");

@@ -24,11 +25,4 @@ /** Object for variation evaluation */

}
RolloutEvaluator.prototype.Evaluate = function (settings, key, defaultValue, user, defaultVariationId) {
RolloutEvaluator.prototype.Evaluate = function (setting, key, defaultValue, user, remoteConfig) {
this.logger.debug("RolloutEvaluator.Evaluate() called.");
if (!settings[key]) {
var s = "Evaluating getValue('" + key + "') failed. Returning default value: '" + defaultValue + "'.";
s += " Here are the available keys: {" + Object.keys(settings).join() + "}.";
this.logger.error(s);
return { Value: defaultValue, VariationId: defaultVariationId };
}
var featureFlag = settings[key];
var eLog = new EvaluateLogger();

@@ -38,39 +32,44 @@ eLog.User = user;

eLog.ReturnValue = defaultValue;
var result = new EvaluateResult();
result.EvaluateLog = eLog;
if (user) {
result = this.EvaluateRules(featureFlag.rolloutRules, user, eLog);
if (result.ValueAndVariationId == null) {
result.ValueAndVariationId = this.EvaluateVariations(featureFlag.rolloutPercentageItems, key, user);
if (result.ValueAndVariationId) {
result.EvaluateLog.ReturnValue = result.ValueAndVariationId.Value;
var result;
try {
if (user) {
// evaluate comparison-based rules
result = this.EvaluateRules(setting.rolloutRules, user, eLog);
if (result !== null) {
eLog.ReturnValue = result.value;
return evaluationDetailsFromEvaluateResult(key, result, (0, Utils_1.getTimestampAsDate)(remoteConfig), user);
}
if (featureFlag.rolloutPercentageItems.length > 0) {
result.EvaluateLog.OpAppendLine("Evaluating % options => " + (result.ValueAndVariationId == null ? "user not targeted" : "user targeted"));
// evaluate percentage-based rules
result = this.EvaluatePercentageRules(setting.rolloutPercentageItems, key, user);
if (setting.rolloutPercentageItems && setting.rolloutPercentageItems.length > 0) {
eLog.OpAppendLine("Evaluating % options => " + (!result ? "user not targeted" : "user targeted"));
}
if (result !== null) {
eLog.ReturnValue = result.value;
return evaluationDetailsFromEvaluateResult(key, result, (0, Utils_1.getTimestampAsDate)(remoteConfig), user);
}
}
}
else {
if ((featureFlag.rolloutRules && featureFlag.rolloutRules.length > 0) ||
(featureFlag.rolloutPercentageItems && featureFlag.rolloutPercentageItems.length > 0)) {
var s = "Evaluating getValue('" + key + "'). ";
s += "UserObject missing! You should pass a UserObject to getValue(), in order to make targeting work properly. ";
s += "Read more: https://configcat.com/docs/advanced/user-object";
this.logger.warn(s);
else {
if ((setting.rolloutRules && setting.rolloutRules.length > 0) ||
(setting.rolloutPercentageItems && setting.rolloutPercentageItems.length > 0)) {
var s = "Evaluating getValue('" + key + "'). ";
s += "UserObject missing! You should pass a UserObject to getValue(), in order to make targeting work properly. ";
s += "Read more: https://configcat.com/docs/advanced/user-object";
this.logger.warn(s);
}
}
}
if (result.ValueAndVariationId == null) {
result.ValueAndVariationId = {
Value: featureFlag.value,
VariationId: featureFlag.variationId,
// regular evaluate
result = {
value: setting.value,
variationId: setting.variationId
};
result.EvaluateLog.ReturnValue = result.ValueAndVariationId.Value;
eLog.ReturnValue = result.value;
return evaluationDetailsFromEvaluateResult(key, result, (0, Utils_1.getTimestampAsDate)(remoteConfig), user);
}
this.logger.info(result.EvaluateLog.GetLog());
return result.ValueAndVariationId;
finally {
this.logger.info(eLog.GetLog());
}
};
RolloutEvaluator.prototype.EvaluateRules = function (rolloutRules, user, eLog) {
this.logger.debug("RolloutEvaluator.EvaluateRules() called.");
var result = new EvaluateResult();
result.ValueAndVariationId = null;
if (rolloutRules && rolloutRules.length > 0) {

@@ -88,2 +87,7 @@ var _loop_1 = function (i) {

}
var result = {
value: rule.value,
variationId: rule.variationId,
matchedRule: rule
};
switch (comparator) {

@@ -96,8 +100,2 @@ case 0: // is one of

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -117,8 +115,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -132,8 +124,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -147,8 +133,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -167,8 +147,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -187,8 +161,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -204,8 +172,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -225,8 +187,2 @@ }

eLog.OpAppendLine(log);
result.ValueAndVariationId = {
Value: rule.value,
VariationId: rule.variationId
};
eLog.ReturnValue = result.ValueAndVariationId.Value;
result.EvaluateLog = eLog;
return { value: result };

@@ -248,9 +204,8 @@ }

}
result.EvaluateLog = eLog;
return result;
return null;
};
RolloutEvaluator.prototype.EvaluateVariations = function (rolloutPercentageItems, key, user) {
RolloutEvaluator.prototype.EvaluatePercentageRules = function (rolloutPercentageItems, key, user) {
this.logger.debug("RolloutEvaluator.EvaluateVariations() called.");
if (rolloutPercentageItems && rolloutPercentageItems.length > 0) {
var hashCandidate = key + ((user.identifier === null || user.identifier === undefined) ? '' : user.identifier);
var hashCandidate = key + ((user.identifier === null || user.identifier === void 0) ? '' : user.identifier);
var hashValue = (0, Sha1_1.sha1)(hashCandidate).substring(0, 7);

@@ -260,8 +215,9 @@ var hashScale = parseInt(hashValue, 16) % 100;

for (var i = 0; i < rolloutPercentageItems.length; i++) {
var variation = rolloutPercentageItems[i];
bucket += +variation.percentage;
var percentageRule = rolloutPercentageItems[i];
bucket += +percentageRule.percentage;
if (hashScale < bucket) {
return {
Value: variation.value,
VariationId: variation.variationId
value: percentageRule.value,
variationId: percentageRule.variationId,
matchedRule: percentageRule
};

@@ -423,12 +379,2 @@ }

exports.RolloutEvaluator = RolloutEvaluator;
var ValueAndVariationId = /** @class */ (function () {
function ValueAndVariationId() {
}
return ValueAndVariationId;
}());
var EvaluateResult = /** @class */ (function () {
function EvaluateResult() {
}
return EvaluateResult;
}());
var EvaluateLogger = /** @class */ (function () {

@@ -449,1 +395,129 @@ function EvaluateLogger() {

}());
/* Helper functions */
function evaluationDetailsFromEvaluateResult(key, evaluateResult, fetchTime, user) {
return {
key: key,
value: evaluateResult.value,
variationId: evaluateResult.variationId,
fetchTime: fetchTime,
user: user,
isDefaultValue: false,
matchedEvaluationRule: evaluateResult.matchedRule instanceof ProjectConfig_1.RolloutRule ? evaluateResult.matchedRule : void 0,
matchedEvaluationPercentageRule: evaluateResult.matchedRule instanceof ProjectConfig_1.RolloutPercentageItem ? evaluateResult.matchedRule : void 0,
};
}
function evaluationDetailsFromDefaultValue(key, defaultValue, fetchTime, user, errorMessage, errorException) {
return {
key: key,
value: defaultValue,
fetchTime: fetchTime,
user: user,
isDefaultValue: true,
errorMessage: errorMessage,
errorException: errorException
};
}
exports.evaluationDetailsFromDefaultValue = evaluationDetailsFromDefaultValue;
function evaluationDetailsFromDefaultVariationId(key, defaultVariationId, fetchTime, user, errorMessage, errorException) {
return {
key: key,
value: null,
variationId: defaultVariationId,
fetchTime: fetchTime,
user: user,
isDefaultValue: true,
errorMessage: errorMessage,
errorException: errorException
};
}
exports.evaluationDetailsFromDefaultVariationId = evaluationDetailsFromDefaultVariationId;
function evaluate(evaluator, settings, key, defaultValue, user, remoteConfig, logger) {
var errorMessage;
if (!settings) {
errorMessage = "config.json is not present. Returning default value: '".concat(defaultValue, "'.");
logger.error(errorMessage);
return evaluationDetailsFromDefaultValue(key, defaultValue, (0, Utils_1.getTimestampAsDate)(remoteConfig), user, errorMessage);
}
var setting = settings[key];
if (!setting) {
errorMessage = "Evaluating '".concat(key, "' failed (key was not found in config.json). Returning default value: '").concat(defaultValue, "'. These are the available keys: ").concat(keysToString(settings), ".");
logger.error(errorMessage);
return evaluationDetailsFromDefaultValue(key, defaultValue, (0, Utils_1.getTimestampAsDate)(remoteConfig), user, errorMessage);
}
ensureAllowedDefaultValue(defaultValue);
var evaluationDetails = evaluator.Evaluate(setting, key, defaultValue, user, remoteConfig);
if (defaultValue !== null && defaultValue !== void 0 && typeof defaultValue !== typeof evaluationDetails.value) {
throw new Error("The type of a setting must match the type of the given default value.\nThe setting's type was ".concat(typeof defaultValue, ", the given default value's type was ").concat(typeof evaluationDetails.value, ".\nPlease pass a corresponding default value type."));
}
return evaluationDetails;
}
exports.evaluate = evaluate;
function evaluateVariationId(evaluator, settings, key, defaultVariationId, user, remoteConfig, logger) {
var errorMessage;
if (!settings) {
errorMessage = "config.json is not present. Returning default variationId: '".concat(defaultVariationId, "'.");
logger.error(errorMessage);
return evaluationDetailsFromDefaultVariationId(key, defaultVariationId, (0, Utils_1.getTimestampAsDate)(remoteConfig), user, errorMessage);
}
var setting = settings[key];
if (!setting) {
errorMessage = "Evaluating '".concat(key, "' failed (key was not found in config.json). Returning default variationId: '").concat(defaultVariationId, "'. These are the available keys: ").concat(keysToString(settings), ".");
logger.error(errorMessage);
return evaluationDetailsFromDefaultVariationId(key, defaultVariationId, (0, Utils_1.getTimestampAsDate)(remoteConfig), user, errorMessage);
}
return evaluator.Evaluate(setting, key, null, user, remoteConfig, defaultVariationId);
}
exports.evaluateVariationId = evaluateVariationId;
function evaluateAllCore(evaluator, settings, user, remoteConfig, logger, getDetailsForError) {
var errors;
if (!checkSettingsAvailable(settings, logger, ", returning empty array")) {
return [[], errors];
}
var evaluationDetailsArray = [];
var index = 0;
for (var _i = 0, _a = Object.entries(settings); _i < _a.length; _i++) {
var _b = _a[_i], key = _b[0], setting = _b[1];
var evaluationDetails = void 0;
try {
evaluationDetails = evaluator.Evaluate(setting, key, null, user, remoteConfig);
}
catch (err) {
errors !== null && errors !== void 0 ? errors : (errors = []);
errors.push(err);
evaluationDetails = getDetailsForError(key, (0, Utils_1.getTimestampAsDate)(remoteConfig), user, err);
}
evaluationDetailsArray[index++] = evaluationDetails;
}
return [evaluationDetailsArray, errors];
}
function evaluateAll(evaluator, settings, user, remoteConfig, logger) {
return evaluateAllCore(evaluator, settings, user, remoteConfig, logger, function (key, fetchTime, user, err) { return evaluationDetailsFromDefaultValue(key, null, fetchTime, user, (0, Utils_1.errorToString)(err), err); });
}
exports.evaluateAll = evaluateAll;
function evaluateAllVariationIds(evaluator, settings, user, remoteConfig, logger) {
return evaluateAllCore(evaluator, settings, user, remoteConfig, logger, function (key, fetchTime, user, err) { return evaluationDetailsFromDefaultVariationId(key, null, fetchTime, user, (0, Utils_1.errorToString)(err), err); });
}
exports.evaluateAllVariationIds = evaluateAllVariationIds;
function checkSettingsAvailable(settings, logger, appendix) {
if (appendix === void 0) { appendix = ""; }
if (!settings) {
logger.error("config.json is not present".concat(appendix));
return false;
}
return true;
}
exports.checkSettingsAvailable = checkSettingsAvailable;
function ensureAllowedDefaultValue(value) {
if (value === null || value === void 0) {
return;
}
var type = typeof value;
if (type === "boolean" || type === "number" || type === "string") {
return;
}
throw new Error("The default value must be boolean, number, string, null or undefined.");
}
exports.ensureAllowedDefaultValue = ensureAllowedDefaultValue;
function keysToString(settings) {
return Object.keys(settings).join();
}

@@ -33,3 +33,3 @@ "use strict";

src[index] = value;
re[index] = new RegExp(value, undefined);
re[index] = new RegExp(value);
};

@@ -167,9 +167,9 @@ createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*');

var b = other.prerelease[i];
if (a === undefined && b === undefined) {
if (a === void 0 && b === void 0) {
return 0;
}
else if (b === undefined) {
else if (b === void 0) {
return 1;
}
else if (a === undefined) {
else if (a === void 0) {
return -1;

@@ -193,9 +193,9 @@ }

var b = other.build[i];
if (a === undefined && b === undefined) {
if (a === void 0 && b === void 0) {
return 0;
}
else if (b === undefined) {
else if (b === void 0) {
return 1;
}
else if (a === undefined) {
else if (a === void 0) {
return -1;

@@ -202,0 +202,0 @@ }

@@ -1,6 +0,9 @@

import { Setting } from "./ProjectConfig";
import { ProjectConfig, Setting } from "./ProjectConfig";
export declare const isUndefined: (comp: any) => boolean;
export declare function delay(delayMs: number, obtainCancel?: (cancel: () => void) => void): Promise<void>;
export declare function getSettingsFromConfig(json: any): {
[name: string]: Setting;
};
export declare function getTimestampAsDate(projectConfig: ProjectConfig | null): Date | undefined;
export declare function errorToString(err: any, includeStackTrace?: boolean): string;
//# sourceMappingURL=Utils.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSettingsFromConfig = exports.isUndefined = void 0;
exports.errorToString = exports.getTimestampAsDate = exports.getSettingsFromConfig = exports.delay = exports.isUndefined = void 0;
var ProjectConfig_1 = require("./ProjectConfig");
var isUndefined = function (comp) { return comp === undefined; };
var isUndefined = function (comp) { return comp === void 0; };
exports.isUndefined = isUndefined;
function delay(delayMs, obtainCancel) {
var timerId;
var promise = new Promise(function (resolve) { return timerId = setTimeout(resolve, delayMs); });
obtainCancel === null || obtainCancel === void 0 ? void 0 : obtainCancel(function () { return clearTimeout(timerId); });
return promise;
}
exports.delay = delay;
;
function getSettingsFromConfig(json) {
if (!json) {
return {};
}
return Object.fromEntries(Object.entries(json[ProjectConfig_1.ConfigFile.FeatureFlags]).map(function (_a) {

@@ -17,1 +22,12 @@ var key = _a[0], value = _a[1];

exports.getSettingsFromConfig = getSettingsFromConfig;
function getTimestampAsDate(projectConfig) {
return projectConfig ? new Date(projectConfig.Timestamp) : void 0;
}
exports.getTimestampAsDate = getTimestampAsDate;
function errorToString(err, includeStackTrace) {
if (includeStackTrace === void 0) { includeStackTrace = false; }
return err instanceof Error
? includeStackTrace && err.stack ? err.stack : err.toString()
: err + "";
}
exports.errorToString = errorToString;
{
"name": "configcat-common",
"version": "6.0.1",
"version": "7.0.0",
"description": "ConfigCat is a configuration as a service that lets you manage your features and configurations without actually deploying new code.",

@@ -10,6 +10,6 @@ "main": "lib/index.js",

"coverage": "nyc npm run test",
"build": "tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json && tsc -p tsconfig.legacy.json",
"build": "tsc -p tsconfig.build.cjs.json && tsc -p tsconfig.build.esm.json",
"prepare": "npm run build",
"test": "mocha --require ts-node/register test/**/*.ts --exit --timeout 30000",
"test-debug": "mocha --fgrep \"TITLE_OF_TEST\" --require ts-node/register test/**/*.ts --exit --timeout 30000"
"test": "cross-env TS_NODE_PROJECT=./tsconfig.mocha.json node --expose-gc node_modules/mocha/bin/_mocha --require ts-node/register 'test/**/*.ts' --exit --timeout 30000",
"test-debug": "cross-env TS_NODE_PROJECT=./tsconfig.mocha.json node --expose-gc node_modules/mocha/bin/_mocha --fgrep \"TITLE_OF_TEST\" --require ts-node/register 'test/**/*.ts' --exit --timeout 30000"
},

@@ -32,8 +32,12 @@ "keywords": [

"homepage": "https://configcat.com",
"dependencies": {
"tslib": "^2.4.1"
},
"devDependencies": {
"@types/chai": "4.3.3",
"@types/mocha": "^9.1.1",
"@types/node": "^17.0.45",
"chai": "^4.3.6",
"mocha": "^10.0.0",
"@types/chai": "4.3.4",
"@types/mocha": "^10.0.1",
"@types/node": "^18.11.18",
"chai": "^4.3.7",
"cross-env": "^7.0.3",
"mocha": "^10.2.0",
"moq.ts": "^7.4.1",

@@ -43,3 +47,3 @@ "nyc": "^15.1.0",

"ts-node": "^10.9.1",
"typescript": "^4.7.4"
"typescript": "^4.9.4"
},

@@ -46,0 +50,0 @@ "repository": {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc