@splitsoftware/splitio-commons 2.4.2-rc.1 → 2.4.2-rc.2
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 +13 -1
- package/cjs/logger/messages/error.js +1 -1
- package/cjs/sdkClient/sdkClient.js +0 -1
- package/cjs/sdkFactory/index.js +3 -10
- package/cjs/services/splitHttpClient.js +1 -1
- package/cjs/storages/AbstractMySegmentsCacheSync.js +31 -23
- package/cjs/storages/AbstractSplitsCacheSync.js +8 -3
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +20 -19
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +33 -37
- package/cjs/storages/inLocalStorage/index.js +28 -13
- package/cjs/storages/inLocalStorage/storageAdapter.js +48 -0
- package/cjs/storages/inLocalStorage/validateCache.js +25 -23
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
- package/cjs/sync/polling/pollingManagerCS.js +5 -4
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +3 -2
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -1
- package/cjs/sync/syncManagerOnline.js +31 -26
- package/cjs/trackers/impressionsTracker.js +4 -4
- package/cjs/utils/env/isLocalStorageAvailable.js +28 -5
- package/cjs/utils/settingsValidation/splitFilters.js +0 -6
- package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
- package/esm/logger/messages/error.js +1 -1
- package/esm/sdkClient/sdkClient.js +0 -1
- package/esm/sdkFactory/index.js +3 -10
- package/esm/services/splitHttpClient.js +1 -1
- package/esm/storages/AbstractMySegmentsCacheSync.js +31 -23
- package/esm/storages/AbstractSplitsCacheSync.js +6 -2
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +20 -19
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +33 -37
- package/esm/storages/inLocalStorage/index.js +29 -14
- package/esm/storages/inLocalStorage/storageAdapter.js +44 -0
- package/esm/storages/inLocalStorage/validateCache.js +25 -23
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
- package/esm/sync/polling/pollingManagerCS.js +5 -4
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +3 -2
- package/esm/sync/polling/updaters/splitChangesUpdater.js +1 -1
- package/esm/sync/syncManagerOnline.js +31 -26
- package/esm/trackers/impressionsTracker.js +4 -4
- package/esm/utils/env/isLocalStorageAvailable.js +24 -3
- package/esm/utils/settingsValidation/splitFilters.js +0 -6
- package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
- package/package.json +1 -1
- package/src/logger/messages/error.ts +1 -1
- package/src/sdkClient/sdkClient.ts +0 -1
- package/src/sdkFactory/index.ts +3 -13
- package/src/services/splitHttpClient.ts +1 -1
- package/src/storages/AbstractMySegmentsCacheSync.ts +26 -20
- package/src/storages/AbstractSplitsCacheSync.ts +8 -3
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +18 -17
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +22 -20
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +34 -37
- package/src/storages/inLocalStorage/index.ts +33 -16
- package/src/storages/inLocalStorage/storageAdapter.ts +50 -0
- package/src/storages/inLocalStorage/validateCache.ts +26 -23
- package/src/storages/types.ts +17 -1
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +1 -2
- package/src/sync/polling/pollingManagerCS.ts +5 -4
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +3 -2
- package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -1
- package/src/sync/syncManagerOnline.ts +30 -24
- package/src/trackers/impressionsTracker.ts +3 -3
- package/src/utils/env/isLocalStorageAvailable.ts +24 -3
- package/src/utils/settingsValidation/splitFilters.ts +0 -6
- package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
- package/types/splitio.d.ts +57 -16
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.storageAdapter = void 0;
|
|
4
|
+
var constants_1 = require("./constants");
|
|
5
|
+
function isTillKey(key) {
|
|
6
|
+
return key.endsWith('.till');
|
|
7
|
+
}
|
|
8
|
+
function storageAdapter(log, prefix, wrapper) {
|
|
9
|
+
var cache = {};
|
|
10
|
+
var connectPromise;
|
|
11
|
+
var disconnectPromise = Promise.resolve();
|
|
12
|
+
return {
|
|
13
|
+
load: function () {
|
|
14
|
+
return connectPromise || (connectPromise = Promise.resolve(wrapper.getItem(prefix)).then(function (storedCache) {
|
|
15
|
+
cache = JSON.parse(storedCache || '{}');
|
|
16
|
+
}).catch(function (e) {
|
|
17
|
+
log.error(constants_1.LOG_PREFIX + 'Rejected promise calling storage getItem, with error: ' + e);
|
|
18
|
+
}));
|
|
19
|
+
},
|
|
20
|
+
save: function () {
|
|
21
|
+
return disconnectPromise = disconnectPromise.then(function () {
|
|
22
|
+
return Promise.resolve(wrapper.setItem(prefix, JSON.stringify(cache))).catch(function (e) {
|
|
23
|
+
log.error(constants_1.LOG_PREFIX + 'Rejected promise calling storage setItem, with error: ' + e);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
get length() {
|
|
28
|
+
return Object.keys(cache).length;
|
|
29
|
+
},
|
|
30
|
+
getItem: function (key) {
|
|
31
|
+
return cache[key] || null;
|
|
32
|
+
},
|
|
33
|
+
key: function (index) {
|
|
34
|
+
return Object.keys(cache)[index] || null;
|
|
35
|
+
},
|
|
36
|
+
removeItem: function (key) {
|
|
37
|
+
delete cache[key];
|
|
38
|
+
if (isTillKey(key))
|
|
39
|
+
this.save();
|
|
40
|
+
},
|
|
41
|
+
setItem: function (key, value) {
|
|
42
|
+
cache[key] = value;
|
|
43
|
+
if (isTillKey(key))
|
|
44
|
+
this.save();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
exports.storageAdapter = storageAdapter;
|
|
@@ -11,10 +11,10 @@ var MILLIS_IN_A_DAY = 86400000;
|
|
|
11
11
|
*
|
|
12
12
|
* @returns `true` if cache should be cleared, `false` otherwise
|
|
13
13
|
*/
|
|
14
|
-
function validateExpiration(options, settings, keys, currentTimestamp, isThereCache) {
|
|
14
|
+
function validateExpiration(options, storage, settings, keys, currentTimestamp, isThereCache) {
|
|
15
15
|
var log = settings.log;
|
|
16
16
|
// Check expiration
|
|
17
|
-
var lastUpdatedTimestamp = parseInt(
|
|
17
|
+
var lastUpdatedTimestamp = parseInt(storage.getItem(keys.buildLastUpdatedKey()), 10);
|
|
18
18
|
if (!(0, lang_1.isNaNNumber)(lastUpdatedTimestamp)) {
|
|
19
19
|
var cacheExpirationInDays = (0, lang_1.isFiniteNumber)(options.expirationDays) && options.expirationDays >= 1 ? options.expirationDays : DEFAULT_CACHE_EXPIRATION_IN_DAYS;
|
|
20
20
|
var expirationTimestamp = currentTimestamp - MILLIS_IN_A_DAY * cacheExpirationInDays;
|
|
@@ -25,11 +25,11 @@ function validateExpiration(options, settings, keys, currentTimestamp, isThereCa
|
|
|
25
25
|
}
|
|
26
26
|
// Check hash
|
|
27
27
|
var storageHashKey = keys.buildHashKey();
|
|
28
|
-
var storageHash =
|
|
28
|
+
var storageHash = storage.getItem(storageHashKey);
|
|
29
29
|
var currentStorageHash = (0, KeyBuilder_1.getStorageHash)(settings);
|
|
30
30
|
if (storageHash !== currentStorageHash) {
|
|
31
31
|
try {
|
|
32
|
-
|
|
32
|
+
storage.setItem(storageHashKey, currentStorageHash);
|
|
33
33
|
}
|
|
34
34
|
catch (e) {
|
|
35
35
|
log.error(constants_1.LOG_PREFIX + e);
|
|
@@ -42,7 +42,7 @@ function validateExpiration(options, settings, keys, currentTimestamp, isThereCa
|
|
|
42
42
|
}
|
|
43
43
|
// Clear on init
|
|
44
44
|
if (options.clearOnInit) {
|
|
45
|
-
var lastClearTimestamp = parseInt(
|
|
45
|
+
var lastClearTimestamp = parseInt(storage.getItem(keys.buildLastClear()), 10);
|
|
46
46
|
if ((0, lang_1.isNaNNumber)(lastClearTimestamp) || lastClearTimestamp < currentTimestamp - MILLIS_IN_A_DAY) {
|
|
47
47
|
log.info(constants_1.LOG_PREFIX + 'clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache');
|
|
48
48
|
return true;
|
|
@@ -57,24 +57,26 @@ function validateExpiration(options, settings, keys, currentTimestamp, isThereCa
|
|
|
57
57
|
*
|
|
58
58
|
* @returns `true` if cache is ready to be used, `false` otherwise (cache was cleared or there is no cache)
|
|
59
59
|
*/
|
|
60
|
-
function validateCache(options, settings, keys, splits, rbSegments, segments, largeSegments) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
60
|
+
function validateCache(options, storage, settings, keys, splits, rbSegments, segments, largeSegments) {
|
|
61
|
+
return Promise.resolve(storage.load && storage.load()).then(function () {
|
|
62
|
+
var currentTimestamp = Date.now();
|
|
63
|
+
var isThereCache = splits.getChangeNumber() > -1;
|
|
64
|
+
if (validateExpiration(options, storage, settings, keys, currentTimestamp, isThereCache)) {
|
|
65
|
+
splits.clear();
|
|
66
|
+
rbSegments.clear();
|
|
67
|
+
segments.clear();
|
|
68
|
+
largeSegments.clear();
|
|
69
|
+
// Update last clear timestamp
|
|
70
|
+
try {
|
|
71
|
+
storage.setItem(keys.buildLastClear(), currentTimestamp + '');
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
settings.log.error(constants_1.LOG_PREFIX + e);
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
74
77
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return isThereCache;
|
|
78
|
+
// Check if ready from cache
|
|
79
|
+
return isThereCache;
|
|
80
|
+
});
|
|
79
81
|
}
|
|
80
82
|
exports.validateCache = validateCache;
|
|
@@ -45,10 +45,9 @@ function fromObjectUpdaterFactory(splitsParser, storage, readiness, settings) {
|
|
|
45
45
|
readiness.splits.emit(constants_2.SDK_SPLITS_ARRIVED);
|
|
46
46
|
if (startingUp) {
|
|
47
47
|
startingUp = false;
|
|
48
|
-
|
|
49
|
-
Promise.resolve().then(function () {
|
|
48
|
+
Promise.resolve(storage.validateCache ? storage.validateCache() : false).then(function (isCacheLoaded) {
|
|
50
49
|
// Emits SDK_READY_FROM_CACHE
|
|
51
|
-
if (
|
|
50
|
+
if (isCacheLoaded)
|
|
52
51
|
readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED);
|
|
53
52
|
// Emits SDK_READY
|
|
54
53
|
readiness.segments.emit(constants_2.SDK_SEGMENTS_ARRIVED);
|
|
@@ -7,6 +7,7 @@ var splitsSyncTask_1 = require("./syncTasks/splitsSyncTask");
|
|
|
7
7
|
var key_1 = require("../../utils/key");
|
|
8
8
|
var constants_1 = require("../../readiness/constants");
|
|
9
9
|
var constants_2 = require("../../logger/constants");
|
|
10
|
+
var AbstractSplitsCacheSync_1 = require("../../storages/AbstractSplitsCacheSync");
|
|
10
11
|
/**
|
|
11
12
|
* Expose start / stop mechanism for polling data from services.
|
|
12
13
|
* For client-side API with multiple clients.
|
|
@@ -34,7 +35,7 @@ function pollingManagerCSFactory(params) {
|
|
|
34
35
|
readiness.splits.on(constants_1.SDK_SPLITS_ARRIVED, function () {
|
|
35
36
|
if (!splitsSyncTask.isRunning())
|
|
36
37
|
return; // noop if not doing polling
|
|
37
|
-
var usingSegments =
|
|
38
|
+
var usingSegments = (0, AbstractSplitsCacheSync_1.usesSegmentsSync)(storage);
|
|
38
39
|
if (usingSegments !== mySegmentsSyncTask.isRunning()) {
|
|
39
40
|
log.info(constants_2.POLLING_SMART_PAUSING, [usingSegments ? 'ON' : 'OFF']);
|
|
40
41
|
if (usingSegments) {
|
|
@@ -49,10 +50,10 @@ function pollingManagerCSFactory(params) {
|
|
|
49
50
|
var mySegmentsSyncTask = (0, mySegmentsSyncTask_1.mySegmentsSyncTaskFactory)(splitApi.fetchMemberships, storage, readiness, settings, matchingKey);
|
|
50
51
|
// smart ready
|
|
51
52
|
function smartReady() {
|
|
52
|
-
if (!readiness.isReady() && !
|
|
53
|
+
if (!readiness.isReady() && !(0, AbstractSplitsCacheSync_1.usesSegmentsSync)(storage))
|
|
53
54
|
readiness.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED);
|
|
54
55
|
}
|
|
55
|
-
if (!
|
|
56
|
+
if (!(0, AbstractSplitsCacheSync_1.usesSegmentsSync)(storage))
|
|
56
57
|
setTimeout(smartReady, 0);
|
|
57
58
|
else
|
|
58
59
|
readiness.splits.once(constants_1.SDK_SPLITS_ARRIVED, smartReady);
|
|
@@ -66,7 +67,7 @@ function pollingManagerCSFactory(params) {
|
|
|
66
67
|
start: function () {
|
|
67
68
|
log.info(constants_2.POLLING_START);
|
|
68
69
|
splitsSyncTask.start();
|
|
69
|
-
if (
|
|
70
|
+
if ((0, AbstractSplitsCacheSync_1.usesSegmentsSync)(storage))
|
|
70
71
|
startMySegmentsSyncTasks();
|
|
71
72
|
},
|
|
72
73
|
// Stop periodic fetching (polling)
|
|
@@ -5,6 +5,7 @@ var timeout_1 = require("../../../utils/promise/timeout");
|
|
|
5
5
|
var constants_1 = require("../../../readiness/constants");
|
|
6
6
|
var constants_2 = require("../../../logger/constants");
|
|
7
7
|
var constants_3 = require("../../streaming/constants");
|
|
8
|
+
var AbstractSplitsCacheSync_1 = require("../../../storages/AbstractSplitsCacheSync");
|
|
8
9
|
/**
|
|
9
10
|
* factory of MySegments updater, a task that:
|
|
10
11
|
* - fetches mySegments using `mySegmentsFetcher`
|
|
@@ -12,7 +13,7 @@ var constants_3 = require("../../streaming/constants");
|
|
|
12
13
|
* - uses `segmentsEventEmitter` to emit events related to segments data updates
|
|
13
14
|
*/
|
|
14
15
|
function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmentsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, matchingKey) {
|
|
15
|
-
var
|
|
16
|
+
var segments = storage.segments, largeSegments = storage.largeSegments;
|
|
16
17
|
var readyOnAlreadyExistentState = true;
|
|
17
18
|
var startingUp = true;
|
|
18
19
|
/** timeout and telemetry decorator for `splitChangesFetcher` promise */
|
|
@@ -34,7 +35,7 @@ function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmentsEvent
|
|
|
34
35
|
shouldNotifyUpdate = largeSegments.resetSegments(segmentsData.ls || {}) || shouldNotifyUpdate;
|
|
35
36
|
}
|
|
36
37
|
// Notify update if required
|
|
37
|
-
if ((
|
|
38
|
+
if ((0, AbstractSplitsCacheSync_1.usesSegmentsSync)(storage) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
|
|
38
39
|
readyOnAlreadyExistentState = false;
|
|
39
40
|
segmentsEventEmitter.emit(constants_1.SDK_SEGMENTS_ARRIVED);
|
|
40
41
|
}
|
|
@@ -46,7 +46,7 @@ function parseSegments(ruleEntity, matcherType) {
|
|
|
46
46
|
exports.parseSegments = parseSegments;
|
|
47
47
|
/**
|
|
48
48
|
* If there are defined filters and one feature flag doesn't match with them, its status is changed to 'ARCHIVE' to avoid storing it
|
|
49
|
-
* If there
|
|
49
|
+
* If there is `bySet` filter, `byName` and `byPrefix` filters are ignored
|
|
50
50
|
*
|
|
51
51
|
* @param featureFlag - feature flag to be evaluated
|
|
52
52
|
* @param filters - splitFiltersValidation bySet | byName
|
|
@@ -7,6 +7,7 @@ var constants_2 = require("../logger/constants");
|
|
|
7
7
|
var consent_1 = require("../consent");
|
|
8
8
|
var constants_3 = require("../utils/constants");
|
|
9
9
|
var constants_4 = require("../readiness/constants");
|
|
10
|
+
var AbstractSplitsCacheSync_1 = require("../storages/AbstractSplitsCacheSync");
|
|
10
11
|
/**
|
|
11
12
|
* Online SyncManager factory.
|
|
12
13
|
* Can be used for server-side API, and client-side API with or without multiple clients.
|
|
@@ -68,35 +69,39 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
68
69
|
*/
|
|
69
70
|
start: function () {
|
|
70
71
|
running = true;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
// @TODO once event, impression and telemetry storages support persistence, call when `validateCache` promise is resolved
|
|
73
|
+
submitterManager.start(!(0, consent_1.isConsentGranted)(settings));
|
|
74
|
+
return Promise.resolve(storage.validateCache ? storage.validateCache() : false).then(function (isCacheLoaded) {
|
|
75
|
+
if (!running)
|
|
76
|
+
return;
|
|
77
|
+
if (startFirstTime) {
|
|
78
|
+
// Emits SDK_READY_FROM_CACHE
|
|
79
|
+
if (isCacheLoaded)
|
|
80
|
+
readiness.splits.emit(constants_4.SDK_SPLITS_CACHE_LOADED);
|
|
81
|
+
}
|
|
82
|
+
// start syncing splits and segments
|
|
83
|
+
if (pollingManager) {
|
|
84
|
+
// If synchronization is disabled pushManager and pollingManager should not start
|
|
85
|
+
if (syncEnabled) {
|
|
86
|
+
if (pushManager) {
|
|
87
|
+
// Doesn't call `syncAll` when the syncManager is resuming
|
|
88
|
+
if (startFirstTime) {
|
|
89
|
+
pollingManager.syncAll();
|
|
90
|
+
}
|
|
91
|
+
pushManager.start();
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
pollingManager.start();
|
|
84
95
|
}
|
|
85
|
-
pushManager.start();
|
|
86
96
|
}
|
|
87
97
|
else {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
else {
|
|
92
|
-
if (startFirstTime) {
|
|
93
|
-
pollingManager.syncAll();
|
|
98
|
+
if (startFirstTime) {
|
|
99
|
+
pollingManager.syncAll();
|
|
100
|
+
}
|
|
94
101
|
}
|
|
95
102
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
submitterManager.start(!(0, consent_1.isConsentGranted)(settings));
|
|
99
|
-
startFirstTime = false;
|
|
103
|
+
startFirstTime = false;
|
|
104
|
+
});
|
|
100
105
|
},
|
|
101
106
|
/**
|
|
102
107
|
* Method used to stop/pause the syncManager.
|
|
@@ -130,7 +135,7 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
130
135
|
if (pushManager) {
|
|
131
136
|
if (pollingManager.isRunning()) {
|
|
132
137
|
// if doing polling, we must start the periodic fetch of data
|
|
133
|
-
if (
|
|
138
|
+
if ((0, AbstractSplitsCacheSync_1.usesSegmentsSync)(storage))
|
|
134
139
|
mySegmentsSyncTask.start();
|
|
135
140
|
}
|
|
136
141
|
else {
|
|
@@ -140,7 +145,7 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
140
145
|
}
|
|
141
146
|
}
|
|
142
147
|
else {
|
|
143
|
-
if (
|
|
148
|
+
if ((0, AbstractSplitsCacheSync_1.usesSegmentsSync)(storage))
|
|
144
149
|
mySegmentsSyncTask.start();
|
|
145
150
|
}
|
|
146
151
|
}
|
|
@@ -9,7 +9,7 @@ var constants_2 = require("../utils/constants");
|
|
|
9
9
|
* Impressions tracker stores impressions in cache and pass them to the listener and integrations manager if provided.
|
|
10
10
|
*/
|
|
11
11
|
function impressionsTrackerFactory(settings, impressionsCache, noneStrategy, strategy, whenInit, integrationsManager, telemetryCache) {
|
|
12
|
-
var log = settings.log, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version;
|
|
12
|
+
var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version;
|
|
13
13
|
return {
|
|
14
14
|
track: function (impressions, attributes) {
|
|
15
15
|
if (settings.userConsent === constants_2.CONSENT_DECLINED)
|
|
@@ -42,7 +42,7 @@ function impressionsTrackerFactory(settings, impressionsCache, noneStrategy, str
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
// @TODO next block might be handled by the integration manager. In that case, the metadata object doesn't need to be passed in the constructor
|
|
45
|
-
if (
|
|
45
|
+
if (impressionListener || integrationsManager) {
|
|
46
46
|
var _loop_1 = function (i) {
|
|
47
47
|
var impressionData = {
|
|
48
48
|
// copy of impression, to avoid unexpected behavior if modified by integrations or impressionListener
|
|
@@ -59,8 +59,8 @@ function impressionsTrackerFactory(settings, impressionsCache, noneStrategy, str
|
|
|
59
59
|
if (integrationsManager)
|
|
60
60
|
integrationsManager.handleImpression(impressionData);
|
|
61
61
|
try { // @ts-ignore. An exception on the listeners should not break the SDK.
|
|
62
|
-
if (
|
|
63
|
-
|
|
62
|
+
if (impressionListener)
|
|
63
|
+
impressionListener.logImpression(impressionData);
|
|
64
64
|
}
|
|
65
65
|
catch (err) {
|
|
66
66
|
log.error(constants_1.ERROR_IMPRESSIONS_LISTENER, [err]);
|
|
@@ -1,16 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isLocalStorageAvailable = void 0;
|
|
4
|
-
/* eslint-disable no-undef */
|
|
3
|
+
exports.isWebStorage = exports.isValidStorageWrapper = exports.isLocalStorageAvailable = void 0;
|
|
5
4
|
function isLocalStorageAvailable() {
|
|
5
|
+
try {
|
|
6
|
+
// eslint-disable-next-line no-undef
|
|
7
|
+
return isValidStorageWrapper(localStorage);
|
|
8
|
+
}
|
|
9
|
+
catch (e) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.isLocalStorageAvailable = isLocalStorageAvailable;
|
|
14
|
+
function isValidStorageWrapper(wrapper) {
|
|
6
15
|
var mod = '__SPLITSOFTWARE__';
|
|
7
16
|
try {
|
|
8
|
-
|
|
9
|
-
|
|
17
|
+
wrapper.setItem(mod, mod);
|
|
18
|
+
wrapper.getItem(mod);
|
|
19
|
+
wrapper.removeItem(mod);
|
|
10
20
|
return true;
|
|
11
21
|
}
|
|
12
22
|
catch (e) {
|
|
13
23
|
return false;
|
|
14
24
|
}
|
|
15
25
|
}
|
|
16
|
-
exports.
|
|
26
|
+
exports.isValidStorageWrapper = isValidStorageWrapper;
|
|
27
|
+
function isWebStorage(wrapper) {
|
|
28
|
+
if (typeof wrapper.length === 'number') {
|
|
29
|
+
try {
|
|
30
|
+
wrapper.key(0);
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
exports.isWebStorage = isWebStorage;
|
|
@@ -61,12 +61,6 @@ function validateSplitFilter(log, type, values, maxLength) {
|
|
|
61
61
|
/**
|
|
62
62
|
* Returns a string representing the URL encoded query component of /splitChanges URL.
|
|
63
63
|
*
|
|
64
|
-
* The possible formats of the query string are:
|
|
65
|
-
* - null: if all filters are empty
|
|
66
|
-
* - '&names=<comma-separated-values>': if only `byPrefix` filter is undefined
|
|
67
|
-
* - '&prefixes=<comma-separated-values>': if only `byName` filter is undefined
|
|
68
|
-
* - '&names=<comma-separated-values>&prefixes=<comma-separated-values>': if no one is undefined
|
|
69
|
-
*
|
|
70
64
|
* @param groupedFilters - object of filters. Each filter must be a list of valid, unique and ordered string values.
|
|
71
65
|
* @returns null or string with the `split filter query` component of the URL.
|
|
72
66
|
*/
|
|
@@ -6,7 +6,7 @@ var constants_1 = require("../../../logger/constants");
|
|
|
6
6
|
var constants_2 = require("../../../utils/constants");
|
|
7
7
|
function __InLocalStorageMockFactory(params) {
|
|
8
8
|
var result = (0, InMemoryStorageCS_1.InMemoryStorageCSFactory)(params);
|
|
9
|
-
result.validateCache = function () { return true; }; // to emit SDK_READY_FROM_CACHE
|
|
9
|
+
result.validateCache = function () { return Promise.resolve(true); }; // to emit SDK_READY_FROM_CACHE
|
|
10
10
|
return result;
|
|
11
11
|
}
|
|
12
12
|
exports.__InLocalStorageMockFactory = __InLocalStorageMockFactory;
|
|
@@ -13,7 +13,7 @@ export var codesError = [
|
|
|
13
13
|
[c.ERROR_SYNC_OFFLINE_LOADING, c.LOG_PREFIX_SYNC_OFFLINE + 'There was an issue loading the mock feature flags data. No changes will be applied to the current cache. %s'],
|
|
14
14
|
[c.ERROR_STREAMING_SSE, c.LOG_PREFIX_SYNC_STREAMING + 'Failed to connect or error on streaming connection, with error message: %s'],
|
|
15
15
|
[c.ERROR_STREAMING_AUTH, c.LOG_PREFIX_SYNC_STREAMING + 'Failed to authenticate for streaming. Error: %s.'],
|
|
16
|
-
[c.ERROR_HTTP, '
|
|
16
|
+
[c.ERROR_HTTP, 'HTTP request failed with %s. URL: %s. Message: %s'],
|
|
17
17
|
// client status
|
|
18
18
|
[c.ERROR_CLIENT_LISTENER, 'A listener was added for %s on the SDK, which has already fired and won\'t be emitted again. The callback won\'t be executed.'],
|
|
19
19
|
[c.ERROR_CLIENT_DESTROYED, '%s: Client has already been destroyed - no calls possible.'],
|
|
@@ -35,7 +35,6 @@ export function sdkClientFactory(params, isSharedClient) {
|
|
|
35
35
|
clientInputValidationDecorator(settings, clientFactory(params), sdkReadinessManager.readinessManager),
|
|
36
36
|
// Sdk destroy
|
|
37
37
|
{
|
|
38
|
-
__ctx: params,
|
|
39
38
|
flush: function () {
|
|
40
39
|
// @TODO define cooldown time
|
|
41
40
|
return __cooldown(__flush, COOLDOWN_TIME_IN_MILLIS);
|
package/esm/sdkFactory/index.js
CHANGED
|
@@ -84,7 +84,8 @@ export function sdkFactory(params) {
|
|
|
84
84
|
initCallbacks.length = 0;
|
|
85
85
|
}
|
|
86
86
|
log.info(NEW_FACTORY);
|
|
87
|
-
|
|
87
|
+
// @ts-ignore
|
|
88
|
+
return objectAssign({
|
|
88
89
|
// Split evaluation and event tracking engine
|
|
89
90
|
client: clientMethod,
|
|
90
91
|
// Manager API to explore available information
|
|
@@ -98,14 +99,6 @@ export function sdkFactory(params) {
|
|
|
98
99
|
destroy: function () {
|
|
99
100
|
hasInit = false;
|
|
100
101
|
return Promise.all(Object.keys(clients).map(function (key) { return clients[key].destroy(); })).then(function () { });
|
|
101
|
-
}
|
|
102
|
-
__ctx: ctx
|
|
102
|
+
}
|
|
103
103
|
}, extraProps && extraProps(ctx), lazyInit ? { init: init } : init());
|
|
104
|
-
// append factory to global
|
|
105
|
-
if (typeof window === 'object') { // @ts-ignore
|
|
106
|
-
// eslint-disable-next-line no-undef
|
|
107
|
-
(window.__HARNESS_FME__ = window.__HARNESS_FME__ || []).push(factory);
|
|
108
|
-
}
|
|
109
|
-
// @ts-ignore
|
|
110
|
-
return factory;
|
|
111
104
|
}
|
|
@@ -66,7 +66,7 @@ export function splitHttpClientFactory(settings, _a) {
|
|
|
66
66
|
msg = error.message || 'Network Error';
|
|
67
67
|
}
|
|
68
68
|
if (!resp || resp.status !== 403) { // 403's log we'll be handled somewhere else.
|
|
69
|
-
log[logErrorsAsInfo ? 'info' : 'error'](ERROR_HTTP, [resp ? resp.status : '
|
|
69
|
+
log[logErrorsAsInfo ? 'info' : 'error'](ERROR_HTTP, [resp ? 'status code ' + resp.status : 'no status code', url, msg]);
|
|
70
70
|
}
|
|
71
71
|
var networkError = new Error(msg);
|
|
72
72
|
// passes `undefined` as statusCode if not an HTTP error (resp === undefined)
|
|
@@ -20,37 +20,45 @@ var AbstractMySegmentsCacheSync = /** @class */ (function () {
|
|
|
20
20
|
*/
|
|
21
21
|
AbstractMySegmentsCacheSync.prototype.resetSegments = function (segmentsData) {
|
|
22
22
|
var _this = this;
|
|
23
|
-
this.setChangeNumber(segmentsData.cn);
|
|
24
23
|
var _a = segmentsData, added = _a.added, removed = _a.removed;
|
|
24
|
+
var isDiff = false;
|
|
25
25
|
if (added && removed) {
|
|
26
|
-
var isDiff_1 = false;
|
|
27
26
|
added.forEach(function (segment) {
|
|
28
|
-
|
|
27
|
+
isDiff = _this.addSegment(segment) || isDiff;
|
|
29
28
|
});
|
|
30
29
|
removed.forEach(function (segment) {
|
|
31
|
-
|
|
30
|
+
isDiff = _this.removeSegment(segment) || isDiff;
|
|
32
31
|
});
|
|
33
|
-
return isDiff_1;
|
|
34
|
-
}
|
|
35
|
-
var names = (segmentsData.k || []).map(function (s) { return s.n; }).sort();
|
|
36
|
-
var storedSegmentKeys = this.getRegisteredSegments().sort();
|
|
37
|
-
// Extreme fast => everything is empty
|
|
38
|
-
if (!names.length && !storedSegmentKeys.length)
|
|
39
|
-
return false;
|
|
40
|
-
var index = 0;
|
|
41
|
-
while (index < names.length && index < storedSegmentKeys.length && names[index] === storedSegmentKeys[index])
|
|
42
|
-
index++;
|
|
43
|
-
// Quick path => no changes
|
|
44
|
-
if (index === names.length && index === storedSegmentKeys.length)
|
|
45
|
-
return false;
|
|
46
|
-
// Slowest path => add and/or remove segments
|
|
47
|
-
for (var removeIndex = index; removeIndex < storedSegmentKeys.length; removeIndex++) {
|
|
48
|
-
this.removeSegment(storedSegmentKeys[removeIndex]);
|
|
49
32
|
}
|
|
50
|
-
|
|
51
|
-
|
|
33
|
+
else {
|
|
34
|
+
var names = (segmentsData.k || []).map(function (s) { return s.n; }).sort();
|
|
35
|
+
var storedSegmentKeys = this.getRegisteredSegments().sort();
|
|
36
|
+
// Extreme fast => everything is empty
|
|
37
|
+
if (!names.length && !storedSegmentKeys.length) {
|
|
38
|
+
isDiff = false;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
var index = 0;
|
|
42
|
+
while (index < names.length && index < storedSegmentKeys.length && names[index] === storedSegmentKeys[index])
|
|
43
|
+
index++;
|
|
44
|
+
// Quick path => no changes
|
|
45
|
+
if (index === names.length && index === storedSegmentKeys.length) {
|
|
46
|
+
isDiff = false;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Slowest path => add and/or remove segments
|
|
50
|
+
for (var removeIndex = index; removeIndex < storedSegmentKeys.length; removeIndex++) {
|
|
51
|
+
this.removeSegment(storedSegmentKeys[removeIndex]);
|
|
52
|
+
}
|
|
53
|
+
for (var addIndex = index; addIndex < names.length; addIndex++) {
|
|
54
|
+
this.addSegment(names[addIndex]);
|
|
55
|
+
}
|
|
56
|
+
isDiff = true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
52
59
|
}
|
|
53
|
-
|
|
60
|
+
this.setChangeNumber(segmentsData.cn);
|
|
61
|
+
return isDiff;
|
|
54
62
|
};
|
|
55
63
|
return AbstractMySegmentsCacheSync;
|
|
56
64
|
}());
|
|
@@ -9,9 +9,10 @@ var AbstractSplitsCacheSync = /** @class */ (function () {
|
|
|
9
9
|
}
|
|
10
10
|
AbstractSplitsCacheSync.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
11
11
|
var _this = this;
|
|
12
|
-
this.setChangeNumber(changeNumber);
|
|
13
12
|
var updated = toAdd.map(function (addedFF) { return _this.addSplit(addedFF); }).some(function (result) { return result; });
|
|
14
|
-
|
|
13
|
+
updated = toRemove.map(function (removedFF) { return _this.removeSplit(removedFF.name); }).some(function (result) { return result; }) || updated;
|
|
14
|
+
this.setChangeNumber(changeNumber);
|
|
15
|
+
return updated;
|
|
15
16
|
};
|
|
16
17
|
AbstractSplitsCacheSync.prototype.getSplits = function (names) {
|
|
17
18
|
var _this = this;
|
|
@@ -65,3 +66,6 @@ export function usesSegments(ruleEntity) {
|
|
|
65
66
|
return true;
|
|
66
67
|
return false;
|
|
67
68
|
}
|
|
69
|
+
export function usesSegmentsSync(storage) {
|
|
70
|
+
return storage.splits.usesSegments() || storage.rbSegments.usesSegments();
|
|
71
|
+
}
|
|
@@ -4,19 +4,20 @@ import { AbstractMySegmentsCacheSync } from '../AbstractMySegmentsCacheSync';
|
|
|
4
4
|
import { LOG_PREFIX, DEFINED } from './constants';
|
|
5
5
|
var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
6
6
|
__extends(MySegmentsCacheInLocal, _super);
|
|
7
|
-
function MySegmentsCacheInLocal(log, keys) {
|
|
7
|
+
function MySegmentsCacheInLocal(log, keys, storage) {
|
|
8
8
|
var _this = _super.call(this) || this;
|
|
9
9
|
_this.log = log;
|
|
10
10
|
_this.keys = keys;
|
|
11
|
+
_this.storage = storage;
|
|
11
12
|
return _this;
|
|
12
13
|
// There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
|
|
13
14
|
}
|
|
14
15
|
MySegmentsCacheInLocal.prototype.addSegment = function (name) {
|
|
15
16
|
var segmentKey = this.keys.buildSegmentNameKey(name);
|
|
16
17
|
try {
|
|
17
|
-
if (
|
|
18
|
+
if (this.storage.getItem(segmentKey) === DEFINED)
|
|
18
19
|
return false;
|
|
19
|
-
|
|
20
|
+
this.storage.setItem(segmentKey, DEFINED);
|
|
20
21
|
return true;
|
|
21
22
|
}
|
|
22
23
|
catch (e) {
|
|
@@ -27,9 +28,9 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
27
28
|
MySegmentsCacheInLocal.prototype.removeSegment = function (name) {
|
|
28
29
|
var segmentKey = this.keys.buildSegmentNameKey(name);
|
|
29
30
|
try {
|
|
30
|
-
if (
|
|
31
|
+
if (this.storage.getItem(segmentKey) !== DEFINED)
|
|
31
32
|
return false;
|
|
32
|
-
|
|
33
|
+
this.storage.removeItem(segmentKey);
|
|
33
34
|
return true;
|
|
34
35
|
}
|
|
35
36
|
catch (e) {
|
|
@@ -38,17 +39,16 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
38
39
|
}
|
|
39
40
|
};
|
|
40
41
|
MySegmentsCacheInLocal.prototype.isInSegment = function (name) {
|
|
41
|
-
return
|
|
42
|
+
return this.storage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
|
|
42
43
|
};
|
|
43
44
|
MySegmentsCacheInLocal.prototype.getRegisteredSegments = function () {
|
|
44
|
-
var
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
var segmentName = _this.keys.extractSegmentName(key);
|
|
45
|
+
var registeredSegments = [];
|
|
46
|
+
for (var i = 0; i < this.storage.length; i++) {
|
|
47
|
+
var segmentName = this.keys.extractSegmentName(this.storage.key(i));
|
|
48
48
|
if (segmentName)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
registeredSegments.push(segmentName);
|
|
50
|
+
}
|
|
51
|
+
return registeredSegments;
|
|
52
52
|
};
|
|
53
53
|
MySegmentsCacheInLocal.prototype.getKeysCount = function () {
|
|
54
54
|
return 1;
|
|
@@ -56,9 +56,9 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
56
56
|
MySegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
57
57
|
try {
|
|
58
58
|
if (changeNumber)
|
|
59
|
-
|
|
59
|
+
this.storage.setItem(this.keys.buildTillKey(), changeNumber + '');
|
|
60
60
|
else
|
|
61
|
-
|
|
61
|
+
this.storage.removeItem(this.keys.buildTillKey());
|
|
62
62
|
}
|
|
63
63
|
catch (e) {
|
|
64
64
|
this.log.error(e);
|
|
@@ -66,7 +66,7 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
66
66
|
};
|
|
67
67
|
MySegmentsCacheInLocal.prototype.getChangeNumber = function () {
|
|
68
68
|
var n = -1;
|
|
69
|
-
var value =
|
|
69
|
+
var value = this.storage.getItem(this.keys.buildTillKey());
|
|
70
70
|
if (value !== null) {
|
|
71
71
|
value = parseInt(value, 10);
|
|
72
72
|
return isNaNNumber(value) ? n : value;
|