@splitsoftware/splitio-commons 2.4.2-rc.3 → 2.5.0-rc.0

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 (51) hide show
  1. package/CHANGES.txt +2 -10
  2. package/cjs/storages/dataLoader.js +102 -43
  3. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  4. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +21 -17
  5. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
  6. package/cjs/storages/inLocalStorage/index.js +13 -31
  7. package/cjs/storages/inLocalStorage/validateCache.js +23 -28
  8. package/cjs/storages/inMemory/InMemoryStorageCS.js +32 -14
  9. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
  10. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  11. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +0 -2
  12. package/cjs/sync/polling/updaters/splitChangesUpdater.js +0 -2
  13. package/cjs/sync/syncManagerOnline.js +24 -28
  14. package/cjs/utils/env/isLocalStorageAvailable.js +5 -28
  15. package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
  16. package/esm/storages/dataLoader.js +99 -41
  17. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  18. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +21 -17
  19. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
  20. package/esm/storages/inLocalStorage/index.js +14 -32
  21. package/esm/storages/inLocalStorage/validateCache.js +23 -28
  22. package/esm/storages/inMemory/InMemoryStorageCS.js +32 -14
  23. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
  24. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  25. package/esm/sync/polling/updaters/mySegmentsUpdater.js +0 -2
  26. package/esm/sync/polling/updaters/splitChangesUpdater.js +0 -2
  27. package/esm/sync/syncManagerOnline.js +24 -28
  28. package/esm/utils/env/isLocalStorageAvailable.js +3 -24
  29. package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
  30. package/package.json +1 -1
  31. package/src/sdkFactory/index.ts +3 -2
  32. package/src/storages/dataLoader.ts +107 -49
  33. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +17 -18
  34. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +22 -19
  35. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +37 -34
  36. package/src/storages/inLocalStorage/index.ts +16 -37
  37. package/src/storages/inLocalStorage/validateCache.ts +23 -29
  38. package/src/storages/inMemory/InMemoryStorageCS.ts +37 -14
  39. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +4 -0
  40. package/src/storages/types.ts +6 -22
  41. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +2 -1
  42. package/src/sync/polling/updaters/mySegmentsUpdater.ts +0 -2
  43. package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -3
  44. package/src/sync/syncManagerOnline.ts +22 -27
  45. package/src/types.ts +0 -35
  46. package/src/utils/env/isLocalStorageAvailable.ts +3 -24
  47. package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
  48. package/types/splitio.d.ts +46 -42
  49. package/cjs/storages/inLocalStorage/storageAdapter.js +0 -54
  50. package/esm/storages/inLocalStorage/storageAdapter.js +0 -50
  51. package/src/storages/inLocalStorage/storageAdapter.ts +0 -62
@@ -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, storage, settings, keys, currentTimestamp, isThereCache) {
14
+ function validateExpiration(options, settings, keys, currentTimestamp, isThereCache) {
15
15
  var log = settings.log;
16
16
  // Check expiration
17
- var lastUpdatedTimestamp = parseInt(storage.getItem(keys.buildLastUpdatedKey()), 10);
17
+ var lastUpdatedTimestamp = parseInt(localStorage.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, storage, settings, keys, currentTimestamp,
25
25
  }
26
26
  // Check hash
27
27
  var storageHashKey = keys.buildHashKey();
28
- var storageHash = storage.getItem(storageHashKey);
28
+ var storageHash = localStorage.getItem(storageHashKey);
29
29
  var currentStorageHash = (0, KeyBuilder_1.getStorageHash)(settings);
30
30
  if (storageHash !== currentStorageHash) {
31
31
  try {
32
- storage.setItem(storageHashKey, currentStorageHash);
32
+ localStorage.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, storage, settings, keys, currentTimestamp,
42
42
  }
43
43
  // Clear on init
44
44
  if (options.clearOnInit) {
45
- var lastClearTimestamp = parseInt(storage.getItem(keys.buildLastClear()), 10);
45
+ var lastClearTimestamp = parseInt(localStorage.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,29 +57,24 @@ function validateExpiration(options, storage, settings, keys, currentTimestamp,
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, 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
- // Persist clear
77
- if (storage.save)
78
- storage.save();
79
- return false;
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);
80
74
  }
81
- // Check if ready from cache
82
- return isThereCache;
83
- });
75
+ return false;
76
+ }
77
+ // Check if ready from cache
78
+ return isThereCache;
84
79
  }
85
80
  exports.validateCache = validateCache;
@@ -9,6 +9,8 @@ var ImpressionCountsCacheInMemory_1 = require("./ImpressionCountsCacheInMemory")
9
9
  var constants_1 = require("../../utils/constants");
10
10
  var TelemetryCacheInMemory_1 = require("./TelemetryCacheInMemory");
11
11
  var UniqueKeysCacheInMemoryCS_1 = require("./UniqueKeysCacheInMemoryCS");
12
+ var key_1 = require("../../utils/key");
13
+ var dataLoader_1 = require("../dataLoader");
12
14
  var RBSegmentsCacheInMemory_1 = require("./RBSegmentsCacheInMemory");
13
15
  /**
14
16
  * InMemory storage factory for standalone client-side SplitFactory
@@ -16,7 +18,8 @@ var RBSegmentsCacheInMemory_1 = require("./RBSegmentsCacheInMemory");
16
18
  * @param params - parameters required by EventsCacheSync
17
19
  */
18
20
  function InMemoryStorageCSFactory(params) {
19
- var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, __splitFiltersValidation = _a.sync.__splitFiltersValidation;
21
+ var _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, __splitFiltersValidation = _a.sync.__splitFiltersValidation, preloadedData = _a.preloadedData, onReadyFromCacheCb = params.onReadyFromCacheCb;
22
+ var storages = {};
20
23
  var splits = new SplitsCacheInMemory_1.SplitsCacheInMemory(__splitFiltersValidation);
21
24
  var rbSegments = new RBSegmentsCacheInMemory_1.RBSegmentsCacheInMemory();
22
25
  var segments = new MySegmentsCacheInMemory_1.MySegmentsCacheInMemory();
@@ -33,19 +36,27 @@ function InMemoryStorageCSFactory(params) {
33
36
  uniqueKeys: new UniqueKeysCacheInMemoryCS_1.UniqueKeysCacheInMemoryCS(),
34
37
  destroy: function () { },
35
38
  // When using shared instantiation with MEMORY we reuse everything but segments (they are unique per key)
36
- shared: function () {
37
- return {
38
- splits: this.splits,
39
- rbSegments: this.rbSegments,
40
- segments: new MySegmentsCacheInMemory_1.MySegmentsCacheInMemory(),
41
- largeSegments: new MySegmentsCacheInMemory_1.MySegmentsCacheInMemory(),
42
- impressions: this.impressions,
43
- impressionCounts: this.impressionCounts,
44
- events: this.events,
45
- telemetry: this.telemetry,
46
- uniqueKeys: this.uniqueKeys,
47
- destroy: function () { }
48
- };
39
+ shared: function (matchingKey) {
40
+ if (!storages[matchingKey]) {
41
+ var segments_1 = new MySegmentsCacheInMemory_1.MySegmentsCacheInMemory();
42
+ var largeSegments_1 = new MySegmentsCacheInMemory_1.MySegmentsCacheInMemory();
43
+ if (preloadedData) {
44
+ (0, dataLoader_1.setCache)(log, preloadedData, { segments: segments_1, largeSegments: largeSegments_1 }, matchingKey);
45
+ }
46
+ storages[matchingKey] = {
47
+ splits: this.splits,
48
+ rbSegments: this.rbSegments,
49
+ segments: segments_1,
50
+ largeSegments: largeSegments_1,
51
+ impressions: this.impressions,
52
+ impressionCounts: this.impressionCounts,
53
+ events: this.events,
54
+ telemetry: this.telemetry,
55
+ uniqueKeys: this.uniqueKeys,
56
+ destroy: function () { }
57
+ };
58
+ }
59
+ return storages[matchingKey];
49
60
  },
50
61
  };
51
62
  // @TODO revisit storage logic in localhost mode
@@ -57,6 +68,13 @@ function InMemoryStorageCSFactory(params) {
57
68
  storage.impressionCounts.track = noopTrack;
58
69
  storage.uniqueKeys.track = noopTrack;
59
70
  }
71
+ var matchingKey = (0, key_1.getMatching)(params.settings.core.key);
72
+ storages[matchingKey] = storage;
73
+ if (preloadedData) {
74
+ (0, dataLoader_1.setCache)(log, preloadedData, storage, matchingKey);
75
+ if (splits.getChangeNumber() > -1)
76
+ onReadyFromCacheCb();
77
+ }
60
78
  return storage;
61
79
  }
62
80
  exports.InMemoryStorageCSFactory = InMemoryStorageCSFactory;
@@ -45,6 +45,10 @@ var RBSegmentsCacheInMemory = /** @class */ (function () {
45
45
  RBSegmentsCacheInMemory.prototype.get = function (name) {
46
46
  return this.cache[name] || null;
47
47
  };
48
+ RBSegmentsCacheInMemory.prototype.getAll = function () {
49
+ var _this = this;
50
+ return this.getNames().map(function (key) { return _this.get(key); });
51
+ };
48
52
  RBSegmentsCacheInMemory.prototype.contains = function (names) {
49
53
  var namesArray = (0, sets_1.setToArray)(names);
50
54
  var namesInStorage = this.getNames();
@@ -45,9 +45,10 @@ 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
- Promise.resolve(storage.validateCache ? storage.validateCache() : false).then(function (isCacheLoaded) {
48
+ var isCacheLoaded_1 = storage.validateCache ? storage.validateCache() : false;
49
+ Promise.resolve().then(function () {
49
50
  // Emits SDK_READY_FROM_CACHE
50
- if (isCacheLoaded)
51
+ if (isCacheLoaded_1)
51
52
  readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED);
52
53
  // Emits SDK_READY
53
54
  readiness.segments.emit(constants_2.SDK_SEGMENTS_ARRIVED);
@@ -34,8 +34,6 @@ function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmentsEvent
34
34
  shouldNotifyUpdate = segments.resetSegments(segmentsData.ms || {});
35
35
  shouldNotifyUpdate = largeSegments.resetSegments(segmentsData.ls || {}) || shouldNotifyUpdate;
36
36
  }
37
- if (storage.save)
38
- storage.save();
39
37
  // Notify update if required
40
38
  if ((0, AbstractSplitsCacheSync_1.usesSegmentsSync)(storage) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
41
39
  readyOnAlreadyExistentState = false;
@@ -154,8 +154,6 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFilt
154
154
  segments.registerSegments((0, sets_1.setToArray)(usedSegments))
155
155
  ]).then(function (_a) {
156
156
  var ffChanged = _a[0], rbsChanged = _a[1];
157
- if (storage.save)
158
- storage.save();
159
157
  if (splitsEventEmitter) {
160
158
  // To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
161
159
  return Promise.resolve(!splitsEventEmitter.splitsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
@@ -69,39 +69,35 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
69
69
  */
70
70
  start: function () {
71
71
  running = true;
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();
95
- }
96
- }
97
- else {
72
+ if (startFirstTime) {
73
+ var isCacheLoaded = storage.validateCache ? storage.validateCache() : false;
74
+ if (isCacheLoaded)
75
+ Promise.resolve().then(function () { readiness.splits.emit(constants_4.SDK_SPLITS_CACHE_LOADED); });
76
+ }
77
+ // start syncing splits and segments
78
+ if (pollingManager) {
79
+ // If synchronization is disabled pushManager and pollingManager should not start
80
+ if (syncEnabled) {
81
+ if (pushManager) {
82
+ // Doesn't call `syncAll` when the syncManager is resuming
98
83
  if (startFirstTime) {
99
84
  pollingManager.syncAll();
100
85
  }
86
+ pushManager.start();
87
+ }
88
+ else {
89
+ pollingManager.start();
90
+ }
91
+ }
92
+ else {
93
+ if (startFirstTime) {
94
+ pollingManager.syncAll();
101
95
  }
102
96
  }
103
- startFirstTime = false;
104
- });
97
+ }
98
+ // start periodic data recording (events, impressions, telemetry).
99
+ submitterManager.start(!(0, consent_1.isConsentGranted)(settings));
100
+ startFirstTime = false;
105
101
  },
106
102
  /**
107
103
  * Method used to stop/pause the syncManager.
@@ -1,39 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isWebStorage = exports.isValidStorageWrapper = exports.isLocalStorageAvailable = void 0;
3
+ exports.isLocalStorageAvailable = void 0;
4
+ /* eslint-disable no-undef */
4
5
  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) {
15
6
  var mod = '__SPLITSOFTWARE__';
16
7
  try {
17
- wrapper.setItem(mod, mod);
18
- wrapper.getItem(mod);
19
- wrapper.removeItem(mod);
8
+ localStorage.setItem(mod, mod);
9
+ localStorage.removeItem(mod);
20
10
  return true;
21
11
  }
22
12
  catch (e) {
23
13
  return false;
24
14
  }
25
15
  }
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;
16
+ exports.isLocalStorageAvailable = isLocalStorageAvailable;
@@ -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 Promise.resolve(true); }; // to emit SDK_READY_FROM_CACHE
9
+ result.validateCache = function () { return true; }; // to emit SDK_READY_FROM_CACHE
10
10
  return result;
11
11
  }
12
12
  exports.__InLocalStorageMockFactory = __InLocalStorageMockFactory;
@@ -1,46 +1,104 @@
1
- // This value might be eventually set via a config parameter
2
- var DEFAULT_CACHE_EXPIRATION_IN_MILLIS = 864000000; // 10 days
1
+ import { setToArray } from '../utils/lang/sets';
2
+ import { getMatching } from '../utils/key';
3
3
  /**
4
- * Factory of client-side storage loader
5
- *
6
- * @param preloadedData - validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
7
- * and extended with a `mySegmentsData` property.
8
- * @returns function to preload the storage
4
+ * Sets the given synchronous storage with the provided preloaded data snapshot.
5
+ * If `matchingKey` is provided, the storage is handled as a client-side storage (segments and largeSegments are instances of MySegmentsCache).
6
+ * Otherwise, the storage is handled as a server-side storage (segments is an instance of SegmentsCache).
9
7
  */
10
- export function dataLoaderFactory(preloadedData) {
11
- /**
12
- * Storage-agnostic adaptation of `loadDataIntoLocalStorage` function
13
- * (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
14
- *
15
- * @param storage - object containing `splits` and `segments` cache (client-side variant)
16
- * @param userId - user key string of the provided MySegmentsCache
17
- */
18
- // @TODO extend to support SegmentsCache (server-side variant) by making `userId` optional and adding the corresponding logic.
19
- // @TODO extend to load data on shared mySegments storages. Be specific when emitting SDK_READY_FROM_CACHE on shared clients. Maybe the serializer should provide the `useSegments` flag.
20
- return function loadData(storage, userId) {
21
- // Do not load data if current preloadedData is empty
22
- if (Object.keys(preloadedData).length === 0)
23
- return;
24
- var _a = preloadedData.lastUpdated, lastUpdated = _a === void 0 ? -1 : _a, _b = preloadedData.segmentsData, segmentsData = _b === void 0 ? {} : _b, _c = preloadedData.since, since = _c === void 0 ? -1 : _c, _d = preloadedData.splitsData, splitsData = _d === void 0 ? {} : _d;
25
- var storedSince = storage.splits.getChangeNumber();
26
- var expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
27
- // Do not load data if current localStorage data is more recent,
28
- // or if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
29
- if (storedSince > since || lastUpdated < expirationTimestamp)
30
- return;
31
- // cleaning up the localStorage data, since some cached splits might need be part of the preloaded data
32
- storage.splits.clear();
33
- // splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
34
- storage.splits.update(Object.keys(splitsData).map(function (splitName) { return JSON.parse(splitsData[splitName]); }), [], since);
35
- // add mySegments data
36
- var mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userId];
37
- if (!mySegmentsData) {
38
- // segmentsData in an object where the property is the segment name and the pertaining value is a stringified object that contains the `added` array of userIds
39
- mySegmentsData = Object.keys(segmentsData).filter(function (segmentName) {
40
- var userIds = JSON.parse(segmentsData[segmentName]).added;
41
- return Array.isArray(userIds) && userIds.indexOf(userId) > -1;
42
- });
8
+ export function setCache(log, preloadedData, storage, matchingKey) {
9
+ // Do not load data if current preloadedData is empty
10
+ if (Object.keys(preloadedData).length === 0)
11
+ return;
12
+ var splits = storage.splits, rbSegments = storage.rbSegments, segments = storage.segments, largeSegments = storage.largeSegments;
13
+ log.debug("set cache" + (matchingKey ? " for key " + matchingKey : ''));
14
+ if (splits) {
15
+ splits.clear();
16
+ splits.update(preloadedData.flags || [], [], preloadedData.since || -1);
17
+ }
18
+ if (rbSegments) {
19
+ rbSegments.clear();
20
+ rbSegments.update(preloadedData.rbSegments || [], [], preloadedData.rbSince || -1);
21
+ }
22
+ var segmentsData = preloadedData.segments || {};
23
+ if (matchingKey) { // add memberships data (client-side)
24
+ var memberships = preloadedData.memberships && preloadedData.memberships[matchingKey];
25
+ if (!memberships && segmentsData) {
26
+ memberships = {
27
+ ms: {
28
+ k: Object.keys(segmentsData).filter(function (segmentName) {
29
+ var segmentKeys = segmentsData[segmentName];
30
+ return segmentKeys.indexOf(matchingKey) > -1;
31
+ }).map(function (segmentName) { return ({ n: segmentName }); })
32
+ }
33
+ };
43
34
  }
44
- storage.segments.resetSegments({ k: mySegmentsData.map(function (s) { return ({ n: s }); }) });
35
+ if (memberships) {
36
+ if (memberships.ms)
37
+ segments.resetSegments(memberships.ms);
38
+ if (memberships.ls && largeSegments)
39
+ largeSegments.resetSegments(memberships.ls);
40
+ }
41
+ }
42
+ else { // add segments data (server-side)
43
+ Object.keys(segmentsData).forEach(function (segmentName) {
44
+ var segmentKeys = segmentsData[segmentName];
45
+ segments.update(segmentName, segmentKeys, [], -1);
46
+ });
47
+ }
48
+ }
49
+ /**
50
+ * Gets the preloaded data snapshot from the given synchronous storage.
51
+ * If `keys` are provided, the memberships for those keys is returned, to protect segments data.
52
+ * Otherwise, the segments data is returned.
53
+ */
54
+ export function getCache(log, storage, keys) {
55
+ log.debug("get cache" + (keys ? " for keys " + keys : ''));
56
+ return {
57
+ since: storage.splits.getChangeNumber(),
58
+ flags: storage.splits.getAll(),
59
+ rbSince: storage.rbSegments.getChangeNumber(),
60
+ rbSegments: storage.rbSegments.getAll(),
61
+ segments: keys ?
62
+ undefined : // @ts-ignore accessing private prop
63
+ Object.keys(storage.segments.segmentCache).reduce(function (prev, cur) {
64
+ prev[cur] = setToArray(storage.segments.segmentCache[cur]);
65
+ return prev;
66
+ }, {}),
67
+ memberships: keys ?
68
+ keys.reduce(function (prev, key) {
69
+ if (storage.shared) {
70
+ // Client-side segments
71
+ // @ts-ignore accessing private prop
72
+ var sharedStorage = storage.shared(key);
73
+ prev[getMatching(key)] = {
74
+ ms: {
75
+ // @ts-ignore accessing private prop
76
+ k: Object.keys(sharedStorage.segments.segmentCache).map(function (segmentName) { return ({ n: segmentName }); }),
77
+ },
78
+ ls: sharedStorage.largeSegments ? {
79
+ // @ts-ignore accessing private prop
80
+ k: Object.keys(sharedStorage.largeSegments.segmentCache).map(function (segmentName) { return ({ n: segmentName }); }),
81
+ } : undefined
82
+ };
83
+ }
84
+ else {
85
+ prev[getMatching(key)] = {
86
+ ms: {
87
+ // Server-side segments
88
+ // @ts-ignore accessing private prop
89
+ k: Object.keys(storage.segments.segmentCache).reduce(function (prev, segmentName) {
90
+ return storage.segments.segmentCache[segmentName].has(key) ?
91
+ prev.concat({ n: segmentName }) :
92
+ prev;
93
+ }, [])
94
+ },
95
+ ls: {
96
+ k: []
97
+ }
98
+ };
99
+ }
100
+ return prev;
101
+ }, {}) :
102
+ undefined
45
103
  };
46
104
  }
@@ -4,20 +4,19 @@ 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, storage) {
7
+ function MySegmentsCacheInLocal(log, keys) {
8
8
  var _this = _super.call(this) || this;
9
9
  _this.log = log;
10
10
  _this.keys = keys;
11
- _this.storage = storage;
12
11
  return _this;
13
12
  // There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
14
13
  }
15
14
  MySegmentsCacheInLocal.prototype.addSegment = function (name) {
16
15
  var segmentKey = this.keys.buildSegmentNameKey(name);
17
16
  try {
18
- if (this.storage.getItem(segmentKey) === DEFINED)
17
+ if (localStorage.getItem(segmentKey) === DEFINED)
19
18
  return false;
20
- this.storage.setItem(segmentKey, DEFINED);
19
+ localStorage.setItem(segmentKey, DEFINED);
21
20
  return true;
22
21
  }
23
22
  catch (e) {
@@ -28,9 +27,9 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
28
27
  MySegmentsCacheInLocal.prototype.removeSegment = function (name) {
29
28
  var segmentKey = this.keys.buildSegmentNameKey(name);
30
29
  try {
31
- if (this.storage.getItem(segmentKey) !== DEFINED)
30
+ if (localStorage.getItem(segmentKey) !== DEFINED)
32
31
  return false;
33
- this.storage.removeItem(segmentKey);
32
+ localStorage.removeItem(segmentKey);
34
33
  return true;
35
34
  }
36
35
  catch (e) {
@@ -39,16 +38,17 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
39
38
  }
40
39
  };
41
40
  MySegmentsCacheInLocal.prototype.isInSegment = function (name) {
42
- return this.storage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
41
+ return localStorage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
43
42
  };
44
43
  MySegmentsCacheInLocal.prototype.getRegisteredSegments = function () {
45
- var registeredSegments = [];
46
- for (var i = 0, len = this.storage.length; i < len; i++) {
47
- var segmentName = this.keys.extractSegmentName(this.storage.key(i));
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);
48
48
  if (segmentName)
49
- registeredSegments.push(segmentName);
50
- }
51
- return registeredSegments;
49
+ accum.push(segmentName);
50
+ return accum;
51
+ }, []);
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
- this.storage.setItem(this.keys.buildTillKey(), changeNumber + '');
59
+ localStorage.setItem(this.keys.buildTillKey(), changeNumber + '');
60
60
  else
61
- this.storage.removeItem(this.keys.buildTillKey());
61
+ localStorage.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 = this.storage.getItem(this.keys.buildTillKey());
69
+ var value = localStorage.getItem(this.keys.buildTillKey());
70
70
  if (value !== null) {
71
71
  value = parseInt(value, 10);
72
72
  return isNaNNumber(value) ? n : value;