@splitsoftware/splitio-commons
Version:
Split JavaScript SDK common components
206 lines (205 loc) • 8.56 kB
JavaScript
import { __extends } from "tslib";
import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
import { LOG_PREFIX } from './constants';
import { setToArray } from '../../utils/lang/sets';
/**
* ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
*/
var SplitsCacheInLocal = /** @class */ (function (_super) {
__extends(SplitsCacheInLocal, _super);
function SplitsCacheInLocal(settings, keys) {
var _this = _super.call(this) || this;
_this.keys = keys;
_this.log = settings.log;
_this.flagSetsFilter = settings.sync.__splitFiltersValidation.groupedFilters.bySet;
return _this;
}
SplitsCacheInLocal.prototype._decrementCount = function (key) {
var count = toNumber(localStorage.getItem(key)) - 1;
// @ts-expect-error
if (count > 0)
localStorage.setItem(key, count);
else
localStorage.removeItem(key);
};
SplitsCacheInLocal.prototype._decrementCounts = function (split) {
try {
var ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
this._decrementCount(ttKey);
if (usesSegments(split)) {
var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
this._decrementCount(segmentsCountKey);
}
}
catch (e) {
this.log.error(LOG_PREFIX + e);
}
};
SplitsCacheInLocal.prototype._incrementCounts = function (split) {
try {
var ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
// @ts-expect-error
localStorage.setItem(ttKey, toNumber(localStorage.getItem(ttKey)) + 1);
if (usesSegments(split)) {
var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
// @ts-expect-error
localStorage.setItem(segmentsCountKey, toNumber(localStorage.getItem(segmentsCountKey)) + 1);
}
}
catch (e) {
this.log.error(LOG_PREFIX + e);
}
};
/**
* Removes all splits cache related data from localStorage (splits, counters, changeNumber and lastUpdated).
* We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
*/
SplitsCacheInLocal.prototype.clear = function () {
// collect item keys
var len = localStorage.length;
var accum = [];
for (var cur = 0; cur < len; cur++) {
var key = localStorage.key(cur);
if (key != null && this.keys.isSplitsCacheKey(key))
accum.push(key);
}
// remove items
accum.forEach(function (key) {
localStorage.removeItem(key);
});
this.hasSync = false;
};
SplitsCacheInLocal.prototype.addSplit = function (split) {
try {
var name_1 = split.name;
var splitKey = this.keys.buildSplitKey(name_1);
var splitFromLocalStorage = localStorage.getItem(splitKey);
var previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
if (previousSplit) {
this._decrementCounts(previousSplit);
this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
}
localStorage.setItem(splitKey, JSON.stringify(split));
this._incrementCounts(split);
this.addToFlagSets(split);
return true;
}
catch (e) {
this.log.error(LOG_PREFIX + e);
return false;
}
};
SplitsCacheInLocal.prototype.removeSplit = function (name) {
try {
var split = this.getSplit(name);
if (!split)
return false;
localStorage.removeItem(this.keys.buildSplitKey(name));
this._decrementCounts(split);
this.removeFromFlagSets(split.name, split.sets);
return true;
}
catch (e) {
this.log.error(LOG_PREFIX + e);
return false;
}
};
SplitsCacheInLocal.prototype.getSplit = function (name) {
var item = localStorage.getItem(this.keys.buildSplitKey(name));
return item && JSON.parse(item);
};
SplitsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
try {
localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
// update "last updated" timestamp with current time
localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
this.hasSync = true;
return true;
}
catch (e) {
this.log.error(LOG_PREFIX + e);
return false;
}
};
SplitsCacheInLocal.prototype.getChangeNumber = function () {
var n = -1;
var value = localStorage.getItem(this.keys.buildSplitsTillKey());
if (value !== null) {
value = parseInt(value, 10);
return isNaNNumber(value) ? n : value;
}
return n;
};
SplitsCacheInLocal.prototype.getSplitNames = function () {
var len = localStorage.length;
var accum = [];
var cur = 0;
while (cur < len) {
var key = localStorage.key(cur);
if (key != null && this.keys.isSplitKey(key))
accum.push(this.keys.extractKey(key));
cur++;
}
return accum;
};
SplitsCacheInLocal.prototype.trafficTypeExists = function (trafficType) {
var ttCount = toNumber(localStorage.getItem(this.keys.buildTrafficTypeKey(trafficType)));
return isFiniteNumber(ttCount) && ttCount > 0;
};
SplitsCacheInLocal.prototype.usesSegments = function () {
// If cache hasn't been synchronized with the cloud, assume we need them.
if (!this.hasSync)
return true;
var storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
var splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
return isFiniteNumber(splitsWithSegmentsCount) ?
splitsWithSegmentsCount > 0 :
true;
};
SplitsCacheInLocal.prototype.getNamesByFlagSets = function (flagSets) {
var _this = this;
return flagSets.map(function (flagSet) {
var flagSetKey = _this.keys.buildFlagSetKey(flagSet);
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
return new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
});
};
SplitsCacheInLocal.prototype.addToFlagSets = function (featureFlag) {
var _this = this;
if (!featureFlag.sets)
return;
featureFlag.sets.forEach(function (featureFlagSet) {
if (_this.flagSetsFilter.length > 0 && !_this.flagSetsFilter.some(function (filterFlagSet) { return filterFlagSet === featureFlagSet; }))
return;
var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
var flagSetCache = new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
flagSetCache.add(featureFlag.name);
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
});
};
SplitsCacheInLocal.prototype.removeFromFlagSets = function (featureFlagName, flagSets) {
var _this = this;
if (!flagSets)
return;
flagSets.forEach(function (flagSet) {
_this.removeNames(flagSet, featureFlagName);
});
};
SplitsCacheInLocal.prototype.removeNames = function (flagSetName, featureFlagName) {
var flagSetKey = this.keys.buildFlagSetKey(flagSetName);
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
if (!flagSetFromLocalStorage)
return;
var flagSetCache = new Set(JSON.parse(flagSetFromLocalStorage));
flagSetCache.delete(featureFlagName);
if (flagSetCache.size === 0) {
localStorage.removeItem(flagSetKey);
return;
}
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
};
return SplitsCacheInLocal;
}(AbstractSplitsCacheSync));
export { SplitsCacheInLocal };