@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
package/CHANGES.txt CHANGED
@@ -1,5 +1,6 @@
1
1
  2.5.0 (August XX, 2025)
2
- - Added `storage.wrapper` configuration option to allow the SDK to use a custom storage wrapper for the storage type `LOCALSTORAGE`. Default value is `window.localStorage`.
2
+ - Added `factory.getCache()` method for standalone server-side SDKs, which returns the rollout plan snapshot from the storage.
3
+ - Added `preloadedData` configuration option for standalone client-side SDKs, which allows preloading the SDK storage with a snapshot of the rollout plan.
3
4
 
4
5
  2.4.1 (June 3, 2025)
5
6
  - Bugfix - Improved the Proxy fallback to flag spec version 1.2 to handle cases where the Proxy does not return an end-of-stream marker in 400 status code responses.
@@ -50,15 +51,6 @@
50
51
  - Removed internal ponyfills for `Map` and `Set` global objects, dropping support for IE and other outdated browsers. The SDK now requires the runtime environment to support these features natively or to provide a polyfill.
51
52
  - Removed the `sync.localhostMode` configuration option to plug the LocalhostMode module.
52
53
 
53
- 1.17.1 (July 25, 2025)
54
- - Updated the Redis storage to avoid lazy require of the `ioredis` dependency when the SDK is initialized.
55
- - Updated some transitive dependencies for vulnerability fixes.
56
- - Bugfix - Enhanced HTTP client module to implement timeouts for failing requests that might otherwise remain pending indefinitely on some Fetch API implementations, pausing the SDK synchronization process.
57
- - Bugfix - Properly handle rejected promises when using targeting rules with segment matchers in consumer modes (e.g., Redis and Pluggable storages).
58
- - Bugfix - Sanitize the `SplitSDKMachineName` header value to avoid exceptions on HTTP/S requests when it contains non ISO-8859-1 characters (Related to issue https://github.com/splitio/javascript-client/issues/847).
59
- - Bugfix - Fixed an issue with the SDK_UPDATE event on server-side, where it was not being emitted if there was an empty segment and the SDK received a feature flag update notification.
60
- - Bugfix - Fixed an issue with the server-side polling manager that caused dangling timers when the SDK was destroyed before it was ready.
61
-
62
54
  1.17.0 (September 6, 2024)
63
55
  - Added `sync.requestOptions.getHeaderOverrides` configuration option to enhance SDK HTTP request Headers for Authorization Frameworks.
64
56
  - Added `isTimedout` and `lastUpdate` properties to IStatusInterface to keep track of the timestamp of the last SDK event, used on React and Redux SDKs.
@@ -1,50 +1,109 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.dataLoaderFactory = void 0;
4
- // This value might be eventually set via a config parameter
5
- var DEFAULT_CACHE_EXPIRATION_IN_MILLIS = 864000000; // 10 days
3
+ exports.getCache = exports.setCache = void 0;
4
+ var sets_1 = require("../utils/lang/sets");
5
+ var key_1 = require("../utils/key");
6
6
  /**
7
- * Factory of client-side storage loader
8
- *
9
- * @param preloadedData - validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
10
- * and extended with a `mySegmentsData` property.
11
- * @returns function to preload the storage
7
+ * Sets the given synchronous storage with the provided preloaded data snapshot.
8
+ * If `matchingKey` is provided, the storage is handled as a client-side storage (segments and largeSegments are instances of MySegmentsCache).
9
+ * Otherwise, the storage is handled as a server-side storage (segments is an instance of SegmentsCache).
12
10
  */
13
- function dataLoaderFactory(preloadedData) {
14
- /**
15
- * Storage-agnostic adaptation of `loadDataIntoLocalStorage` function
16
- * (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
17
- *
18
- * @param storage - object containing `splits` and `segments` cache (client-side variant)
19
- * @param userId - user key string of the provided MySegmentsCache
20
- */
21
- // @TODO extend to support SegmentsCache (server-side variant) by making `userId` optional and adding the corresponding logic.
22
- // @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.
23
- return function loadData(storage, userId) {
24
- // Do not load data if current preloadedData is empty
25
- if (Object.keys(preloadedData).length === 0)
26
- return;
27
- 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;
28
- var storedSince = storage.splits.getChangeNumber();
29
- var expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
30
- // Do not load data if current localStorage data is more recent,
31
- // or if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
32
- if (storedSince > since || lastUpdated < expirationTimestamp)
33
- return;
34
- // cleaning up the localStorage data, since some cached splits might need be part of the preloaded data
35
- storage.splits.clear();
36
- // splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
37
- storage.splits.update(Object.keys(splitsData).map(function (splitName) { return JSON.parse(splitsData[splitName]); }), [], since);
38
- // add mySegments data
39
- var mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userId];
40
- if (!mySegmentsData) {
41
- // 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
42
- mySegmentsData = Object.keys(segmentsData).filter(function (segmentName) {
43
- var userIds = JSON.parse(segmentsData[segmentName]).added;
44
- return Array.isArray(userIds) && userIds.indexOf(userId) > -1;
45
- });
11
+ function setCache(log, preloadedData, storage, matchingKey) {
12
+ // Do not load data if current preloadedData is empty
13
+ if (Object.keys(preloadedData).length === 0)
14
+ return;
15
+ var splits = storage.splits, rbSegments = storage.rbSegments, segments = storage.segments, largeSegments = storage.largeSegments;
16
+ log.debug("set cache" + (matchingKey ? " for key " + matchingKey : ''));
17
+ if (splits) {
18
+ splits.clear();
19
+ splits.update(preloadedData.flags || [], [], preloadedData.since || -1);
20
+ }
21
+ if (rbSegments) {
22
+ rbSegments.clear();
23
+ rbSegments.update(preloadedData.rbSegments || [], [], preloadedData.rbSince || -1);
24
+ }
25
+ var segmentsData = preloadedData.segments || {};
26
+ if (matchingKey) { // add memberships data (client-side)
27
+ var memberships = preloadedData.memberships && preloadedData.memberships[matchingKey];
28
+ if (!memberships && segmentsData) {
29
+ memberships = {
30
+ ms: {
31
+ k: Object.keys(segmentsData).filter(function (segmentName) {
32
+ var segmentKeys = segmentsData[segmentName];
33
+ return segmentKeys.indexOf(matchingKey) > -1;
34
+ }).map(function (segmentName) { return ({ n: segmentName }); })
35
+ }
36
+ };
46
37
  }
47
- storage.segments.resetSegments({ k: mySegmentsData.map(function (s) { return ({ n: s }); }) });
38
+ if (memberships) {
39
+ if (memberships.ms)
40
+ segments.resetSegments(memberships.ms);
41
+ if (memberships.ls && largeSegments)
42
+ largeSegments.resetSegments(memberships.ls);
43
+ }
44
+ }
45
+ else { // add segments data (server-side)
46
+ Object.keys(segmentsData).forEach(function (segmentName) {
47
+ var segmentKeys = segmentsData[segmentName];
48
+ segments.update(segmentName, segmentKeys, [], -1);
49
+ });
50
+ }
51
+ }
52
+ exports.setCache = setCache;
53
+ /**
54
+ * Gets the preloaded data snapshot from the given synchronous storage.
55
+ * If `keys` are provided, the memberships for those keys is returned, to protect segments data.
56
+ * Otherwise, the segments data is returned.
57
+ */
58
+ function getCache(log, storage, keys) {
59
+ log.debug("get cache" + (keys ? " for keys " + keys : ''));
60
+ return {
61
+ since: storage.splits.getChangeNumber(),
62
+ flags: storage.splits.getAll(),
63
+ rbSince: storage.rbSegments.getChangeNumber(),
64
+ rbSegments: storage.rbSegments.getAll(),
65
+ segments: keys ?
66
+ undefined : // @ts-ignore accessing private prop
67
+ Object.keys(storage.segments.segmentCache).reduce(function (prev, cur) {
68
+ prev[cur] = (0, sets_1.setToArray)(storage.segments.segmentCache[cur]);
69
+ return prev;
70
+ }, {}),
71
+ memberships: keys ?
72
+ keys.reduce(function (prev, key) {
73
+ if (storage.shared) {
74
+ // Client-side segments
75
+ // @ts-ignore accessing private prop
76
+ var sharedStorage = storage.shared(key);
77
+ prev[(0, key_1.getMatching)(key)] = {
78
+ ms: {
79
+ // @ts-ignore accessing private prop
80
+ k: Object.keys(sharedStorage.segments.segmentCache).map(function (segmentName) { return ({ n: segmentName }); }),
81
+ },
82
+ ls: sharedStorage.largeSegments ? {
83
+ // @ts-ignore accessing private prop
84
+ k: Object.keys(sharedStorage.largeSegments.segmentCache).map(function (segmentName) { return ({ n: segmentName }); }),
85
+ } : undefined
86
+ };
87
+ }
88
+ else {
89
+ prev[(0, key_1.getMatching)(key)] = {
90
+ ms: {
91
+ // Server-side segments
92
+ // @ts-ignore accessing private prop
93
+ k: Object.keys(storage.segments.segmentCache).reduce(function (prev, segmentName) {
94
+ return storage.segments.segmentCache[segmentName].has(key) ?
95
+ prev.concat({ n: segmentName }) :
96
+ prev;
97
+ }, [])
98
+ },
99
+ ls: {
100
+ k: []
101
+ }
102
+ };
103
+ }
104
+ return prev;
105
+ }, {}) :
106
+ undefined
48
107
  };
49
108
  }
50
- exports.dataLoaderFactory = dataLoaderFactory;
109
+ exports.getCache = getCache;
@@ -7,20 +7,19 @@ var AbstractMySegmentsCacheSync_1 = require("../AbstractMySegmentsCacheSync");
7
7
  var constants_1 = require("./constants");
8
8
  var MySegmentsCacheInLocal = /** @class */ (function (_super) {
9
9
  (0, tslib_1.__extends)(MySegmentsCacheInLocal, _super);
10
- function MySegmentsCacheInLocal(log, keys, storage) {
10
+ function MySegmentsCacheInLocal(log, keys) {
11
11
  var _this = _super.call(this) || this;
12
12
  _this.log = log;
13
13
  _this.keys = keys;
14
- _this.storage = storage;
15
14
  return _this;
16
15
  // There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
17
16
  }
18
17
  MySegmentsCacheInLocal.prototype.addSegment = function (name) {
19
18
  var segmentKey = this.keys.buildSegmentNameKey(name);
20
19
  try {
21
- if (this.storage.getItem(segmentKey) === constants_1.DEFINED)
20
+ if (localStorage.getItem(segmentKey) === constants_1.DEFINED)
22
21
  return false;
23
- this.storage.setItem(segmentKey, constants_1.DEFINED);
22
+ localStorage.setItem(segmentKey, constants_1.DEFINED);
24
23
  return true;
25
24
  }
26
25
  catch (e) {
@@ -31,9 +30,9 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
31
30
  MySegmentsCacheInLocal.prototype.removeSegment = function (name) {
32
31
  var segmentKey = this.keys.buildSegmentNameKey(name);
33
32
  try {
34
- if (this.storage.getItem(segmentKey) !== constants_1.DEFINED)
33
+ if (localStorage.getItem(segmentKey) !== constants_1.DEFINED)
35
34
  return false;
36
- this.storage.removeItem(segmentKey);
35
+ localStorage.removeItem(segmentKey);
37
36
  return true;
38
37
  }
39
38
  catch (e) {
@@ -42,16 +41,17 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
42
41
  }
43
42
  };
44
43
  MySegmentsCacheInLocal.prototype.isInSegment = function (name) {
45
- return this.storage.getItem(this.keys.buildSegmentNameKey(name)) === constants_1.DEFINED;
44
+ return localStorage.getItem(this.keys.buildSegmentNameKey(name)) === constants_1.DEFINED;
46
45
  };
47
46
  MySegmentsCacheInLocal.prototype.getRegisteredSegments = function () {
48
- var registeredSegments = [];
49
- for (var i = 0, len = this.storage.length; i < len; i++) {
50
- var segmentName = this.keys.extractSegmentName(this.storage.key(i));
47
+ var _this = this;
48
+ // Scan current values from localStorage
49
+ return Object.keys(localStorage).reduce(function (accum, key) {
50
+ var segmentName = _this.keys.extractSegmentName(key);
51
51
  if (segmentName)
52
- registeredSegments.push(segmentName);
53
- }
54
- return registeredSegments;
52
+ accum.push(segmentName);
53
+ return accum;
54
+ }, []);
55
55
  };
56
56
  MySegmentsCacheInLocal.prototype.getKeysCount = function () {
57
57
  return 1;
@@ -59,9 +59,9 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
59
59
  MySegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
60
60
  try {
61
61
  if (changeNumber)
62
- this.storage.setItem(this.keys.buildTillKey(), changeNumber + '');
62
+ localStorage.setItem(this.keys.buildTillKey(), changeNumber + '');
63
63
  else
64
- this.storage.removeItem(this.keys.buildTillKey());
64
+ localStorage.removeItem(this.keys.buildTillKey());
65
65
  }
66
66
  catch (e) {
67
67
  this.log.error(e);
@@ -69,7 +69,7 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
69
69
  };
70
70
  MySegmentsCacheInLocal.prototype.getChangeNumber = function () {
71
71
  var n = -1;
72
- var value = this.storage.getItem(this.keys.buildTillKey());
72
+ var value = localStorage.getItem(this.keys.buildTillKey());
73
73
  if (value !== null) {
74
74
  value = parseInt(value, 10);
75
75
  return (0, lang_1.isNaNNumber)(value) ? n : value;
@@ -6,15 +6,14 @@ var sets_1 = require("../../utils/lang/sets");
6
6
  var AbstractSplitsCacheSync_1 = require("../AbstractSplitsCacheSync");
7
7
  var constants_1 = require("./constants");
8
8
  var RBSegmentsCacheInLocal = /** @class */ (function () {
9
- function RBSegmentsCacheInLocal(settings, keys, storage) {
9
+ function RBSegmentsCacheInLocal(settings, keys) {
10
10
  this.keys = keys;
11
11
  this.log = settings.log;
12
- this.storage = storage;
13
12
  }
14
13
  RBSegmentsCacheInLocal.prototype.clear = function () {
15
14
  var _this = this;
16
15
  this.getNames().forEach(function (name) { return _this.remove(name); });
17
- this.storage.removeItem(this.keys.buildRBSegmentsTillKey());
16
+ localStorage.removeItem(this.keys.buildRBSegmentsTillKey());
18
17
  };
19
18
  RBSegmentsCacheInLocal.prototype.update = function (toAdd, toRemove, changeNumber) {
20
19
  var _this = this;
@@ -24,8 +23,8 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
24
23
  };
25
24
  RBSegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
26
25
  try {
27
- this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
28
- this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
26
+ localStorage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
27
+ localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
29
28
  }
30
29
  catch (e) {
31
30
  this.log.error(constants_1.LOG_PREFIX + e);
@@ -33,19 +32,20 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
33
32
  };
34
33
  RBSegmentsCacheInLocal.prototype.updateSegmentCount = function (diff) {
35
34
  var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
36
- var count = (0, lang_1.toNumber)(this.storage.getItem(segmentsCountKey)) + diff;
35
+ var count = (0, lang_1.toNumber)(localStorage.getItem(segmentsCountKey)) + diff;
36
+ // @ts-expect-error
37
37
  if (count > 0)
38
- this.storage.setItem(segmentsCountKey, count + '');
38
+ localStorage.setItem(segmentsCountKey, count);
39
39
  else
40
- this.storage.removeItem(segmentsCountKey);
40
+ localStorage.removeItem(segmentsCountKey);
41
41
  };
42
42
  RBSegmentsCacheInLocal.prototype.add = function (rbSegment) {
43
43
  try {
44
44
  var name_1 = rbSegment.name;
45
45
  var rbSegmentKey = this.keys.buildRBSegmentKey(name_1);
46
- var rbSegmentFromStorage = this.storage.getItem(rbSegmentKey);
47
- var previous = rbSegmentFromStorage ? JSON.parse(rbSegmentFromStorage) : null;
48
- this.storage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
46
+ var rbSegmentFromLocalStorage = localStorage.getItem(rbSegmentKey);
47
+ var previous = rbSegmentFromLocalStorage ? JSON.parse(rbSegmentFromLocalStorage) : null;
48
+ localStorage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
49
49
  var usesSegmentsDiff = 0;
50
50
  if (previous && (0, AbstractSplitsCacheSync_1.usesSegments)(previous))
51
51
  usesSegmentsDiff--;
@@ -65,7 +65,7 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
65
65
  var rbSegment = this.get(name);
66
66
  if (!rbSegment)
67
67
  return false;
68
- this.storage.removeItem(this.keys.buildRBSegmentKey(name));
68
+ localStorage.removeItem(this.keys.buildRBSegmentKey(name));
69
69
  if ((0, AbstractSplitsCacheSync_1.usesSegments)(rbSegment))
70
70
  this.updateSegmentCount(-1);
71
71
  return true;
@@ -76,11 +76,11 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
76
76
  }
77
77
  };
78
78
  RBSegmentsCacheInLocal.prototype.getNames = function () {
79
- var len = this.storage.length;
79
+ var len = localStorage.length;
80
80
  var accum = [];
81
81
  var cur = 0;
82
82
  while (cur < len) {
83
- var key = this.storage.key(cur);
83
+ var key = localStorage.key(cur);
84
84
  if (key != null && this.keys.isRBSegmentKey(key))
85
85
  accum.push(this.keys.extractKey(key));
86
86
  cur++;
@@ -88,9 +88,13 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
88
88
  return accum;
89
89
  };
90
90
  RBSegmentsCacheInLocal.prototype.get = function (name) {
91
- var item = this.storage.getItem(this.keys.buildRBSegmentKey(name));
91
+ var item = localStorage.getItem(this.keys.buildRBSegmentKey(name));
92
92
  return item && JSON.parse(item);
93
93
  };
94
+ RBSegmentsCacheInLocal.prototype.getAll = function () {
95
+ var _this = this;
96
+ return this.getNames().map(function (key) { return _this.get(key); });
97
+ };
94
98
  RBSegmentsCacheInLocal.prototype.contains = function (names) {
95
99
  var namesArray = (0, sets_1.setToArray)(names);
96
100
  var namesInStorage = this.getNames();
@@ -98,7 +102,7 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
98
102
  };
99
103
  RBSegmentsCacheInLocal.prototype.getChangeNumber = function () {
100
104
  var n = -1;
101
- var value = this.storage.getItem(this.keys.buildRBSegmentsTillKey());
105
+ var value = localStorage.getItem(this.keys.buildRBSegmentsTillKey());
102
106
  if (value !== null) {
103
107
  value = parseInt(value, 10);
104
108
  return (0, lang_1.isNaNNumber)(value) ? n : value;
@@ -106,7 +110,7 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
106
110
  return n;
107
111
  };
108
112
  RBSegmentsCacheInLocal.prototype.usesSegments = function () {
109
- var storedCount = this.storage.getItem(this.keys.buildSplitsWithSegmentCountKey());
113
+ var storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
110
114
  var splitsWithSegmentsCount = storedCount === null ? 0 : (0, lang_1.toNumber)(storedCount);
111
115
  return (0, lang_1.isFiniteNumber)(splitsWithSegmentsCount) ?
112
116
  splitsWithSegmentsCount > 0 :
@@ -6,22 +6,25 @@ var AbstractSplitsCacheSync_1 = require("../AbstractSplitsCacheSync");
6
6
  var lang_1 = require("../../utils/lang");
7
7
  var constants_1 = require("./constants");
8
8
  var sets_1 = require("../../utils/lang/sets");
9
+ /**
10
+ * ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
11
+ */
9
12
  var SplitsCacheInLocal = /** @class */ (function (_super) {
10
13
  (0, tslib_1.__extends)(SplitsCacheInLocal, _super);
11
- function SplitsCacheInLocal(settings, keys, storage) {
14
+ function SplitsCacheInLocal(settings, keys) {
12
15
  var _this = _super.call(this) || this;
13
16
  _this.keys = keys;
14
17
  _this.log = settings.log;
15
18
  _this.flagSetsFilter = settings.sync.__splitFiltersValidation.groupedFilters.bySet;
16
- _this.storage = storage;
17
19
  return _this;
18
20
  }
19
21
  SplitsCacheInLocal.prototype._decrementCount = function (key) {
20
- var count = (0, lang_1.toNumber)(this.storage.getItem(key)) - 1;
22
+ var count = (0, lang_1.toNumber)(localStorage.getItem(key)) - 1;
23
+ // @ts-expect-error
21
24
  if (count > 0)
22
- this.storage.setItem(key, count + '');
25
+ localStorage.setItem(key, count);
23
26
  else
24
- this.storage.removeItem(key);
27
+ localStorage.removeItem(key);
25
28
  };
26
29
  SplitsCacheInLocal.prototype._decrementCounts = function (split) {
27
30
  try {
@@ -39,10 +42,12 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
39
42
  SplitsCacheInLocal.prototype._incrementCounts = function (split) {
40
43
  try {
41
44
  var ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
42
- this.storage.setItem(ttKey, ((0, lang_1.toNumber)(this.storage.getItem(ttKey)) + 1) + '');
45
+ // @ts-expect-error
46
+ localStorage.setItem(ttKey, (0, lang_1.toNumber)(localStorage.getItem(ttKey)) + 1);
43
47
  if ((0, AbstractSplitsCacheSync_1.usesSegments)(split)) {
44
48
  var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
45
- this.storage.setItem(segmentsCountKey, ((0, lang_1.toNumber)(this.storage.getItem(segmentsCountKey)) + 1) + '');
49
+ // @ts-expect-error
50
+ localStorage.setItem(segmentsCountKey, (0, lang_1.toNumber)(localStorage.getItem(segmentsCountKey)) + 1);
46
51
  }
47
52
  }
48
53
  catch (e) {
@@ -54,18 +59,17 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
54
59
  * We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
55
60
  */
56
61
  SplitsCacheInLocal.prototype.clear = function () {
57
- var _this = this;
58
62
  // collect item keys
59
- var len = this.storage.length;
63
+ var len = localStorage.length;
60
64
  var accum = [];
61
65
  for (var cur = 0; cur < len; cur++) {
62
- var key = this.storage.key(cur);
66
+ var key = localStorage.key(cur);
63
67
  if (key != null && this.keys.isSplitsCacheKey(key))
64
68
  accum.push(key);
65
69
  }
66
70
  // remove items
67
71
  accum.forEach(function (key) {
68
- _this.storage.removeItem(key);
72
+ localStorage.removeItem(key);
69
73
  });
70
74
  this.hasSync = false;
71
75
  };
@@ -73,13 +77,13 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
73
77
  try {
74
78
  var name_1 = split.name;
75
79
  var splitKey = this.keys.buildSplitKey(name_1);
76
- var splitFromStorage = this.storage.getItem(splitKey);
77
- var previousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : null;
80
+ var splitFromLocalStorage = localStorage.getItem(splitKey);
81
+ var previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
78
82
  if (previousSplit) {
79
83
  this._decrementCounts(previousSplit);
80
84
  this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
81
85
  }
82
- this.storage.setItem(splitKey, JSON.stringify(split));
86
+ localStorage.setItem(splitKey, JSON.stringify(split));
83
87
  this._incrementCounts(split);
84
88
  this.addToFlagSets(split);
85
89
  return true;
@@ -94,7 +98,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
94
98
  var split = this.getSplit(name);
95
99
  if (!split)
96
100
  return false;
97
- this.storage.removeItem(this.keys.buildSplitKey(name));
101
+ localStorage.removeItem(this.keys.buildSplitKey(name));
98
102
  this._decrementCounts(split);
99
103
  this.removeFromFlagSets(split.name, split.sets);
100
104
  return true;
@@ -105,14 +109,14 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
105
109
  }
106
110
  };
107
111
  SplitsCacheInLocal.prototype.getSplit = function (name) {
108
- var item = this.storage.getItem(this.keys.buildSplitKey(name));
112
+ var item = localStorage.getItem(this.keys.buildSplitKey(name));
109
113
  return item && JSON.parse(item);
110
114
  };
111
115
  SplitsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
112
116
  try {
113
- this.storage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
117
+ localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
114
118
  // update "last updated" timestamp with current time
115
- this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
119
+ localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
116
120
  this.hasSync = true;
117
121
  return true;
118
122
  }
@@ -123,7 +127,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
123
127
  };
124
128
  SplitsCacheInLocal.prototype.getChangeNumber = function () {
125
129
  var n = -1;
126
- var value = this.storage.getItem(this.keys.buildSplitsTillKey());
130
+ var value = localStorage.getItem(this.keys.buildSplitsTillKey());
127
131
  if (value !== null) {
128
132
  value = parseInt(value, 10);
129
133
  return (0, lang_1.isNaNNumber)(value) ? n : value;
@@ -131,11 +135,11 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
131
135
  return n;
132
136
  };
133
137
  SplitsCacheInLocal.prototype.getSplitNames = function () {
134
- var len = this.storage.length;
138
+ var len = localStorage.length;
135
139
  var accum = [];
136
140
  var cur = 0;
137
141
  while (cur < len) {
138
- var key = this.storage.key(cur);
142
+ var key = localStorage.key(cur);
139
143
  if (key != null && this.keys.isSplitKey(key))
140
144
  accum.push(this.keys.extractKey(key));
141
145
  cur++;
@@ -143,14 +147,14 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
143
147
  return accum;
144
148
  };
145
149
  SplitsCacheInLocal.prototype.trafficTypeExists = function (trafficType) {
146
- var ttCount = (0, lang_1.toNumber)(this.storage.getItem(this.keys.buildTrafficTypeKey(trafficType)));
150
+ var ttCount = (0, lang_1.toNumber)(localStorage.getItem(this.keys.buildTrafficTypeKey(trafficType)));
147
151
  return (0, lang_1.isFiniteNumber)(ttCount) && ttCount > 0;
148
152
  };
149
153
  SplitsCacheInLocal.prototype.usesSegments = function () {
150
154
  // If cache hasn't been synchronized with the cloud, assume we need them.
151
155
  if (!this.hasSync)
152
156
  return true;
153
- var storedCount = this.storage.getItem(this.keys.buildSplitsWithSegmentCountKey());
157
+ var storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
154
158
  var splitsWithSegmentsCount = storedCount === null ? 0 : (0, lang_1.toNumber)(storedCount);
155
159
  return (0, lang_1.isFiniteNumber)(splitsWithSegmentsCount) ?
156
160
  splitsWithSegmentsCount > 0 :
@@ -160,8 +164,8 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
160
164
  var _this = this;
161
165
  return flagSets.map(function (flagSet) {
162
166
  var flagSetKey = _this.keys.buildFlagSetKey(flagSet);
163
- var flagSetFromStorage = _this.storage.getItem(flagSetKey);
164
- return new Set(flagSetFromStorage ? JSON.parse(flagSetFromStorage) : []);
167
+ var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
168
+ return new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
165
169
  });
166
170
  };
167
171
  SplitsCacheInLocal.prototype.addToFlagSets = function (featureFlag) {
@@ -172,10 +176,10 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
172
176
  if (_this.flagSetsFilter.length > 0 && !_this.flagSetsFilter.some(function (filterFlagSet) { return filterFlagSet === featureFlagSet; }))
173
177
  return;
174
178
  var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
175
- var flagSetFromStorage = _this.storage.getItem(flagSetKey);
176
- var flagSetCache = new Set(flagSetFromStorage ? JSON.parse(flagSetFromStorage) : []);
179
+ var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
180
+ var flagSetCache = new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
177
181
  flagSetCache.add(featureFlag.name);
178
- _this.storage.setItem(flagSetKey, JSON.stringify((0, sets_1.setToArray)(flagSetCache)));
182
+ localStorage.setItem(flagSetKey, JSON.stringify((0, sets_1.setToArray)(flagSetCache)));
179
183
  });
180
184
  };
181
185
  SplitsCacheInLocal.prototype.removeFromFlagSets = function (featureFlagName, flagSets) {
@@ -188,16 +192,16 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
188
192
  };
189
193
  SplitsCacheInLocal.prototype.removeNames = function (flagSetName, featureFlagName) {
190
194
  var flagSetKey = this.keys.buildFlagSetKey(flagSetName);
191
- var flagSetFromStorage = this.storage.getItem(flagSetKey);
192
- if (!flagSetFromStorage)
195
+ var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
196
+ if (!flagSetFromLocalStorage)
193
197
  return;
194
- var flagSetCache = new Set(JSON.parse(flagSetFromStorage));
198
+ var flagSetCache = new Set(JSON.parse(flagSetFromLocalStorage));
195
199
  flagSetCache.delete(featureFlagName);
196
200
  if (flagSetCache.size === 0) {
197
- this.storage.removeItem(flagSetKey);
201
+ localStorage.removeItem(flagSetKey);
198
202
  return;
199
203
  }
200
- this.storage.setItem(flagSetKey, JSON.stringify((0, sets_1.setToArray)(flagSetCache)));
204
+ localStorage.setItem(flagSetKey, JSON.stringify((0, sets_1.setToArray)(flagSetCache)));
201
205
  };
202
206
  return SplitsCacheInLocal;
203
207
  }(AbstractSplitsCacheSync_1.AbstractSplitsCacheSync));
@@ -17,20 +17,6 @@ var TelemetryCacheInMemory_1 = require("../inMemory/TelemetryCacheInMemory");
17
17
  var UniqueKeysCacheInMemoryCS_1 = require("../inMemory/UniqueKeysCacheInMemoryCS");
18
18
  var key_1 = require("../../utils/key");
19
19
  var validateCache_1 = require("./validateCache");
20
- var storageAdapter_1 = require("./storageAdapter");
21
- function validateStorage(log, prefix, wrapper) {
22
- if (wrapper) {
23
- if ((0, isLocalStorageAvailable_1.isValidStorageWrapper)(wrapper)) {
24
- return (0, isLocalStorageAvailable_1.isWebStorage)(wrapper) ?
25
- wrapper : // localStorage and sessionStorage don't need adapter
26
- (0, storageAdapter_1.storageAdapter)(log, prefix, wrapper);
27
- }
28
- log.warn(constants_1.LOG_PREFIX + 'Invalid storage provided. Falling back to LocalStorage API');
29
- }
30
- if ((0, isLocalStorageAvailable_1.isLocalStorageAvailable)())
31
- return localStorage;
32
- log.warn(constants_1.LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
33
- }
34
20
  /**
35
21
  * InLocal storage factory for standalone client-side SplitFactory
36
22
  */
@@ -38,17 +24,18 @@ function InLocalStorage(options) {
38
24
  if (options === void 0) { options = {}; }
39
25
  var prefix = (0, KeyBuilder_1.validatePrefix)(options.prefix);
40
26
  function InLocalStorageCSFactory(params) {
41
- var settings = params.settings, _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
42
- var storage = validateStorage(log, prefix, options.wrapper);
43
- if (!storage)
27
+ // Fallback to InMemoryStorage if LocalStorage API is not available
28
+ if (!(0, isLocalStorageAvailable_1.isLocalStorageAvailable)()) {
29
+ params.settings.log.warn(constants_1.LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
44
30
  return (0, InMemoryStorageCS_1.InMemoryStorageCSFactory)(params);
31
+ }
32
+ var settings = params.settings, _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
45
33
  var matchingKey = (0, key_1.getMatching)(settings.core.key);
46
34
  var keys = new KeyBuilderCS_1.KeyBuilderCS(prefix, matchingKey);
47
- var splits = new SplitsCacheInLocal_1.SplitsCacheInLocal(settings, keys, storage);
48
- var rbSegments = new RBSegmentsCacheInLocal_1.RBSegmentsCacheInLocal(settings, keys, storage);
49
- var segments = new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, keys, storage);
50
- var largeSegments = new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, (0, KeyBuilderCS_1.myLargeSegmentsKeyBuilder)(prefix, matchingKey), storage);
51
- var validateCachePromise;
35
+ var splits = new SplitsCacheInLocal_1.SplitsCacheInLocal(settings, keys);
36
+ var rbSegments = new RBSegmentsCacheInLocal_1.RBSegmentsCacheInLocal(settings, keys);
37
+ var segments = new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, keys);
38
+ var largeSegments = new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, (0, KeyBuilderCS_1.myLargeSegmentsKeyBuilder)(prefix, matchingKey));
52
39
  return {
53
40
  splits: splits,
54
41
  rbSegments: rbSegments,
@@ -60,21 +47,16 @@ function InLocalStorage(options) {
60
47
  telemetry: (0, TelemetryCacheInMemory_1.shouldRecordTelemetry)(params) ? new TelemetryCacheInMemory_1.TelemetryCacheInMemory(splits, segments) : undefined,
61
48
  uniqueKeys: new UniqueKeysCacheInMemoryCS_1.UniqueKeysCacheInMemoryCS(),
62
49
  validateCache: function () {
63
- return validateCachePromise || (validateCachePromise = (0, validateCache_1.validateCache)(options, storage, settings, keys, splits, rbSegments, segments, largeSegments));
64
- },
65
- save: function () {
66
- return storage.save && storage.save();
67
- },
68
- destroy: function () {
69
- return storage.whenSaved && storage.whenSaved();
50
+ return (0, validateCache_1.validateCache)(options, settings, keys, splits, rbSegments, segments, largeSegments);
70
51
  },
52
+ destroy: function () { },
71
53
  // When using shared instantiation with MEMORY we reuse everything but segments (they are customer per key).
72
54
  shared: function (matchingKey) {
73
55
  return {
74
56
  splits: this.splits,
75
57
  rbSegments: this.rbSegments,
76
- segments: new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, new KeyBuilderCS_1.KeyBuilderCS(prefix, matchingKey), storage),
77
- largeSegments: new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, (0, KeyBuilderCS_1.myLargeSegmentsKeyBuilder)(prefix, matchingKey), storage),
58
+ segments: new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, new KeyBuilderCS_1.KeyBuilderCS(prefix, matchingKey)),
59
+ largeSegments: new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, (0, KeyBuilderCS_1.myLargeSegmentsKeyBuilder)(prefix, matchingKey)),
78
60
  impressions: this.impressions,
79
61
  impressionCounts: this.impressionCounts,
80
62
  events: this.events,