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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGES.txt +3 -11
  2. package/cjs/evaluator/convertions/index.js +9 -1
  3. package/cjs/evaluator/matchersTransform/index.js +2 -3
  4. package/cjs/sdkClient/sdkClientMethodCS.js +5 -1
  5. package/cjs/sdkFactory/index.js +8 -2
  6. package/cjs/storages/getRolloutPlan.js +69 -0
  7. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  8. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +21 -17
  9. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
  10. package/cjs/storages/inLocalStorage/index.js +13 -31
  11. package/cjs/storages/inLocalStorage/validateCache.js +25 -30
  12. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
  13. package/cjs/storages/setRolloutPlan.js +66 -0
  14. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  15. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +0 -2
  16. package/cjs/sync/polling/updaters/splitChangesUpdater.js +0 -2
  17. package/cjs/sync/syncManagerOnline.js +24 -28
  18. package/cjs/utils/env/isLocalStorageAvailable.js +5 -28
  19. package/cjs/utils/inputValidation/index.js +1 -3
  20. package/cjs/utils/settingsValidation/index.js +4 -0
  21. package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
  22. package/esm/evaluator/convertions/index.js +7 -0
  23. package/esm/evaluator/matchersTransform/index.js +3 -4
  24. package/esm/sdkClient/sdkClientMethodCS.js +5 -1
  25. package/esm/sdkFactory/index.js +8 -2
  26. package/esm/storages/getRolloutPlan.js +65 -0
  27. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +16 -16
  28. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +21 -17
  29. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +37 -33
  30. package/esm/storages/inLocalStorage/index.js +14 -32
  31. package/esm/storages/inLocalStorage/validateCache.js +25 -30
  32. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +4 -0
  33. package/esm/storages/setRolloutPlan.js +61 -0
  34. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  35. package/esm/sync/polling/updaters/mySegmentsUpdater.js +0 -2
  36. package/esm/sync/polling/updaters/splitChangesUpdater.js +0 -2
  37. package/esm/sync/syncManagerOnline.js +24 -28
  38. package/esm/utils/env/isLocalStorageAvailable.js +3 -24
  39. package/esm/utils/inputValidation/index.js +0 -1
  40. package/esm/utils/settingsValidation/index.js +4 -0
  41. package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
  42. package/package.json +1 -1
  43. package/src/evaluator/convertions/index.ts +10 -0
  44. package/src/evaluator/matchersTransform/index.ts +3 -4
  45. package/src/sdkClient/sdkClientMethodCS.ts +7 -1
  46. package/src/sdkFactory/index.ts +12 -4
  47. package/src/storages/getRolloutPlan.ts +72 -0
  48. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +17 -18
  49. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +22 -19
  50. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +37 -34
  51. package/src/storages/inLocalStorage/index.ts +16 -37
  52. package/src/storages/inLocalStorage/validateCache.ts +25 -31
  53. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +4 -0
  54. package/src/storages/setRolloutPlan.ts +71 -0
  55. package/src/storages/types.ts +25 -23
  56. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +2 -1
  57. package/src/sync/polling/updaters/mySegmentsUpdater.ts +0 -2
  58. package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -3
  59. package/src/sync/syncManagerOnline.ts +22 -27
  60. package/src/types.ts +2 -35
  61. package/src/utils/env/isLocalStorageAvailable.ts +3 -24
  62. package/src/utils/inputValidation/index.ts +0 -1
  63. package/src/utils/settingsValidation/index.ts +4 -0
  64. package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
  65. package/types/splitio.d.ts +36 -44
  66. package/cjs/storages/dataLoader.js +0 -50
  67. package/cjs/storages/inLocalStorage/storageAdapter.js +0 -54
  68. package/cjs/utils/inputValidation/preloadedData.js +0 -59
  69. package/esm/storages/dataLoader.js +0 -46
  70. package/esm/storages/inLocalStorage/storageAdapter.js +0 -50
  71. package/esm/utils/inputValidation/preloadedData.js +0 -55
  72. package/src/storages/dataLoader.ts +0 -55
  73. package/src/storages/inLocalStorage/storageAdapter.ts +0 -62
  74. package/src/utils/inputValidation/preloadedData.ts +0 -57
@@ -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;
@@ -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) {
12
- var log = settings.log;
11
+ function validateExpiration(options, settings, keys, currentTimestamp, isThereCache) {
12
+ var log = settings.log, initialRolloutPlan = settings.initialRolloutPlan;
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,16 +22,16 @@ 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);
33
33
  }
34
- if (isThereCache) {
34
+ if (isThereCache && !initialRolloutPlan) {
35
35
  log.info(LOG_PREFIX + 'SDK key, flags filter criteria, or flags spec version has changed. Cleaning up cache');
36
36
  return true;
37
37
  }
@@ -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
  }
@@ -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();
@@ -0,0 +1,61 @@
1
+ import { isObject } from '../utils/lang';
2
+ import { isConsumerMode } from '../utils/settingsValidation/mode';
3
+ /**
4
+ * Validates if the given rollout plan is valid.
5
+ */
6
+ export function validateRolloutPlan(log, settings) {
7
+ var mode = settings.mode, initialRolloutPlan = settings.initialRolloutPlan;
8
+ if (isConsumerMode(mode)) {
9
+ log.warn('storage: initial rollout plan is ignored in consumer mode');
10
+ return;
11
+ }
12
+ if (isObject(initialRolloutPlan) && isObject(initialRolloutPlan.splitChanges))
13
+ return initialRolloutPlan;
14
+ log.error('storage: invalid rollout plan provided');
15
+ return;
16
+ }
17
+ /**
18
+ * Sets the given synchronous storage with the provided rollout plan snapshot.
19
+ * If `matchingKey` is provided, the storage is handled as a client-side storage (segments and largeSegments are instances of MySegmentsCache).
20
+ * Otherwise, the storage is handled as a server-side storage (segments is an instance of SegmentsCache).
21
+ */
22
+ export function setRolloutPlan(log, rolloutPlan, storage, matchingKey) {
23
+ var splits = storage.splits, rbSegments = storage.rbSegments, segments = storage.segments, largeSegments = storage.largeSegments;
24
+ var _a = rolloutPlan.splitChanges, ff = _a.ff, rbs = _a.rbs;
25
+ log.debug("storage: set feature flags and segments" + (matchingKey ? " for key " + matchingKey : ''));
26
+ if (splits && ff) {
27
+ splits.clear();
28
+ splits.update(ff.d, [], ff.t);
29
+ }
30
+ if (rbSegments && rbs) {
31
+ rbSegments.clear();
32
+ rbSegments.update(rbs.d, [], rbs.t);
33
+ }
34
+ var segmentChanges = rolloutPlan.segmentChanges;
35
+ if (matchingKey) { // add memberships data (client-side)
36
+ var memberships = rolloutPlan.memberships && rolloutPlan.memberships[matchingKey];
37
+ if (!memberships && segmentChanges) {
38
+ memberships = {
39
+ ms: {
40
+ k: segmentChanges.filter(function (segment) {
41
+ return segment.added.indexOf(matchingKey) > -1;
42
+ }).map(function (segment) { return ({ n: segment.name }); })
43
+ }
44
+ };
45
+ }
46
+ if (memberships) {
47
+ if (memberships.ms)
48
+ segments.resetSegments(memberships.ms);
49
+ if (memberships.ls && largeSegments)
50
+ largeSegments.resetSegments(memberships.ls);
51
+ }
52
+ }
53
+ else { // add segments data (server-side)
54
+ if (segmentChanges) {
55
+ segments.clear();
56
+ segmentChanges.forEach(function (segment) {
57
+ segments.update(segment.name, segment.added, segment.removed, segment.till);
58
+ });
59
+ }
60
+ }
61
+ }
@@ -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);