@splitsoftware/splitio-commons 2.0.3-rc.0 → 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 (108) hide show
  1. package/CHANGES.txt +0 -4
  2. package/README.md +2 -2
  3. package/cjs/evaluator/index.js +0 -2
  4. package/cjs/listeners/browser.js +6 -4
  5. package/cjs/listeners/node.js +2 -2
  6. package/cjs/sdkClient/client.js +13 -13
  7. package/cjs/sdkClient/sdkClient.js +1 -1
  8. package/cjs/sdkFactory/index.js +14 -9
  9. package/cjs/sdkManager/index.js +1 -2
  10. package/cjs/storages/AbstractSplitsCacheAsync.js +0 -7
  11. package/cjs/storages/AbstractSplitsCacheSync.js +0 -7
  12. package/cjs/storages/KeyBuilderCS.js +3 -0
  13. package/cjs/storages/dataLoader.js +3 -2
  14. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +1 -57
  15. package/cjs/storages/inLocalStorage/index.js +8 -7
  16. package/cjs/storages/inLocalStorage/validateCache.js +80 -0
  17. package/cjs/storages/inMemory/InMemoryStorage.js +3 -3
  18. package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -4
  19. package/cjs/storages/inRedis/index.js +13 -9
  20. package/cjs/storages/pluggable/index.js +21 -16
  21. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  22. package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -10
  23. package/cjs/sync/streaming/pushManager.js +8 -6
  24. package/cjs/sync/submitters/impressionCountsSubmitter.js +4 -2
  25. package/cjs/sync/submitters/submitterManager.js +6 -3
  26. package/cjs/sync/syncManagerOnline.js +10 -4
  27. package/cjs/trackers/eventTracker.js +1 -1
  28. package/cjs/trackers/impressionsTracker.js +19 -18
  29. package/cjs/trackers/strategy/strategyDebug.js +11 -4
  30. package/cjs/trackers/strategy/strategyNone.js +16 -11
  31. package/cjs/trackers/strategy/strategyOptimized.js +21 -11
  32. package/cjs/utils/settingsValidation/index.js +1 -1
  33. package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
  34. package/esm/evaluator/index.js +0 -2
  35. package/esm/listeners/browser.js +3 -1
  36. package/esm/listeners/node.js +2 -2
  37. package/esm/sdkClient/client.js +13 -13
  38. package/esm/sdkClient/sdkClient.js +1 -1
  39. package/esm/sdkFactory/index.js +15 -10
  40. package/esm/sdkManager/index.js +1 -2
  41. package/esm/storages/AbstractSplitsCacheAsync.js +0 -7
  42. package/esm/storages/AbstractSplitsCacheSync.js +0 -7
  43. package/esm/storages/KeyBuilderCS.js +3 -0
  44. package/esm/storages/dataLoader.js +2 -1
  45. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +1 -57
  46. package/esm/storages/inLocalStorage/index.js +9 -8
  47. package/esm/storages/inLocalStorage/validateCache.js +76 -0
  48. package/esm/storages/inMemory/InMemoryStorage.js +4 -4
  49. package/esm/storages/inMemory/InMemoryStorageCS.js +4 -5
  50. package/esm/storages/inRedis/index.js +14 -10
  51. package/esm/storages/pluggable/index.js +22 -17
  52. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  53. package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -11
  54. package/esm/sync/streaming/pushManager.js +8 -6
  55. package/esm/sync/submitters/impressionCountsSubmitter.js +4 -2
  56. package/esm/sync/submitters/submitterManager.js +6 -3
  57. package/esm/sync/syncManagerOnline.js +10 -4
  58. package/esm/trackers/eventTracker.js +1 -1
  59. package/esm/trackers/impressionsTracker.js +19 -18
  60. package/esm/trackers/strategy/strategyDebug.js +11 -4
  61. package/esm/trackers/strategy/strategyNone.js +16 -11
  62. package/esm/trackers/strategy/strategyOptimized.js +21 -11
  63. package/esm/utils/settingsValidation/index.js +1 -1
  64. package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
  65. package/package.json +1 -1
  66. package/src/dtos/types.ts +1 -2
  67. package/src/evaluator/index.ts +0 -2
  68. package/src/evaluator/types.ts +1 -1
  69. package/src/listeners/browser.ts +3 -1
  70. package/src/listeners/node.ts +2 -2
  71. package/src/sdkClient/client.ts +11 -11
  72. package/src/sdkClient/sdkClient.ts +1 -1
  73. package/src/sdkFactory/index.ts +16 -11
  74. package/src/sdkFactory/types.ts +1 -1
  75. package/src/sdkManager/index.ts +1 -2
  76. package/src/storages/AbstractSplitsCacheAsync.ts +0 -8
  77. package/src/storages/AbstractSplitsCacheSync.ts +0 -8
  78. package/src/storages/KeyBuilderCS.ts +4 -0
  79. package/src/storages/dataLoader.ts +3 -1
  80. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +1 -66
  81. package/src/storages/inLocalStorage/index.ts +12 -13
  82. package/src/storages/inLocalStorage/validateCache.ts +92 -0
  83. package/src/storages/inMemory/InMemoryStorage.ts +4 -4
  84. package/src/storages/inMemory/InMemoryStorageCS.ts +4 -5
  85. package/src/storages/inRedis/index.ts +10 -10
  86. package/src/storages/pluggable/index.ts +22 -17
  87. package/src/storages/types.ts +3 -6
  88. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +6 -5
  89. package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -11
  90. package/src/sync/streaming/pushManager.ts +8 -6
  91. package/src/sync/submitters/impressionCountsSubmitter.ts +4 -2
  92. package/src/sync/submitters/submitterManager.ts +4 -3
  93. package/src/sync/submitters/uniqueKeysSubmitter.ts +3 -2
  94. package/src/sync/syncManagerOnline.ts +11 -5
  95. package/src/trackers/eventTracker.ts +1 -1
  96. package/src/trackers/impressionsTracker.ts +19 -18
  97. package/src/trackers/strategy/strategyDebug.ts +11 -4
  98. package/src/trackers/strategy/strategyNone.ts +17 -11
  99. package/src/trackers/strategy/strategyOptimized.ts +20 -10
  100. package/src/trackers/types.ts +8 -2
  101. package/src/utils/lang/index.ts +1 -1
  102. package/src/utils/settingsValidation/index.ts +1 -1
  103. package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
  104. package/types/index.d.ts +1 -1
  105. package/types/splitio.d.ts +26 -6
  106. package/cjs/utils/constants/browser.js +0 -5
  107. package/esm/utils/constants/browser.js +0 -2
  108. package/src/utils/constants/browser.ts +0 -2
@@ -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
  *
@@ -2,21 +2,17 @@ import { __extends } from "tslib";
2
2
  import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
3
3
  import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
4
4
  import { LOG_PREFIX } from './constants';
5
- import { getStorageHash } from '../KeyBuilder';
6
5
  import { setToArray } from '../../utils/lang/sets';
7
6
  /**
8
7
  * ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
9
8
  */
10
9
  var SplitsCacheInLocal = /** @class */ (function (_super) {
11
10
  __extends(SplitsCacheInLocal, _super);
12
- function SplitsCacheInLocal(settings, keys, expirationTimestamp) {
11
+ function SplitsCacheInLocal(settings, keys) {
13
12
  var _this = _super.call(this) || this;
14
13
  _this.keys = keys;
15
14
  _this.log = settings.log;
16
- _this.storageHash = getStorageHash(settings);
17
15
  _this.flagSetsFilter = settings.sync.__splitFiltersValidation.groupedFilters.bySet;
18
- _this._checkExpiration(expirationTimestamp);
19
- _this._checkFilterQuery();
20
16
  return _this;
21
17
  }
22
18
  SplitsCacheInLocal.prototype._decrementCount = function (key) {
@@ -64,7 +60,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
64
60
  * We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
65
61
  */
66
62
  SplitsCacheInLocal.prototype.clear = function () {
67
- this.log.info(LOG_PREFIX + 'Flushing Splits data from localStorage');
68
63
  // collect item keys
69
64
  var len = localStorage.length;
70
65
  var accum = [];
@@ -116,18 +111,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
116
111
  return item && JSON.parse(item);
117
112
  };
118
113
  SplitsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
119
- // when using a new split query, we must update it at the store
120
- if (this.updateNewFilter) {
121
- this.log.info(LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version was modified. Updating cache');
122
- var storageHashKey = this.keys.buildHashKey();
123
- try {
124
- localStorage.setItem(storageHashKey, this.storageHash);
125
- }
126
- catch (e) {
127
- this.log.error(LOG_PREFIX + e);
128
- }
129
- this.updateNewFilter = false;
130
- }
131
114
  try {
132
115
  localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
133
116
  // update "last updated" timestamp with current time
@@ -178,45 +161,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
178
161
  return true;
179
162
  }
180
163
  };
181
- /**
182
- * Check if the splits information is already stored in browser LocalStorage.
183
- * In this function we could add more code to check if the data is valid.
184
- * @override
185
- */
186
- SplitsCacheInLocal.prototype.checkCache = function () {
187
- return this.getChangeNumber() > -1;
188
- };
189
- /**
190
- * Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
191
- *
192
- * @param expirationTimestamp - if the value is not a number, data will not be cleaned
193
- */
194
- SplitsCacheInLocal.prototype._checkExpiration = function (expirationTimestamp) {
195
- var value = localStorage.getItem(this.keys.buildLastUpdatedKey());
196
- if (value !== null) {
197
- value = parseInt(value, 10);
198
- if (!isNaNNumber(value) && expirationTimestamp && value < expirationTimestamp)
199
- this.clear();
200
- }
201
- };
202
- // @TODO eventually remove `_checkFilterQuery`. Cache should be cleared at the storage level, reusing same logic than PluggableStorage
203
- SplitsCacheInLocal.prototype._checkFilterQuery = function () {
204
- var storageHashKey = this.keys.buildHashKey();
205
- var storageHash = localStorage.getItem(storageHashKey);
206
- if (storageHash !== this.storageHash) {
207
- try {
208
- // mark cache to update the new query filter on first successful splits fetch
209
- this.updateNewFilter = true;
210
- // if there is cache, clear it
211
- if (this.checkCache())
212
- this.clear();
213
- }
214
- catch (e) {
215
- this.log.error(LOG_PREFIX + e);
216
- }
217
- }
218
- // if the filter didn't change, nothing is done
219
- };
220
164
  SplitsCacheInLocal.prototype.getNamesByFlagSets = function (flagSets) {
221
165
  var _this = this;
222
166
  return flagSets.map(function (flagSet) {
@@ -6,13 +6,13 @@ import { KeyBuilderCS, myLargeSegmentsKeyBuilder } from '../KeyBuilderCS';
6
6
  import { isLocalStorageAvailable } from '../../utils/env/isLocalStorageAvailable';
7
7
  import { SplitsCacheInLocal } from './SplitsCacheInLocal';
8
8
  import { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
9
- import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../../utils/constants/browser';
10
9
  import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS';
11
10
  import { LOG_PREFIX } from './constants';
12
- import { STORAGE_LOCALSTORAGE } from '../../utils/constants';
11
+ import { DEBUG, NONE, STORAGE_LOCALSTORAGE } from '../../utils/constants';
13
12
  import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
14
13
  import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
15
14
  import { getMatching } from '../../utils/key';
15
+ import { validateCache } from './validateCache';
16
16
  /**
17
17
  * InLocal storage factory for standalone client-side SplitFactory
18
18
  */
@@ -25,11 +25,10 @@ export function InLocalStorage(options) {
25
25
  params.settings.log.warn(LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
26
26
  return InMemoryStorageCSFactory(params);
27
27
  }
28
- var settings = params.settings, _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
28
+ var settings = params.settings, _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, impressionsMode = _a.sync.impressionsMode;
29
29
  var matchingKey = getMatching(settings.core.key);
30
30
  var keys = new KeyBuilderCS(prefix, matchingKey);
31
- var expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
32
- var splits = new SplitsCacheInLocal(settings, keys, expirationTimestamp);
31
+ var splits = new SplitsCacheInLocal(settings, keys);
33
32
  var segments = new MySegmentsCacheInLocal(log, keys);
34
33
  var largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey));
35
34
  return {
@@ -37,10 +36,13 @@ export function InLocalStorage(options) {
37
36
  segments: segments,
38
37
  largeSegments: largeSegments,
39
38
  impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
40
- impressionCounts: new ImpressionCountsCacheInMemory(),
39
+ impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
41
40
  events: new EventsCacheInMemory(eventsQueueSize),
42
41
  telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
43
- uniqueKeys: new UniqueKeysCacheInMemoryCS(),
42
+ uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
43
+ validateCache: function () {
44
+ return validateCache(options, settings, keys, splits, segments, largeSegments);
45
+ },
44
46
  destroy: function () { },
45
47
  // When using shared instantiation with MEMORY we reuse everything but segments (they are customer per key).
46
48
  shared: function (matchingKey) {
@@ -52,7 +54,6 @@ export function InLocalStorage(options) {
52
54
  impressionCounts: this.impressionCounts,
53
55
  events: this.events,
54
56
  telemetry: this.telemetry,
55
- uniqueKeys: this.uniqueKeys,
56
57
  destroy: function () { }
57
58
  };
58
59
  },
@@ -0,0 +1,76 @@
1
+ import { isFiniteNumber, isNaNNumber } from '../../utils/lang';
2
+ import { getStorageHash } from '../KeyBuilder';
3
+ import { LOG_PREFIX } from './constants';
4
+ // milliseconds in a day
5
+ var DEFAULT_CACHE_EXPIRATION_IN_DAYS = 10;
6
+ var MILLIS_IN_A_DAY = 86400000;
7
+ /**
8
+ * Validates if cache should be cleared and sets the cache `hash` if needed.
9
+ *
10
+ * @returns `true` if cache should be cleared, `false` otherwise
11
+ */
12
+ function validateExpiration(options, settings, keys, currentTimestamp, isThereCache) {
13
+ var log = settings.log;
14
+ // Check expiration
15
+ var lastUpdatedTimestamp = parseInt(localStorage.getItem(keys.buildLastUpdatedKey()), 10);
16
+ if (!isNaNNumber(lastUpdatedTimestamp)) {
17
+ var cacheExpirationInDays = isFiniteNumber(options.expirationDays) && options.expirationDays >= 1 ? options.expirationDays : DEFAULT_CACHE_EXPIRATION_IN_DAYS;
18
+ var expirationTimestamp = currentTimestamp - MILLIS_IN_A_DAY * cacheExpirationInDays;
19
+ if (lastUpdatedTimestamp < expirationTimestamp) {
20
+ log.info(LOG_PREFIX + 'Cache expired more than ' + cacheExpirationInDays + ' days ago. Cleaning up cache');
21
+ return true;
22
+ }
23
+ }
24
+ // Check hash
25
+ var storageHashKey = keys.buildHashKey();
26
+ var storageHash = localStorage.getItem(storageHashKey);
27
+ var currentStorageHash = getStorageHash(settings);
28
+ if (storageHash !== currentStorageHash) {
29
+ try {
30
+ localStorage.setItem(storageHashKey, currentStorageHash);
31
+ }
32
+ catch (e) {
33
+ log.error(LOG_PREFIX + e);
34
+ }
35
+ if (isThereCache) {
36
+ log.info(LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version has changed. Cleaning up cache');
37
+ return true;
38
+ }
39
+ return false; // No cache to clear
40
+ }
41
+ // Clear on init
42
+ if (options.clearOnInit) {
43
+ var lastClearTimestamp = parseInt(localStorage.getItem(keys.buildLastClear()), 10);
44
+ if (isNaNNumber(lastClearTimestamp) || lastClearTimestamp < currentTimestamp - MILLIS_IN_A_DAY) {
45
+ log.info(LOG_PREFIX + 'clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache');
46
+ return true;
47
+ }
48
+ }
49
+ }
50
+ /**
51
+ * Clean cache if:
52
+ * - it has expired, i.e., its `lastUpdated` timestamp is older than the given `expirationTimestamp`
53
+ * - its hash has changed, i.e., the SDK key, flags filter criteria or flags spec version was modified
54
+ * - `clearOnInit` was set and cache was not cleared in the last 24 hours
55
+ *
56
+ * @returns `true` if cache is ready to be used, `false` otherwise (cache was cleared or there is no cache)
57
+ */
58
+ export function validateCache(options, settings, keys, splits, segments, largeSegments) {
59
+ var currentTimestamp = Date.now();
60
+ var isThereCache = splits.getChangeNumber() > -1;
61
+ if (validateExpiration(options, settings, keys, currentTimestamp, isThereCache)) {
62
+ splits.clear();
63
+ segments.clear();
64
+ largeSegments.clear();
65
+ // Update last clear timestamp
66
+ try {
67
+ localStorage.setItem(keys.buildLastClear(), currentTimestamp + '');
68
+ }
69
+ catch (e) {
70
+ settings.log.error(LOG_PREFIX + e);
71
+ }
72
+ return false;
73
+ }
74
+ // Check if ready from cache
75
+ return isThereCache;
76
+ }
@@ -3,7 +3,7 @@ import { SegmentsCacheInMemory } from './SegmentsCacheInMemory';
3
3
  import { ImpressionsCacheInMemory } from './ImpressionsCacheInMemory';
4
4
  import { EventsCacheInMemory } from './EventsCacheInMemory';
5
5
  import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
6
- import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
6
+ import { DEBUG, LOCALHOST_MODE, NONE, STORAGE_MEMORY } from '../../utils/constants';
7
7
  import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
8
8
  import { UniqueKeysCacheInMemory } from './UniqueKeysCacheInMemory';
9
9
  /**
@@ -12,17 +12,17 @@ import { UniqueKeysCacheInMemory } from './UniqueKeysCacheInMemory';
12
12
  * @param params - parameters required by EventsCacheSync
13
13
  */
14
14
  export function InMemoryStorageFactory(params) {
15
- var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, __splitFiltersValidation = _a.sync.__splitFiltersValidation;
15
+ var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, _c = _a.sync, impressionsMode = _c.impressionsMode, __splitFiltersValidation = _c.__splitFiltersValidation;
16
16
  var splits = new SplitsCacheInMemory(__splitFiltersValidation);
17
17
  var segments = new SegmentsCacheInMemory();
18
18
  var storage = {
19
19
  splits: splits,
20
20
  segments: segments,
21
21
  impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
22
- impressionCounts: new ImpressionCountsCacheInMemory(),
22
+ impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
23
23
  events: new EventsCacheInMemory(eventsQueueSize),
24
24
  telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
25
- uniqueKeys: new UniqueKeysCacheInMemory(),
25
+ uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemory() : undefined,
26
26
  destroy: function () { }
27
27
  };
28
28
  // @TODO revisit storage logic in localhost mode
@@ -3,7 +3,7 @@ import { MySegmentsCacheInMemory } from './MySegmentsCacheInMemory';
3
3
  import { ImpressionsCacheInMemory } from './ImpressionsCacheInMemory';
4
4
  import { EventsCacheInMemory } from './EventsCacheInMemory';
5
5
  import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
6
- import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
6
+ import { DEBUG, LOCALHOST_MODE, NONE, STORAGE_MEMORY } from '../../utils/constants';
7
7
  import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
8
8
  import { UniqueKeysCacheInMemoryCS } from './UniqueKeysCacheInMemoryCS';
9
9
  /**
@@ -12,7 +12,7 @@ import { UniqueKeysCacheInMemoryCS } from './UniqueKeysCacheInMemoryCS';
12
12
  * @param params - parameters required by EventsCacheSync
13
13
  */
14
14
  export function InMemoryStorageCSFactory(params) {
15
- var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, __splitFiltersValidation = _a.sync.__splitFiltersValidation;
15
+ var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, _c = _a.sync, impressionsMode = _c.impressionsMode, __splitFiltersValidation = _c.__splitFiltersValidation;
16
16
  var splits = new SplitsCacheInMemory(__splitFiltersValidation);
17
17
  var segments = new MySegmentsCacheInMemory();
18
18
  var largeSegments = new MySegmentsCacheInMemory();
@@ -21,10 +21,10 @@ export function InMemoryStorageCSFactory(params) {
21
21
  segments: segments,
22
22
  largeSegments: largeSegments,
23
23
  impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
24
- impressionCounts: new ImpressionCountsCacheInMemory(),
24
+ impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
25
25
  events: new EventsCacheInMemory(eventsQueueSize),
26
26
  telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
27
- uniqueKeys: new UniqueKeysCacheInMemoryCS(),
27
+ uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
28
28
  destroy: function () { },
29
29
  // When using shared instantiation with MEMORY we reuse everything but segments (they are unique per key)
30
30
  shared: function () {
@@ -36,7 +36,6 @@ export function InMemoryStorageCSFactory(params) {
36
36
  impressionCounts: this.impressionCounts,
37
37
  events: this.events,
38
38
  telemetry: this.telemetry,
39
- uniqueKeys: this.uniqueKeys,
40
39
  destroy: function () { }
41
40
  };
42
41
  },
@@ -4,7 +4,7 @@ import { SplitsCacheInRedis } from './SplitsCacheInRedis';
4
4
  import { SegmentsCacheInRedis } from './SegmentsCacheInRedis';
5
5
  import { ImpressionsCacheInRedis } from './ImpressionsCacheInRedis';
6
6
  import { EventsCacheInRedis } from './EventsCacheInRedis';
7
- import { STORAGE_REDIS } from '../../utils/constants';
7
+ import { DEBUG, NONE, STORAGE_REDIS } from '../../utils/constants';
8
8
  import { TelemetryCacheInRedis } from './TelemetryCacheInRedis';
9
9
  import { UniqueKeysCacheInRedis } from './UniqueKeysCacheInRedis';
10
10
  import { ImpressionCountsCacheInRedis } from './ImpressionCountsCacheInRedis';
@@ -20,18 +20,20 @@ export function InRedisStorage(options) {
20
20
  var RD = require('./RedisAdapter').RedisAdapter;
21
21
  var prefix = validatePrefix(options.prefix);
22
22
  function InRedisStorageFactory(params) {
23
- var onReadyCb = params.onReadyCb, settings = params.settings, log = params.settings.log;
23
+ var onReadyCb = params.onReadyCb, settings = params.settings, _a = params.settings, log = _a.log, impressionsMode = _a.sync.impressionsMode;
24
24
  var metadata = metadataBuilder(settings);
25
25
  var keys = new KeyBuilderSS(prefix, metadata);
26
26
  var redisClient = new RD(log, options.options || {});
27
27
  var telemetry = new TelemetryCacheInRedis(log, keys, redisClient);
28
- var impressionCountsCache = new ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient);
29
- var uniqueKeysCache = new UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient);
28
+ var impressionCountsCache = impressionsMode !== DEBUG ? new ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient) : undefined;
29
+ var uniqueKeysCache = impressionsMode === NONE ? new UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient) : undefined;
30
30
  // subscription to Redis connect event in order to emit SDK_READY event on consumer mode
31
31
  redisClient.on('connect', function () {
32
32
  onReadyCb();
33
- impressionCountsCache.start();
34
- uniqueKeysCache.start();
33
+ if (impressionCountsCache)
34
+ impressionCountsCache.start();
35
+ if (uniqueKeysCache)
36
+ uniqueKeysCache.start();
35
37
  // Synchronize config
36
38
  telemetry.recordConfig();
37
39
  });
@@ -46,10 +48,12 @@ export function InRedisStorage(options) {
46
48
  // When using REDIS we should:
47
49
  // 1- Disconnect from the storage
48
50
  destroy: function () {
49
- return Promise.all([
50
- impressionCountsCache.stop(),
51
- uniqueKeysCache.stop()
52
- ]).then(function () { redisClient.disconnect(); });
51
+ var promises = [];
52
+ if (impressionCountsCache)
53
+ promises.push(impressionCountsCache.stop());
54
+ if (uniqueKeysCache)
55
+ promises.push(uniqueKeysCache.stop());
56
+ return Promise.all(promises).then(function () { redisClient.disconnect(); });
53
57
  // @TODO check that caches works as expected when redisClient is disconnected
54
58
  }
55
59
  };
@@ -7,7 +7,7 @@ import { EventsCachePluggable } from './EventsCachePluggable';
7
7
  import { wrapperAdapter, METHODS_TO_PROMISE_WRAP } from './wrapperAdapter';
8
8
  import { isObject } from '../../utils/lang';
9
9
  import { getStorageHash, validatePrefix } from '../KeyBuilder';
10
- import { CONSUMER_PARTIAL_MODE, STORAGE_PLUGGABLE } from '../../utils/constants';
10
+ import { CONSUMER_PARTIAL_MODE, DEBUG, NONE, STORAGE_PLUGGABLE } from '../../utils/constants';
11
11
  import { ImpressionsCacheInMemory } from '../inMemory/ImpressionsCacheInMemory';
12
12
  import { EventsCacheInMemory } from '../inMemory/EventsCacheInMemory';
13
13
  import { ImpressionCountsCacheInMemory } from '../inMemory/ImpressionCountsCacheInMemory';
@@ -51,27 +51,32 @@ export function PluggableStorage(options) {
51
51
  validatePluggableStorageOptions(options);
52
52
  var prefix = validatePrefix(options.prefix);
53
53
  function PluggableStorageFactory(params) {
54
- var onReadyCb = params.onReadyCb, settings = params.settings, _a = params.settings, log = _a.log, mode = _a.mode, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
54
+ var onReadyCb = params.onReadyCb, settings = params.settings, _a = params.settings, log = _a.log, mode = _a.mode, impressionsMode = _a.sync.impressionsMode, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
55
55
  var metadata = metadataBuilder(settings);
56
56
  var keys = new KeyBuilderSS(prefix, metadata);
57
57
  var wrapper = wrapperAdapter(log, options.wrapper);
58
- var isSynchronizer = mode === undefined; // If mode is not defined, the synchronizer is running
58
+ var isSyncronizer = mode === undefined; // If mode is not defined, the synchronizer is running
59
59
  var isPartialConsumer = mode === CONSUMER_PARTIAL_MODE;
60
- var telemetry = shouldRecordTelemetry(params) || isSynchronizer ?
60
+ var telemetry = shouldRecordTelemetry(params) || isSyncronizer ?
61
61
  isPartialConsumer ?
62
62
  new TelemetryCacheInMemory() :
63
63
  new TelemetryCachePluggable(log, keys, wrapper) :
64
64
  undefined;
65
- var impressionCountsCache = isPartialConsumer ?
66
- new ImpressionCountsCacheInMemory() :
67
- new ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper);
68
- var uniqueKeysCache = isPartialConsumer ?
69
- settings.core.key === undefined ? new UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS() :
70
- new UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper);
65
+ var impressionCountsCache = impressionsMode !== DEBUG || isSyncronizer ?
66
+ isPartialConsumer ?
67
+ new ImpressionCountsCacheInMemory() :
68
+ new ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper) :
69
+ undefined;
70
+ var uniqueKeysCache = impressionsMode === NONE || isSyncronizer ?
71
+ isPartialConsumer ?
72
+ settings.core.key === undefined ? new UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS() :
73
+ new UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper) :
74
+ undefined;
71
75
  // Connects to wrapper and emits SDK_READY event on main client
72
76
  var connectPromise = wrapper.connect().then(function () {
73
- if (isSynchronizer) {
74
- // In standalone or producer mode, clear storage if SDK key or feature flag filter has changed
77
+ if (isSyncronizer) {
78
+ // @TODO reuse InLocalStorage::validateCache logic
79
+ // In standalone or producer mode, clear storage if SDK key, flags filter criteria or flags spec version was modified
75
80
  return wrapper.get(keys.buildHashKey()).then(function (hash) {
76
81
  var currentHash = getStorageHash(settings);
77
82
  if (hash !== currentHash) {
@@ -86,9 +91,9 @@ export function PluggableStorage(options) {
86
91
  }
87
92
  else {
88
93
  // Start periodic flush of async storages if not running synchronizer (producer mode)
89
- if (impressionCountsCache.start)
94
+ if (impressionCountsCache && impressionCountsCache.start)
90
95
  impressionCountsCache.start();
91
- if (uniqueKeysCache.start)
96
+ if (uniqueKeysCache && uniqueKeysCache.start)
92
97
  uniqueKeysCache.start();
93
98
  if (telemetry && telemetry.recordConfig)
94
99
  telemetry.recordConfig();
@@ -109,9 +114,9 @@ export function PluggableStorage(options) {
109
114
  uniqueKeys: uniqueKeysCache,
110
115
  // Stop periodic flush and disconnect the underlying storage
111
116
  destroy: function () {
112
- return Promise.all(isSynchronizer ? [] : [
113
- impressionCountsCache.stop && impressionCountsCache.stop(),
114
- uniqueKeysCache.stop && uniqueKeysCache.stop(),
117
+ return Promise.all(isSyncronizer ? [] : [
118
+ impressionCountsCache && impressionCountsCache.stop && impressionCountsCache.stop(),
119
+ uniqueKeysCache && uniqueKeysCache.stop && uniqueKeysCache.stop(),
115
120
  ]).then(function () { return wrapper.disconnect(); });
116
121
  },
117
122
  // emits SDK_READY event on shared clients and returns a reference to the storage
@@ -43,9 +43,10 @@ export function fromObjectUpdaterFactory(splitsParser, storage, readiness, setti
43
43
  readiness.splits.emit(SDK_SPLITS_ARRIVED);
44
44
  if (startingUp) {
45
45
  startingUp = false;
46
- Promise.resolve(splitsCache.checkCache()).then(function (cacheReady) {
46
+ var isCacheLoaded_1 = storage.validateCache ? storage.validateCache() : false;
47
+ Promise.resolve().then(function () {
47
48
  // Emits SDK_READY_FROM_CACHE
48
- if (cacheReady)
49
+ if (isCacheLoaded_1)
49
50
  readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
50
51
  // Emits SDK_READY
51
52
  readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
@@ -1,5 +1,5 @@
1
1
  import { timeout } from '../../../utils/promise/timeout';
2
- import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
2
+ import { SDK_SPLITS_ARRIVED } from '../../../readiness/constants';
3
3
  import { SYNC_SPLITS_FETCH, SYNC_SPLITS_NEW, SYNC_SPLITS_REMOVED, SYNC_SPLITS_SEGMENTS, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
4
4
  import { startsWith } from '../../../utils/lang';
5
5
  import { IN_SEGMENT } from '../../../utils/constants';
@@ -121,7 +121,7 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
121
121
  function _splitChangesUpdater(since, retry) {
122
122
  if (retry === void 0) { retry = 0; }
123
123
  log.debug(SYNC_SPLITS_FETCH, [since]);
124
- var fetcherPromise = Promise.resolve(splitUpdateNotification ?
124
+ return Promise.resolve(splitUpdateNotification ?
125
125
  { splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
126
126
  splitChangesFetcher(since, noCache, till, _promiseDecorator))
127
127
  .then(function (splitChanges) {
@@ -165,15 +165,6 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
165
165
  }
166
166
  return false;
167
167
  });
168
- // After triggering the requests, if we have cached splits information let's notify that to emit SDK_READY_FROM_CACHE.
169
- // Wrapping in a promise since checkCache can be async.
170
- if (splitsEventEmitter && startingUp) {
171
- Promise.resolve(splits.checkCache()).then(function (isCacheReady) {
172
- if (isCacheReady)
173
- splitsEventEmitter.emit(SDK_SPLITS_CACHE_LOADED);
174
- });
175
- }
176
- return fetcherPromise;
177
168
  }
178
169
  var sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error
179
170
  return sincePromise.then(_splitChangesUpdater);
@@ -306,12 +306,14 @@ export function pushManagerFactory(params, pollingManager) {
306
306
  // Reconnects in case of a new client.
307
307
  // Run in next event-loop cycle to save authentication calls
308
308
  // in case multiple clients are created in the current cycle.
309
- setTimeout(function checkForReconnect() {
310
- if (connectForNewClient) {
311
- connectForNewClient = false;
312
- connectPush();
313
- }
314
- }, 0);
309
+ if (this.isRunning()) {
310
+ setTimeout(function checkForReconnect() {
311
+ if (connectForNewClient) {
312
+ connectForNewClient = false;
313
+ connectPush();
314
+ }
315
+ }, 0);
316
+ }
315
317
  }
316
318
  },
317
319
  // [Only for client-side]
@@ -26,6 +26,8 @@ var IMPRESSIONS_COUNT_RATE = 1800000; // 30 minutes
26
26
  */
27
27
  export function impressionCountsSubmitterFactory(params) {
28
28
  var log = params.settings.log, postTestImpressionsCount = params.splitApi.postTestImpressionsCount, impressionCounts = params.storage.impressionCounts;
29
- // retry impressions counts only once.
30
- return submitterFactory(log, postTestImpressionsCount, impressionCounts, IMPRESSIONS_COUNT_RATE, 'impression counts', fromImpressionCountsCollector, 1);
29
+ if (impressionCounts) {
30
+ // retry impressions counts only once.
31
+ return submitterFactory(log, postTestImpressionsCount, impressionCounts, IMPRESSIONS_COUNT_RATE, 'impression counts', fromImpressionCountsCollector, 1);
32
+ }
31
33
  }
@@ -6,11 +6,14 @@ import { uniqueKeysSubmitterFactory } from './uniqueKeysSubmitter';
6
6
  export function submitterManagerFactory(params) {
7
7
  var submitters = [
8
8
  impressionsSubmitterFactory(params),
9
- eventsSubmitterFactory(params),
10
- impressionCountsSubmitterFactory(params),
11
- uniqueKeysSubmitterFactory(params)
9
+ eventsSubmitterFactory(params)
12
10
  ];
11
+ var impressionCountsSubmitter = impressionCountsSubmitterFactory(params);
12
+ if (impressionCountsSubmitter)
13
+ submitters.push(impressionCountsSubmitter);
13
14
  var telemetrySubmitter = telemetrySubmitterFactory(params);
15
+ if (params.storage.uniqueKeys)
16
+ submitters.push(uniqueKeysSubmitterFactory(params));
14
17
  return {
15
18
  // `onlyTelemetry` true if SDK is created with userConsent not GRANTED
16
19
  start: function (onlyTelemetry) {
@@ -3,6 +3,7 @@ import { PUSH_SUBSYSTEM_UP, PUSH_SUBSYSTEM_DOWN } from './streaming/constants';
3
3
  import { SYNC_START_POLLING, SYNC_CONTINUE_POLLING, SYNC_STOP_POLLING } from '../logger/constants';
4
4
  import { isConsentGranted } from '../consent';
5
5
  import { POLLING, STREAMING, SYNC_MODE_UPDATE } from '../utils/constants';
6
+ import { SDK_SPLITS_CACHE_LOADED } from '../readiness/constants';
6
7
  /**
7
8
  * Online SyncManager factory.
8
9
  * Can be used for server-side API, and client-side API with or without multiple clients.
@@ -16,7 +17,7 @@ export function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFacto
16
17
  * SyncManager factory for modular SDK
17
18
  */
18
19
  return function (params) {
19
- var settings = params.settings, _a = params.settings, log = _a.log, streamingEnabled = _a.streamingEnabled, syncEnabled = _a.sync.enabled, telemetryTracker = params.telemetryTracker;
20
+ 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;
20
21
  /** Polling Manager */
21
22
  var pollingManager = pollingManagerFactory && pollingManagerFactory(params);
22
23
  /** Push Manager */
@@ -64,6 +65,11 @@ export function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFacto
64
65
  */
65
66
  start: function () {
66
67
  running = true;
68
+ if (startFirstTime) {
69
+ var isCacheLoaded = storage.validateCache ? storage.validateCache() : false;
70
+ if (isCacheLoaded)
71
+ Promise.resolve().then(function () { readiness.splits.emit(SDK_SPLITS_CACHE_LOADED); });
72
+ }
67
73
  // start syncing splits and segments
68
74
  if (pollingManager) {
69
75
  // If synchronization is disabled pushManager and pollingManager should not start
@@ -72,7 +78,6 @@ export function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFacto
72
78
  // Doesn't call `syncAll` when the syncManager is resuming
73
79
  if (startFirstTime) {
74
80
  pollingManager.syncAll();
75
- startFirstTime = false;
76
81
  }
77
82
  pushManager.start();
78
83
  }
@@ -83,12 +88,12 @@ export function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFacto
83
88
  else {
84
89
  if (startFirstTime) {
85
90
  pollingManager.syncAll();
86
- startFirstTime = false;
87
91
  }
88
92
  }
89
93
  }
90
94
  // start periodic data recording (events, impressions, telemetry).
91
95
  submitterManager.start(!isConsentGranted(settings));
96
+ startFirstTime = false;
92
97
  },
93
98
  /**
94
99
  * Method used to stop/pause the syncManager.
@@ -115,6 +120,8 @@ export function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFacto
115
120
  if (!pollingManager)
116
121
  return;
117
122
  var mySegmentsSyncTask = pollingManager.add(matchingKey, readinessManager, storage);
123
+ if (syncEnabled && pushManager)
124
+ pushManager.add(matchingKey, mySegmentsSyncTask);
118
125
  if (running) {
119
126
  if (syncEnabled) {
120
127
  if (pushManager) {
@@ -128,7 +135,6 @@ export function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFacto
128
135
  // of segments since `syncAll` was already executed when starting the main client
129
136
  mySegmentsSyncTask.execute();
130
137
  }
131
- pushManager.add(matchingKey, mySegmentsSyncTask);
132
138
  }
133
139
  else {
134
140
  if (storage.splits.usesSegments())