@splitsoftware/splitio-commons 2.0.2 → 2.1.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 (60) hide show
  1. package/README.md +2 -2
  2. package/cjs/listeners/node.js +2 -2
  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 +1 -57
  8. package/cjs/storages/inLocalStorage/index.js +5 -3
  9. package/cjs/storages/inLocalStorage/validateCache.js +80 -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 -10
  13. package/cjs/sync/streaming/pushManager.js +8 -6
  14. package/cjs/sync/syncManagerOnline.js +10 -4
  15. package/cjs/trackers/eventTracker.js +1 -1
  16. package/cjs/trackers/impressionsTracker.js +1 -1
  17. package/cjs/utils/settingsValidation/index.js +1 -1
  18. package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
  19. package/esm/listeners/node.js +2 -2
  20. package/esm/storages/AbstractSplitsCacheAsync.js +0 -7
  21. package/esm/storages/AbstractSplitsCacheSync.js +0 -7
  22. package/esm/storages/KeyBuilderCS.js +3 -0
  23. package/esm/storages/dataLoader.js +2 -1
  24. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +1 -57
  25. package/esm/storages/inLocalStorage/index.js +5 -3
  26. package/esm/storages/inLocalStorage/validateCache.js +76 -0
  27. package/esm/storages/pluggable/index.js +2 -1
  28. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  29. package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -11
  30. package/esm/sync/streaming/pushManager.js +8 -6
  31. package/esm/sync/syncManagerOnline.js +10 -4
  32. package/esm/trackers/eventTracker.js +1 -1
  33. package/esm/trackers/impressionsTracker.js +1 -1
  34. package/esm/utils/settingsValidation/index.js +1 -1
  35. package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
  36. package/package.json +1 -1
  37. package/src/listeners/node.ts +2 -2
  38. package/src/storages/AbstractSplitsCacheAsync.ts +0 -8
  39. package/src/storages/AbstractSplitsCacheSync.ts +0 -8
  40. package/src/storages/KeyBuilderCS.ts +4 -0
  41. package/src/storages/dataLoader.ts +3 -1
  42. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +1 -66
  43. package/src/storages/inLocalStorage/index.ts +8 -8
  44. package/src/storages/inLocalStorage/validateCache.ts +92 -0
  45. package/src/storages/pluggable/index.ts +2 -1
  46. package/src/storages/types.ts +1 -4
  47. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +6 -5
  48. package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -11
  49. package/src/sync/streaming/pushManager.ts +8 -6
  50. package/src/sync/syncManagerOnline.ts +11 -5
  51. package/src/trackers/eventTracker.ts +1 -1
  52. package/src/trackers/impressionsTracker.ts +1 -1
  53. package/src/utils/lang/index.ts +1 -1
  54. package/src/utils/settingsValidation/index.ts +1 -1
  55. package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
  56. package/types/index.d.ts +1 -1
  57. package/types/splitio.d.ts +26 -2
  58. package/cjs/utils/constants/browser.js +0 -5
  59. package/esm/utils/constants/browser.js +0 -2
  60. package/src/utils/constants/browser.ts +0 -2
package/README.md CHANGED
@@ -14,7 +14,7 @@ This library is compatible with JavaScript ES5 and above.
14
14
  Please see [Contributors Guide](CONTRIBUTORS-GUIDE.md) to find all you need to submit a Pull Request (PR).
15
15
 
16
16
  ## License
17
- Licensed under the Apache License, Version 2.0. See: [Apache License](http://www.apache.org/licenses/).
17
+ Licensed under the Apache License, Version 2.0. See: [Apache License](https://www.apache.org/licenses/).
18
18
 
19
19
  ## About Split
20
20
 
@@ -46,4 +46,4 @@ For a comprehensive list of open source projects visit our [Github page](https:/
46
46
 
47
47
  **Learn more about Split:**
48
48
 
49
- Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](http://help.split.io) for more detailed information.
49
+ Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](https://help.split.io) for more detailed information.
@@ -43,7 +43,7 @@ var NodeSignalListener = /** @class */ (function () {
43
43
  var wrapUp = function () {
44
44
  // Cleaned up, remove handlers.
45
45
  _this.stop();
46
- // This handler prevented the default behaviour, start again.
46
+ // This handler prevented the default behavior, start again.
47
47
  // eslint-disable-next-line no-undef
48
48
  process.kill(process.pid, SIGTERM);
49
49
  };
@@ -56,7 +56,7 @@ var NodeSignalListener = /** @class */ (function () {
56
56
  this.settings.log.error(constants_1.LOG_PREFIX_CLEANUP + "Error with Split SDK graceful shutdown: " + err);
57
57
  }
58
58
  if ((0, thenable_1.thenable)(handlerResult)) {
59
- // Always exit, even with errors. The promise is returned for UT purposses.
59
+ // Always exit, even with errors. The promise is returned for UT purposes.
60
60
  return handlerResult.then(wrapUp).catch(wrapUp);
61
61
  }
62
62
  else {
@@ -14,13 +14,6 @@ var AbstractSplitsCacheAsync = /** @class */ (function () {
14
14
  AbstractSplitsCacheAsync.prototype.usesSegments = function () {
15
15
  return Promise.resolve(true);
16
16
  };
17
- /**
18
- * Check if the splits information is already stored in cache.
19
- * Noop, just keeping the interface. This is used by client-side implementations only.
20
- */
21
- AbstractSplitsCacheAsync.prototype.checkCache = function () {
22
- return Promise.resolve(false);
23
- };
24
17
  /**
25
18
  * Kill `name` split and set `defaultTreatment` and `changeNumber`.
26
19
  * Used for SPLIT_KILL push notifications.
@@ -30,13 +30,6 @@ var AbstractSplitsCacheSync = /** @class */ (function () {
30
30
  var _this = this;
31
31
  return this.getSplitNames().map(function (key) { return _this.getSplit(key); });
32
32
  };
33
- /**
34
- * Check if the splits information is already stored in cache. This data can be preloaded.
35
- * It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE.
36
- */
37
- AbstractSplitsCacheSync.prototype.checkCache = function () {
38
- return false;
39
- };
40
33
  /**
41
34
  * Kill `name` split and set `defaultTreatment` and `changeNumber`.
42
35
  * Used for SPLIT_KILL push notifications.
@@ -32,6 +32,9 @@ var KeyBuilderCS = /** @class */ (function (_super) {
32
32
  KeyBuilderCS.prototype.buildTillKey = function () {
33
33
  return this.prefix + "." + this.matchingKey + ".segments.till";
34
34
  };
35
+ KeyBuilderCS.prototype.buildLastClear = function () {
36
+ return this.prefix + ".lastClear";
37
+ };
35
38
  return KeyBuilderCS;
36
39
  }(KeyBuilder_1.KeyBuilder));
37
40
  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) {
@@ -67,7 +63,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
67
63
  * We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
68
64
  */
69
65
  SplitsCacheInLocal.prototype.clear = function () {
70
- this.log.info(constants_1.LOG_PREFIX + 'Flushing Splits data from localStorage');
71
66
  // collect item keys
72
67
  var len = localStorage.length;
73
68
  var accum = [];
@@ -119,18 +114,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
119
114
  return item && JSON.parse(item);
120
115
  };
121
116
  SplitsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
122
- // when using a new split query, we must update it at the store
123
- if (this.updateNewFilter) {
124
- this.log.info(constants_1.LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version was modified. Updating cache');
125
- var storageHashKey = this.keys.buildHashKey();
126
- try {
127
- localStorage.setItem(storageHashKey, this.storageHash);
128
- }
129
- catch (e) {
130
- this.log.error(constants_1.LOG_PREFIX + e);
131
- }
132
- this.updateNewFilter = false;
133
- }
134
117
  try {
135
118
  localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
136
119
  // update "last updated" timestamp with current time
@@ -181,45 +164,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
181
164
  return true;
182
165
  }
183
166
  };
184
- /**
185
- * Check if the splits information is already stored in browser LocalStorage.
186
- * In this function we could add more code to check if the data is valid.
187
- * @override
188
- */
189
- SplitsCacheInLocal.prototype.checkCache = function () {
190
- return this.getChangeNumber() > -1;
191
- };
192
- /**
193
- * Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
194
- *
195
- * @param expirationTimestamp - if the value is not a number, data will not be cleaned
196
- */
197
- SplitsCacheInLocal.prototype._checkExpiration = function (expirationTimestamp) {
198
- var value = localStorage.getItem(this.keys.buildLastUpdatedKey());
199
- if (value !== null) {
200
- value = parseInt(value, 10);
201
- if (!(0, lang_1.isNaNNumber)(value) && expirationTimestamp && value < expirationTimestamp)
202
- this.clear();
203
- }
204
- };
205
- // @TODO eventually remove `_checkFilterQuery`. Cache should be cleared at the storage level, reusing same logic than PluggableStorage
206
- SplitsCacheInLocal.prototype._checkFilterQuery = function () {
207
- var storageHashKey = this.keys.buildHashKey();
208
- var storageHash = localStorage.getItem(storageHashKey);
209
- if (storageHash !== this.storageHash) {
210
- try {
211
- // mark cache to update the new query filter on first successful splits fetch
212
- this.updateNewFilter = true;
213
- // if there is cache, clear it
214
- if (this.checkCache())
215
- this.clear();
216
- }
217
- catch (e) {
218
- this.log.error(constants_1.LOG_PREFIX + e);
219
- }
220
- }
221
- // if the filter didn't change, nothing is done
222
- };
223
167
  SplitsCacheInLocal.prototype.getNamesByFlagSets = function (flagSets) {
224
168
  var _this = this;
225
169
  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, impressionsMode = _a.sync.impressionsMode;
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: impressionsMode === constants_2.NONE ? new UniqueKeysCacheInMemoryCS_1.UniqueKeysCacheInMemoryCS() : undefined,
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,80 @@
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
+ // milliseconds in a day
8
+ var DEFAULT_CACHE_EXPIRATION_IN_DAYS = 10;
9
+ var MILLIS_IN_A_DAY = 86400000;
10
+ /**
11
+ * Validates if cache should be cleared and sets the cache `hash` if needed.
12
+ *
13
+ * @returns `true` if cache should be cleared, `false` otherwise
14
+ */
15
+ function validateExpiration(options, settings, keys, currentTimestamp, isThereCache) {
16
+ var log = settings.log;
17
+ // Check expiration
18
+ var lastUpdatedTimestamp = parseInt(localStorage.getItem(keys.buildLastUpdatedKey()), 10);
19
+ if (!(0, lang_1.isNaNNumber)(lastUpdatedTimestamp)) {
20
+ var cacheExpirationInDays = (0, lang_1.isFiniteNumber)(options.expirationDays) && options.expirationDays >= 1 ? options.expirationDays : DEFAULT_CACHE_EXPIRATION_IN_DAYS;
21
+ var expirationTimestamp = currentTimestamp - MILLIS_IN_A_DAY * cacheExpirationInDays;
22
+ if (lastUpdatedTimestamp < expirationTimestamp) {
23
+ log.info(constants_1.LOG_PREFIX + 'Cache expired more than ' + cacheExpirationInDays + ' days ago. Cleaning up cache');
24
+ return true;
25
+ }
26
+ }
27
+ // Check hash
28
+ var storageHashKey = keys.buildHashKey();
29
+ var storageHash = localStorage.getItem(storageHashKey);
30
+ var currentStorageHash = (0, KeyBuilder_1.getStorageHash)(settings);
31
+ if (storageHash !== currentStorageHash) {
32
+ try {
33
+ localStorage.setItem(storageHashKey, currentStorageHash);
34
+ }
35
+ catch (e) {
36
+ log.error(constants_1.LOG_PREFIX + e);
37
+ }
38
+ if (isThereCache) {
39
+ log.info(constants_1.LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version has changed. Cleaning up cache');
40
+ return true;
41
+ }
42
+ return false; // No cache to clear
43
+ }
44
+ // Clear on init
45
+ if (options.clearOnInit) {
46
+ var lastClearTimestamp = parseInt(localStorage.getItem(keys.buildLastClear()), 10);
47
+ if ((0, lang_1.isNaNNumber)(lastClearTimestamp) || lastClearTimestamp < currentTimestamp - MILLIS_IN_A_DAY) {
48
+ log.info(constants_1.LOG_PREFIX + 'clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache');
49
+ return true;
50
+ }
51
+ }
52
+ }
53
+ /**
54
+ * Clean cache if:
55
+ * - it has expired, i.e., its `lastUpdated` timestamp is older than the given `expirationTimestamp`
56
+ * - its hash has changed, i.e., the SDK key, flags filter criteria or flags spec version was modified
57
+ * - `clearOnInit` was set and cache was not cleared in the last 24 hours
58
+ *
59
+ * @returns `true` if cache is ready to be used, `false` otherwise (cache was cleared or there is no cache)
60
+ */
61
+ function validateCache(options, settings, keys, splits, segments, largeSegments) {
62
+ var currentTimestamp = Date.now();
63
+ var isThereCache = splits.getChangeNumber() > -1;
64
+ if (validateExpiration(options, settings, keys, currentTimestamp, isThereCache)) {
65
+ splits.clear();
66
+ segments.clear();
67
+ largeSegments.clear();
68
+ // Update last clear timestamp
69
+ try {
70
+ localStorage.setItem(keys.buildLastClear(), currentTimestamp + '');
71
+ }
72
+ catch (e) {
73
+ settings.log.error(constants_1.LOG_PREFIX + e);
74
+ }
75
+ return false;
76
+ }
77
+ // Check if ready from cache
78
+ return isThereCache;
79
+ }
80
+ exports.validateCache = validateCache;
@@ -78,7 +78,8 @@ function PluggableStorage(options) {
78
78
  // Connects to wrapper and emits SDK_READY event on main client
79
79
  var connectPromise = wrapper.connect().then(function () {
80
80
  if (isSyncronizer) {
81
- // In standalone or producer mode, clear storage if SDK key or feature flag filter has changed
81
+ // @TODO reuse InLocalStorage::validateCache logic
82
+ // In standalone or producer mode, clear storage if SDK key, flags filter criteria or flags spec version was modified
82
83
  return wrapper.get(keys.buildHashKey()).then(function (hash) {
83
84
  var currentHash = (0, KeyBuilder_1.getStorageHash)(settings);
84
85
  if (hash !== currentHash) {
@@ -46,9 +46,10 @@ function fromObjectUpdaterFactory(splitsParser, storage, readiness, settings) {
46
46
  readiness.splits.emit(constants_2.SDK_SPLITS_ARRIVED);
47
47
  if (startingUp) {
48
48
  startingUp = false;
49
- Promise.resolve(splitsCache.checkCache()).then(function (cacheReady) {
49
+ var isCacheLoaded_1 = storage.validateCache ? storage.validateCache() : false;
50
+ Promise.resolve().then(function () {
50
51
  // Emits SDK_READY_FROM_CACHE
51
- if (cacheReady)
52
+ if (isCacheLoaded_1)
52
53
  readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED);
53
54
  // Emits SDK_READY
54
55
  readiness.segments.emit(constants_2.SDK_SEGMENTS_ARRIVED);
@@ -126,7 +126,7 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
126
126
  function _splitChangesUpdater(since, retry) {
127
127
  if (retry === void 0) { retry = 0; }
128
128
  log.debug(constants_2.SYNC_SPLITS_FETCH, [since]);
129
- var fetcherPromise = Promise.resolve(splitUpdateNotification ?
129
+ return Promise.resolve(splitUpdateNotification ?
130
130
  { splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
131
131
  splitChangesFetcher(since, noCache, till, _promiseDecorator))
132
132
  .then(function (splitChanges) {
@@ -170,15 +170,6 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
170
170
  }
171
171
  return false;
172
172
  });
173
- // After triggering the requests, if we have cached splits information let's notify that to emit SDK_READY_FROM_CACHE.
174
- // Wrapping in a promise since checkCache can be async.
175
- if (splitsEventEmitter && startingUp) {
176
- Promise.resolve(splits.checkCache()).then(function (isCacheReady) {
177
- if (isCacheReady)
178
- splitsEventEmitter.emit(constants_1.SDK_SPLITS_CACHE_LOADED);
179
- });
180
- }
181
- return fetcherPromise;
182
173
  }
183
174
  var sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error
184
175
  return sincePromise.then(_splitChangesUpdater);
@@ -309,12 +309,14 @@ function pushManagerFactory(params, pollingManager) {
309
309
  // Reconnects in case of a new client.
310
310
  // Run in next event-loop cycle to save authentication calls
311
311
  // in case multiple clients are created in the current cycle.
312
- setTimeout(function checkForReconnect() {
313
- if (connectForNewClient) {
314
- connectForNewClient = false;
315
- connectPush();
316
- }
317
- }, 0);
312
+ if (this.isRunning()) {
313
+ setTimeout(function checkForReconnect() {
314
+ if (connectForNewClient) {
315
+ connectForNewClient = false;
316
+ connectPush();
317
+ }
318
+ }, 0);
319
+ }
318
320
  }
319
321
  },
320
322
  // [Only for client-side]
@@ -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.
@@ -118,6 +123,8 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
118
123
  if (!pollingManager)
119
124
  return;
120
125
  var mySegmentsSyncTask = pollingManager.add(matchingKey, readinessManager, storage);
126
+ if (syncEnabled && pushManager)
127
+ pushManager.add(matchingKey, mySegmentsSyncTask);
121
128
  if (running) {
122
129
  if (syncEnabled) {
123
130
  if (pushManager) {
@@ -131,7 +138,6 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
131
138
  // of segments since `syncAll` was already executed when starting the main client
132
139
  mySegmentsSyncTask.execute();
133
140
  }
134
- pushManager.add(matchingKey, mySegmentsSyncTask);
135
141
  }
136
142
  else {
137
143
  if (storage.splits.usesSegments())
@@ -25,7 +25,7 @@ function eventTrackerFactory(settings, eventsCache, whenInit, integrationsManage
25
25
  whenInit(function () {
26
26
  // Wrap in a timeout because we don't want it to be blocking.
27
27
  setTimeout(function () {
28
- // copy of event, to avoid unexpected behaviour if modified by integrations
28
+ // copy of event, to avoid unexpected behavior if modified by integrations
29
29
  var eventDataCopy = (0, objectAssign_1.objectAssign)({}, eventData);
30
30
  if (properties)
31
31
  eventDataCopy.properties = (0, objectAssign_1.objectAssign)({}, properties);
@@ -46,7 +46,7 @@ function impressionsTrackerFactory(settings, impressionsCache, strategy, whenIni
46
46
  if (impressionListener || integrationsManager) {
47
47
  var _loop_1 = function (i) {
48
48
  var impressionData = {
49
- // copy of impression, to avoid unexpected behaviour if modified by integrations or impressionListener
49
+ // copy of impression, to avoid unexpected behavior if modified by integrations or impressionListener
50
50
  impression: (0, objectAssign_1.objectAssign)({}, impressionsToListener[i]),
51
51
  attributes: attributes,
52
52
  ip: ip,
@@ -139,7 +139,7 @@ function settingsValidation(config, validationParams) {
139
139
  withDefaults.core.key = 'localhost_key';
140
140
  }
141
141
  else {
142
- // Keeping same behaviour than JS SDK: if settings key or TT are invalid,
142
+ // Keeping same behavior than JS SDK: if settings key or TT are invalid,
143
143
  // `false` value is used as bound key/TT of the default client, which leads to some issues.
144
144
  // @ts-ignore, @TODO handle invalid keys as a non-recoverable error?
145
145
  withDefaults.core.key = (0, key_1.validateKey)(log, maybeKey, constants_2.LOG_PREFIX_CLIENT_INSTANTIATION);
@@ -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;
@@ -40,7 +40,7 @@ var NodeSignalListener = /** @class */ (function () {
40
40
  var wrapUp = function () {
41
41
  // Cleaned up, remove handlers.
42
42
  _this.stop();
43
- // This handler prevented the default behaviour, start again.
43
+ // This handler prevented the default behavior, start again.
44
44
  // eslint-disable-next-line no-undef
45
45
  process.kill(process.pid, SIGTERM);
46
46
  };
@@ -53,7 +53,7 @@ var NodeSignalListener = /** @class */ (function () {
53
53
  this.settings.log.error(LOG_PREFIX_CLEANUP + "Error with Split SDK graceful shutdown: " + err);
54
54
  }
55
55
  if (thenable(handlerResult)) {
56
- // Always exit, even with errors. The promise is returned for UT purposses.
56
+ // Always exit, even with errors. The promise is returned for UT purposes.
57
57
  return handlerResult.then(wrapUp).catch(wrapUp);
58
58
  }
59
59
  else {
@@ -11,13 +11,6 @@ var AbstractSplitsCacheAsync = /** @class */ (function () {
11
11
  AbstractSplitsCacheAsync.prototype.usesSegments = function () {
12
12
  return Promise.resolve(true);
13
13
  };
14
- /**
15
- * Check if the splits information is already stored in cache.
16
- * Noop, just keeping the interface. This is used by client-side implementations only.
17
- */
18
- AbstractSplitsCacheAsync.prototype.checkCache = function () {
19
- return Promise.resolve(false);
20
- };
21
14
  /**
22
15
  * Kill `name` split and set `defaultTreatment` and `changeNumber`.
23
16
  * Used for SPLIT_KILL push notifications.
@@ -27,13 +27,6 @@ var AbstractSplitsCacheSync = /** @class */ (function () {
27
27
  var _this = this;
28
28
  return this.getSplitNames().map(function (key) { return _this.getSplit(key); });
29
29
  };
30
- /**
31
- * Check if the splits information is already stored in cache. This data can be preloaded.
32
- * It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE.
33
- */
34
- AbstractSplitsCacheSync.prototype.checkCache = function () {
35
- return false;
36
- };
37
30
  /**
38
31
  * Kill `name` split and set `defaultTreatment` and `changeNumber`.
39
32
  * Used for SPLIT_KILL push notifications.
@@ -29,6 +29,9 @@ var KeyBuilderCS = /** @class */ (function (_super) {
29
29
  KeyBuilderCS.prototype.buildTillKey = function () {
30
30
  return this.prefix + "." + this.matchingKey + ".segments.till";
31
31
  };
32
+ KeyBuilderCS.prototype.buildLastClear = function () {
33
+ return this.prefix + ".lastClear";
34
+ };
32
35
  return KeyBuilderCS;
33
36
  }(KeyBuilder));
34
37
  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
  *