@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.
Files changed (67) hide show
  1. package/CHANGES.txt +13 -1
  2. package/cjs/logger/messages/error.js +1 -1
  3. package/cjs/sdkClient/sdkClient.js +0 -1
  4. package/cjs/sdkFactory/index.js +3 -10
  5. package/cjs/services/splitHttpClient.js +1 -1
  6. package/cjs/storages/AbstractMySegmentsCacheSync.js +31 -23
  7. package/cjs/storages/AbstractSplitsCacheSync.js +8 -3
  8. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  9. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +20 -19
  10. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +33 -37
  11. package/cjs/storages/inLocalStorage/index.js +28 -13
  12. package/cjs/storages/inLocalStorage/storageAdapter.js +48 -0
  13. package/cjs/storages/inLocalStorage/validateCache.js +25 -23
  14. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
  15. package/cjs/sync/polling/pollingManagerCS.js +5 -4
  16. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +3 -2
  17. package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -1
  18. package/cjs/sync/syncManagerOnline.js +31 -26
  19. package/cjs/trackers/impressionsTracker.js +4 -4
  20. package/cjs/utils/env/isLocalStorageAvailable.js +28 -5
  21. package/cjs/utils/settingsValidation/splitFilters.js +0 -6
  22. package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
  23. package/esm/logger/messages/error.js +1 -1
  24. package/esm/sdkClient/sdkClient.js +0 -1
  25. package/esm/sdkFactory/index.js +3 -10
  26. package/esm/services/splitHttpClient.js +1 -1
  27. package/esm/storages/AbstractMySegmentsCacheSync.js +31 -23
  28. package/esm/storages/AbstractSplitsCacheSync.js +6 -2
  29. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  30. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +20 -19
  31. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +33 -37
  32. package/esm/storages/inLocalStorage/index.js +29 -14
  33. package/esm/storages/inLocalStorage/storageAdapter.js +44 -0
  34. package/esm/storages/inLocalStorage/validateCache.js +25 -23
  35. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
  36. package/esm/sync/polling/pollingManagerCS.js +5 -4
  37. package/esm/sync/polling/updaters/mySegmentsUpdater.js +3 -2
  38. package/esm/sync/polling/updaters/splitChangesUpdater.js +1 -1
  39. package/esm/sync/syncManagerOnline.js +31 -26
  40. package/esm/trackers/impressionsTracker.js +4 -4
  41. package/esm/utils/env/isLocalStorageAvailable.js +24 -3
  42. package/esm/utils/settingsValidation/splitFilters.js +0 -6
  43. package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
  44. package/package.json +1 -1
  45. package/src/logger/messages/error.ts +1 -1
  46. package/src/sdkClient/sdkClient.ts +0 -1
  47. package/src/sdkFactory/index.ts +3 -13
  48. package/src/services/splitHttpClient.ts +1 -1
  49. package/src/storages/AbstractMySegmentsCacheSync.ts +26 -20
  50. package/src/storages/AbstractSplitsCacheSync.ts +8 -3
  51. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +18 -17
  52. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +22 -20
  53. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +34 -37
  54. package/src/storages/inLocalStorage/index.ts +33 -16
  55. package/src/storages/inLocalStorage/storageAdapter.ts +50 -0
  56. package/src/storages/inLocalStorage/validateCache.ts +26 -23
  57. package/src/storages/types.ts +17 -1
  58. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +1 -2
  59. package/src/sync/polling/pollingManagerCS.ts +5 -4
  60. package/src/sync/polling/updaters/mySegmentsUpdater.ts +3 -2
  61. package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -1
  62. package/src/sync/syncManagerOnline.ts +30 -24
  63. package/src/trackers/impressionsTracker.ts +3 -3
  64. package/src/utils/env/isLocalStorageAvailable.ts +24 -3
  65. package/src/utils/settingsValidation/splitFilters.ts +0 -6
  66. package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
  67. 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(localStorage.getItem(keys.buildLastUpdatedKey()), 10);
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 = localStorage.getItem(storageHashKey);
28
+ var storageHash = storage.getItem(storageHashKey);
29
29
  var currentStorageHash = (0, KeyBuilder_1.getStorageHash)(settings);
30
30
  if (storageHash !== currentStorageHash) {
31
31
  try {
32
- localStorage.setItem(storageHashKey, currentStorageHash);
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(localStorage.getItem(keys.buildLastClear()), 10);
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
- var currentTimestamp = Date.now();
62
- var isThereCache = splits.getChangeNumber() > -1;
63
- if (validateExpiration(options, settings, keys, currentTimestamp, isThereCache)) {
64
- splits.clear();
65
- rbSegments.clear();
66
- segments.clear();
67
- largeSegments.clear();
68
- // Update last clear timestamp
69
- try {
70
- localStorage.setItem(keys.buildLastClear(), currentTimestamp + '');
71
- }
72
- catch (e) {
73
- settings.log.error(constants_1.LOG_PREFIX + e);
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
- return false;
76
- }
77
- // Check if ready from cache
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
- var isCacheLoaded_1 = storage.validateCache ? storage.validateCache() : false;
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 (isCacheLoaded_1)
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 = storage.splits.usesSegments() || storage.rbSegments.usesSegments();
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() && !storage.splits.usesSegments() && !storage.rbSegments.usesSegments())
53
+ if (!readiness.isReady() && !(0, AbstractSplitsCacheSync_1.usesSegmentsSync)(storage))
53
54
  readiness.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED);
54
55
  }
55
- if (!storage.splits.usesSegments() && !storage.rbSegments.usesSegments())
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 (storage.splits.usesSegments() || storage.rbSegments.usesSegments())
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 splits = storage.splits, rbSegments = storage.rbSegments, segments = storage.segments, largeSegments = storage.largeSegments;
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 ((splits.usesSegments() || rbSegments.usesSegments()) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
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 are set filter defined, names filter is ignored
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
- if (startFirstTime) {
72
- var isCacheLoaded = storage.validateCache ? storage.validateCache() : false;
73
- if (isCacheLoaded)
74
- Promise.resolve().then(function () { readiness.splits.emit(constants_4.SDK_SPLITS_CACHE_LOADED); });
75
- }
76
- // start syncing splits and segments
77
- if (pollingManager) {
78
- // If synchronization is disabled pushManager and pollingManager should not start
79
- if (syncEnabled) {
80
- if (pushManager) {
81
- // Doesn't call `syncAll` when the syncManager is resuming
82
- if (startFirstTime) {
83
- pollingManager.syncAll();
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
- pollingManager.start();
89
- }
90
- }
91
- else {
92
- if (startFirstTime) {
93
- pollingManager.syncAll();
98
+ if (startFirstTime) {
99
+ pollingManager.syncAll();
100
+ }
94
101
  }
95
102
  }
96
- }
97
- // start periodic data recording (events, impressions, telemetry).
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 (storage.splits.usesSegments() || storage.rbSegments.usesSegments())
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 (storage.splits.usesSegments() || storage.rbSegments.usesSegments())
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 (settings.impressionListener || integrationsManager) {
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 (settings.impressionListener)
63
- settings.impressionListener.logImpression(impressionData);
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
- localStorage.setItem(mod, mod);
9
- localStorage.removeItem(mod);
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.isLocalStorageAvailable = isLocalStorageAvailable;
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, 'Response status is not OK. Status: %s. URL: %s. Message: %s'],
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);
@@ -84,7 +84,8 @@ export function sdkFactory(params) {
84
84
  initCallbacks.length = 0;
85
85
  }
86
86
  log.info(NEW_FACTORY);
87
- var factory = objectAssign({
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 : 'NO_STATUS', url, msg]);
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
- isDiff_1 = _this.addSegment(segment) || isDiff_1;
27
+ isDiff = _this.addSegment(segment) || isDiff;
29
28
  });
30
29
  removed.forEach(function (segment) {
31
- isDiff_1 = _this.removeSegment(segment) || isDiff_1;
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
- for (var addIndex = index; addIndex < names.length; addIndex++) {
51
- this.addSegment(names[addIndex]);
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
- return true;
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
- return toRemove.map(function (removedFF) { return _this.removeSplit(removedFF.name); }).some(function (result) { return result; }) || updated;
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 (localStorage.getItem(segmentKey) === DEFINED)
18
+ if (this.storage.getItem(segmentKey) === DEFINED)
18
19
  return false;
19
- localStorage.setItem(segmentKey, DEFINED);
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 (localStorage.getItem(segmentKey) !== DEFINED)
31
+ if (this.storage.getItem(segmentKey) !== DEFINED)
31
32
  return false;
32
- localStorage.removeItem(segmentKey);
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 localStorage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
42
+ return this.storage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
42
43
  };
43
44
  MySegmentsCacheInLocal.prototype.getRegisteredSegments = function () {
44
- var _this = this;
45
- // Scan current values from localStorage
46
- return Object.keys(localStorage).reduce(function (accum, key) {
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
- accum.push(segmentName);
50
- return accum;
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
- localStorage.setItem(this.keys.buildTillKey(), changeNumber + '');
59
+ this.storage.setItem(this.keys.buildTillKey(), changeNumber + '');
60
60
  else
61
- localStorage.removeItem(this.keys.buildTillKey());
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 = localStorage.getItem(this.keys.buildTillKey());
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;