statsig-js
Version:
Statsig JavaScript client SDK for single user environments.
1,002 lines • 57 kB
JavaScript
"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 };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var DynamicConfig_1 = __importDefault(require("./DynamicConfig"));
var ErrorBoundary_1 = __importDefault(require("./ErrorBoundary"));
var Errors_1 = require("./Errors");
var Layer_1 = __importDefault(require("./Layer"));
var LogEvent_1 = __importDefault(require("./LogEvent"));
var StatsigIdentity_1 = __importDefault(require("./StatsigIdentity"));
var StatsigLogger_1 = __importDefault(require("./StatsigLogger"));
var StatsigNetwork_1 = __importDefault(require("./StatsigNetwork"));
var StatsigSDKOptions_1 = __importDefault(require("./StatsigSDKOptions"));
var StatsigStore_1 = __importDefault(require("./StatsigStore"));
var EvaluationReason_1 = require("./utils/EvaluationReason");
var Hashing_1 = require("./utils/Hashing");
var StatsigAsyncStorage_1 = __importDefault(require("./utils/StatsigAsyncStorage"));
var StatsigLocalStorage_1 = __importDefault(require("./utils/StatsigLocalStorage"));
var Diagnostics_1 = __importDefault(require("./utils/Diagnostics"));
var ConsoleLogger_1 = __importDefault(require("./utils/ConsoleLogger"));
var Timing_1 = require("./utils/Timing");
var ResponseVerification_1 = require("./utils/ResponseVerification");
var MAX_VALUE_SIZE = 64;
var MAX_OBJ_SIZE = 2048;
var StatsigClient = /** @class */ (function () {
function StatsigClient(sdkKey, user, options) {
var _this = this;
this.appState = null;
this.currentAppState = null;
this.onCacheLoadedForReact = null;
this.initCalled = false;
this.pendingInitPromise = null;
this.optionalLoggingSetup = false;
this.prefetchedUsersByCacheKey = {};
this.logLayerParameterExposureForLayer = function (layer, parameterName, isManualExposure) {
if (isManualExposure === void 0) { isManualExposure = false; }
var allocatedExperiment = '';
var exposures = layer._getUndelegatedSecondaryExposures();
var isExplicit = layer._getExplicitParameters().includes(parameterName);
if (isExplicit) {
allocatedExperiment = layer._getAllocatedExperimentName();
exposures = layer._getSecondaryExposures();
}
_this.logger.logLayerExposure(_this.getCurrentUser(), layer.getName(), layer.getRuleID(), exposures, allocatedExperiment, parameterName, isExplicit, layer._getEvaluationDetails(), isManualExposure);
};
if ((options === null || options === void 0 ? void 0 : options.localMode) !== true &&
(typeof sdkKey !== 'string' || !sdkKey.startsWith('client-'))) {
throw new Errors_1.StatsigInvalidArgumentError('Invalid key provided. You must use a Client SDK Key from the Statsig console to initialize the sdk');
}
this.startTime = (0, Timing_1.now)();
this.options = new StatsigSDKOptions_1.default(options);
this.logger = new StatsigLogger_1.default(this);
Diagnostics_1.default.initialize({
options: this.options,
});
this.errorBoundary = new ErrorBoundary_1.default(sdkKey, this.options);
this.ready = false;
this.sdkKey = sdkKey;
this.consoleLogger = new ConsoleLogger_1.default(this.options.getLogLevel());
StatsigLocalStorage_1.default.disabled = this.options.getDisableLocalStorage();
this.identity = new StatsigIdentity_1.default(this.normalizeUser(user !== null && user !== void 0 ? user : null), this.options.getOverrideStableID(), StatsigClient.reactNativeUUID);
this.network = new StatsigNetwork_1.default(this);
this.store = new StatsigStore_1.default(this, this.options.getInitializeValues());
this.errorBoundary.setStatsigMetadata(this.getStatsigMetadata());
if (this.options.getInitializeValues() != null) {
var cb = this.options.getInitCompletionCallback();
this.ready = true;
this.initCalled = true;
setTimeout(function () { return _this.delayedSetup(); }, 20);
this.handleOptionalLogging();
if (cb) {
cb((0, Timing_1.now)() - this.startTime, true, null);
}
}
}
StatsigClient.prototype.getErrorBoundary = function () {
return this.errorBoundary;
};
StatsigClient.prototype.getNetwork = function () {
return this.network;
};
StatsigClient.prototype.getStore = function () {
return this.store;
};
StatsigClient.prototype.getLogger = function () {
return this.logger;
};
StatsigClient.prototype.getOptions = function () {
return this.options;
};
StatsigClient.prototype.getSDKKey = function () {
var _this = this;
return this.errorBoundary.capture('getSDKKey', function () {
var _a;
return (_a = _this.sdkKey) !== null && _a !== void 0 ? _a : '';
}, function () { return ''; });
};
StatsigClient.prototype.getCurrentUser = function () {
var _this = this;
return this.errorBoundary.capture('getCurrentUser', function () { return _this.identity.getUser(); }, function () { return null; });
};
StatsigClient.prototype.getCurrentUserCacheKey = function () {
var _this = this;
return this.errorBoundary.capture('getCurrentUserCacheKey', function () {
return (0, Hashing_1.getUserCacheKey)(_this.getStableID(), _this.getCurrentUser(), _this.getSDKKey());
}, function () { return ({ v1: '', v2: '', v3: '' }); });
};
StatsigClient.prototype.getCurrentUserUnitID = function (idType) {
var _this = this;
return this.errorBoundary.capture('getCurrentUserUnitID', function () { return _this.getUnitID(_this.getCurrentUser(), idType); }, function () { return ''; });
};
StatsigClient.prototype.getCurrentUserID = function () {
var _this = this;
return this.errorBoundary.capture('getCurrentUserID', function () { return _this.getUnitID(_this.getCurrentUser(), 'userid'); }, function () { return ''; });
};
StatsigClient.prototype.getUnitID = function (user, idType) {
var _a, _b, _c;
if (!user) {
return null;
}
if (idType.toLowerCase() === 'userid') {
return (_b = (_a = user.userID) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : null;
}
if (user.customIDs) {
return (_c = user.customIDs[idType]) !== null && _c !== void 0 ? _c : user.customIDs[idType.toLowerCase()];
}
return null;
};
StatsigClient.prototype.getStatsigMetadata = function () {
var _this = this;
return this.errorBoundary.capture('getStatsigMetadata', function () { return _this.identity.getStatsigMetadata(); }, function () {
return {};
});
};
StatsigClient.prototype.getSDKType = function () {
var _this = this;
return this.errorBoundary.capture('getSDKType', function () { return _this.identity.getSDKType(); }, function () { return ''; });
};
StatsigClient.prototype.getSDKVersion = function () {
var _this = this;
return this.errorBoundary.capture('getSDKVersion', function () { return _this.identity.getSDKVersion(); }, function () { return ''; });
};
StatsigClient.prototype.getConsoleLogger = function () {
return this.consoleLogger;
};
StatsigClient.prototype.delayedSetup = function () {
var _this = this;
this.errorBoundary.swallow('delayedSetup', function () {
if (_this.options.getInitializeValues() != null) {
_this.fireAndForgetPrefechUsers();
}
_this.identity.saveStableID();
_this.logger
.sendSavedRequests()
.catch(function (reason) {
return _this.errorBoundary.logError('sendSavedRequests:delayedSetup', reason);
});
});
};
StatsigClient.prototype.setInitializeValues = function (initializeValues) {
var _this = this;
this.errorBoundary.capture('setInitializeValues', function () {
_this.store.bootstrap(initializeValues);
var cb = null;
if (!_this.ready) {
// the sdk is usable and considered initialized when configured
// with initializeValues
_this.ready = true;
_this.initCalled = true;
// only callback on the first time initialize values are set and the
// sdk is usable
cb = _this.options.getInitCompletionCallback();
}
// we wont have access to window/document/localStorage if these run on the server
// so try to run whenever this is called
_this.handleOptionalLogging();
_this.logger
.sendSavedRequests()
.catch(function (reason) {
return _this.errorBoundary.logError('sendSavedRequests:setInitializeValues', reason);
});
if (cb) {
cb((0, Timing_1.now)() - _this.startTime, true, null);
}
}, function () {
_this.ready = true;
_this.initCalled = true;
var cb = _this.options.getInitCompletionCallback();
if (cb) {
cb((0, Timing_1.now)() - _this.startTime, false, 'Caught an exception during setInitializeValues');
}
});
};
StatsigClient.prototype.initializeAsync = function () {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
return [2 /*return*/, this.errorBoundary.capture('initializeAsync', function () { return __awaiter(_this, void 0, void 0, function () {
var user;
var _this = this;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (this.pendingInitPromise != null) {
return [2 /*return*/, this.pendingInitPromise];
}
if (this.ready) {
return [2 /*return*/, Promise.resolve()];
}
Diagnostics_1.default.mark.overall.start({});
this.initCalled = true;
if (!StatsigAsyncStorage_1.default.asyncStorage) return [3 /*break*/, 3];
return [4 /*yield*/, this.identity.initAsync()];
case 1:
_b.sent();
return [4 /*yield*/, this.store.loadAsync()];
case 2:
_b.sent();
_b.label = 3;
case 3:
(_a = this.onCacheLoadedForReact) === null || _a === void 0 ? void 0 : _a.call(this);
if (this.appState &&
this.appState.addEventListener &&
typeof this.appState.addEventListener === 'function') {
this.currentAppState = this.appState.currentState;
this.appState.addEventListener('change', this.handleAppStateChange.bind(this));
}
if (this.options.getLocalModeEnabled()) {
return [2 /*return*/, Promise.resolve()];
}
user = this.identity.getUser();
this.pendingInitPromise = this.fetchAndSaveValues({
user: user,
prefetchUsers: this.options.getPrefetchUsers(),
timeout: this.options.getInitTimeoutMs(),
})
.then(function () {
Diagnostics_1.default.mark.overall.end({
success: true,
evaluationDetails: _this.store.getGlobalEvaluationDetails(),
});
return { success: true, message: null };
})
.catch(function (e) {
var _a;
_this.errorBoundary.logError('initializeAsync:fetchAndSaveValues', e);
Diagnostics_1.default.mark.overall.end({
success: false,
error: Diagnostics_1.default.formatError(e),
evaluationDetails: _this.store.getGlobalEvaluationDetails(),
});
return { success: false, message: (_a = e.message) !== null && _a !== void 0 ? _a : null };
})
.then(function (_a) {
var success = _a.success, message = _a.message;
var cb = _this.options.getInitCompletionCallback();
if (cb) {
cb((0, Timing_1.now)() - _this.startTime, success, message);
}
return;
})
.finally(function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
this.pendingInitPromise = null;
this.ready = true;
this.delayedSetup();
this.logger.logDiagnostics(user, 'initialize');
return [2 /*return*/];
});
}); });
this.handleOptionalLogging();
return [2 /*return*/, this.pendingInitPromise];
}
});
}); }, function () {
_this.ready = true;
_this.initCalled = true;
return Promise.resolve();
})];
});
});
};
StatsigClient.prototype.prefetchUsers = function (users) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
return [2 /*return*/, this.errorBoundary.capture('prefetchUsers', function () {
if (!users || users.length == 0) {
return;
}
return _this.fetchAndSaveValues({
user: null,
prefetchUsers: users,
timeout: 0,
});
}, function () {
return Promise.resolve();
})];
});
});
};
StatsigClient.prototype.getEvaluationDetails = function () {
var _this = this;
return this.errorBoundary.capture('getEvaluationDetails', function () {
return _this.store.getGlobalEvaluationDetails();
}, function () {
return {
time: Date.now(),
reason: EvaluationReason_1.EvaluationReason.Error,
};
});
};
/**
* Checks the value of a gate for the current user
* @param {string} gateName - the name of the gate to check
* @param {boolean} ignoreOverrides = false if this check should ignore local overrides
* @returns {boolean} - value of a gate for the user. Gates are "off" (return false) by default
* @throws Error if initialize() is not called first, or gateName is not a string
*/
StatsigClient.prototype.checkGate = function (gateName, ignoreOverrides) {
var _this = this;
if (ignoreOverrides === void 0) { ignoreOverrides = false; }
return this.errorBoundary.capture('checkGate', function () {
var result = _this.checkGateImpl(gateName, ignoreOverrides);
_this.logGateExposureImpl(gateName, result);
var cb = _this.options.getGateEvaluationCallback();
if (cb) {
cb(gateName, result.gate.value, {
withExposureLoggingDisabled: false,
});
}
return result.gate.value === true;
}, function () { return false; }, { configName: gateName });
};
StatsigClient.prototype.checkGateWithExposureLoggingDisabled = function (gateName, ignoreOverrides) {
var _this = this;
if (ignoreOverrides === void 0) { ignoreOverrides = false; }
return this.errorBoundary.capture('checkGateWithExposureLoggingDisabled', function () {
var result = _this.checkGateImpl(gateName, ignoreOverrides);
var cb = _this.options.getGateEvaluationCallback();
if (cb) {
cb(gateName, result.gate.value, {
withExposureLoggingDisabled: true,
});
}
return result.gate.value === true;
}, function () { return false; });
};
StatsigClient.prototype.logGateExposure = function (gateName) {
var _this = this;
this.errorBoundary.swallow('logGateExposure', function () {
_this.logGateExposureImpl(gateName);
});
};
/**
* Checks the value of a config for the current user
* @param {string} configName - the name of the config to get
* @param {boolean} ignoreOverrides = false if this check should ignore local overrides
* @returns {DynamicConfig} - value of a config for the user
* @throws Error if initialize() is not called first, or configName is not a string
*/
StatsigClient.prototype.getConfig = function (configName, ignoreOverrides) {
var _this = this;
if (ignoreOverrides === void 0) { ignoreOverrides = false; }
return this.errorBoundary.capture('getConfig', function () {
var result = _this.getConfigImpl(configName, ignoreOverrides);
_this.logConfigExposureImpl(configName, result);
return result;
}, function () { return _this.getEmptyConfig(configName); }, { configName: configName });
};
StatsigClient.prototype.getConfigWithExposureLoggingDisabled = function (configName, ignoreOverrides) {
var _this = this;
if (ignoreOverrides === void 0) { ignoreOverrides = false; }
return this.errorBoundary.capture('getConfig', function () {
return _this.getConfigImpl(configName, ignoreOverrides);
}, function () { return _this.getEmptyConfig(configName); });
};
StatsigClient.prototype.logConfigExposure = function (configName) {
var _this = this;
this.errorBoundary.swallow('logConfigExposure', function () {
_this.logConfigExposureImpl(configName);
});
};
/**
* Gets the experiment for a given user
* @param {string} experimentName - the name of the experiment to get
* @param {boolean} keepDeviceValue = false if this should use "sticky" values persisted in local storage
* @param {boolean} ignoreOverrides = false if this check should ignore local overrides
* @returns {DynamicConfig} - value of the experiment for the user, represented by a Dynamic Config object
* @throws Error if initialize() is not called first, or experimentName is not a string
*/
StatsigClient.prototype.getExperiment = function (experimentName, keepDeviceValue, ignoreOverrides) {
var _this = this;
if (keepDeviceValue === void 0) { keepDeviceValue = false; }
if (ignoreOverrides === void 0) { ignoreOverrides = false; }
return this.errorBoundary.capture('getExperiment', function () {
var result = _this.getExperimentImpl(experimentName, keepDeviceValue, ignoreOverrides);
_this.logExperimentExposureImpl(experimentName, keepDeviceValue, result);
return result;
}, function () { return _this.getEmptyConfig(experimentName); }, { configName: experimentName });
};
StatsigClient.prototype.getExperimentWithExposureLoggingDisabled = function (experimentName, keepDeviceValue, ignoreOverrides) {
var _this = this;
if (keepDeviceValue === void 0) { keepDeviceValue = false; }
if (ignoreOverrides === void 0) { ignoreOverrides = false; }
return this.errorBoundary.capture('getExperimentWithExposureLoggingDisabled', function () {
return _this.getExperimentImpl(experimentName, keepDeviceValue, ignoreOverrides);
}, function () { return _this.getEmptyConfig(experimentName); });
};
StatsigClient.prototype.logExperimentExposure = function (experimentName, keepDeviceValue) {
var _this = this;
this.errorBoundary.swallow('logExperimentExposure', function () {
_this.logExperimentExposureImpl(experimentName, keepDeviceValue);
});
};
StatsigClient.prototype.getLayer = function (layerName, keepDeviceValue) {
var _this = this;
if (keepDeviceValue === void 0) { keepDeviceValue = false; }
return this.errorBoundary.capture('getLayer', function () {
return _this.getLayerImpl(_this.logLayerParameterExposureForLayer, layerName, keepDeviceValue);
}, function () {
return Layer_1.default._create(layerName, {}, '', _this.getEvalutionDetailsForError());
}, { configName: layerName });
};
StatsigClient.prototype.getLayerWithExposureLoggingDisabled = function (layerName, keepDeviceValue) {
var _this = this;
if (keepDeviceValue === void 0) { keepDeviceValue = false; }
return this.errorBoundary.capture('getLayerWithExposureLoggingDisabled', function () {
return _this.getLayerImpl(null, layerName, keepDeviceValue);
}, function () {
return Layer_1.default._create(layerName, {}, '', _this.getEvalutionDetailsForError());
});
};
StatsigClient.prototype.logLayerParameterExposure = function (layerName, parameterName, keepDeviceValue) {
var _this = this;
if (keepDeviceValue === void 0) { keepDeviceValue = false; }
this.errorBoundary.swallow('logLayerParameterExposure', function () {
var layer = _this.getLayerImpl(null, layerName, keepDeviceValue);
_this.logLayerParameterExposureForLayer(layer, parameterName, true);
});
};
StatsigClient.prototype.logEvent = function (eventName, value, metadata) {
var _this = this;
if (value === void 0) { value = null; }
if (metadata === void 0) { metadata = null; }
this.errorBoundary.swallow('logEvent', function () {
if (!_this.logger || !_this.sdkKey) {
throw new Errors_1.StatsigUninitializedError('Must initialize() before logging events.');
}
if (typeof eventName !== 'string' || eventName.length === 0) {
_this.consoleLogger.error('Event not logged. No valid eventName passed.');
return;
}
if (_this.shouldTrimParam(eventName, MAX_VALUE_SIZE)) {
_this.consoleLogger.info('eventName is too long, trimming to ' +
MAX_VALUE_SIZE +
' characters.');
eventName = eventName.substring(0, MAX_VALUE_SIZE);
}
if (typeof value === 'string' &&
_this.shouldTrimParam(value, MAX_VALUE_SIZE)) {
_this.consoleLogger.info('value is too long, trimming to ' + MAX_VALUE_SIZE + '.');
value = value.substring(0, MAX_VALUE_SIZE);
}
if (_this.shouldTrimParam(metadata, MAX_OBJ_SIZE)) {
_this.consoleLogger.info('metadata is too big. Dropping the metadata.');
metadata = { error: 'not logged due to size too large' };
}
var event = new LogEvent_1.default(eventName);
event.setValue(value);
event.setMetadata(metadata);
event.setUser(_this.getCurrentUser());
_this.logger.log(event);
});
};
StatsigClient.prototype.updateUserWithValues = function (user, values) {
var _this = this;
// eslint-disable-next-line statsig-linter/public-methods-error-boundary
var fireCompletionCallback;
return this.errorBoundary.capture('updateUserWithValues', function () {
var updateStartTime = Date.now();
if (!_this.initializeCalled()) {
throw new Errors_1.StatsigUninitializedError('Call initialize() first.');
}
fireCompletionCallback = function (success, error) {
var cb = _this.options.getUpdateUserCompletionCallback();
cb === null || cb === void 0 ? void 0 : cb(Date.now() - updateStartTime, success, error);
};
_this.identity.updateUser(_this.normalizeUser(user));
_this.store.bootstrap(values);
fireCompletionCallback(true, null);
return true;
}, function () {
fireCompletionCallback === null || fireCompletionCallback === void 0 ? void 0 : fireCompletionCallback(false, 'Failed to update user. An unexpected error occured.');
return false;
});
};
StatsigClient.prototype.updateUser = function (user) {
return __awaiter(this, void 0, void 0, function () {
var fireCompletionCallback;
var _this = this;
return __generator(this, function (_a) {
return [2 /*return*/, this.errorBoundary.capture('updateUser', function () { return __awaiter(_this, void 0, void 0, function () {
var updateStartTime, userCacheKey, isUserPrefetched, cachedTime, currentUser;
var _this = this;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
updateStartTime = Date.now();
if (!this.initializeCalled()) {
throw new Errors_1.StatsigUninitializedError('Call initialize() first.');
}
fireCompletionCallback = function (success, error) {
var cb = _this.options.getUpdateUserCompletionCallback();
cb === null || cb === void 0 ? void 0 : cb(Date.now() - updateStartTime, success, error);
};
if (!(StatsigAsyncStorage_1.default.asyncStorage &&
((_a = this.identity.getStatsigMetadata().stableID) !== null && _a !== void 0 ? _a : '') == '')) return [3 /*break*/, 2];
return [4 /*yield*/, this.identity.initAsync()];
case 1:
_b.sent();
_b.label = 2;
case 2:
this.identity.updateUser(this.normalizeUser(user));
userCacheKey = this.getCurrentUserCacheKey();
isUserPrefetched = Boolean(this.prefetchedUsersByCacheKey[userCacheKey.v3]);
cachedTime = this.store.updateUser(isUserPrefetched);
Diagnostics_1.default.clearContext('api_call');
this.logger.resetDedupeKeys();
if (cachedTime != null &&
(isUserPrefetched || this.isCacheValidForFetchMode(cachedTime))) {
fireCompletionCallback(true, null);
return [2 /*return*/, Promise.resolve(true)];
}
if (!(this.pendingInitPromise != null)) return [3 /*break*/, 4];
return [4 /*yield*/, this.pendingInitPromise];
case 3:
_b.sent();
_b.label = 4;
case 4:
if (this.options.getLocalModeEnabled()) {
fireCompletionCallback(true, null);
return [2 /*return*/, Promise.resolve(true)];
}
currentUser = this.identity.getUser();
this.pendingInitPromise = this.fetchAndSaveValues({
user: currentUser,
prefetchUsers: [],
timeout: undefined,
}).finally(function () {
_this.pendingInitPromise = null;
});
return [2 /*return*/, this.pendingInitPromise
.then(function () {
fireCompletionCallback(true, null);
return Promise.resolve(true);
})
.catch(function (error) {
fireCompletionCallback(false, "Failed to update user: " + error);
return Promise.resolve(false);
})];
}
});
}); }, function () {
fireCompletionCallback === null || fireCompletionCallback === void 0 ? void 0 : fireCompletionCallback(false, 'Failed to update user. An unexpected error occured.');
return Promise.resolve(false);
})];
});
});
};
/**
* Informs the statsig SDK that the client is closing or shutting down
* so the SDK can clean up internal state
*/
StatsigClient.prototype.shutdown = function () {
var _this = this;
this.errorBoundary.swallow('shutdown', function () {
_this.logger.shutdown();
if (_this.appState &&
_this.appState.removeEventListener &&
typeof _this.appState.removeEventListener === 'function') {
_this.appState.removeEventListener('change', _this.handleAppStateChange.bind(_this));
}
StatsigLocalStorage_1.default.cleanup();
});
};
StatsigClient.prototype.getInitializeResponseJson = function () {
var _this = this;
return this.errorBoundary.capture('getInitializeResponseJson', function () {
var _a;
return {
values: _this.store.getInitializeResponseJson(),
evaluationDetails: (_a = _this.getEvaluationDetails()) !== null && _a !== void 0 ? _a : {
reason: EvaluationReason_1.EvaluationReason.Uninitialized,
time: 0,
},
};
}, function () {
var _a;
return {
values: '',
evaluationDetails: (_a = _this.getEvaluationDetails()) !== null && _a !== void 0 ? _a : {
reason: EvaluationReason_1.EvaluationReason.Uninitialized,
time: 0,
},
};
});
};
/**
* Stores a local gate override
* @param gateName the gate to override
* @param value the value to override the gate to
*/
StatsigClient.prototype.overrideGate = function (gateName, value) {
var _this = this;
this.errorBoundary.swallow('overrideGate', function () {
_this.ensureStoreLoaded();
_this.store.overrideGate(gateName, value);
});
};
/**
* Stores a local config override
* @param configName the config to override
* @param value the json value to override the config to
*/
StatsigClient.prototype.overrideConfig = function (configName, value) {
var _this = this;
this.errorBoundary.swallow('overrideConfig', function () {
_this.ensureStoreLoaded();
_this.store.overrideConfig(configName, value);
});
};
/**
* Stores a local layer override
* @param layerName the layer to override
* @param value the json value to override the config to
*/
StatsigClient.prototype.overrideLayer = function (layerName, value) {
var _this = this;
this.errorBoundary.swallow('overrideLayer', function () {
_this.ensureStoreLoaded();
_this.store.overrideLayer(layerName, value);
});
};
/**
* Removes the given gate override
* @param gateName
*/
StatsigClient.prototype.removeGateOverride = function (gateName) {
var _this = this;
this.errorBoundary.swallow('removeGateOverride', function () {
_this.ensureStoreLoaded();
_this.store.removeGateOverride(gateName);
});
};
/**
* Removes the given config override
* @param configName
*/
StatsigClient.prototype.removeConfigOverride = function (configName) {
var _this = this;
this.errorBoundary.swallow('removeConfigOverride', function () {
_this.ensureStoreLoaded();
_this.store.removeConfigOverride(configName);
});
};
/**
* Removes the given layer override
* @param layerName
*/
StatsigClient.prototype.removeLayerOverride = function (layerName) {
var _this = this;
this.errorBoundary.swallow('removeLayerOverride', function () {
_this.ensureStoreLoaded();
_this.store.removeLayerOverride(layerName);
});
};
/**
* @deprecated - use removeGateOverride or removeConfig override
* Removes the given gate override
* @param gateName
*/
StatsigClient.prototype.removeOverride = function (gateName) {
var _this = this;
this.errorBoundary.swallow('removeOverride', function () {
_this.ensureStoreLoaded();
_this.store.removeGateOverride(gateName);
});
};
/**
* @deprecated - use getAllOverrides to get gate and config overrides
* @returns Gate overrides
*/
StatsigClient.prototype.getOverrides = function () {
var _this = this;
return this.errorBoundary.capture('getOverrides', function () {
_this.ensureStoreLoaded();
return _this.store.getAllOverrides().gates;
}, function () { return ({}); });
};
/**
* @returns The local gate and config overrides
*/
StatsigClient.prototype.getAllOverrides = function () {
var _this = this;
return this.errorBoundary.capture('getAllOverrides', function () {
_this.ensureStoreLoaded();
return _this.store.getAllOverrides();
}, function () { return ({ gates: {}, configs: {}, layers: {} }); });
};
/**
* @returns The Statsig stable ID used for device level experiments
*/
StatsigClient.prototype.getStableID = function () {
var _this = this;
return this.errorBoundary.capture('getStableID', function () { return _this.identity.getStatsigMetadata().stableID; }, function () { return ''; });
};
StatsigClient.prototype.initializeCalled = function () {
return this.initCalled;
};
// All methods below are for the statsig react native SDK internal usage only!
/* eslint-disable statsig-linter/public-methods-error-boundary */
StatsigClient.prototype.setSDKPackageInfo = function (sdkPackageInfo) {
if (sdkPackageInfo != null) {
this.identity.setSDKPackageInfo(sdkPackageInfo);
this.errorBoundary.setStatsigMetadata(this.getStatsigMetadata());
}
};
StatsigClient.setAsyncStorage = function (asyncStorage) {
if (asyncStorage != null) {
StatsigAsyncStorage_1.default.asyncStorage = asyncStorage;
}
};
StatsigClient.prototype.setOnCacheLoadedReactCallback = function (fn) {
this.onCacheLoadedForReact = fn !== null && fn !== void 0 ? fn : null;
};
StatsigClient.setReactNativeUUID = function (uuid) {
if (uuid != null) {
StatsigClient.reactNativeUUID = uuid;
}
};
StatsigClient.prototype.setAppState = function (appState) {
if (appState != null) {
this.appState = appState;
}
};
StatsigClient.prototype.setNativeModules = function (nativeModules) {
if (nativeModules != null) {
this.identity.setNativeModules(nativeModules);
}
};
StatsigClient.prototype.setPlatform = function (platform) {
if (platform != null) {
this.identity.setPlatform(platform);
}
};
StatsigClient.prototype.setRNDeviceInfo = function (deviceInfo) {
if (deviceInfo != null) {
this.identity.setRNDeviceInfo(deviceInfo);
}
};
StatsigClient.prototype.setExpoConstants = function (expoConstants) {
if (expoConstants != null) {
this.identity.setExpoConstants(expoConstants);
}
};
StatsigClient.prototype.setExpoDevice = function (expoDevice) {
if (expoDevice != null) {
this.identity.setExpoDevice(expoDevice);
}
};
StatsigClient.prototype.flushEvents = function () {
this.logger.flush();
};
StatsigClient.prototype.reenableAllLogging = function () {
this.getOptions().reenableAllLogging();
};
StatsigClient.prototype.isCacheValidForFetchMode = function (cachedTime) {
if (this.options.getFetchMode() !== 'cache-or-network') {
return false;
}
// Only valid if the cache was during this session
return cachedTime > this.startTime;
};
StatsigClient.prototype.handleOptionalLogging = function () {
var _this = this;
var isErrorLoggingDisabled = this.options.getDisableErrorLogging();
var isAutoMetricsLoggingDisabled = this.options.getDisableAutoMetricsLogging();
if (isErrorLoggingDisabled && isAutoMetricsLoggingDisabled) {
return;
}
if (this.optionalLoggingSetup ||
typeof window === 'undefined' ||
!window ||
!window.addEventListener) {
return;
}
var user = this.identity.getUser();
if (!isErrorLoggingDisabled) {
window.addEventListener('error', function (e) {
var _a;
var errorObj = e.error;
if (errorObj != null && typeof errorObj === 'object') {
try {
errorObj = JSON.stringify(errorObj);
}
catch (e) {
errorObj = 'Failed to stringify Error';
}
}
_this.logger.logAppError(user, (_a = e.message) !== null && _a !== void 0 ? _a : '', {
filename: e.filename,
lineno: e.lineno,
colno: e.colno,
error_obj: errorObj,
});
});
}
if (!isAutoMetricsLoggingDisabled) {
if (typeof document === 'undefined' ||
!document ||
typeof setTimeout === 'undefined' ||
!setTimeout) {
return;
}
var work_1 = function () {
setTimeout(function () {
_this.logger.logAppMetrics(user);
}, 1000);
};
if (document.readyState === 'complete') {
work_1();
}
else {
window.addEventListener('load', function () { return work_1(); });
}
}
this.optionalLoggingSetup = true;
};
StatsigClient.prototype.handleAppStateChange = function (nextAppState) {
var _this = this;
var _a;
if (this.currentAppState === 'active' &&
nextAppState.match(/inactive|background/)) {
this.logger.flush(true);
}
else if (((_a = this.currentAppState) === null || _a === void 0 ? void 0 : _a.match(/inactive|background/)) &&
nextAppState === 'active') {
this.logger
.sendSavedRequests()
.catch(function (reason) {
return _this.errorBoundary.logError('sendSavedRequests:handleAppStateChange', reason);
});
}
this.currentAppState = nextAppState;
};
StatsigClient.prototype.shouldTrimParam = function (entity, size) {
if (entity == null)
return false;
if (typeof entity === 'string')
return entity.length > size;
if (typeof entity === 'object') {
return JSON.stringify(entity).length > size;
}
if (typeof entity === 'number')
return entity.toString().length > size;
return false;
};
StatsigClient.prototype.normalizePrefetchUsers = function (users) {
var _this = this;
if (users == null) {
return [];
}
return users.map(function (user) { return _this.normalizeUser(user); });
};
StatsigClient.prototype.normalizeUser = function (user) {
var userCopy = {};
try {
userCopy = JSON.parse(JSON.stringify(user));
}
catch (error) {
throw new Errors_1.StatsigInvalidArgumentError('User object must be convertable to JSON string.');
}
userCopy = this.trimUserObjIfNeeded(userCopy);
if (this.options.getEnvironment() != null) {
userCopy.statsigEnvironment = this.options.getEnvironment();
}
return userCopy;
};
StatsigClient.prototype.trimUserObjIfNeeded = function (user) {
var _a, _b;
if (user == null) {
return {};
}
if (this.shouldTrimParam((_a = user.userID) !== null && _a !== void 0 ? _a : null, MAX_VALUE_SIZE)) {
this.consoleLogger.info('User ID is too large, trimming to ' + MAX_VALUE_SIZE + 'characters');
user.userID = (_b = user.userID) === null || _b === void 0 ? void 0 : _b.toString().substring(0, MAX_VALUE_SIZE);
}
if (this.shouldTrimParam(user, MAX_OBJ_SIZE)) {
user.custom = {};
if (this.shouldTrimParam(user, MAX_OBJ_SIZE)) {
this.consoleLogger.info('User object is too large, only keeping the user ID.');
user = { userID: user.userID };
}
else {
this.consoleLogger.info('User object is too large, dropping the custom property.');
}
}
return user;
};
StatsigClient.prototype.ensureStoreLoaded = function () {
if (!this.store.isLoaded()) {
throw new Errors_1.StatsigUninitializedError('Call and wait for initialize() to finish first.');
}
};
StatsigClient.prototype.getEvalutionDetailsForError = function () {
return {
time: Date.now(),
reason: EvaluationReason_1.EvaluationReason.Error,
};
};
StatsigClient.prototype.fetchAndSaveValues = function (args) {
var _a, _b, _c, _d, _e, _f;
return __awaiter(this, void 0, void 0, function () {
var user, prefetchUsers, timeout, keyedPrefetchUsers, sinceTime, previousDerivedFields;
var _this = this;
return __generator(this, function (_g) {
user = args.user;
prefetchUsers = (_a = args.prefetchUsers) !== null && _a !== void 0 ? _a : [];
timeout = (_b = args.timeout) !== null && _b !== void 0 ? _b : this.options.getInitTimeoutMs();
if (prefetchUsers.length > 5) {
this.consoleLogger.info('Cannot prefetch more than 5 users.');
}
keyedPrefetchUsers = this.normalizePrefetchUsers(prefetchUsers)
.slice(0, 5)
.reduce(function (acc, curr) {
acc[(0, Hashing_1.getUserCacheKey)(_this.getStableID(), curr, _this.getSDKKey()).v3] =
curr;
return acc;
}, {});
sinceTime = null;
if (prefetchUsers.length === 0) {
sinceTime = this.store.getLastUpdateTime(user, String((_d = (_c = this.getStatsigMetadata()) === null || _c === void 0 ? void 0 : _c.stableID) !== null && _d !== void 0 ? _d : ''));
}
previousDerivedFields = this.store.getPreviousDerivedFields(user, String((_f = (_e = this.getStatsigMetadata()) === null || _e === void 0 ? void 0 : _e.stableID) !== null && _f !== void 0 ? _f : ''));
return [2 /*return*/, this.network
.fetchValues({
user: user,
sinceTime: sinceTime,
timeout: timeout,
useDeltas: sinceTime != null,
prefetchUsers: prefetchUsers.length > 0 ? keyedPref