@splitsoftware/splitio-commons 2.0.3-rc.0 → 2.1.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/CHANGES.txt +5 -2
  2. package/README.md +2 -2
  3. package/cjs/evaluator/index.js +0 -2
  4. package/cjs/evaluator/matchers/large_segment.js +0 -6
  5. package/cjs/evaluator/matchers/segment.js +0 -6
  6. package/cjs/listeners/browser.js +6 -4
  7. package/cjs/listeners/node.js +2 -2
  8. package/cjs/readiness/readinessManager.js +6 -0
  9. package/cjs/sdkClient/client.js +13 -13
  10. package/cjs/sdkClient/sdkClient.js +1 -1
  11. package/cjs/sdkFactory/index.js +14 -9
  12. package/cjs/sdkManager/index.js +1 -2
  13. package/cjs/storages/AbstractSplitsCacheAsync.js +0 -7
  14. package/cjs/storages/AbstractSplitsCacheSync.js +0 -7
  15. package/cjs/storages/KeyBuilderCS.js +3 -0
  16. package/cjs/storages/dataLoader.js +3 -2
  17. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +1 -57
  18. package/cjs/storages/inLocalStorage/index.js +8 -7
  19. package/cjs/storages/inLocalStorage/validateCache.js +79 -0
  20. package/cjs/storages/inMemory/InMemoryStorage.js +3 -3
  21. package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -4
  22. package/cjs/storages/inRedis/SplitsCacheInRedis.js +1 -1
  23. package/cjs/storages/inRedis/index.js +13 -9
  24. package/cjs/storages/pluggable/index.js +21 -16
  25. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  26. package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -10
  27. package/cjs/sync/streaming/pushManager.js +8 -6
  28. package/cjs/sync/submitters/impressionCountsSubmitter.js +4 -2
  29. package/cjs/sync/submitters/submitterManager.js +6 -3
  30. package/cjs/sync/syncManagerOnline.js +10 -4
  31. package/cjs/trackers/eventTracker.js +1 -1
  32. package/cjs/trackers/impressionsTracker.js +19 -18
  33. package/cjs/trackers/strategy/strategyDebug.js +11 -4
  34. package/cjs/trackers/strategy/strategyNone.js +16 -11
  35. package/cjs/trackers/strategy/strategyOptimized.js +21 -11
  36. package/cjs/utils/settingsValidation/index.js +1 -1
  37. package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
  38. package/esm/evaluator/index.js +0 -2
  39. package/esm/evaluator/matchers/large_segment.js +0 -6
  40. package/esm/evaluator/matchers/segment.js +0 -6
  41. package/esm/listeners/browser.js +3 -1
  42. package/esm/listeners/node.js +2 -2
  43. package/esm/readiness/readinessManager.js +6 -0
  44. package/esm/sdkClient/client.js +13 -13
  45. package/esm/sdkClient/sdkClient.js +1 -1
  46. package/esm/sdkFactory/index.js +15 -10
  47. package/esm/sdkManager/index.js +1 -2
  48. package/esm/storages/AbstractSplitsCacheAsync.js +0 -7
  49. package/esm/storages/AbstractSplitsCacheSync.js +0 -7
  50. package/esm/storages/KeyBuilderCS.js +3 -0
  51. package/esm/storages/dataLoader.js +2 -1
  52. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +1 -57
  53. package/esm/storages/inLocalStorage/index.js +9 -8
  54. package/esm/storages/inLocalStorage/validateCache.js +75 -0
  55. package/esm/storages/inMemory/InMemoryStorage.js +4 -4
  56. package/esm/storages/inMemory/InMemoryStorageCS.js +4 -5
  57. package/esm/storages/inRedis/SplitsCacheInRedis.js +1 -1
  58. package/esm/storages/inRedis/index.js +14 -10
  59. package/esm/storages/pluggable/index.js +22 -17
  60. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
  61. package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -11
  62. package/esm/sync/streaming/pushManager.js +8 -6
  63. package/esm/sync/submitters/impressionCountsSubmitter.js +4 -2
  64. package/esm/sync/submitters/submitterManager.js +6 -3
  65. package/esm/sync/syncManagerOnline.js +10 -4
  66. package/esm/trackers/eventTracker.js +1 -1
  67. package/esm/trackers/impressionsTracker.js +19 -18
  68. package/esm/trackers/strategy/strategyDebug.js +11 -4
  69. package/esm/trackers/strategy/strategyNone.js +16 -11
  70. package/esm/trackers/strategy/strategyOptimized.js +21 -11
  71. package/esm/utils/settingsValidation/index.js +1 -1
  72. package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
  73. package/package.json +1 -1
  74. package/src/dtos/types.ts +1 -2
  75. package/src/evaluator/index.ts +0 -2
  76. package/src/evaluator/matchers/large_segment.ts +0 -7
  77. package/src/evaluator/matchers/segment.ts +0 -7
  78. package/src/evaluator/types.ts +1 -1
  79. package/src/listeners/browser.ts +3 -1
  80. package/src/listeners/node.ts +2 -2
  81. package/src/readiness/readinessManager.ts +5 -0
  82. package/src/sdkClient/client.ts +11 -11
  83. package/src/sdkClient/sdkClient.ts +1 -1
  84. package/src/sdkFactory/index.ts +16 -11
  85. package/src/sdkFactory/types.ts +1 -1
  86. package/src/sdkManager/index.ts +1 -2
  87. package/src/storages/AbstractSplitsCacheAsync.ts +0 -8
  88. package/src/storages/AbstractSplitsCacheSync.ts +0 -8
  89. package/src/storages/KeyBuilderCS.ts +4 -0
  90. package/src/storages/dataLoader.ts +3 -1
  91. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +1 -66
  92. package/src/storages/inLocalStorage/index.ts +12 -13
  93. package/src/storages/inLocalStorage/validateCache.ts +91 -0
  94. package/src/storages/inMemory/InMemoryStorage.ts +4 -4
  95. package/src/storages/inMemory/InMemoryStorageCS.ts +4 -5
  96. package/src/storages/inRedis/SplitsCacheInRedis.ts +1 -1
  97. package/src/storages/inRedis/index.ts +10 -10
  98. package/src/storages/pluggable/index.ts +22 -17
  99. package/src/storages/types.ts +3 -6
  100. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +6 -5
  101. package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -11
  102. package/src/sync/streaming/pushManager.ts +8 -6
  103. package/src/sync/submitters/impressionCountsSubmitter.ts +4 -2
  104. package/src/sync/submitters/submitterManager.ts +4 -3
  105. package/src/sync/submitters/uniqueKeysSubmitter.ts +3 -2
  106. package/src/sync/syncManagerOnline.ts +11 -5
  107. package/src/trackers/eventTracker.ts +1 -1
  108. package/src/trackers/impressionsTracker.ts +19 -18
  109. package/src/trackers/strategy/strategyDebug.ts +11 -4
  110. package/src/trackers/strategy/strategyNone.ts +17 -11
  111. package/src/trackers/strategy/strategyOptimized.ts +20 -10
  112. package/src/trackers/types.ts +8 -2
  113. package/src/utils/lang/index.ts +1 -1
  114. package/src/utils/settingsValidation/index.ts +1 -1
  115. package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
  116. package/types/index.d.ts +1 -1
  117. package/types/splitio.d.ts +26 -6
  118. package/cjs/utils/constants/browser.js +0 -5
  119. package/esm/utils/constants/browser.js +0 -2
  120. package/src/utils/constants/browser.ts +0 -2
@@ -23,18 +23,20 @@ function InRedisStorage(options) {
23
23
  var RD = require('./RedisAdapter').RedisAdapter;
24
24
  var prefix = (0, KeyBuilder_1.validatePrefix)(options.prefix);
25
25
  function InRedisStorageFactory(params) {
26
- var onReadyCb = params.onReadyCb, settings = params.settings, log = params.settings.log;
26
+ var onReadyCb = params.onReadyCb, settings = params.settings, _a = params.settings, log = _a.log, impressionsMode = _a.sync.impressionsMode;
27
27
  var metadata = (0, utils_1.metadataBuilder)(settings);
28
28
  var keys = new KeyBuilderSS_1.KeyBuilderSS(prefix, metadata);
29
29
  var redisClient = new RD(log, options.options || {});
30
30
  var telemetry = new TelemetryCacheInRedis_1.TelemetryCacheInRedis(log, keys, redisClient);
31
- var impressionCountsCache = new ImpressionCountsCacheInRedis_1.ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient);
32
- var uniqueKeysCache = new UniqueKeysCacheInRedis_1.UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient);
31
+ var impressionCountsCache = impressionsMode !== constants_1.DEBUG ? new ImpressionCountsCacheInRedis_1.ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient) : undefined;
32
+ var uniqueKeysCache = impressionsMode === constants_1.NONE ? new UniqueKeysCacheInRedis_1.UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient) : undefined;
33
33
  // subscription to Redis connect event in order to emit SDK_READY event on consumer mode
34
34
  redisClient.on('connect', function () {
35
35
  onReadyCb();
36
- impressionCountsCache.start();
37
- uniqueKeysCache.start();
36
+ if (impressionCountsCache)
37
+ impressionCountsCache.start();
38
+ if (uniqueKeysCache)
39
+ uniqueKeysCache.start();
38
40
  // Synchronize config
39
41
  telemetry.recordConfig();
40
42
  });
@@ -49,10 +51,12 @@ function InRedisStorage(options) {
49
51
  // When using REDIS we should:
50
52
  // 1- Disconnect from the storage
51
53
  destroy: function () {
52
- return Promise.all([
53
- impressionCountsCache.stop(),
54
- uniqueKeysCache.stop()
55
- ]).then(function () { redisClient.disconnect(); });
54
+ var promises = [];
55
+ if (impressionCountsCache)
56
+ promises.push(impressionCountsCache.stop());
57
+ if (uniqueKeysCache)
58
+ promises.push(uniqueKeysCache.stop());
59
+ return Promise.all(promises).then(function () { redisClient.disconnect(); });
56
60
  // @TODO check that caches works as expected when redisClient is disconnected
57
61
  }
58
62
  };
@@ -54,27 +54,32 @@ function PluggableStorage(options) {
54
54
  validatePluggableStorageOptions(options);
55
55
  var prefix = (0, KeyBuilder_1.validatePrefix)(options.prefix);
56
56
  function PluggableStorageFactory(params) {
57
- 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;
57
+ 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;
58
58
  var metadata = (0, utils_1.metadataBuilder)(settings);
59
59
  var keys = new KeyBuilderSS_1.KeyBuilderSS(prefix, metadata);
60
60
  var wrapper = (0, wrapperAdapter_1.wrapperAdapter)(log, options.wrapper);
61
- var isSynchronizer = mode === undefined; // If mode is not defined, the synchronizer is running
61
+ var isSyncronizer = mode === undefined; // If mode is not defined, the synchronizer is running
62
62
  var isPartialConsumer = mode === constants_1.CONSUMER_PARTIAL_MODE;
63
- var telemetry = (0, TelemetryCacheInMemory_1.shouldRecordTelemetry)(params) || isSynchronizer ?
63
+ var telemetry = (0, TelemetryCacheInMemory_1.shouldRecordTelemetry)(params) || isSyncronizer ?
64
64
  isPartialConsumer ?
65
65
  new TelemetryCacheInMemory_1.TelemetryCacheInMemory() :
66
66
  new TelemetryCachePluggable_1.TelemetryCachePluggable(log, keys, wrapper) :
67
67
  undefined;
68
- var impressionCountsCache = isPartialConsumer ?
69
- new ImpressionCountsCacheInMemory_1.ImpressionCountsCacheInMemory() :
70
- new ImpressionCountsCachePluggable_1.ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper);
71
- var uniqueKeysCache = isPartialConsumer ?
72
- settings.core.key === undefined ? new UniqueKeysCacheInMemory_1.UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS_1.UniqueKeysCacheInMemoryCS() :
73
- new UniqueKeysCachePluggable_1.UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper);
68
+ var impressionCountsCache = impressionsMode !== constants_1.DEBUG || isSyncronizer ?
69
+ isPartialConsumer ?
70
+ new ImpressionCountsCacheInMemory_1.ImpressionCountsCacheInMemory() :
71
+ new ImpressionCountsCachePluggable_1.ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper) :
72
+ undefined;
73
+ var uniqueKeysCache = impressionsMode === constants_1.NONE || isSyncronizer ?
74
+ isPartialConsumer ?
75
+ settings.core.key === undefined ? new UniqueKeysCacheInMemory_1.UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS_1.UniqueKeysCacheInMemoryCS() :
76
+ new UniqueKeysCachePluggable_1.UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper) :
77
+ undefined;
74
78
  // Connects to wrapper and emits SDK_READY event on main client
75
79
  var connectPromise = wrapper.connect().then(function () {
76
- if (isSynchronizer) {
77
- // In standalone or producer mode, clear storage if SDK key or feature flag filter has changed
80
+ if (isSyncronizer) {
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
78
83
  return wrapper.get(keys.buildHashKey()).then(function (hash) {
79
84
  var currentHash = (0, KeyBuilder_1.getStorageHash)(settings);
80
85
  if (hash !== currentHash) {
@@ -89,9 +94,9 @@ function PluggableStorage(options) {
89
94
  }
90
95
  else {
91
96
  // Start periodic flush of async storages if not running synchronizer (producer mode)
92
- if (impressionCountsCache.start)
97
+ if (impressionCountsCache && impressionCountsCache.start)
93
98
  impressionCountsCache.start();
94
- if (uniqueKeysCache.start)
99
+ if (uniqueKeysCache && uniqueKeysCache.start)
95
100
  uniqueKeysCache.start();
96
101
  if (telemetry && telemetry.recordConfig)
97
102
  telemetry.recordConfig();
@@ -112,9 +117,9 @@ function PluggableStorage(options) {
112
117
  uniqueKeys: uniqueKeysCache,
113
118
  // Stop periodic flush and disconnect the underlying storage
114
119
  destroy: function () {
115
- return Promise.all(isSynchronizer ? [] : [
116
- impressionCountsCache.stop && impressionCountsCache.stop(),
117
- uniqueKeysCache.stop && uniqueKeysCache.stop(),
120
+ return Promise.all(isSyncronizer ? [] : [
121
+ impressionCountsCache && impressionCountsCache.stop && impressionCountsCache.stop(),
122
+ uniqueKeysCache && uniqueKeysCache.stop && uniqueKeysCache.stop(),
118
123
  ]).then(function () { return wrapper.disconnect(); });
119
124
  },
120
125
  // emits SDK_READY event on shared clients and returns a reference to the storage
@@ -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]
@@ -30,7 +30,9 @@ var IMPRESSIONS_COUNT_RATE = 1800000; // 30 minutes
30
30
  */
31
31
  function impressionCountsSubmitterFactory(params) {
32
32
  var log = params.settings.log, postTestImpressionsCount = params.splitApi.postTestImpressionsCount, impressionCounts = params.storage.impressionCounts;
33
- // retry impressions counts only once.
34
- return (0, submitter_1.submitterFactory)(log, postTestImpressionsCount, impressionCounts, IMPRESSIONS_COUNT_RATE, 'impression counts', fromImpressionCountsCollector, 1);
33
+ if (impressionCounts) {
34
+ // retry impressions counts only once.
35
+ return (0, submitter_1.submitterFactory)(log, postTestImpressionsCount, impressionCounts, IMPRESSIONS_COUNT_RATE, 'impression counts', fromImpressionCountsCollector, 1);
36
+ }
35
37
  }
36
38
  exports.impressionCountsSubmitterFactory = impressionCountsSubmitterFactory;
@@ -9,11 +9,14 @@ var uniqueKeysSubmitter_1 = require("./uniqueKeysSubmitter");
9
9
  function submitterManagerFactory(params) {
10
10
  var submitters = [
11
11
  (0, impressionsSubmitter_1.impressionsSubmitterFactory)(params),
12
- (0, eventsSubmitter_1.eventsSubmitterFactory)(params),
13
- (0, impressionCountsSubmitter_1.impressionCountsSubmitterFactory)(params),
14
- (0, uniqueKeysSubmitter_1.uniqueKeysSubmitterFactory)(params)
12
+ (0, eventsSubmitter_1.eventsSubmitterFactory)(params)
15
13
  ];
14
+ var impressionCountsSubmitter = (0, impressionCountsSubmitter_1.impressionCountsSubmitterFactory)(params);
15
+ if (impressionCountsSubmitter)
16
+ submitters.push(impressionCountsSubmitter);
16
17
  var telemetrySubmitter = (0, telemetrySubmitter_1.telemetrySubmitterFactory)(params);
18
+ if (params.storage.uniqueKeys)
19
+ submitters.push((0, uniqueKeysSubmitter_1.uniqueKeysSubmitterFactory)(params));
17
20
  return {
18
21
  // `onlyTelemetry` true if SDK is created with userConsent not GRANTED
19
22
  start: function (onlyTelemetry) {
@@ -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);
@@ -7,37 +7,38 @@ var constants_1 = require("../logger/constants");
7
7
  var constants_2 = require("../utils/constants");
8
8
  /**
9
9
  * Impressions tracker stores impressions in cache and pass them to the listener and integrations manager if provided.
10
+ *
11
+ * @param impressionsCache - cache to save impressions
12
+ * @param metadata - runtime metadata (ip, hostname and version)
13
+ * @param impressionListener - optional impression listener
14
+ * @param integrationsManager - optional integrations manager
15
+ * @param strategy - strategy for impressions tracking.
10
16
  */
11
- function impressionsTrackerFactory(settings, impressionsCache, noneStrategy, strategy, whenInit, integrationsManager, telemetryCache) {
17
+ function impressionsTrackerFactory(settings, impressionsCache, strategy, whenInit, integrationsManager, telemetryCache) {
12
18
  var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version;
13
19
  return {
14
20
  track: function (impressions, attributes) {
15
21
  if (settings.userConsent === constants_2.CONSENT_DECLINED)
16
22
  return;
17
- var impressionsToStore = impressions.filter(function (_a) {
18
- var impression = _a[0], track = _a[1];
19
- return track === false ?
20
- noneStrategy.process(impression) :
21
- strategy.process(impression);
22
- });
23
- var impressionsLength = impressions.length;
24
- var impressionsToStoreLength = impressionsToStore.length;
25
- if (impressionsToStoreLength) {
26
- var res = impressionsCache.track(impressionsToStore.map(function (item) { return item[0]; }));
23
+ var impressionsCount = impressions.length;
24
+ var _a = strategy.process(impressions), impressionsToStore = _a.impressionsToStore, impressionsToListener = _a.impressionsToListener, deduped = _a.deduped;
25
+ var impressionsToListenerCount = impressionsToListener.length;
26
+ if (impressionsToStore.length > 0) {
27
+ var res = impressionsCache.track(impressionsToStore);
27
28
  // If we're on an async storage, handle error and log it.
28
29
  if ((0, thenable_1.thenable)(res)) {
29
30
  res.then(function () {
30
- log.info(constants_1.IMPRESSIONS_TRACKER_SUCCESS, [impressionsLength]);
31
+ log.info(constants_1.IMPRESSIONS_TRACKER_SUCCESS, [impressionsCount]);
31
32
  }).catch(function (err) {
32
- log.error(constants_1.ERROR_IMPRESSIONS_TRACKER, [impressionsLength, err]);
33
+ log.error(constants_1.ERROR_IMPRESSIONS_TRACKER, [impressionsCount, err]);
33
34
  });
34
35
  }
35
36
  else {
36
37
  // Record when impressionsCache is sync only (standalone mode)
37
38
  // @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
38
39
  if (telemetryCache) {
39
- telemetryCache.recordImpressionStats(constants_2.QUEUED, impressionsToStoreLength);
40
- telemetryCache.recordImpressionStats(constants_2.DEDUPED, impressionsLength - impressionsToStoreLength);
40
+ telemetryCache.recordImpressionStats(constants_2.QUEUED, impressionsToStore.length);
41
+ telemetryCache.recordImpressionStats(constants_2.DEDUPED, deduped);
41
42
  }
42
43
  }
43
44
  }
@@ -45,8 +46,8 @@ function impressionsTrackerFactory(settings, impressionsCache, noneStrategy, str
45
46
  if (impressionListener || integrationsManager) {
46
47
  var _loop_1 = function (i) {
47
48
  var impressionData = {
48
- // copy of impression, to avoid unexpected behaviour if modified by integrations or impressionListener
49
- impression: (0, objectAssign_1.objectAssign)({}, impressions[i][0]),
49
+ // copy of impression, to avoid unexpected behavior if modified by integrations or impressionListener
50
+ impression: (0, objectAssign_1.objectAssign)({}, impressionsToListener[i]),
50
51
  attributes: attributes,
51
52
  ip: ip,
52
53
  hostname: hostname,
@@ -68,7 +69,7 @@ function impressionsTrackerFactory(settings, impressionsCache, noneStrategy, str
68
69
  });
69
70
  });
70
71
  };
71
- for (var i = 0; i < impressionsLength; i++) {
72
+ for (var i = 0; i < impressionsToListenerCount; i++) {
72
73
  _loop_1(i);
73
74
  }
74
75
  }
@@ -5,13 +5,20 @@ exports.strategyDebugFactory = void 0;
5
5
  * Debug strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
6
6
  *
7
7
  * @param impressionsObserver - impression observer. Previous time (pt property) is included in impression instances
8
- * @returns Debug strategy
8
+ * @returns IStrategyResult
9
9
  */
10
10
  function strategyDebugFactory(impressionsObserver) {
11
11
  return {
12
- process: function (impression) {
13
- impression.pt = impressionsObserver.testAndSet(impression);
14
- return true;
12
+ process: function (impressions) {
13
+ impressions.forEach(function (impression) {
14
+ // Adds previous time if it is enabled
15
+ impression.pt = impressionsObserver.testAndSet(impression);
16
+ });
17
+ return {
18
+ impressionsToStore: impressions,
19
+ impressionsToListener: impressions,
20
+ deduped: 0
21
+ };
15
22
  }
16
23
  };
17
24
  }
@@ -4,20 +4,25 @@ exports.strategyNoneFactory = void 0;
4
4
  /**
5
5
  * None strategy for impressions tracker.
6
6
  *
7
- * @param impressionCounts - cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
7
+ * @param impressionsCounter - cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
8
8
  * @param uniqueKeysTracker - unique keys tracker in charge of tracking the unique keys per split.
9
- * @returns None strategy
9
+ * @returns IStrategyResult
10
10
  */
11
- function strategyNoneFactory(impressionCounts, uniqueKeysTracker) {
11
+ function strategyNoneFactory(impressionsCounter, uniqueKeysTracker) {
12
12
  return {
13
- process: function (impression) {
14
- var now = Date.now();
15
- // Increments impression counter per featureName
16
- impressionCounts.track(impression.feature, now, 1);
17
- // Keep track by unique key
18
- uniqueKeysTracker.track(impression.keyName, impression.feature);
19
- // Do not store impressions
20
- return false;
13
+ process: function (impressions) {
14
+ impressions.forEach(function (impression) {
15
+ var now = Date.now();
16
+ // Increments impression counter per featureName
17
+ impressionsCounter.track(impression.feature, now, 1);
18
+ // Keep track by unique key
19
+ uniqueKeysTracker.track(impression.keyName, impression.feature);
20
+ });
21
+ return {
22
+ impressionsToStore: [],
23
+ impressionsToListener: impressions,
24
+ deduped: 0
25
+ };
21
26
  }
22
27
  };
23
28
  }
@@ -6,19 +6,29 @@ var time_1 = require("../../utils/time");
6
6
  * Optimized strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
7
7
  *
8
8
  * @param impressionsObserver - impression observer. previous time (pt property) is included in impression instances
9
- * @param impressionCounts - cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
10
- * @returns Optimized strategy
9
+ * @param impressionsCounter - cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
10
+ * @returns IStrategyResult
11
11
  */
12
- function strategyOptimizedFactory(impressionsObserver, impressionCounts) {
12
+ function strategyOptimizedFactory(impressionsObserver, impressionsCounter) {
13
13
  return {
14
- process: function (impression) {
15
- impression.pt = impressionsObserver.testAndSet(impression);
16
- var now = Date.now();
17
- // Increments impression counter per featureName
18
- if (impression.pt)
19
- impressionCounts.track(impression.feature, now, 1);
20
- // Checks if the impression should be added in queue to be sent
21
- return (!impression.pt || impression.pt < (0, time_1.truncateTimeFrame)(now)) ? true : false;
14
+ process: function (impressions) {
15
+ var impressionsToStore = [];
16
+ impressions.forEach(function (impression) {
17
+ impression.pt = impressionsObserver.testAndSet(impression);
18
+ var now = Date.now();
19
+ // Increments impression counter per featureName
20
+ if (impression.pt)
21
+ impressionsCounter.track(impression.feature, now, 1);
22
+ // Checks if the impression should be added in queue to be sent
23
+ if (!impression.pt || impression.pt < (0, time_1.truncateTimeFrame)(now)) {
24
+ impressionsToStore.push(impression);
25
+ }
26
+ });
27
+ return {
28
+ impressionsToStore: impressionsToStore,
29
+ impressionsToListener: impressions,
30
+ deduped: impressions.length - impressionsToStore.length
31
+ };
22
32
  }
23
33
  };
24
34
  }
@@ -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;
@@ -98,14 +98,12 @@ function getEvaluation(log, splitJSON, key, attributes, storage) {
98
98
  return evaluation.then(function (result) {
99
99
  result.changeNumber = split_1.getChangeNumber();
100
100
  result.config = splitJSON.configurations && splitJSON.configurations[result.treatment] || null;
101
- result.track = splitJSON.trackImpressions;
102
101
  return result;
103
102
  });
104
103
  }
105
104
  else {
106
105
  evaluation.changeNumber = split_1.getChangeNumber(); // Always sync and optional
107
106
  evaluation.config = splitJSON.configurations && splitJSON.configurations[evaluation.treatment] || null;
108
- evaluation.track = splitJSON.trackImpressions;
109
107
  }
110
108
  }
111
109
  return evaluation;
@@ -1,12 +1,6 @@
1
- import { thenable } from '../../utils/promise/thenable';
2
1
  export function largeSegmentMatcherContext(largeSegmentName, storage) {
3
2
  return function largeSegmentMatcher(key) {
4
3
  var isInLargeSegment = storage.largeSegments ? storage.largeSegments.isInSegment(largeSegmentName, key) : false;
5
- if (thenable(isInLargeSegment)) {
6
- isInLargeSegment.then(function (result) {
7
- return result;
8
- });
9
- }
10
4
  return isInLargeSegment;
11
5
  };
12
6
  }
@@ -1,12 +1,6 @@
1
- import { thenable } from '../../utils/promise/thenable';
2
1
  export function segmentMatcherContext(segmentName, storage) {
3
2
  return function segmentMatcher(key) {
4
3
  var isInSegment = storage.segments.isInSegment(segmentName, key);
5
- if (thenable(isInSegment)) {
6
- isInSegment.then(function (result) {
7
- return result;
8
- });
9
- }
10
4
  return isInSegment;
11
5
  };
12
6
  }
@@ -1,5 +1,6 @@
1
1
  import { fromImpressionsCollector } from '../sync/submitters/impressionsSubmitter';
2
2
  import { fromImpressionCountsCollector } from '../sync/submitters/impressionCountsSubmitter';
3
+ import { OPTIMIZED, DEBUG, NONE } from '../utils/constants';
3
4
  import { objectAssign } from '../utils/lang/objectAssign';
4
5
  import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
5
6
  import { isConsentGranted } from '../consent';
@@ -59,9 +60,10 @@ var BrowserSignalListener = /** @class */ (function () {
59
60
  var _a = this.settings.urls, events = _a.events, telemetry = _a.telemetry;
60
61
  // Flush impressions & events data if there is user consent
61
62
  if (isConsentGranted(this.settings)) {
63
+ var sim = this.settings.sync.impressionsMode;
62
64
  var extraMetadata = {
63
65
  // sim stands for Sync/Split Impressions Mode
64
- sim: this.settings.sync.impressionsMode
66
+ sim: sim === OPTIMIZED ? OPTIMIZED : sim === DEBUG ? DEBUG : NONE
65
67
  };
66
68
  this._flushData(events + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata);
67
69
  this._flushData(events + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
@@ -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 {
@@ -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) {