@splitsoftware/splitio-commons 2.4.2-rc.3 → 2.5.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +3 -11
- package/cjs/evaluator/convertions/index.js +9 -1
- package/cjs/evaluator/matchersTransform/index.js +2 -3
- package/cjs/sdkClient/sdkClientMethodCS.js +5 -1
- package/cjs/sdkFactory/index.js +8 -2
- package/cjs/storages/getRolloutPlan.js +69 -0
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +21 -17
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
- package/cjs/storages/inLocalStorage/index.js +13 -31
- package/cjs/storages/inLocalStorage/validateCache.js +25 -30
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
- package/cjs/storages/setRolloutPlan.js +66 -0
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +0 -2
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +0 -2
- package/cjs/sync/syncManagerOnline.js +24 -28
- package/cjs/utils/env/isLocalStorageAvailable.js +5 -28
- package/cjs/utils/inputValidation/index.js +1 -3
- package/cjs/utils/settingsValidation/index.js +4 -0
- package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
- package/esm/evaluator/convertions/index.js +7 -0
- package/esm/evaluator/matchersTransform/index.js +3 -4
- package/esm/sdkClient/sdkClientMethodCS.js +5 -1
- package/esm/sdkFactory/index.js +8 -2
- package/esm/storages/getRolloutPlan.js +65 -0
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +21 -17
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
- package/esm/storages/inLocalStorage/index.js +14 -32
- package/esm/storages/inLocalStorage/validateCache.js +25 -30
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
- package/esm/storages/setRolloutPlan.js +61 -0
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +0 -2
- package/esm/sync/polling/updaters/splitChangesUpdater.js +0 -2
- package/esm/sync/syncManagerOnline.js +24 -28
- package/esm/utils/env/isLocalStorageAvailable.js +3 -24
- package/esm/utils/inputValidation/index.js +0 -1
- package/esm/utils/settingsValidation/index.js +4 -0
- package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
- package/package.json +1 -1
- package/src/evaluator/convertions/index.ts +10 -0
- package/src/evaluator/matchersTransform/index.ts +3 -4
- package/src/sdkClient/sdkClientMethodCS.ts +7 -1
- package/src/sdkFactory/index.ts +12 -4
- package/src/storages/getRolloutPlan.ts +72 -0
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +17 -18
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +22 -19
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +37 -34
- package/src/storages/inLocalStorage/index.ts +16 -37
- package/src/storages/inLocalStorage/validateCache.ts +25 -31
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +4 -0
- package/src/storages/setRolloutPlan.ts +71 -0
- package/src/storages/types.ts +25 -23
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +2 -1
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +0 -2
- package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -3
- package/src/sync/syncManagerOnline.ts +22 -27
- package/src/types.ts +2 -35
- package/src/utils/env/isLocalStorageAvailable.ts +3 -24
- package/src/utils/inputValidation/index.ts +0 -1
- package/src/utils/settingsValidation/index.ts +4 -0
- package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
- package/types/splitio.d.ts +36 -44
- package/cjs/storages/dataLoader.js +0 -50
- package/cjs/storages/inLocalStorage/storageAdapter.js +0 -54
- package/cjs/utils/inputValidation/preloadedData.js +0 -59
- package/esm/storages/dataLoader.js +0 -46
- package/esm/storages/inLocalStorage/storageAdapter.js +0 -50
- package/esm/utils/inputValidation/preloadedData.js +0 -55
- package/src/storages/dataLoader.ts +0 -55
- package/src/storages/inLocalStorage/storageAdapter.ts +0 -62
- package/src/utils/inputValidation/preloadedData.ts +0 -57
package/CHANGES.txt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
2.5.0 (
|
|
2
|
-
- Added `
|
|
1
|
+
2.5.0 (September 9, 2025)
|
|
2
|
+
- Added `factory.getRolloutPlan()` method for standalone server-side SDKs, which returns the rollout plan snapshot from the storage.
|
|
3
|
+
- Added `initialRolloutPlan` configuration option for standalone client-side SDKs, which allows preloading the SDK storage with a snapshot of the rollout plan.
|
|
3
4
|
|
|
4
5
|
2.4.1 (June 3, 2025)
|
|
5
6
|
- Bugfix - Improved the Proxy fallback to flag spec version 1.2 to handle cases where the Proxy does not return an end-of-stream marker in 400 status code responses.
|
|
@@ -50,15 +51,6 @@
|
|
|
50
51
|
- Removed internal ponyfills for `Map` and `Set` global objects, dropping support for IE and other outdated browsers. The SDK now requires the runtime environment to support these features natively or to provide a polyfill.
|
|
51
52
|
- Removed the `sync.localhostMode` configuration option to plug the LocalhostMode module.
|
|
52
53
|
|
|
53
|
-
1.17.1 (July 25, 2025)
|
|
54
|
-
- Updated the Redis storage to avoid lazy require of the `ioredis` dependency when the SDK is initialized.
|
|
55
|
-
- Updated some transitive dependencies for vulnerability fixes.
|
|
56
|
-
- Bugfix - Enhanced HTTP client module to implement timeouts for failing requests that might otherwise remain pending indefinitely on some Fetch API implementations, pausing the SDK synchronization process.
|
|
57
|
-
- Bugfix - Properly handle rejected promises when using targeting rules with segment matchers in consumer modes (e.g., Redis and Pluggable storages).
|
|
58
|
-
- Bugfix - Sanitize the `SplitSDKMachineName` header value to avoid exceptions on HTTP/S requests when it contains non ISO-8859-1 characters (Related to issue https://github.com/splitio/javascript-client/issues/847).
|
|
59
|
-
- Bugfix - Fixed an issue with the SDK_UPDATE event on server-side, where it was not being emitted if there was an empty segment and the SDK received a feature flag update notification.
|
|
60
|
-
- Bugfix - Fixed an issue with the server-side polling manager that caused dangling timers when the SDK was destroyed before it was ready.
|
|
61
|
-
|
|
62
54
|
1.17.0 (September 6, 2024)
|
|
63
55
|
- Added `sync.requestOptions.getHeaderOverrides` configuration option to enhance SDK HTTP request Headers for Authorization Frameworks.
|
|
64
56
|
- Added `isTimedout` and `lastUpdate` properties to IStatusInterface to keep track of the timestamp of the last SDK event, used on React and Redux SDKs.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.zeroSinceSS = exports.zeroSinceHH = void 0;
|
|
3
|
+
exports.betweenDateTimeTransform = exports.zeroSinceSS = exports.zeroSinceHH = void 0;
|
|
4
4
|
function zeroSinceHH(millisSinceEpoch) {
|
|
5
5
|
return new Date(millisSinceEpoch).setUTCHours(0, 0, 0, 0);
|
|
6
6
|
}
|
|
@@ -9,3 +9,11 @@ function zeroSinceSS(millisSinceEpoch) {
|
|
|
9
9
|
return new Date(millisSinceEpoch).setUTCSeconds(0, 0);
|
|
10
10
|
}
|
|
11
11
|
exports.zeroSinceSS = zeroSinceSS;
|
|
12
|
+
function betweenDateTimeTransform(betweenMatcherData) {
|
|
13
|
+
return {
|
|
14
|
+
dataType: betweenMatcherData.dataType,
|
|
15
|
+
start: zeroSinceSS(betweenMatcherData.start),
|
|
16
|
+
end: zeroSinceSS(betweenMatcherData.end)
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
exports.betweenDateTimeTransform = betweenDateTimeTransform;
|
|
@@ -17,7 +17,7 @@ function matchersTransform(matchers) {
|
|
|
17
17
|
var type = (0, matcherTypes_1.matcherTypesMapper)(matcherType);
|
|
18
18
|
// As default input data type we use string (even for ALL_KEYS)
|
|
19
19
|
var dataType = matcherTypes_1.matcherDataTypes.STRING;
|
|
20
|
-
var value
|
|
20
|
+
var value;
|
|
21
21
|
if (type === matcherTypes_1.matcherTypes.IN_SEGMENT) {
|
|
22
22
|
value = (0, segment_1.segmentTransform)(userDefinedSegmentMatcherData);
|
|
23
23
|
}
|
|
@@ -45,8 +45,7 @@ function matchersTransform(matchers) {
|
|
|
45
45
|
value = betweenMatcherData;
|
|
46
46
|
dataType = matcherTypes_1.matcherDataTypes.NUMBER;
|
|
47
47
|
if (value.dataType === 'DATETIME') {
|
|
48
|
-
value
|
|
49
|
-
value.end = (0, convertions_1.zeroSinceSS)(value.end);
|
|
48
|
+
value = (0, convertions_1.betweenDateTimeTransform)(value);
|
|
50
49
|
dataType = matcherTypes_1.matcherDataTypes.DATETIME;
|
|
51
50
|
}
|
|
52
51
|
}
|
|
@@ -9,12 +9,13 @@ var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
|
9
9
|
var constants_1 = require("../logger/constants");
|
|
10
10
|
var constants_2 = require("../readiness/constants");
|
|
11
11
|
var identity_1 = require("./identity");
|
|
12
|
+
var setRolloutPlan_1 = require("../storages/setRolloutPlan");
|
|
12
13
|
/**
|
|
13
14
|
* Factory of client method for the client-side API variant where TT is ignored.
|
|
14
15
|
* Therefore, clients don't have a bound TT for the track method.
|
|
15
16
|
*/
|
|
16
17
|
function sdkClientMethodCSFactory(params) {
|
|
17
|
-
var clients = params.clients, storage = params.storage, syncManager = params.syncManager, sdkReadinessManager = params.sdkReadinessManager, _a = params.settings, key = _a.core.key, log = _a.log;
|
|
18
|
+
var clients = params.clients, storage = params.storage, syncManager = params.syncManager, sdkReadinessManager = params.sdkReadinessManager, _a = params.settings, key = _a.core.key, log = _a.log, initialRolloutPlan = _a.initialRolloutPlan;
|
|
18
19
|
var mainClientInstance = (0, clientCS_1.clientCSDecorator)(log, (0, sdkClient_1.sdkClientFactory)(params), key);
|
|
19
20
|
var parsedDefaultKey = (0, key_2.keyParser)(key);
|
|
20
21
|
var defaultInstanceId = (0, identity_1.buildInstanceId)(parsedDefaultKey);
|
|
@@ -42,6 +43,9 @@ function sdkClientMethodCSFactory(params) {
|
|
|
42
43
|
// Emit SDK_READY in consumer mode for shared clients
|
|
43
44
|
sharedSdkReadiness_1.readinessManager.segments.emit(constants_2.SDK_SEGMENTS_ARRIVED);
|
|
44
45
|
});
|
|
46
|
+
if (sharedStorage && initialRolloutPlan) {
|
|
47
|
+
(0, setRolloutPlan_1.setRolloutPlan)(log, initialRolloutPlan, { segments: sharedStorage.segments, largeSegments: sharedStorage.largeSegments }, matchingKey);
|
|
48
|
+
}
|
|
45
49
|
// 3 possibilities:
|
|
46
50
|
// - Standalone mode: both syncManager and sharedSyncManager are defined
|
|
47
51
|
// - Consumer mode: both syncManager and sharedSyncManager are undefined
|
package/cjs/sdkFactory/index.js
CHANGED
|
@@ -15,12 +15,14 @@ var strategyOptimized_1 = require("../trackers/strategy/strategyOptimized");
|
|
|
15
15
|
var strategyNone_1 = require("../trackers/strategy/strategyNone");
|
|
16
16
|
var uniqueKeysTracker_1 = require("../trackers/uniqueKeysTracker");
|
|
17
17
|
var constants_3 = require("../utils/constants");
|
|
18
|
+
var setRolloutPlan_1 = require("../storages/setRolloutPlan");
|
|
19
|
+
var key_1 = require("../utils/key");
|
|
18
20
|
/**
|
|
19
21
|
* Modular SDK factory
|
|
20
22
|
*/
|
|
21
23
|
function sdkFactory(params) {
|
|
22
24
|
var settings = params.settings, platform = params.platform, storageFactory = params.storageFactory, splitApiFactory = params.splitApiFactory, extraProps = params.extraProps, syncManagerFactory = params.syncManagerFactory, SignalListener = params.SignalListener, impressionsObserverFactory = params.impressionsObserverFactory, integrationsManagerFactory = params.integrationsManagerFactory, sdkManagerFactory = params.sdkManagerFactory, sdkClientMethodFactory = params.sdkClientMethodFactory, filterAdapterFactory = params.filterAdapterFactory, lazyInit = params.lazyInit;
|
|
23
|
-
var log = settings.log, impressionsMode = settings.sync.impressionsMode;
|
|
25
|
+
var log = settings.log, impressionsMode = settings.sync.impressionsMode, initialRolloutPlan = settings.initialRolloutPlan, key = settings.core.key;
|
|
24
26
|
// @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid SDK Key, etc.
|
|
25
27
|
// On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
|
|
26
28
|
// initialization
|
|
@@ -49,7 +51,11 @@ function sdkFactory(params) {
|
|
|
49
51
|
readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED);
|
|
50
52
|
}
|
|
51
53
|
});
|
|
52
|
-
|
|
54
|
+
if (initialRolloutPlan) {
|
|
55
|
+
(0, setRolloutPlan_1.setRolloutPlan)(log, initialRolloutPlan, storage, key && (0, key_1.getMatching)(key));
|
|
56
|
+
if (storage.splits.getChangeNumber() > -1)
|
|
57
|
+
readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED);
|
|
58
|
+
}
|
|
53
59
|
var clients = {};
|
|
54
60
|
var telemetryTracker = (0, telemetryTracker_1.telemetryTrackerFactory)(storage.telemetry, platform.now);
|
|
55
61
|
var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage, telemetryTracker: telemetryTracker });
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getRolloutPlan = void 0;
|
|
4
|
+
var sets_1 = require("../utils/lang/sets");
|
|
5
|
+
var key_1 = require("../utils/key");
|
|
6
|
+
/**
|
|
7
|
+
* Gets the rollout plan snapshot from the given synchronous storage.
|
|
8
|
+
*/
|
|
9
|
+
function getRolloutPlan(log, storage, options) {
|
|
10
|
+
if (options === void 0) { options = {}; }
|
|
11
|
+
var keys = options.keys, exposeSegments = options.exposeSegments;
|
|
12
|
+
var splits = storage.splits, segments = storage.segments, rbSegments = storage.rbSegments;
|
|
13
|
+
log.debug("storage: get feature flags" + (keys ? ", and memberships for keys " + keys : '') + (exposeSegments ? ', and segments' : ''));
|
|
14
|
+
return {
|
|
15
|
+
splitChanges: {
|
|
16
|
+
ff: {
|
|
17
|
+
t: splits.getChangeNumber(),
|
|
18
|
+
s: -1,
|
|
19
|
+
d: splits.getAll(),
|
|
20
|
+
},
|
|
21
|
+
rbs: {
|
|
22
|
+
t: rbSegments.getChangeNumber(),
|
|
23
|
+
s: -1,
|
|
24
|
+
d: rbSegments.getAll(),
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
segmentChanges: exposeSegments ? // @ts-ignore accessing private prop
|
|
28
|
+
Object.keys(segments.segmentCache).map(function (segmentName) { return ({
|
|
29
|
+
name: segmentName,
|
|
30
|
+
added: (0, sets_1.setToArray)(segments.segmentCache[segmentName]),
|
|
31
|
+
removed: [],
|
|
32
|
+
since: -1,
|
|
33
|
+
till: segments.getChangeNumber(segmentName)
|
|
34
|
+
}); }) :
|
|
35
|
+
undefined,
|
|
36
|
+
memberships: keys ?
|
|
37
|
+
keys.reduce(function (prev, key) {
|
|
38
|
+
var matchingKey = (0, key_1.getMatching)(key);
|
|
39
|
+
if (storage.shared) { // Client-side segments
|
|
40
|
+
var sharedStorage = storage.shared(matchingKey);
|
|
41
|
+
prev[matchingKey] = {
|
|
42
|
+
ms: {
|
|
43
|
+
k: Object.keys(sharedStorage.segments.segmentCache).map(function (segmentName) { return ({ n: segmentName }); }),
|
|
44
|
+
},
|
|
45
|
+
ls: sharedStorage.largeSegments ? {
|
|
46
|
+
k: Object.keys(sharedStorage.largeSegments.segmentCache).map(function (segmentName) { return ({ n: segmentName }); }),
|
|
47
|
+
} : undefined
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
else { // Server-side segments
|
|
51
|
+
prev[matchingKey] = {
|
|
52
|
+
ms: {
|
|
53
|
+
k: Object.keys(storage.segments.segmentCache).reduce(function (prev, segmentName) {
|
|
54
|
+
return storage.segments.segmentCache[segmentName].has(matchingKey) ?
|
|
55
|
+
prev.concat({ n: segmentName }) :
|
|
56
|
+
prev;
|
|
57
|
+
}, [])
|
|
58
|
+
},
|
|
59
|
+
ls: {
|
|
60
|
+
k: []
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return prev;
|
|
65
|
+
}, {}) :
|
|
66
|
+
undefined
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
exports.getRolloutPlan = getRolloutPlan;
|
|
@@ -7,20 +7,19 @@ var AbstractMySegmentsCacheSync_1 = require("../AbstractMySegmentsCacheSync");
|
|
|
7
7
|
var constants_1 = require("./constants");
|
|
8
8
|
var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
9
9
|
(0, tslib_1.__extends)(MySegmentsCacheInLocal, _super);
|
|
10
|
-
function MySegmentsCacheInLocal(log, keys
|
|
10
|
+
function MySegmentsCacheInLocal(log, keys) {
|
|
11
11
|
var _this = _super.call(this) || this;
|
|
12
12
|
_this.log = log;
|
|
13
13
|
_this.keys = keys;
|
|
14
|
-
_this.storage = storage;
|
|
15
14
|
return _this;
|
|
16
15
|
// There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
|
|
17
16
|
}
|
|
18
17
|
MySegmentsCacheInLocal.prototype.addSegment = function (name) {
|
|
19
18
|
var segmentKey = this.keys.buildSegmentNameKey(name);
|
|
20
19
|
try {
|
|
21
|
-
if (
|
|
20
|
+
if (localStorage.getItem(segmentKey) === constants_1.DEFINED)
|
|
22
21
|
return false;
|
|
23
|
-
|
|
22
|
+
localStorage.setItem(segmentKey, constants_1.DEFINED);
|
|
24
23
|
return true;
|
|
25
24
|
}
|
|
26
25
|
catch (e) {
|
|
@@ -31,9 +30,9 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
31
30
|
MySegmentsCacheInLocal.prototype.removeSegment = function (name) {
|
|
32
31
|
var segmentKey = this.keys.buildSegmentNameKey(name);
|
|
33
32
|
try {
|
|
34
|
-
if (
|
|
33
|
+
if (localStorage.getItem(segmentKey) !== constants_1.DEFINED)
|
|
35
34
|
return false;
|
|
36
|
-
|
|
35
|
+
localStorage.removeItem(segmentKey);
|
|
37
36
|
return true;
|
|
38
37
|
}
|
|
39
38
|
catch (e) {
|
|
@@ -42,16 +41,17 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
42
41
|
}
|
|
43
42
|
};
|
|
44
43
|
MySegmentsCacheInLocal.prototype.isInSegment = function (name) {
|
|
45
|
-
return
|
|
44
|
+
return localStorage.getItem(this.keys.buildSegmentNameKey(name)) === constants_1.DEFINED;
|
|
46
45
|
};
|
|
47
46
|
MySegmentsCacheInLocal.prototype.getRegisteredSegments = function () {
|
|
48
|
-
var
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
var _this = this;
|
|
48
|
+
// Scan current values from localStorage
|
|
49
|
+
return Object.keys(localStorage).reduce(function (accum, key) {
|
|
50
|
+
var segmentName = _this.keys.extractSegmentName(key);
|
|
51
51
|
if (segmentName)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
accum.push(segmentName);
|
|
53
|
+
return accum;
|
|
54
|
+
}, []);
|
|
55
55
|
};
|
|
56
56
|
MySegmentsCacheInLocal.prototype.getKeysCount = function () {
|
|
57
57
|
return 1;
|
|
@@ -59,9 +59,9 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
59
59
|
MySegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
60
60
|
try {
|
|
61
61
|
if (changeNumber)
|
|
62
|
-
|
|
62
|
+
localStorage.setItem(this.keys.buildTillKey(), changeNumber + '');
|
|
63
63
|
else
|
|
64
|
-
|
|
64
|
+
localStorage.removeItem(this.keys.buildTillKey());
|
|
65
65
|
}
|
|
66
66
|
catch (e) {
|
|
67
67
|
this.log.error(e);
|
|
@@ -69,7 +69,7 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
69
69
|
};
|
|
70
70
|
MySegmentsCacheInLocal.prototype.getChangeNumber = function () {
|
|
71
71
|
var n = -1;
|
|
72
|
-
var value =
|
|
72
|
+
var value = localStorage.getItem(this.keys.buildTillKey());
|
|
73
73
|
if (value !== null) {
|
|
74
74
|
value = parseInt(value, 10);
|
|
75
75
|
return (0, lang_1.isNaNNumber)(value) ? n : value;
|
|
@@ -6,15 +6,14 @@ var sets_1 = require("../../utils/lang/sets");
|
|
|
6
6
|
var AbstractSplitsCacheSync_1 = require("../AbstractSplitsCacheSync");
|
|
7
7
|
var constants_1 = require("./constants");
|
|
8
8
|
var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
9
|
-
function RBSegmentsCacheInLocal(settings, keys
|
|
9
|
+
function RBSegmentsCacheInLocal(settings, keys) {
|
|
10
10
|
this.keys = keys;
|
|
11
11
|
this.log = settings.log;
|
|
12
|
-
this.storage = storage;
|
|
13
12
|
}
|
|
14
13
|
RBSegmentsCacheInLocal.prototype.clear = function () {
|
|
15
14
|
var _this = this;
|
|
16
15
|
this.getNames().forEach(function (name) { return _this.remove(name); });
|
|
17
|
-
|
|
16
|
+
localStorage.removeItem(this.keys.buildRBSegmentsTillKey());
|
|
18
17
|
};
|
|
19
18
|
RBSegmentsCacheInLocal.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
20
19
|
var _this = this;
|
|
@@ -24,8 +23,8 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
24
23
|
};
|
|
25
24
|
RBSegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
26
25
|
try {
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
localStorage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
|
|
27
|
+
localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
|
|
29
28
|
}
|
|
30
29
|
catch (e) {
|
|
31
30
|
this.log.error(constants_1.LOG_PREFIX + e);
|
|
@@ -33,19 +32,20 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
33
32
|
};
|
|
34
33
|
RBSegmentsCacheInLocal.prototype.updateSegmentCount = function (diff) {
|
|
35
34
|
var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
|
|
36
|
-
var count = (0, lang_1.toNumber)(
|
|
35
|
+
var count = (0, lang_1.toNumber)(localStorage.getItem(segmentsCountKey)) + diff;
|
|
36
|
+
// @ts-expect-error
|
|
37
37
|
if (count > 0)
|
|
38
|
-
|
|
38
|
+
localStorage.setItem(segmentsCountKey, count);
|
|
39
39
|
else
|
|
40
|
-
|
|
40
|
+
localStorage.removeItem(segmentsCountKey);
|
|
41
41
|
};
|
|
42
42
|
RBSegmentsCacheInLocal.prototype.add = function (rbSegment) {
|
|
43
43
|
try {
|
|
44
44
|
var name_1 = rbSegment.name;
|
|
45
45
|
var rbSegmentKey = this.keys.buildRBSegmentKey(name_1);
|
|
46
|
-
var
|
|
47
|
-
var previous =
|
|
48
|
-
|
|
46
|
+
var rbSegmentFromLocalStorage = localStorage.getItem(rbSegmentKey);
|
|
47
|
+
var previous = rbSegmentFromLocalStorage ? JSON.parse(rbSegmentFromLocalStorage) : null;
|
|
48
|
+
localStorage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
|
|
49
49
|
var usesSegmentsDiff = 0;
|
|
50
50
|
if (previous && (0, AbstractSplitsCacheSync_1.usesSegments)(previous))
|
|
51
51
|
usesSegmentsDiff--;
|
|
@@ -65,7 +65,7 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
65
65
|
var rbSegment = this.get(name);
|
|
66
66
|
if (!rbSegment)
|
|
67
67
|
return false;
|
|
68
|
-
|
|
68
|
+
localStorage.removeItem(this.keys.buildRBSegmentKey(name));
|
|
69
69
|
if ((0, AbstractSplitsCacheSync_1.usesSegments)(rbSegment))
|
|
70
70
|
this.updateSegmentCount(-1);
|
|
71
71
|
return true;
|
|
@@ -76,11 +76,11 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
76
76
|
}
|
|
77
77
|
};
|
|
78
78
|
RBSegmentsCacheInLocal.prototype.getNames = function () {
|
|
79
|
-
var len =
|
|
79
|
+
var len = localStorage.length;
|
|
80
80
|
var accum = [];
|
|
81
81
|
var cur = 0;
|
|
82
82
|
while (cur < len) {
|
|
83
|
-
var key =
|
|
83
|
+
var key = localStorage.key(cur);
|
|
84
84
|
if (key != null && this.keys.isRBSegmentKey(key))
|
|
85
85
|
accum.push(this.keys.extractKey(key));
|
|
86
86
|
cur++;
|
|
@@ -88,9 +88,13 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
88
88
|
return accum;
|
|
89
89
|
};
|
|
90
90
|
RBSegmentsCacheInLocal.prototype.get = function (name) {
|
|
91
|
-
var item =
|
|
91
|
+
var item = localStorage.getItem(this.keys.buildRBSegmentKey(name));
|
|
92
92
|
return item && JSON.parse(item);
|
|
93
93
|
};
|
|
94
|
+
RBSegmentsCacheInLocal.prototype.getAll = function () {
|
|
95
|
+
var _this = this;
|
|
96
|
+
return this.getNames().map(function (key) { return _this.get(key); });
|
|
97
|
+
};
|
|
94
98
|
RBSegmentsCacheInLocal.prototype.contains = function (names) {
|
|
95
99
|
var namesArray = (0, sets_1.setToArray)(names);
|
|
96
100
|
var namesInStorage = this.getNames();
|
|
@@ -98,7 +102,7 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
98
102
|
};
|
|
99
103
|
RBSegmentsCacheInLocal.prototype.getChangeNumber = function () {
|
|
100
104
|
var n = -1;
|
|
101
|
-
var value =
|
|
105
|
+
var value = localStorage.getItem(this.keys.buildRBSegmentsTillKey());
|
|
102
106
|
if (value !== null) {
|
|
103
107
|
value = parseInt(value, 10);
|
|
104
108
|
return (0, lang_1.isNaNNumber)(value) ? n : value;
|
|
@@ -106,7 +110,7 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
106
110
|
return n;
|
|
107
111
|
};
|
|
108
112
|
RBSegmentsCacheInLocal.prototype.usesSegments = function () {
|
|
109
|
-
var storedCount =
|
|
113
|
+
var storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
|
|
110
114
|
var splitsWithSegmentsCount = storedCount === null ? 0 : (0, lang_1.toNumber)(storedCount);
|
|
111
115
|
return (0, lang_1.isFiniteNumber)(splitsWithSegmentsCount) ?
|
|
112
116
|
splitsWithSegmentsCount > 0 :
|
|
@@ -6,22 +6,25 @@ var AbstractSplitsCacheSync_1 = require("../AbstractSplitsCacheSync");
|
|
|
6
6
|
var lang_1 = require("../../utils/lang");
|
|
7
7
|
var constants_1 = require("./constants");
|
|
8
8
|
var sets_1 = require("../../utils/lang/sets");
|
|
9
|
+
/**
|
|
10
|
+
* ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
|
|
11
|
+
*/
|
|
9
12
|
var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
10
13
|
(0, tslib_1.__extends)(SplitsCacheInLocal, _super);
|
|
11
|
-
function SplitsCacheInLocal(settings, keys
|
|
14
|
+
function SplitsCacheInLocal(settings, keys) {
|
|
12
15
|
var _this = _super.call(this) || this;
|
|
13
16
|
_this.keys = keys;
|
|
14
17
|
_this.log = settings.log;
|
|
15
18
|
_this.flagSetsFilter = settings.sync.__splitFiltersValidation.groupedFilters.bySet;
|
|
16
|
-
_this.storage = storage;
|
|
17
19
|
return _this;
|
|
18
20
|
}
|
|
19
21
|
SplitsCacheInLocal.prototype._decrementCount = function (key) {
|
|
20
|
-
var count = (0, lang_1.toNumber)(
|
|
22
|
+
var count = (0, lang_1.toNumber)(localStorage.getItem(key)) - 1;
|
|
23
|
+
// @ts-expect-error
|
|
21
24
|
if (count > 0)
|
|
22
|
-
|
|
25
|
+
localStorage.setItem(key, count);
|
|
23
26
|
else
|
|
24
|
-
|
|
27
|
+
localStorage.removeItem(key);
|
|
25
28
|
};
|
|
26
29
|
SplitsCacheInLocal.prototype._decrementCounts = function (split) {
|
|
27
30
|
try {
|
|
@@ -39,10 +42,12 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
39
42
|
SplitsCacheInLocal.prototype._incrementCounts = function (split) {
|
|
40
43
|
try {
|
|
41
44
|
var ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
|
|
42
|
-
|
|
45
|
+
// @ts-expect-error
|
|
46
|
+
localStorage.setItem(ttKey, (0, lang_1.toNumber)(localStorage.getItem(ttKey)) + 1);
|
|
43
47
|
if ((0, AbstractSplitsCacheSync_1.usesSegments)(split)) {
|
|
44
48
|
var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
|
|
45
|
-
|
|
49
|
+
// @ts-expect-error
|
|
50
|
+
localStorage.setItem(segmentsCountKey, (0, lang_1.toNumber)(localStorage.getItem(segmentsCountKey)) + 1);
|
|
46
51
|
}
|
|
47
52
|
}
|
|
48
53
|
catch (e) {
|
|
@@ -54,18 +59,17 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
54
59
|
* We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
|
|
55
60
|
*/
|
|
56
61
|
SplitsCacheInLocal.prototype.clear = function () {
|
|
57
|
-
var _this = this;
|
|
58
62
|
// collect item keys
|
|
59
|
-
var len =
|
|
63
|
+
var len = localStorage.length;
|
|
60
64
|
var accum = [];
|
|
61
65
|
for (var cur = 0; cur < len; cur++) {
|
|
62
|
-
var key =
|
|
66
|
+
var key = localStorage.key(cur);
|
|
63
67
|
if (key != null && this.keys.isSplitsCacheKey(key))
|
|
64
68
|
accum.push(key);
|
|
65
69
|
}
|
|
66
70
|
// remove items
|
|
67
71
|
accum.forEach(function (key) {
|
|
68
|
-
|
|
72
|
+
localStorage.removeItem(key);
|
|
69
73
|
});
|
|
70
74
|
this.hasSync = false;
|
|
71
75
|
};
|
|
@@ -73,13 +77,13 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
73
77
|
try {
|
|
74
78
|
var name_1 = split.name;
|
|
75
79
|
var splitKey = this.keys.buildSplitKey(name_1);
|
|
76
|
-
var
|
|
77
|
-
var previousSplit =
|
|
80
|
+
var splitFromLocalStorage = localStorage.getItem(splitKey);
|
|
81
|
+
var previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
|
|
78
82
|
if (previousSplit) {
|
|
79
83
|
this._decrementCounts(previousSplit);
|
|
80
84
|
this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
81
85
|
}
|
|
82
|
-
|
|
86
|
+
localStorage.setItem(splitKey, JSON.stringify(split));
|
|
83
87
|
this._incrementCounts(split);
|
|
84
88
|
this.addToFlagSets(split);
|
|
85
89
|
return true;
|
|
@@ -94,7 +98,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
94
98
|
var split = this.getSplit(name);
|
|
95
99
|
if (!split)
|
|
96
100
|
return false;
|
|
97
|
-
|
|
101
|
+
localStorage.removeItem(this.keys.buildSplitKey(name));
|
|
98
102
|
this._decrementCounts(split);
|
|
99
103
|
this.removeFromFlagSets(split.name, split.sets);
|
|
100
104
|
return true;
|
|
@@ -105,14 +109,14 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
105
109
|
}
|
|
106
110
|
};
|
|
107
111
|
SplitsCacheInLocal.prototype.getSplit = function (name) {
|
|
108
|
-
var item =
|
|
112
|
+
var item = localStorage.getItem(this.keys.buildSplitKey(name));
|
|
109
113
|
return item && JSON.parse(item);
|
|
110
114
|
};
|
|
111
115
|
SplitsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
112
116
|
try {
|
|
113
|
-
|
|
117
|
+
localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
|
|
114
118
|
// update "last updated" timestamp with current time
|
|
115
|
-
|
|
119
|
+
localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
|
|
116
120
|
this.hasSync = true;
|
|
117
121
|
return true;
|
|
118
122
|
}
|
|
@@ -123,7 +127,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
123
127
|
};
|
|
124
128
|
SplitsCacheInLocal.prototype.getChangeNumber = function () {
|
|
125
129
|
var n = -1;
|
|
126
|
-
var value =
|
|
130
|
+
var value = localStorage.getItem(this.keys.buildSplitsTillKey());
|
|
127
131
|
if (value !== null) {
|
|
128
132
|
value = parseInt(value, 10);
|
|
129
133
|
return (0, lang_1.isNaNNumber)(value) ? n : value;
|
|
@@ -131,11 +135,11 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
131
135
|
return n;
|
|
132
136
|
};
|
|
133
137
|
SplitsCacheInLocal.prototype.getSplitNames = function () {
|
|
134
|
-
var len =
|
|
138
|
+
var len = localStorage.length;
|
|
135
139
|
var accum = [];
|
|
136
140
|
var cur = 0;
|
|
137
141
|
while (cur < len) {
|
|
138
|
-
var key =
|
|
142
|
+
var key = localStorage.key(cur);
|
|
139
143
|
if (key != null && this.keys.isSplitKey(key))
|
|
140
144
|
accum.push(this.keys.extractKey(key));
|
|
141
145
|
cur++;
|
|
@@ -143,14 +147,14 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
143
147
|
return accum;
|
|
144
148
|
};
|
|
145
149
|
SplitsCacheInLocal.prototype.trafficTypeExists = function (trafficType) {
|
|
146
|
-
var ttCount = (0, lang_1.toNumber)(
|
|
150
|
+
var ttCount = (0, lang_1.toNumber)(localStorage.getItem(this.keys.buildTrafficTypeKey(trafficType)));
|
|
147
151
|
return (0, lang_1.isFiniteNumber)(ttCount) && ttCount > 0;
|
|
148
152
|
};
|
|
149
153
|
SplitsCacheInLocal.prototype.usesSegments = function () {
|
|
150
154
|
// If cache hasn't been synchronized with the cloud, assume we need them.
|
|
151
155
|
if (!this.hasSync)
|
|
152
156
|
return true;
|
|
153
|
-
var storedCount =
|
|
157
|
+
var storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
|
|
154
158
|
var splitsWithSegmentsCount = storedCount === null ? 0 : (0, lang_1.toNumber)(storedCount);
|
|
155
159
|
return (0, lang_1.isFiniteNumber)(splitsWithSegmentsCount) ?
|
|
156
160
|
splitsWithSegmentsCount > 0 :
|
|
@@ -160,8 +164,8 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
160
164
|
var _this = this;
|
|
161
165
|
return flagSets.map(function (flagSet) {
|
|
162
166
|
var flagSetKey = _this.keys.buildFlagSetKey(flagSet);
|
|
163
|
-
var
|
|
164
|
-
return new Set(
|
|
167
|
+
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
168
|
+
return new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
165
169
|
});
|
|
166
170
|
};
|
|
167
171
|
SplitsCacheInLocal.prototype.addToFlagSets = function (featureFlag) {
|
|
@@ -172,10 +176,10 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
172
176
|
if (_this.flagSetsFilter.length > 0 && !_this.flagSetsFilter.some(function (filterFlagSet) { return filterFlagSet === featureFlagSet; }))
|
|
173
177
|
return;
|
|
174
178
|
var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
|
|
175
|
-
var
|
|
176
|
-
var flagSetCache = new Set(
|
|
179
|
+
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
180
|
+
var flagSetCache = new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
177
181
|
flagSetCache.add(featureFlag.name);
|
|
178
|
-
|
|
182
|
+
localStorage.setItem(flagSetKey, JSON.stringify((0, sets_1.setToArray)(flagSetCache)));
|
|
179
183
|
});
|
|
180
184
|
};
|
|
181
185
|
SplitsCacheInLocal.prototype.removeFromFlagSets = function (featureFlagName, flagSets) {
|
|
@@ -188,16 +192,16 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
188
192
|
};
|
|
189
193
|
SplitsCacheInLocal.prototype.removeNames = function (flagSetName, featureFlagName) {
|
|
190
194
|
var flagSetKey = this.keys.buildFlagSetKey(flagSetName);
|
|
191
|
-
var
|
|
192
|
-
if (!
|
|
195
|
+
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
196
|
+
if (!flagSetFromLocalStorage)
|
|
193
197
|
return;
|
|
194
|
-
var flagSetCache = new Set(JSON.parse(
|
|
198
|
+
var flagSetCache = new Set(JSON.parse(flagSetFromLocalStorage));
|
|
195
199
|
flagSetCache.delete(featureFlagName);
|
|
196
200
|
if (flagSetCache.size === 0) {
|
|
197
|
-
|
|
201
|
+
localStorage.removeItem(flagSetKey);
|
|
198
202
|
return;
|
|
199
203
|
}
|
|
200
|
-
|
|
204
|
+
localStorage.setItem(flagSetKey, JSON.stringify((0, sets_1.setToArray)(flagSetCache)));
|
|
201
205
|
};
|
|
202
206
|
return SplitsCacheInLocal;
|
|
203
207
|
}(AbstractSplitsCacheSync_1.AbstractSplitsCacheSync));
|