@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
@@ -3,15 +3,14 @@ import { setToArray } from '../../utils/lang/sets';
3
3
  import { usesSegments } from '../AbstractSplitsCacheSync';
4
4
  import { LOG_PREFIX } from './constants';
5
5
  var RBSegmentsCacheInLocal = /** @class */ (function () {
6
- function RBSegmentsCacheInLocal(settings, keys, storage) {
6
+ function RBSegmentsCacheInLocal(settings, keys) {
7
7
  this.keys = keys;
8
8
  this.log = settings.log;
9
- this.storage = storage;
10
9
  }
11
10
  RBSegmentsCacheInLocal.prototype.clear = function () {
12
11
  var _this = this;
13
12
  this.getNames().forEach(function (name) { return _this.remove(name); });
14
- this.storage.removeItem(this.keys.buildRBSegmentsTillKey());
13
+ localStorage.removeItem(this.keys.buildRBSegmentsTillKey());
15
14
  };
16
15
  RBSegmentsCacheInLocal.prototype.update = function (toAdd, toRemove, changeNumber) {
17
16
  var _this = this;
@@ -21,8 +20,8 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
21
20
  };
22
21
  RBSegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
23
22
  try {
24
- this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
25
- this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
23
+ localStorage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
24
+ localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
26
25
  }
27
26
  catch (e) {
28
27
  this.log.error(LOG_PREFIX + e);
@@ -30,19 +29,20 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
30
29
  };
31
30
  RBSegmentsCacheInLocal.prototype.updateSegmentCount = function (diff) {
32
31
  var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
33
- var count = toNumber(this.storage.getItem(segmentsCountKey)) + diff;
32
+ var count = toNumber(localStorage.getItem(segmentsCountKey)) + diff;
33
+ // @ts-expect-error
34
34
  if (count > 0)
35
- this.storage.setItem(segmentsCountKey, count + '');
35
+ localStorage.setItem(segmentsCountKey, count);
36
36
  else
37
- this.storage.removeItem(segmentsCountKey);
37
+ localStorage.removeItem(segmentsCountKey);
38
38
  };
39
39
  RBSegmentsCacheInLocal.prototype.add = function (rbSegment) {
40
40
  try {
41
41
  var name_1 = rbSegment.name;
42
42
  var rbSegmentKey = this.keys.buildRBSegmentKey(name_1);
43
- var rbSegmentFromStorage = this.storage.getItem(rbSegmentKey);
44
- var previous = rbSegmentFromStorage ? JSON.parse(rbSegmentFromStorage) : null;
45
- this.storage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
43
+ var rbSegmentFromLocalStorage = localStorage.getItem(rbSegmentKey);
44
+ var previous = rbSegmentFromLocalStorage ? JSON.parse(rbSegmentFromLocalStorage) : null;
45
+ localStorage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
46
46
  var usesSegmentsDiff = 0;
47
47
  if (previous && usesSegments(previous))
48
48
  usesSegmentsDiff--;
@@ -62,7 +62,7 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
62
62
  var rbSegment = this.get(name);
63
63
  if (!rbSegment)
64
64
  return false;
65
- this.storage.removeItem(this.keys.buildRBSegmentKey(name));
65
+ localStorage.removeItem(this.keys.buildRBSegmentKey(name));
66
66
  if (usesSegments(rbSegment))
67
67
  this.updateSegmentCount(-1);
68
68
  return true;
@@ -73,11 +73,11 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
73
73
  }
74
74
  };
75
75
  RBSegmentsCacheInLocal.prototype.getNames = function () {
76
- var len = this.storage.length;
76
+ var len = localStorage.length;
77
77
  var accum = [];
78
78
  var cur = 0;
79
79
  while (cur < len) {
80
- var key = this.storage.key(cur);
80
+ var key = localStorage.key(cur);
81
81
  if (key != null && this.keys.isRBSegmentKey(key))
82
82
  accum.push(this.keys.extractKey(key));
83
83
  cur++;
@@ -85,9 +85,13 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
85
85
  return accum;
86
86
  };
87
87
  RBSegmentsCacheInLocal.prototype.get = function (name) {
88
- var item = this.storage.getItem(this.keys.buildRBSegmentKey(name));
88
+ var item = localStorage.getItem(this.keys.buildRBSegmentKey(name));
89
89
  return item && JSON.parse(item);
90
90
  };
91
+ RBSegmentsCacheInLocal.prototype.getAll = function () {
92
+ var _this = this;
93
+ return this.getNames().map(function (key) { return _this.get(key); });
94
+ };
91
95
  RBSegmentsCacheInLocal.prototype.contains = function (names) {
92
96
  var namesArray = setToArray(names);
93
97
  var namesInStorage = this.getNames();
@@ -95,7 +99,7 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
95
99
  };
96
100
  RBSegmentsCacheInLocal.prototype.getChangeNumber = function () {
97
101
  var n = -1;
98
- var value = this.storage.getItem(this.keys.buildRBSegmentsTillKey());
102
+ var value = localStorage.getItem(this.keys.buildRBSegmentsTillKey());
99
103
  if (value !== null) {
100
104
  value = parseInt(value, 10);
101
105
  return isNaNNumber(value) ? n : value;
@@ -103,7 +107,7 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
103
107
  return n;
104
108
  };
105
109
  RBSegmentsCacheInLocal.prototype.usesSegments = function () {
106
- var storedCount = this.storage.getItem(this.keys.buildSplitsWithSegmentCountKey());
110
+ var storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
107
111
  var splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
108
112
  return isFiniteNumber(splitsWithSegmentsCount) ?
109
113
  splitsWithSegmentsCount > 0 :
@@ -3,22 +3,25 @@ import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSyn
3
3
  import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
4
4
  import { LOG_PREFIX } from './constants';
5
5
  import { setToArray } from '../../utils/lang/sets';
6
+ /**
7
+ * ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
8
+ */
6
9
  var SplitsCacheInLocal = /** @class */ (function (_super) {
7
10
  __extends(SplitsCacheInLocal, _super);
8
- function SplitsCacheInLocal(settings, keys, storage) {
11
+ function SplitsCacheInLocal(settings, keys) {
9
12
  var _this = _super.call(this) || this;
10
13
  _this.keys = keys;
11
14
  _this.log = settings.log;
12
15
  _this.flagSetsFilter = settings.sync.__splitFiltersValidation.groupedFilters.bySet;
13
- _this.storage = storage;
14
16
  return _this;
15
17
  }
16
18
  SplitsCacheInLocal.prototype._decrementCount = function (key) {
17
- var count = toNumber(this.storage.getItem(key)) - 1;
19
+ var count = toNumber(localStorage.getItem(key)) - 1;
20
+ // @ts-expect-error
18
21
  if (count > 0)
19
- this.storage.setItem(key, count + '');
22
+ localStorage.setItem(key, count);
20
23
  else
21
- this.storage.removeItem(key);
24
+ localStorage.removeItem(key);
22
25
  };
23
26
  SplitsCacheInLocal.prototype._decrementCounts = function (split) {
24
27
  try {
@@ -36,10 +39,12 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
36
39
  SplitsCacheInLocal.prototype._incrementCounts = function (split) {
37
40
  try {
38
41
  var ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
39
- this.storage.setItem(ttKey, (toNumber(this.storage.getItem(ttKey)) + 1) + '');
42
+ // @ts-expect-error
43
+ localStorage.setItem(ttKey, toNumber(localStorage.getItem(ttKey)) + 1);
40
44
  if (usesSegments(split)) {
41
45
  var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
42
- this.storage.setItem(segmentsCountKey, (toNumber(this.storage.getItem(segmentsCountKey)) + 1) + '');
46
+ // @ts-expect-error
47
+ localStorage.setItem(segmentsCountKey, toNumber(localStorage.getItem(segmentsCountKey)) + 1);
43
48
  }
44
49
  }
45
50
  catch (e) {
@@ -51,18 +56,17 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
51
56
  * We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
52
57
  */
53
58
  SplitsCacheInLocal.prototype.clear = function () {
54
- var _this = this;
55
59
  // collect item keys
56
- var len = this.storage.length;
60
+ var len = localStorage.length;
57
61
  var accum = [];
58
62
  for (var cur = 0; cur < len; cur++) {
59
- var key = this.storage.key(cur);
63
+ var key = localStorage.key(cur);
60
64
  if (key != null && this.keys.isSplitsCacheKey(key))
61
65
  accum.push(key);
62
66
  }
63
67
  // remove items
64
68
  accum.forEach(function (key) {
65
- _this.storage.removeItem(key);
69
+ localStorage.removeItem(key);
66
70
  });
67
71
  this.hasSync = false;
68
72
  };
@@ -70,13 +74,13 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
70
74
  try {
71
75
  var name_1 = split.name;
72
76
  var splitKey = this.keys.buildSplitKey(name_1);
73
- var splitFromStorage = this.storage.getItem(splitKey);
74
- var previousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : null;
77
+ var splitFromLocalStorage = localStorage.getItem(splitKey);
78
+ var previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
75
79
  if (previousSplit) {
76
80
  this._decrementCounts(previousSplit);
77
81
  this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
78
82
  }
79
- this.storage.setItem(splitKey, JSON.stringify(split));
83
+ localStorage.setItem(splitKey, JSON.stringify(split));
80
84
  this._incrementCounts(split);
81
85
  this.addToFlagSets(split);
82
86
  return true;
@@ -91,7 +95,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
91
95
  var split = this.getSplit(name);
92
96
  if (!split)
93
97
  return false;
94
- this.storage.removeItem(this.keys.buildSplitKey(name));
98
+ localStorage.removeItem(this.keys.buildSplitKey(name));
95
99
  this._decrementCounts(split);
96
100
  this.removeFromFlagSets(split.name, split.sets);
97
101
  return true;
@@ -102,14 +106,14 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
102
106
  }
103
107
  };
104
108
  SplitsCacheInLocal.prototype.getSplit = function (name) {
105
- var item = this.storage.getItem(this.keys.buildSplitKey(name));
109
+ var item = localStorage.getItem(this.keys.buildSplitKey(name));
106
110
  return item && JSON.parse(item);
107
111
  };
108
112
  SplitsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
109
113
  try {
110
- this.storage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
114
+ localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
111
115
  // update "last updated" timestamp with current time
112
- this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
116
+ localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
113
117
  this.hasSync = true;
114
118
  return true;
115
119
  }
@@ -120,7 +124,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
120
124
  };
121
125
  SplitsCacheInLocal.prototype.getChangeNumber = function () {
122
126
  var n = -1;
123
- var value = this.storage.getItem(this.keys.buildSplitsTillKey());
127
+ var value = localStorage.getItem(this.keys.buildSplitsTillKey());
124
128
  if (value !== null) {
125
129
  value = parseInt(value, 10);
126
130
  return isNaNNumber(value) ? n : value;
@@ -128,11 +132,11 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
128
132
  return n;
129
133
  };
130
134
  SplitsCacheInLocal.prototype.getSplitNames = function () {
131
- var len = this.storage.length;
135
+ var len = localStorage.length;
132
136
  var accum = [];
133
137
  var cur = 0;
134
138
  while (cur < len) {
135
- var key = this.storage.key(cur);
139
+ var key = localStorage.key(cur);
136
140
  if (key != null && this.keys.isSplitKey(key))
137
141
  accum.push(this.keys.extractKey(key));
138
142
  cur++;
@@ -140,14 +144,14 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
140
144
  return accum;
141
145
  };
142
146
  SplitsCacheInLocal.prototype.trafficTypeExists = function (trafficType) {
143
- var ttCount = toNumber(this.storage.getItem(this.keys.buildTrafficTypeKey(trafficType)));
147
+ var ttCount = toNumber(localStorage.getItem(this.keys.buildTrafficTypeKey(trafficType)));
144
148
  return isFiniteNumber(ttCount) && ttCount > 0;
145
149
  };
146
150
  SplitsCacheInLocal.prototype.usesSegments = function () {
147
151
  // If cache hasn't been synchronized with the cloud, assume we need them.
148
152
  if (!this.hasSync)
149
153
  return true;
150
- var storedCount = this.storage.getItem(this.keys.buildSplitsWithSegmentCountKey());
154
+ var storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
151
155
  var splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
152
156
  return isFiniteNumber(splitsWithSegmentsCount) ?
153
157
  splitsWithSegmentsCount > 0 :
@@ -157,8 +161,8 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
157
161
  var _this = this;
158
162
  return flagSets.map(function (flagSet) {
159
163
  var flagSetKey = _this.keys.buildFlagSetKey(flagSet);
160
- var flagSetFromStorage = _this.storage.getItem(flagSetKey);
161
- return new Set(flagSetFromStorage ? JSON.parse(flagSetFromStorage) : []);
164
+ var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
165
+ return new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
162
166
  });
163
167
  };
164
168
  SplitsCacheInLocal.prototype.addToFlagSets = function (featureFlag) {
@@ -169,10 +173,10 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
169
173
  if (_this.flagSetsFilter.length > 0 && !_this.flagSetsFilter.some(function (filterFlagSet) { return filterFlagSet === featureFlagSet; }))
170
174
  return;
171
175
  var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
172
- var flagSetFromStorage = _this.storage.getItem(flagSetKey);
173
- var flagSetCache = new Set(flagSetFromStorage ? JSON.parse(flagSetFromStorage) : []);
176
+ var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
177
+ var flagSetCache = new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
174
178
  flagSetCache.add(featureFlag.name);
175
- _this.storage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
179
+ localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
176
180
  });
177
181
  };
178
182
  SplitsCacheInLocal.prototype.removeFromFlagSets = function (featureFlagName, flagSets) {
@@ -185,16 +189,16 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
185
189
  };
186
190
  SplitsCacheInLocal.prototype.removeNames = function (flagSetName, featureFlagName) {
187
191
  var flagSetKey = this.keys.buildFlagSetKey(flagSetName);
188
- var flagSetFromStorage = this.storage.getItem(flagSetKey);
189
- if (!flagSetFromStorage)
192
+ var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
193
+ if (!flagSetFromLocalStorage)
190
194
  return;
191
- var flagSetCache = new Set(JSON.parse(flagSetFromStorage));
195
+ var flagSetCache = new Set(JSON.parse(flagSetFromLocalStorage));
192
196
  flagSetCache.delete(featureFlagName);
193
197
  if (flagSetCache.size === 0) {
194
- this.storage.removeItem(flagSetKey);
198
+ localStorage.removeItem(flagSetKey);
195
199
  return;
196
200
  }
197
- this.storage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
201
+ localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
198
202
  };
199
203
  return SplitsCacheInLocal;
200
204
  }(AbstractSplitsCacheSync));
@@ -3,7 +3,7 @@ import { ImpressionCountsCacheInMemory } from '../inMemory/ImpressionCountsCache
3
3
  import { EventsCacheInMemory } from '../inMemory/EventsCacheInMemory';
4
4
  import { validatePrefix } from '../KeyBuilder';
5
5
  import { KeyBuilderCS, myLargeSegmentsKeyBuilder } from '../KeyBuilderCS';
6
- import { isLocalStorageAvailable, isValidStorageWrapper, isWebStorage } from '../../utils/env/isLocalStorageAvailable';
6
+ import { isLocalStorageAvailable } from '../../utils/env/isLocalStorageAvailable';
7
7
  import { SplitsCacheInLocal } from './SplitsCacheInLocal';
8
8
  import { RBSegmentsCacheInLocal } from './RBSegmentsCacheInLocal';
9
9
  import { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
@@ -14,20 +14,6 @@ import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/Telem
14
14
  import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
15
15
  import { getMatching } from '../../utils/key';
16
16
  import { validateCache } from './validateCache';
17
- import { storageAdapter } from './storageAdapter';
18
- function validateStorage(log, prefix, wrapper) {
19
- if (wrapper) {
20
- if (isValidStorageWrapper(wrapper)) {
21
- return isWebStorage(wrapper) ?
22
- wrapper : // localStorage and sessionStorage don't need adapter
23
- storageAdapter(log, prefix, wrapper);
24
- }
25
- log.warn(LOG_PREFIX + 'Invalid storage provided. Falling back to LocalStorage API');
26
- }
27
- if (isLocalStorageAvailable())
28
- return localStorage;
29
- log.warn(LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
30
- }
31
17
  /**
32
18
  * InLocal storage factory for standalone client-side SplitFactory
33
19
  */
@@ -35,17 +21,18 @@ export function InLocalStorage(options) {
35
21
  if (options === void 0) { options = {}; }
36
22
  var prefix = validatePrefix(options.prefix);
37
23
  function InLocalStorageCSFactory(params) {
38
- var settings = params.settings, _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
39
- var storage = validateStorage(log, prefix, options.wrapper);
40
- if (!storage)
24
+ // Fallback to InMemoryStorage if LocalStorage API is not available
25
+ if (!isLocalStorageAvailable()) {
26
+ params.settings.log.warn(LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
41
27
  return InMemoryStorageCSFactory(params);
28
+ }
29
+ var settings = params.settings, _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
42
30
  var matchingKey = getMatching(settings.core.key);
43
31
  var keys = new KeyBuilderCS(prefix, matchingKey);
44
- var splits = new SplitsCacheInLocal(settings, keys, storage);
45
- var rbSegments = new RBSegmentsCacheInLocal(settings, keys, storage);
46
- var segments = new MySegmentsCacheInLocal(log, keys, storage);
47
- var largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey), storage);
48
- var validateCachePromise;
32
+ var splits = new SplitsCacheInLocal(settings, keys);
33
+ var rbSegments = new RBSegmentsCacheInLocal(settings, keys);
34
+ var segments = new MySegmentsCacheInLocal(log, keys);
35
+ var largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey));
49
36
  return {
50
37
  splits: splits,
51
38
  rbSegments: rbSegments,
@@ -57,21 +44,16 @@ export function InLocalStorage(options) {
57
44
  telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
58
45
  uniqueKeys: new UniqueKeysCacheInMemoryCS(),
59
46
  validateCache: function () {
60
- return validateCachePromise || (validateCachePromise = validateCache(options, storage, settings, keys, splits, rbSegments, segments, largeSegments));
61
- },
62
- save: function () {
63
- return storage.save && storage.save();
64
- },
65
- destroy: function () {
66
- return storage.whenSaved && storage.whenSaved();
47
+ return validateCache(options, settings, keys, splits, rbSegments, segments, largeSegments);
67
48
  },
49
+ destroy: function () { },
68
50
  // When using shared instantiation with MEMORY we reuse everything but segments (they are customer per key).
69
51
  shared: function (matchingKey) {
70
52
  return {
71
53
  splits: this.splits,
72
54
  rbSegments: this.rbSegments,
73
- segments: new MySegmentsCacheInLocal(log, new KeyBuilderCS(prefix, matchingKey), storage),
74
- largeSegments: new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey), storage),
55
+ segments: new MySegmentsCacheInLocal(log, new KeyBuilderCS(prefix, matchingKey)),
56
+ largeSegments: new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey)),
75
57
  impressions: this.impressions,
76
58
  impressionCounts: this.impressionCounts,
77
59
  events: this.events,
@@ -8,10 +8,10 @@ var MILLIS_IN_A_DAY = 86400000;
8
8
  *
9
9
  * @returns `true` if cache should be cleared, `false` otherwise
10
10
  */
11
- function validateExpiration(options, storage, settings, keys, currentTimestamp, isThereCache) {
11
+ function validateExpiration(options, settings, keys, currentTimestamp, isThereCache) {
12
12
  var log = settings.log;
13
13
  // Check expiration
14
- var lastUpdatedTimestamp = parseInt(storage.getItem(keys.buildLastUpdatedKey()), 10);
14
+ var lastUpdatedTimestamp = parseInt(localStorage.getItem(keys.buildLastUpdatedKey()), 10);
15
15
  if (!isNaNNumber(lastUpdatedTimestamp)) {
16
16
  var cacheExpirationInDays = isFiniteNumber(options.expirationDays) && options.expirationDays >= 1 ? options.expirationDays : DEFAULT_CACHE_EXPIRATION_IN_DAYS;
17
17
  var expirationTimestamp = currentTimestamp - MILLIS_IN_A_DAY * cacheExpirationInDays;
@@ -22,11 +22,11 @@ function validateExpiration(options, storage, settings, keys, currentTimestamp,
22
22
  }
23
23
  // Check hash
24
24
  var storageHashKey = keys.buildHashKey();
25
- var storageHash = storage.getItem(storageHashKey);
25
+ var storageHash = localStorage.getItem(storageHashKey);
26
26
  var currentStorageHash = getStorageHash(settings);
27
27
  if (storageHash !== currentStorageHash) {
28
28
  try {
29
- storage.setItem(storageHashKey, currentStorageHash);
29
+ localStorage.setItem(storageHashKey, currentStorageHash);
30
30
  }
31
31
  catch (e) {
32
32
  log.error(LOG_PREFIX + e);
@@ -39,7 +39,7 @@ function validateExpiration(options, storage, settings, keys, currentTimestamp,
39
39
  }
40
40
  // Clear on init
41
41
  if (options.clearOnInit) {
42
- var lastClearTimestamp = parseInt(storage.getItem(keys.buildLastClear()), 10);
42
+ var lastClearTimestamp = parseInt(localStorage.getItem(keys.buildLastClear()), 10);
43
43
  if (isNaNNumber(lastClearTimestamp) || lastClearTimestamp < currentTimestamp - MILLIS_IN_A_DAY) {
44
44
  log.info(LOG_PREFIX + 'clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache');
45
45
  return true;
@@ -54,28 +54,23 @@ function validateExpiration(options, storage, settings, keys, currentTimestamp,
54
54
  *
55
55
  * @returns `true` if cache is ready to be used, `false` otherwise (cache was cleared or there is no cache)
56
56
  */
57
- export function validateCache(options, storage, settings, keys, splits, rbSegments, segments, largeSegments) {
58
- return Promise.resolve(storage.load && storage.load()).then(function () {
59
- var currentTimestamp = Date.now();
60
- var isThereCache = splits.getChangeNumber() > -1;
61
- if (validateExpiration(options, storage, settings, keys, currentTimestamp, isThereCache)) {
62
- splits.clear();
63
- rbSegments.clear();
64
- segments.clear();
65
- largeSegments.clear();
66
- // Update last clear timestamp
67
- try {
68
- storage.setItem(keys.buildLastClear(), currentTimestamp + '');
69
- }
70
- catch (e) {
71
- settings.log.error(LOG_PREFIX + e);
72
- }
73
- // Persist clear
74
- if (storage.save)
75
- storage.save();
76
- return false;
57
+ export function validateCache(options, settings, keys, splits, rbSegments, segments, largeSegments) {
58
+ var currentTimestamp = Date.now();
59
+ var isThereCache = splits.getChangeNumber() > -1;
60
+ if (validateExpiration(options, settings, keys, currentTimestamp, isThereCache)) {
61
+ splits.clear();
62
+ rbSegments.clear();
63
+ segments.clear();
64
+ largeSegments.clear();
65
+ // Update last clear timestamp
66
+ try {
67
+ localStorage.setItem(keys.buildLastClear(), currentTimestamp + '');
68
+ }
69
+ catch (e) {
70
+ settings.log.error(LOG_PREFIX + e);
77
71
  }
78
- // Check if ready from cache
79
- return isThereCache;
80
- });
72
+ return false;
73
+ }
74
+ // Check if ready from cache
75
+ return isThereCache;
81
76
  }
@@ -6,6 +6,8 @@ import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
6
6
  import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
7
7
  import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
8
8
  import { UniqueKeysCacheInMemoryCS } from './UniqueKeysCacheInMemoryCS';
9
+ import { getMatching } from '../../utils/key';
10
+ import { setCache } from '../dataLoader';
9
11
  import { RBSegmentsCacheInMemory } from './RBSegmentsCacheInMemory';
10
12
  /**
11
13
  * InMemory storage factory for standalone client-side SplitFactory
@@ -13,7 +15,8 @@ import { RBSegmentsCacheInMemory } from './RBSegmentsCacheInMemory';
13
15
  * @param params - parameters required by EventsCacheSync
14
16
  */
15
17
  export function InMemoryStorageCSFactory(params) {
16
- var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, __splitFiltersValidation = _a.sync.__splitFiltersValidation;
18
+ 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;
19
+ var storages = {};
17
20
  var splits = new SplitsCacheInMemory(__splitFiltersValidation);
18
21
  var rbSegments = new RBSegmentsCacheInMemory();
19
22
  var segments = new MySegmentsCacheInMemory();
@@ -30,19 +33,27 @@ export function InMemoryStorageCSFactory(params) {
30
33
  uniqueKeys: new UniqueKeysCacheInMemoryCS(),
31
34
  destroy: function () { },
32
35
  // When using shared instantiation with MEMORY we reuse everything but segments (they are unique per key)
33
- shared: function () {
34
- return {
35
- splits: this.splits,
36
- rbSegments: this.rbSegments,
37
- segments: new MySegmentsCacheInMemory(),
38
- largeSegments: new MySegmentsCacheInMemory(),
39
- impressions: this.impressions,
40
- impressionCounts: this.impressionCounts,
41
- events: this.events,
42
- telemetry: this.telemetry,
43
- uniqueKeys: this.uniqueKeys,
44
- destroy: function () { }
45
- };
36
+ shared: function (matchingKey) {
37
+ if (!storages[matchingKey]) {
38
+ var segments_1 = new MySegmentsCacheInMemory();
39
+ var largeSegments_1 = new MySegmentsCacheInMemory();
40
+ if (preloadedData) {
41
+ setCache(log, preloadedData, { segments: segments_1, largeSegments: largeSegments_1 }, matchingKey);
42
+ }
43
+ storages[matchingKey] = {
44
+ splits: this.splits,
45
+ rbSegments: this.rbSegments,
46
+ segments: segments_1,
47
+ largeSegments: largeSegments_1,
48
+ impressions: this.impressions,
49
+ impressionCounts: this.impressionCounts,
50
+ events: this.events,
51
+ telemetry: this.telemetry,
52
+ uniqueKeys: this.uniqueKeys,
53
+ destroy: function () { }
54
+ };
55
+ }
56
+ return storages[matchingKey];
46
57
  },
47
58
  };
48
59
  // @TODO revisit storage logic in localhost mode
@@ -54,6 +65,13 @@ export function InMemoryStorageCSFactory(params) {
54
65
  storage.impressionCounts.track = noopTrack;
55
66
  storage.uniqueKeys.track = noopTrack;
56
67
  }
68
+ var matchingKey = getMatching(params.settings.core.key);
69
+ storages[matchingKey] = storage;
70
+ if (preloadedData) {
71
+ setCache(log, preloadedData, storage, matchingKey);
72
+ if (splits.getChangeNumber() > -1)
73
+ onReadyFromCacheCb();
74
+ }
57
75
  return storage;
58
76
  }
59
77
  InMemoryStorageCSFactory.type = STORAGE_MEMORY;
@@ -42,6 +42,10 @@ var RBSegmentsCacheInMemory = /** @class */ (function () {
42
42
  RBSegmentsCacheInMemory.prototype.get = function (name) {
43
43
  return this.cache[name] || null;
44
44
  };
45
+ RBSegmentsCacheInMemory.prototype.getAll = function () {
46
+ var _this = this;
47
+ return this.getNames().map(function (key) { return _this.get(key); });
48
+ };
45
49
  RBSegmentsCacheInMemory.prototype.contains = function (names) {
46
50
  var namesArray = setToArray(names);
47
51
  var namesInStorage = this.getNames();
@@ -42,9 +42,10 @@ export function fromObjectUpdaterFactory(splitsParser, storage, readiness, setti
42
42
  readiness.splits.emit(SDK_SPLITS_ARRIVED);
43
43
  if (startingUp) {
44
44
  startingUp = false;
45
- Promise.resolve(storage.validateCache ? storage.validateCache() : false).then(function (isCacheLoaded) {
45
+ var isCacheLoaded_1 = storage.validateCache ? storage.validateCache() : false;
46
+ Promise.resolve().then(function () {
46
47
  // Emits SDK_READY_FROM_CACHE
47
- if (isCacheLoaded)
48
+ if (isCacheLoaded_1)
48
49
  readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
49
50
  // Emits SDK_READY
50
51
  readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
@@ -31,8 +31,6 @@ export function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmen
31
31
  shouldNotifyUpdate = segments.resetSegments(segmentsData.ms || {});
32
32
  shouldNotifyUpdate = largeSegments.resetSegments(segmentsData.ls || {}) || shouldNotifyUpdate;
33
33
  }
34
- if (storage.save)
35
- storage.save();
36
34
  // Notify update if required
37
35
  if (usesSegmentsSync(storage) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
38
36
  readyOnAlreadyExistentState = false;
@@ -149,8 +149,6 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, sp
149
149
  segments.registerSegments(setToArray(usedSegments))
150
150
  ]).then(function (_a) {
151
151
  var ffChanged = _a[0], rbsChanged = _a[1];
152
- if (storage.save)
153
- storage.save();
154
152
  if (splitsEventEmitter) {
155
153
  // To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
156
154
  return Promise.resolve(!splitsEventEmitter.splitsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))