@splitsoftware/splitio-commons 2.1.1-rc.1 → 2.2.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 (50) hide show
  1. package/CHANGES.txt +5 -1
  2. package/cjs/readiness/readinessManager.js +6 -0
  3. package/cjs/storages/AbstractSplitsCacheAsync.js +0 -7
  4. package/cjs/storages/AbstractSplitsCacheSync.js +0 -7
  5. package/cjs/storages/KeyBuilderCS.js +3 -0
  6. package/cjs/storages/dataLoader.js +3 -2
  7. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +11 -69
  8. package/cjs/storages/inLocalStorage/index.js +5 -3
  9. package/cjs/storages/inLocalStorage/validateCache.js +79 -0
  10. package/cjs/storages/pluggable/index.js +2 -1
  11. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  12. package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -12
  13. package/cjs/sync/syncManagerOnline.js +8 -3
  14. package/cjs/trackers/strategy/strategyDebug.js +2 -0
  15. package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
  16. package/esm/readiness/readinessManager.js +6 -0
  17. package/esm/storages/AbstractSplitsCacheAsync.js +0 -7
  18. package/esm/storages/AbstractSplitsCacheSync.js +0 -7
  19. package/esm/storages/KeyBuilderCS.js +3 -0
  20. package/esm/storages/dataLoader.js +2 -1
  21. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +11 -69
  22. package/esm/storages/inLocalStorage/index.js +5 -3
  23. package/esm/storages/inLocalStorage/validateCache.js +75 -0
  24. package/esm/storages/pluggable/index.js +2 -1
  25. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  26. package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -13
  27. package/esm/sync/syncManagerOnline.js +8 -3
  28. package/esm/trackers/strategy/strategyDebug.js +2 -0
  29. package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
  30. package/package.json +1 -1
  31. package/src/readiness/readinessManager.ts +5 -0
  32. package/src/storages/AbstractSplitsCacheAsync.ts +0 -8
  33. package/src/storages/AbstractSplitsCacheSync.ts +0 -8
  34. package/src/storages/KeyBuilderCS.ts +4 -0
  35. package/src/storages/dataLoader.ts +3 -1
  36. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +13 -78
  37. package/src/storages/inLocalStorage/index.ts +8 -8
  38. package/src/storages/inLocalStorage/validateCache.ts +91 -0
  39. package/src/storages/pluggable/index.ts +2 -1
  40. package/src/storages/types.ts +1 -4
  41. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +6 -5
  42. package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -13
  43. package/src/sync/syncManagerOnline.ts +9 -3
  44. package/src/trackers/strategy/strategyDebug.ts +2 -0
  45. package/src/utils/lang/index.ts +1 -1
  46. package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
  47. package/types/splitio.d.ts +28 -1
  48. package/cjs/utils/constants/browser.js +0 -5
  49. package/esm/utils/constants/browser.js +0 -2
  50. package/src/utils/constants/browser.ts +0 -2
package/CHANGES.txt CHANGED
@@ -1,5 +1,9 @@
1
1
  2.2.0 (March 28, 2025)
2
- - Added new optional argument to the client `getTreatment` methods to allow passing additional evaluation options, such as a map of properties to append to the generated impression object sent to Split's backend. Read more in our docs.
2
+ - Added a new optional argument to the client `getTreatment` methods to allow passing additional evaluation options, such as a map of properties to append to the generated impressions sent to Split backend. Read more in our docs.
3
+ - Added two new configuration options for the SDK storage in browsers when using storage type `LOCALSTORAGE`:
4
+ - `storage.expirationDays` to specify the validity period of the rollout cache.
5
+ - `storage.clearOnInit` to clear the rollout cache on SDK initialization.
6
+ - Updated SDK_READY_FROM_CACHE event when using the `LOCALSTORAGE` storage type to be emitted alongside the SDK_READY event if it has not already been emitted.
3
7
 
4
8
  2.1.0 (January 17, 2025)
5
9
  - Added support for the new impressions tracking toggle available on feature flags, both respecting the setting and including the new field being returned on `SplitView` type objects. Read more in our docs.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readinessManagerFactory = void 0;
4
4
  var objectAssign_1 = require("../utils/lang/objectAssign");
5
5
  var constants_1 = require("./constants");
6
+ var constants_2 = require("../utils/constants");
6
7
  function splitsEventEmitterFactory(EventEmitter) {
7
8
  var splitsEventEmitter = (0, objectAssign_1.objectAssign)(new EventEmitter(), {
8
9
  splitsArrived: false,
@@ -83,6 +84,7 @@ function readinessManagerFactory(EventEmitter, settings, splits, isShared) {
83
84
  }
84
85
  }
85
86
  function checkIsReadyOrUpdate(diff) {
87
+ var _a;
86
88
  if (isDestroyed)
87
89
  return;
88
90
  if (isReady) {
@@ -101,6 +103,10 @@ function readinessManagerFactory(EventEmitter, settings, splits, isShared) {
101
103
  isReady = true;
102
104
  try {
103
105
  syncLastUpdate();
106
+ if (!isReadyFromCache && ((_a = settings.storage) === null || _a === void 0 ? void 0 : _a.type) === constants_2.STORAGE_LOCALSTORAGE) {
107
+ isReadyFromCache = true;
108
+ gate.emit(constants_1.SDK_READY_FROM_CACHE);
109
+ }
104
110
  gate.emit(constants_1.SDK_READY);
105
111
  }
106
112
  catch (e) {
@@ -25,13 +25,6 @@ var AbstractSplitsCacheAsync = /** @class */ (function () {
25
25
  AbstractSplitsCacheAsync.prototype.usesSegments = function () {
26
26
  return Promise.resolve(true);
27
27
  };
28
- /**
29
- * Check if the splits information is already stored in cache.
30
- * Noop, just keeping the interface. This is used by client-side implementations only.
31
- */
32
- AbstractSplitsCacheAsync.prototype.checkCache = function () {
33
- return Promise.resolve(false);
34
- };
35
28
  /**
36
29
  * Kill `name` split and set `defaultTreatment` and `changeNumber`.
37
30
  * Used for SPLIT_KILL push notifications.
@@ -28,13 +28,6 @@ var AbstractSplitsCacheSync = /** @class */ (function () {
28
28
  var _this = this;
29
29
  return this.getSplitNames().map(function (key) { return _this.getSplit(key); });
30
30
  };
31
- /**
32
- * Check if the splits information is already stored in cache. This data can be preloaded.
33
- * It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE.
34
- */
35
- AbstractSplitsCacheSync.prototype.checkCache = function () {
36
- return false;
37
- };
38
31
  /**
39
32
  * Kill `name` split and set `defaultTreatment` and `changeNumber`.
40
33
  * Used for SPLIT_KILL push notifications.
@@ -38,6 +38,9 @@ var KeyBuilderCS = /** @class */ (function (_super) {
38
38
  KeyBuilderCS.prototype.buildSplitsWithSegmentCountKey = function () {
39
39
  return this.prefix + ".splits.usingSegments";
40
40
  };
41
+ KeyBuilderCS.prototype.buildLastClear = function () {
42
+ return this.prefix + ".lastClear";
43
+ };
41
44
  return KeyBuilderCS;
42
45
  }(KeyBuilder_1.KeyBuilder));
43
46
  exports.KeyBuilderCS = KeyBuilderCS;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dataLoaderFactory = void 0;
4
- var browser_1 = require("../utils/constants/browser");
4
+ // This value might be eventually set via a config parameter
5
+ var DEFAULT_CACHE_EXPIRATION_IN_MILLIS = 864000000; // 10 days
5
6
  /**
6
7
  * Factory of client-side storage loader
7
8
  *
@@ -25,7 +26,7 @@ function dataLoaderFactory(preloadedData) {
25
26
  return;
26
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;
27
28
  var storedSince = storage.splits.getChangeNumber();
28
- var expirationTimestamp = Date.now() - browser_1.DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
29
+ var expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
29
30
  // Do not load data if current localStorage data is more recent,
30
31
  // or if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
31
32
  if (storedSince > since || lastUpdated < expirationTimestamp)
@@ -5,21 +5,17 @@ var tslib_1 = require("tslib");
5
5
  var AbstractSplitsCacheSync_1 = require("../AbstractSplitsCacheSync");
6
6
  var lang_1 = require("../../utils/lang");
7
7
  var constants_1 = require("./constants");
8
- var KeyBuilder_1 = require("../KeyBuilder");
9
8
  var sets_1 = require("../../utils/lang/sets");
10
9
  /**
11
10
  * ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
12
11
  */
13
12
  var SplitsCacheInLocal = /** @class */ (function (_super) {
14
13
  (0, tslib_1.__extends)(SplitsCacheInLocal, _super);
15
- function SplitsCacheInLocal(settings, keys, expirationTimestamp) {
14
+ function SplitsCacheInLocal(settings, keys) {
16
15
  var _this = _super.call(this) || this;
17
16
  _this.keys = keys;
18
17
  _this.log = settings.log;
19
- _this.storageHash = (0, KeyBuilder_1.getStorageHash)(settings);
20
18
  _this.flagSetsFilter = settings.sync.__splitFiltersValidation.groupedFilters.bySet;
21
- _this._checkExpiration(expirationTimestamp);
22
- _this._checkFilterQuery();
23
19
  return _this;
24
20
  }
25
21
  SplitsCacheInLocal.prototype._decrementCount = function (key) {
@@ -32,13 +28,11 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
32
28
  };
33
29
  SplitsCacheInLocal.prototype._decrementCounts = function (split) {
34
30
  try {
35
- if (split) {
36
- var ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
37
- this._decrementCount(ttKey);
38
- if ((0, AbstractSplitsCacheSync_1.usesSegments)(split)) {
39
- var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
40
- this._decrementCount(segmentsCountKey);
41
- }
31
+ var ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
32
+ this._decrementCount(ttKey);
33
+ if ((0, AbstractSplitsCacheSync_1.usesSegments)(split)) {
34
+ var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
35
+ this._decrementCount(segmentsCountKey);
42
36
  }
43
37
  }
44
38
  catch (e) {
@@ -67,7 +61,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
67
61
  * We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
68
62
  */
69
63
  SplitsCacheInLocal.prototype.clear = function () {
70
- this.log.info(constants_1.LOG_PREFIX + 'Flushing Splits data from localStorage');
71
64
  // collect item keys
72
65
  var len = localStorage.length;
73
66
  var accum = [];
@@ -88,11 +81,12 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
88
81
  var splitKey = this.keys.buildSplitKey(name_1);
89
82
  var splitFromLocalStorage = localStorage.getItem(splitKey);
90
83
  var previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
84
+ if (previousSplit) {
85
+ this._decrementCounts(previousSplit);
86
+ this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
87
+ }
91
88
  localStorage.setItem(splitKey, JSON.stringify(split));
92
89
  this._incrementCounts(split);
93
- this._decrementCounts(previousSplit);
94
- if (previousSplit)
95
- this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
96
90
  this.addToFlagSets(split);
97
91
  return true;
98
92
  }
@@ -108,8 +102,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
108
102
  return false;
109
103
  localStorage.removeItem(this.keys.buildSplitKey(name));
110
104
  this._decrementCounts(split);
111
- if (split)
112
- this.removeFromFlagSets(split.name, split.sets);
105
+ this.removeFromFlagSets(split.name, split.sets);
113
106
  return true;
114
107
  }
115
108
  catch (e) {
@@ -122,18 +115,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
122
115
  return item && JSON.parse(item);
123
116
  };
124
117
  SplitsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
125
- // when using a new split query, we must update it at the store
126
- if (this.updateNewFilter) {
127
- this.log.info(constants_1.LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version was modified. Updating cache');
128
- var storageHashKey = this.keys.buildHashKey();
129
- try {
130
- localStorage.setItem(storageHashKey, this.storageHash);
131
- }
132
- catch (e) {
133
- this.log.error(constants_1.LOG_PREFIX + e);
134
- }
135
- this.updateNewFilter = false;
136
- }
137
118
  try {
138
119
  localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
139
120
  // update "last updated" timestamp with current time
@@ -184,45 +165,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
184
165
  return true;
185
166
  }
186
167
  };
187
- /**
188
- * Check if the splits information is already stored in browser LocalStorage.
189
- * In this function we could add more code to check if the data is valid.
190
- * @override
191
- */
192
- SplitsCacheInLocal.prototype.checkCache = function () {
193
- return this.getChangeNumber() > -1;
194
- };
195
- /**
196
- * Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
197
- *
198
- * @param expirationTimestamp - if the value is not a number, data will not be cleaned
199
- */
200
- SplitsCacheInLocal.prototype._checkExpiration = function (expirationTimestamp) {
201
- var value = localStorage.getItem(this.keys.buildLastUpdatedKey());
202
- if (value !== null) {
203
- value = parseInt(value, 10);
204
- if (!(0, lang_1.isNaNNumber)(value) && expirationTimestamp && value < expirationTimestamp)
205
- this.clear();
206
- }
207
- };
208
- // @TODO eventually remove `_checkFilterQuery`. Cache should be cleared at the storage level, reusing same logic than PluggableStorage
209
- SplitsCacheInLocal.prototype._checkFilterQuery = function () {
210
- var storageHashKey = this.keys.buildHashKey();
211
- var storageHash = localStorage.getItem(storageHashKey);
212
- if (storageHash !== this.storageHash) {
213
- try {
214
- // mark cache to update the new query filter on first successful splits fetch
215
- this.updateNewFilter = true;
216
- // if there is cache, clear it
217
- if (this.checkCache())
218
- this.clear();
219
- }
220
- catch (e) {
221
- this.log.error(constants_1.LOG_PREFIX + e);
222
- }
223
- }
224
- // if the filter didn't change, nothing is done
225
- };
226
168
  SplitsCacheInLocal.prototype.getNamesByFlagSets = function (flagSets) {
227
169
  var _this = this;
228
170
  return flagSets.map(function (flagSet) {
@@ -9,13 +9,13 @@ var KeyBuilderCS_1 = require("../KeyBuilderCS");
9
9
  var isLocalStorageAvailable_1 = require("../../utils/env/isLocalStorageAvailable");
10
10
  var SplitsCacheInLocal_1 = require("./SplitsCacheInLocal");
11
11
  var MySegmentsCacheInLocal_1 = require("./MySegmentsCacheInLocal");
12
- var browser_1 = require("../../utils/constants/browser");
13
12
  var InMemoryStorageCS_1 = require("../inMemory/InMemoryStorageCS");
14
13
  var constants_1 = require("./constants");
15
14
  var constants_2 = require("../../utils/constants");
16
15
  var TelemetryCacheInMemory_1 = require("../inMemory/TelemetryCacheInMemory");
17
16
  var UniqueKeysCacheInMemoryCS_1 = require("../inMemory/UniqueKeysCacheInMemoryCS");
18
17
  var key_1 = require("../../utils/key");
18
+ var validateCache_1 = require("./validateCache");
19
19
  /**
20
20
  * InLocal storage factory for standalone client-side SplitFactory
21
21
  */
@@ -31,8 +31,7 @@ function InLocalStorage(options) {
31
31
  var settings = params.settings, _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
32
32
  var matchingKey = (0, key_1.getMatching)(settings.core.key);
33
33
  var keys = new KeyBuilderCS_1.KeyBuilderCS(prefix, matchingKey);
34
- var expirationTimestamp = Date.now() - browser_1.DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
35
- var splits = new SplitsCacheInLocal_1.SplitsCacheInLocal(settings, keys, expirationTimestamp);
34
+ var splits = new SplitsCacheInLocal_1.SplitsCacheInLocal(settings, keys);
36
35
  var segments = new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, keys);
37
36
  var largeSegments = new MySegmentsCacheInLocal_1.MySegmentsCacheInLocal(log, (0, KeyBuilderCS_1.myLargeSegmentsKeyBuilder)(prefix, matchingKey));
38
37
  return {
@@ -44,6 +43,9 @@ function InLocalStorage(options) {
44
43
  events: new EventsCacheInMemory_1.EventsCacheInMemory(eventsQueueSize),
45
44
  telemetry: (0, TelemetryCacheInMemory_1.shouldRecordTelemetry)(params) ? new TelemetryCacheInMemory_1.TelemetryCacheInMemory(splits, segments) : undefined,
46
45
  uniqueKeys: new UniqueKeysCacheInMemoryCS_1.UniqueKeysCacheInMemoryCS(),
46
+ validateCache: function () {
47
+ return (0, validateCache_1.validateCache)(options, settings, keys, splits, segments, largeSegments);
48
+ },
47
49
  destroy: function () { },
48
50
  // When using shared instantiation with MEMORY we reuse everything but segments (they are customer per key).
49
51
  shared: function (matchingKey) {
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateCache = void 0;
4
+ var lang_1 = require("../../utils/lang");
5
+ var KeyBuilder_1 = require("../KeyBuilder");
6
+ var constants_1 = require("./constants");
7
+ var DEFAULT_CACHE_EXPIRATION_IN_DAYS = 10;
8
+ var MILLIS_IN_A_DAY = 86400000;
9
+ /**
10
+ * Validates if cache should be cleared and sets the cache `hash` if needed.
11
+ *
12
+ * @returns `true` if cache should be cleared, `false` otherwise
13
+ */
14
+ function validateExpiration(options, settings, keys, currentTimestamp, isThereCache) {
15
+ var log = settings.log;
16
+ // Check expiration
17
+ var lastUpdatedTimestamp = parseInt(localStorage.getItem(keys.buildLastUpdatedKey()), 10);
18
+ if (!(0, lang_1.isNaNNumber)(lastUpdatedTimestamp)) {
19
+ var cacheExpirationInDays = (0, lang_1.isFiniteNumber)(options.expirationDays) && options.expirationDays >= 1 ? options.expirationDays : DEFAULT_CACHE_EXPIRATION_IN_DAYS;
20
+ var expirationTimestamp = currentTimestamp - MILLIS_IN_A_DAY * cacheExpirationInDays;
21
+ if (lastUpdatedTimestamp < expirationTimestamp) {
22
+ log.info(constants_1.LOG_PREFIX + 'Cache expired more than ' + cacheExpirationInDays + ' days ago. Cleaning up cache');
23
+ return true;
24
+ }
25
+ }
26
+ // Check hash
27
+ var storageHashKey = keys.buildHashKey();
28
+ var storageHash = localStorage.getItem(storageHashKey);
29
+ var currentStorageHash = (0, KeyBuilder_1.getStorageHash)(settings);
30
+ if (storageHash !== currentStorageHash) {
31
+ try {
32
+ localStorage.setItem(storageHashKey, currentStorageHash);
33
+ }
34
+ catch (e) {
35
+ log.error(constants_1.LOG_PREFIX + e);
36
+ }
37
+ if (isThereCache) {
38
+ log.info(constants_1.LOG_PREFIX + 'SDK key, flags filter criteria, or flags spec version has changed. Cleaning up cache');
39
+ return true;
40
+ }
41
+ return false; // No cache to clear
42
+ }
43
+ // Clear on init
44
+ if (options.clearOnInit) {
45
+ var lastClearTimestamp = parseInt(localStorage.getItem(keys.buildLastClear()), 10);
46
+ if ((0, lang_1.isNaNNumber)(lastClearTimestamp) || lastClearTimestamp < currentTimestamp - MILLIS_IN_A_DAY) {
47
+ log.info(constants_1.LOG_PREFIX + 'clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache');
48
+ return true;
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * Clean cache if:
54
+ * - it has expired, i.e., its `lastUpdated` timestamp is older than the given `expirationTimestamp`
55
+ * - its hash has changed, i.e., the SDK key, flags filter criteria or flags spec version was modified
56
+ * - `clearOnInit` was set and cache was not cleared in the last 24 hours
57
+ *
58
+ * @returns `true` if cache is ready to be used, `false` otherwise (cache was cleared or there is no cache)
59
+ */
60
+ function validateCache(options, settings, keys, splits, segments, largeSegments) {
61
+ var currentTimestamp = Date.now();
62
+ var isThereCache = splits.getChangeNumber() > -1;
63
+ if (validateExpiration(options, settings, keys, currentTimestamp, isThereCache)) {
64
+ splits.clear();
65
+ segments.clear();
66
+ largeSegments.clear();
67
+ // Update last clear timestamp
68
+ try {
69
+ localStorage.setItem(keys.buildLastClear(), currentTimestamp + '');
70
+ }
71
+ catch (e) {
72
+ settings.log.error(constants_1.LOG_PREFIX + e);
73
+ }
74
+ return false;
75
+ }
76
+ // Check if ready from cache
77
+ return isThereCache;
78
+ }
79
+ exports.validateCache = validateCache;
@@ -74,7 +74,8 @@ function PluggableStorage(options) {
74
74
  // Connects to wrapper and emits SDK_READY event on main client
75
75
  var connectPromise = wrapper.connect().then(function () {
76
76
  if (isSynchronizer) {
77
- // In standalone or producer mode, clear storage if SDK key or feature flag filter has changed
77
+ // @TODO reuse InLocalStorage::validateCache logic
78
+ // In standalone or producer mode, clear storage if SDK key, flags filter criteria or flags spec version was modified
78
79
  return wrapper.get(keys.buildHashKey()).then(function (hash) {
79
80
  var currentHash = (0, KeyBuilder_1.getStorageHash)(settings);
80
81
  if (hash !== currentHash) {
@@ -45,9 +45,10 @@ function fromObjectUpdaterFactory(splitsParser, storage, readiness, settings) {
45
45
  readiness.splits.emit(constants_2.SDK_SPLITS_ARRIVED);
46
46
  if (startingUp) {
47
47
  startingUp = false;
48
- Promise.resolve(splitsCache.checkCache()).then(function (cacheReady) {
48
+ var isCacheLoaded_1 = storage.validateCache ? storage.validateCache() : false;
49
+ Promise.resolve().then(function () {
49
50
  // Emits SDK_READY_FROM_CACHE
50
- if (cacheReady)
51
+ if (isCacheLoaded_1)
51
52
  readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED);
52
53
  // Emits SDK_READY
53
54
  readiness.segments.emit(constants_2.SDK_SEGMENTS_ARRIVED);
@@ -116,15 +116,13 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFilt
116
116
  function _splitChangesUpdater(since, retry) {
117
117
  if (retry === void 0) { retry = 0; }
118
118
  log.debug(constants_2.SYNC_SPLITS_FETCH, [since]);
119
- var fetcherPromise = Promise.resolve(splitUpdateNotification ?
119
+ return Promise.resolve(splitUpdateNotification ?
120
120
  { splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
121
121
  splitChangesFetcher(since, noCache, till, _promiseDecorator))
122
122
  .then(function (splitChanges) {
123
123
  startingUp = false;
124
124
  var mutation = computeSplitsMutation(splitChanges.splits, splitFiltersValidation);
125
125
  log.debug(constants_2.SYNC_SPLITS_UPDATE, [mutation.added.length, mutation.removed.length, mutation.segments.length]);
126
- // Write into storage
127
- // @TODO call `setChangeNumber` only if the other storage operations have succeeded, in order to keep storage consistency
128
126
  return Promise.all([
129
127
  splits.update(mutation.added, mutation.removed, splitChanges.till),
130
128
  segments.registerSegments(mutation.segments)
@@ -156,15 +154,6 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFilt
156
154
  }
157
155
  return false;
158
156
  });
159
- // After triggering the requests, if we have cached splits information let's notify that to emit SDK_READY_FROM_CACHE.
160
- // Wrapping in a promise since checkCache can be async.
161
- if (splitsEventEmitter && startingUp) {
162
- Promise.resolve(splits.checkCache()).then(function (isCacheReady) {
163
- if (isCacheReady)
164
- splitsEventEmitter.emit(constants_1.SDK_SPLITS_CACHE_LOADED);
165
- });
166
- }
167
- return fetcherPromise;
168
157
  }
169
158
  var sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error
170
159
  return sincePromise.then(_splitChangesUpdater);
@@ -6,6 +6,7 @@ var constants_1 = require("./streaming/constants");
6
6
  var constants_2 = require("../logger/constants");
7
7
  var consent_1 = require("../consent");
8
8
  var constants_3 = require("../utils/constants");
9
+ var constants_4 = require("../readiness/constants");
9
10
  /**
10
11
  * Online SyncManager factory.
11
12
  * Can be used for server-side API, and client-side API with or without multiple clients.
@@ -19,7 +20,7 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
19
20
  * SyncManager factory for modular SDK
20
21
  */
21
22
  return function (params) {
22
- var settings = params.settings, _a = params.settings, log = _a.log, streamingEnabled = _a.streamingEnabled, syncEnabled = _a.sync.enabled, telemetryTracker = params.telemetryTracker;
23
+ var settings = params.settings, _a = params.settings, log = _a.log, streamingEnabled = _a.streamingEnabled, syncEnabled = _a.sync.enabled, telemetryTracker = params.telemetryTracker, storage = params.storage, readiness = params.readiness;
23
24
  /** Polling Manager */
24
25
  var pollingManager = pollingManagerFactory && pollingManagerFactory(params);
25
26
  /** Push Manager */
@@ -67,6 +68,11 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
67
68
  */
68
69
  start: function () {
69
70
  running = true;
71
+ if (startFirstTime) {
72
+ var isCacheLoaded = storage.validateCache ? storage.validateCache() : false;
73
+ if (isCacheLoaded)
74
+ Promise.resolve().then(function () { readiness.splits.emit(constants_4.SDK_SPLITS_CACHE_LOADED); });
75
+ }
70
76
  // start syncing splits and segments
71
77
  if (pollingManager) {
72
78
  // If synchronization is disabled pushManager and pollingManager should not start
@@ -75,7 +81,6 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
75
81
  // Doesn't call `syncAll` when the syncManager is resuming
76
82
  if (startFirstTime) {
77
83
  pollingManager.syncAll();
78
- startFirstTime = false;
79
84
  }
80
85
  pushManager.start();
81
86
  }
@@ -86,12 +91,12 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
86
91
  else {
87
92
  if (startFirstTime) {
88
93
  pollingManager.syncAll();
89
- startFirstTime = false;
90
94
  }
91
95
  }
92
96
  }
93
97
  // start periodic data recording (events, impressions, telemetry).
94
98
  submitterManager.start(!(0, consent_1.isConsentGranted)(settings));
99
+ startFirstTime = false;
95
100
  },
96
101
  /**
97
102
  * Method used to stop/pause the syncManager.
@@ -10,6 +10,8 @@ exports.strategyDebugFactory = void 0;
10
10
  function strategyDebugFactory(impressionsObserver) {
11
11
  return {
12
12
  process: function (impression) {
13
+ if (impression.properties)
14
+ return true;
13
15
  impression.pt = impressionsObserver.testAndSet(impression);
14
16
  return true;
15
17
  }
@@ -6,7 +6,7 @@ var constants_1 = require("../../../logger/constants");
6
6
  var constants_2 = require("../../../utils/constants");
7
7
  function __InLocalStorageMockFactory(params) {
8
8
  var result = (0, InMemoryStorageCS_1.InMemoryStorageCSFactory)(params);
9
- result.splits.checkCache = function () { return true; }; // to emit SDK_READY_FROM_CACHE
9
+ result.validateCache = function () { return true; }; // to emit SDK_READY_FROM_CACHE
10
10
  return result;
11
11
  }
12
12
  exports.__InLocalStorageMockFactory = __InLocalStorageMockFactory;
@@ -1,5 +1,6 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
2
  import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED, SDK_SEGMENTS_ARRIVED, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE, SDK_READY } from './constants';
3
+ import { STORAGE_LOCALSTORAGE } from '../utils/constants';
3
4
  function splitsEventEmitterFactory(EventEmitter) {
4
5
  var splitsEventEmitter = objectAssign(new EventEmitter(), {
5
6
  splitsArrived: false,
@@ -80,6 +81,7 @@ export function readinessManagerFactory(EventEmitter, settings, splits, isShared
80
81
  }
81
82
  }
82
83
  function checkIsReadyOrUpdate(diff) {
84
+ var _a;
83
85
  if (isDestroyed)
84
86
  return;
85
87
  if (isReady) {
@@ -98,6 +100,10 @@ export function readinessManagerFactory(EventEmitter, settings, splits, isShared
98
100
  isReady = true;
99
101
  try {
100
102
  syncLastUpdate();
103
+ if (!isReadyFromCache && ((_a = settings.storage) === null || _a === void 0 ? void 0 : _a.type) === STORAGE_LOCALSTORAGE) {
104
+ isReadyFromCache = true;
105
+ gate.emit(SDK_READY_FROM_CACHE);
106
+ }
101
107
  gate.emit(SDK_READY);
102
108
  }
103
109
  catch (e) {
@@ -22,13 +22,6 @@ var AbstractSplitsCacheAsync = /** @class */ (function () {
22
22
  AbstractSplitsCacheAsync.prototype.usesSegments = function () {
23
23
  return Promise.resolve(true);
24
24
  };
25
- /**
26
- * Check if the splits information is already stored in cache.
27
- * Noop, just keeping the interface. This is used by client-side implementations only.
28
- */
29
- AbstractSplitsCacheAsync.prototype.checkCache = function () {
30
- return Promise.resolve(false);
31
- };
32
25
  /**
33
26
  * Kill `name` split and set `defaultTreatment` and `changeNumber`.
34
27
  * Used for SPLIT_KILL push notifications.
@@ -25,13 +25,6 @@ var AbstractSplitsCacheSync = /** @class */ (function () {
25
25
  var _this = this;
26
26
  return this.getSplitNames().map(function (key) { return _this.getSplit(key); });
27
27
  };
28
- /**
29
- * Check if the splits information is already stored in cache. This data can be preloaded.
30
- * It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE.
31
- */
32
- AbstractSplitsCacheSync.prototype.checkCache = function () {
33
- return false;
34
- };
35
28
  /**
36
29
  * Kill `name` split and set `defaultTreatment` and `changeNumber`.
37
30
  * Used for SPLIT_KILL push notifications.
@@ -35,6 +35,9 @@ var KeyBuilderCS = /** @class */ (function (_super) {
35
35
  KeyBuilderCS.prototype.buildSplitsWithSegmentCountKey = function () {
36
36
  return this.prefix + ".splits.usingSegments";
37
37
  };
38
+ KeyBuilderCS.prototype.buildLastClear = function () {
39
+ return this.prefix + ".lastClear";
40
+ };
38
41
  return KeyBuilderCS;
39
42
  }(KeyBuilder));
40
43
  export { KeyBuilderCS };
@@ -1,4 +1,5 @@
1
- import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../utils/constants/browser';
1
+ // This value might be eventually set via a config parameter
2
+ var DEFAULT_CACHE_EXPIRATION_IN_MILLIS = 864000000; // 10 days
2
3
  /**
3
4
  * Factory of client-side storage loader
4
5
  *