@splitsoftware/splitio-commons 2.0.1 → 2.0.3-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 (69) hide show
  1. package/CHANGES.txt +8 -0
  2. package/cjs/evaluator/index.js +2 -0
  3. package/cjs/listeners/browser.js +4 -6
  4. package/cjs/readiness/readinessManager.js +16 -18
  5. package/cjs/sdkClient/client.js +13 -13
  6. package/cjs/sdkClient/sdkClient.js +1 -1
  7. package/cjs/sdkFactory/index.js +10 -14
  8. package/cjs/sdkManager/index.js +2 -1
  9. package/cjs/services/decorateHeaders.js +6 -1
  10. package/cjs/services/splitHttpClient.js +1 -1
  11. package/cjs/storages/inLocalStorage/index.js +6 -20
  12. package/cjs/storages/inMemory/InMemoryStorage.js +4 -12
  13. package/cjs/storages/inMemory/InMemoryStorageCS.js +6 -19
  14. package/cjs/storages/inRedis/index.js +9 -13
  15. package/cjs/storages/pluggable/index.js +15 -19
  16. package/cjs/sync/submitters/impressionCountsSubmitter.js +2 -4
  17. package/cjs/sync/submitters/submitterManager.js +3 -6
  18. package/cjs/trackers/impressionsTracker.js +17 -18
  19. package/cjs/trackers/strategy/strategyDebug.js +4 -11
  20. package/cjs/trackers/strategy/strategyNone.js +11 -16
  21. package/cjs/trackers/strategy/strategyOptimized.js +11 -21
  22. package/esm/evaluator/index.js +2 -0
  23. package/esm/listeners/browser.js +1 -3
  24. package/esm/readiness/readinessManager.js +16 -18
  25. package/esm/sdkClient/client.js +13 -13
  26. package/esm/sdkClient/sdkClient.js +1 -1
  27. package/esm/sdkFactory/index.js +11 -15
  28. package/esm/sdkManager/index.js +2 -1
  29. package/esm/services/decorateHeaders.js +4 -0
  30. package/esm/services/splitHttpClient.js +2 -2
  31. package/esm/storages/inLocalStorage/index.js +7 -21
  32. package/esm/storages/inMemory/InMemoryStorage.js +5 -13
  33. package/esm/storages/inMemory/InMemoryStorageCS.js +7 -20
  34. package/esm/storages/inRedis/index.js +10 -14
  35. package/esm/storages/pluggable/index.js +16 -20
  36. package/esm/sync/submitters/impressionCountsSubmitter.js +2 -4
  37. package/esm/sync/submitters/submitterManager.js +3 -6
  38. package/esm/trackers/impressionsTracker.js +17 -18
  39. package/esm/trackers/strategy/strategyDebug.js +4 -11
  40. package/esm/trackers/strategy/strategyNone.js +11 -16
  41. package/esm/trackers/strategy/strategyOptimized.js +11 -21
  42. package/package.json +1 -1
  43. package/src/dtos/types.ts +2 -1
  44. package/src/evaluator/index.ts +2 -0
  45. package/src/evaluator/types.ts +1 -1
  46. package/src/listeners/browser.ts +1 -3
  47. package/src/readiness/readinessManager.ts +15 -16
  48. package/src/sdkClient/client.ts +11 -11
  49. package/src/sdkClient/sdkClient.ts +1 -1
  50. package/src/sdkFactory/index.ts +12 -16
  51. package/src/sdkFactory/types.ts +1 -1
  52. package/src/sdkManager/index.ts +2 -1
  53. package/src/services/decorateHeaders.ts +5 -0
  54. package/src/services/splitHttpClient.ts +2 -2
  55. package/src/storages/inLocalStorage/index.ts +7 -20
  56. package/src/storages/inMemory/InMemoryStorage.ts +5 -13
  57. package/src/storages/inMemory/InMemoryStorageCS.ts +7 -20
  58. package/src/storages/inRedis/index.ts +10 -10
  59. package/src/storages/pluggable/index.ts +16 -20
  60. package/src/storages/types.ts +2 -2
  61. package/src/sync/submitters/impressionCountsSubmitter.ts +2 -4
  62. package/src/sync/submitters/submitterManager.ts +3 -4
  63. package/src/sync/submitters/uniqueKeysSubmitter.ts +2 -3
  64. package/src/trackers/impressionsTracker.ts +17 -18
  65. package/src/trackers/strategy/strategyDebug.ts +4 -11
  66. package/src/trackers/strategy/strategyNone.ts +11 -17
  67. package/src/trackers/strategy/strategyOptimized.ts +10 -20
  68. package/src/trackers/types.ts +2 -8
  69. package/types/splitio.d.ts +4 -0
@@ -7,38 +7,37 @@ 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.
16
10
  */
17
- function impressionsTrackerFactory(settings, impressionsCache, strategy, whenInit, integrationsManager, telemetryCache) {
11
+ function impressionsTrackerFactory(settings, impressionsCache, noneStrategy, strategy, whenInit, integrationsManager, telemetryCache) {
18
12
  var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version;
19
13
  return {
20
14
  track: function (impressions, attributes) {
21
15
  if (settings.userConsent === constants_2.CONSENT_DECLINED)
22
16
  return;
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);
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]; }));
28
27
  // If we're on an async storage, handle error and log it.
29
28
  if ((0, thenable_1.thenable)(res)) {
30
29
  res.then(function () {
31
- log.info(constants_1.IMPRESSIONS_TRACKER_SUCCESS, [impressionsCount]);
30
+ log.info(constants_1.IMPRESSIONS_TRACKER_SUCCESS, [impressionsLength]);
32
31
  }).catch(function (err) {
33
- log.error(constants_1.ERROR_IMPRESSIONS_TRACKER, [impressionsCount, err]);
32
+ log.error(constants_1.ERROR_IMPRESSIONS_TRACKER, [impressionsLength, err]);
34
33
  });
35
34
  }
36
35
  else {
37
36
  // Record when impressionsCache is sync only (standalone mode)
38
37
  // @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
39
38
  if (telemetryCache) {
40
- telemetryCache.recordImpressionStats(constants_2.QUEUED, impressionsToStore.length);
41
- telemetryCache.recordImpressionStats(constants_2.DEDUPED, deduped);
39
+ telemetryCache.recordImpressionStats(constants_2.QUEUED, impressionsToStoreLength);
40
+ telemetryCache.recordImpressionStats(constants_2.DEDUPED, impressionsLength - impressionsToStoreLength);
42
41
  }
43
42
  }
44
43
  }
@@ -47,7 +46,7 @@ function impressionsTrackerFactory(settings, impressionsCache, strategy, whenIni
47
46
  var _loop_1 = function (i) {
48
47
  var impressionData = {
49
48
  // copy of impression, to avoid unexpected behaviour if modified by integrations or impressionListener
50
- impression: (0, objectAssign_1.objectAssign)({}, impressionsToListener[i]),
49
+ impression: (0, objectAssign_1.objectAssign)({}, impressions[i][0]),
51
50
  attributes: attributes,
52
51
  ip: ip,
53
52
  hostname: hostname,
@@ -69,7 +68,7 @@ function impressionsTrackerFactory(settings, impressionsCache, strategy, whenIni
69
68
  });
70
69
  });
71
70
  };
72
- for (var i = 0; i < impressionsToListenerCount; i++) {
71
+ for (var i = 0; i < impressionsLength; i++) {
73
72
  _loop_1(i);
74
73
  }
75
74
  }
@@ -5,20 +5,13 @@ 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 IStrategyResult
8
+ * @returns Debug strategy
9
9
  */
10
10
  function strategyDebugFactory(impressionsObserver) {
11
11
  return {
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
- };
12
+ process: function (impression) {
13
+ impression.pt = impressionsObserver.testAndSet(impression);
14
+ return true;
22
15
  }
23
16
  };
24
17
  }
@@ -4,25 +4,20 @@ exports.strategyNoneFactory = void 0;
4
4
  /**
5
5
  * None strategy for impressions tracker.
6
6
  *
7
- * @param impressionsCounter - cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
7
+ * @param impressionCounts - 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 IStrategyResult
9
+ * @returns None strategy
10
10
  */
11
- function strategyNoneFactory(impressionsCounter, uniqueKeysTracker) {
11
+ function strategyNoneFactory(impressionCounts, uniqueKeysTracker) {
12
12
  return {
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
- };
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;
26
21
  }
27
22
  };
28
23
  }
@@ -6,29 +6,19 @@ 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 impressionsCounter - cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
10
- * @returns IStrategyResult
9
+ * @param impressionCounts - cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
10
+ * @returns Optimized strategy
11
11
  */
12
- function strategyOptimizedFactory(impressionsObserver, impressionsCounter) {
12
+ function strategyOptimizedFactory(impressionsObserver, impressionCounts) {
13
13
  return {
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
- };
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;
32
22
  }
33
23
  };
34
24
  }
@@ -98,12 +98,14 @@ 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;
101
102
  return result;
102
103
  });
103
104
  }
104
105
  else {
105
106
  evaluation.changeNumber = split_1.getChangeNumber(); // Always sync and optional
106
107
  evaluation.config = splitJSON.configurations && splitJSON.configurations[evaluation.treatment] || null;
108
+ evaluation.track = splitJSON.trackImpressions;
107
109
  }
108
110
  }
109
111
  return evaluation;
@@ -1,6 +1,5 @@
1
1
  import { fromImpressionsCollector } from '../sync/submitters/impressionsSubmitter';
2
2
  import { fromImpressionCountsCollector } from '../sync/submitters/impressionCountsSubmitter';
3
- import { OPTIMIZED, DEBUG, NONE } from '../utils/constants';
4
3
  import { objectAssign } from '../utils/lang/objectAssign';
5
4
  import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
6
5
  import { isConsentGranted } from '../consent';
@@ -60,10 +59,9 @@ var BrowserSignalListener = /** @class */ (function () {
60
59
  var _a = this.settings.urls, events = _a.events, telemetry = _a.telemetry;
61
60
  // Flush impressions & events data if there is user consent
62
61
  if (isConsentGranted(this.settings)) {
63
- var sim = this.settings.sync.impressionsMode;
64
62
  var extraMetadata = {
65
63
  // sim stands for Sync/Split Impressions Mode
66
- sim: sim === OPTIMIZED ? OPTIMIZED : sim === DEBUG ? DEBUG : NONE
64
+ sim: this.settings.sync.impressionsMode
67
65
  };
68
66
  this._flushData(events + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata);
69
67
  this._flushData(events + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
@@ -25,7 +25,7 @@ function segmentsEventEmitterFactory(EventEmitter) {
25
25
  /**
26
26
  * Factory of readiness manager, which handles the ready / update event propagation.
27
27
  */
28
- export function readinessManagerFactory(EventEmitter, settings, splits) {
28
+ export function readinessManagerFactory(EventEmitter, settings, splits, isShared) {
29
29
  if (splits === void 0) { splits = splitsEventEmitterFactory(EventEmitter); }
30
30
  var readyTimeout = settings.startup.readyTimeout;
31
31
  var segments = segmentsEventEmitterFactory(EventEmitter);
@@ -51,22 +51,24 @@ export function readinessManagerFactory(EventEmitter, settings, splits) {
51
51
  syncLastUpdate();
52
52
  gate.emit(SDK_READY_TIMED_OUT, 'Split SDK emitted SDK_READY_TIMED_OUT event.');
53
53
  }
54
- var readyTimeoutId;
55
- if (readyTimeout > 0) {
56
- if (splits.hasInit)
57
- readyTimeoutId = setTimeout(timeout, readyTimeout);
58
- else
59
- splits.initCallbacks.push(function () { readyTimeoutId = setTimeout(timeout, readyTimeout); });
60
- }
61
54
  // emit SDK_READY and SDK_UPDATE
62
55
  var isReady = false;
63
56
  splits.on(SDK_SPLITS_ARRIVED, checkIsReadyOrUpdate);
64
57
  segments.on(SDK_SEGMENTS_ARRIVED, checkIsReadyOrUpdate);
65
58
  var isDestroyed = false;
59
+ var readyTimeoutId;
60
+ function __init() {
61
+ isDestroyed = false;
62
+ if (readyTimeout > 0 && !isReady)
63
+ readyTimeoutId = setTimeout(timeout, readyTimeout);
64
+ }
65
+ splits.initCallbacks.push(__init);
66
+ if (splits.hasInit)
67
+ __init();
66
68
  function checkIsReadyFromCache() {
67
69
  isReadyFromCache = true;
68
70
  // Don't emit SDK_READY_FROM_CACHE if SDK_READY has been emitted
69
- if (!isReady) {
71
+ if (!isReady && !isDestroyed) {
70
72
  try {
71
73
  syncLastUpdate();
72
74
  gate.emit(SDK_READY_FROM_CACHE);
@@ -78,6 +80,8 @@ export function readinessManagerFactory(EventEmitter, settings, splits) {
78
80
  }
79
81
  }
80
82
  function checkIsReadyOrUpdate(diff) {
83
+ if (isDestroyed)
84
+ return;
81
85
  if (isReady) {
82
86
  try {
83
87
  syncLastUpdate();
@@ -103,14 +107,12 @@ export function readinessManagerFactory(EventEmitter, settings, splits) {
103
107
  }
104
108
  }
105
109
  }
106
- var refCount = 1;
107
110
  return {
108
111
  splits: splits,
109
112
  segments: segments,
110
113
  gate: gate,
111
114
  shared: function () {
112
- refCount++;
113
- return readinessManagerFactory(EventEmitter, settings, splits);
115
+ return readinessManagerFactory(EventEmitter, settings, splits, true);
114
116
  },
115
117
  // @TODO review/remove next methods when non-recoverable errors are reworked
116
118
  // Called on consumer mode, when storage fails to connect
@@ -127,13 +129,9 @@ export function readinessManagerFactory(EventEmitter, settings, splits) {
127
129
  destroy: function () {
128
130
  isDestroyed = true;
129
131
  syncLastUpdate();
130
- segments.removeAllListeners();
131
- gate.removeAllListeners();
132
132
  clearTimeout(readyTimeoutId);
133
- if (refCount > 0)
134
- refCount--;
135
- if (refCount === 0)
136
- splits.removeAllListeners();
133
+ if (!isShared)
134
+ splits.hasInit = false;
137
135
  },
138
136
  isReady: function () { return isReady; },
139
137
  isReadyFromCache: function () { return isReadyFromCache; },
@@ -30,7 +30,7 @@ export function clientFactory(params) {
30
30
  var queue = [];
31
31
  var treatment = processEvaluation(evaluationResult, featureFlagName, key, attributes, withConfig, methodName, queue);
32
32
  impressionsTracker.track(queue, attributes);
33
- stopTelemetryTracker(queue[0] && queue[0].label);
33
+ stopTelemetryTracker(queue[0] && queue[0][0].label);
34
34
  return treatment;
35
35
  };
36
36
  var evaluation = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
@@ -54,7 +54,7 @@ export function clientFactory(params) {
54
54
  treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, attributes, withConfig, methodName, queue);
55
55
  });
56
56
  impressionsTracker.track(queue, attributes);
57
- stopTelemetryTracker(queue[0] && queue[0].label);
57
+ stopTelemetryTracker(queue[0] && queue[0][0].label);
58
58
  return treatments;
59
59
  };
60
60
  var evaluations = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
@@ -80,7 +80,7 @@ export function clientFactory(params) {
80
80
  treatments[featureFlagName] = processEvaluation(evaluations[featureFlagName], featureFlagName, key, attributes, withConfig, methodName, queue);
81
81
  });
82
82
  impressionsTracker.track(queue, attributes);
83
- stopTelemetryTracker(queue[0] && queue[0].label);
83
+ stopTelemetryTracker(queue[0] && queue[0][0].label);
84
84
  return treatments;
85
85
  };
86
86
  var evaluations = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
@@ -103,19 +103,19 @@ export function clientFactory(params) {
103
103
  function processEvaluation(evaluation, featureFlagName, key, attributes, withConfig, invokingMethodName, queue) {
104
104
  var matchingKey = getMatching(key);
105
105
  var bucketingKey = getBucketing(key);
106
- var treatment = evaluation.treatment, label = evaluation.label, changeNumber = evaluation.changeNumber, _a = evaluation.config, config = _a === void 0 ? null : _a;
106
+ var treatment = evaluation.treatment, label = evaluation.label, changeNumber = evaluation.changeNumber, _a = evaluation.config, config = _a === void 0 ? null : _a, track = evaluation.track;
107
107
  log.info(IMPRESSION, [featureFlagName, matchingKey, treatment, label]);
108
108
  if (validateSplitExistence(log, readinessManager, featureFlagName, label, invokingMethodName)) {
109
109
  log.info(IMPRESSION_QUEUEING);
110
- queue.push({
111
- feature: featureFlagName,
112
- keyName: matchingKey,
113
- treatment: treatment,
114
- time: Date.now(),
115
- bucketingKey: bucketingKey,
116
- label: label,
117
- changeNumber: changeNumber
118
- });
110
+ queue.push([{
111
+ feature: featureFlagName,
112
+ keyName: matchingKey,
113
+ treatment: treatment,
114
+ time: Date.now(),
115
+ bucketingKey: bucketingKey,
116
+ label: label,
117
+ changeNumber: changeNumber,
118
+ }, track]);
119
119
  }
120
120
  if (withConfig) {
121
121
  return {
@@ -47,7 +47,7 @@ export function sdkClientFactory(params, isSharedClient) {
47
47
  releaseApiKey(settings.core.authorizationKey);
48
48
  telemetryTracker.sessionLength();
49
49
  signalListener && signalListener.stop();
50
- uniqueKeysTracker && uniqueKeysTracker.stop();
50
+ uniqueKeysTracker.stop();
51
51
  }
52
52
  // Stop background jobs
53
53
  syncManager && syncManager.stop();
@@ -11,7 +11,7 @@ import { strategyDebugFactory } from '../trackers/strategy/strategyDebug';
11
11
  import { strategyOptimizedFactory } from '../trackers/strategy/strategyOptimized';
12
12
  import { strategyNoneFactory } from '../trackers/strategy/strategyNone';
13
13
  import { uniqueKeysTrackerFactory } from '../trackers/uniqueKeysTracker';
14
- import { NONE, OPTIMIZED } from '../utils/constants';
14
+ import { DEBUG, OPTIMIZED } from '../utils/constants';
15
15
  /**
16
16
  * Modular SDK factory
17
17
  */
@@ -48,19 +48,14 @@ export function sdkFactory(params) {
48
48
  var telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
49
49
  var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage, telemetryTracker: telemetryTracker });
50
50
  var observer = impressionsObserverFactory();
51
- var uniqueKeysTracker = impressionsMode === NONE ? uniqueKeysTrackerFactory(log, storage.uniqueKeys, filterAdapterFactory && filterAdapterFactory()) : undefined;
52
- var strategy;
53
- switch (impressionsMode) {
54
- case OPTIMIZED:
55
- strategy = strategyOptimizedFactory(observer, storage.impressionCounts);
56
- break;
57
- case NONE:
58
- strategy = strategyNoneFactory(storage.impressionCounts, uniqueKeysTracker);
59
- break;
60
- default:
61
- strategy = strategyDebugFactory(observer);
62
- }
63
- var impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, strategy, whenInit, integrationsManager, storage.telemetry);
51
+ var uniqueKeysTracker = uniqueKeysTrackerFactory(log, storage.uniqueKeys, filterAdapterFactory && filterAdapterFactory());
52
+ var noneStrategy = strategyNoneFactory(storage.impressionCounts, uniqueKeysTracker);
53
+ var strategy = impressionsMode === OPTIMIZED ?
54
+ strategyOptimizedFactory(observer, storage.impressionCounts) :
55
+ impressionsMode === DEBUG ?
56
+ strategyDebugFactory(observer) :
57
+ noneStrategy;
58
+ var impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, noneStrategy, strategy, whenInit, integrationsManager, storage.telemetry);
64
59
  var eventTracker = eventTrackerFactory(settings, storage.events, whenInit, integrationsManager, storage.telemetry);
65
60
  // splitApi is used by SyncManager and Browser signal listener
66
61
  var splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
@@ -79,7 +74,7 @@ export function sdkFactory(params) {
79
74
  // We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle.
80
75
  validateAndTrackApiKey(log, settings.core.authorizationKey);
81
76
  readiness.init();
82
- uniqueKeysTracker && uniqueKeysTracker.start();
77
+ uniqueKeysTracker.start();
83
78
  syncManager && syncManager.start();
84
79
  signalListener && signalListener.start();
85
80
  initCallbacks.forEach(function (cb) { return cb(); });
@@ -99,6 +94,7 @@ export function sdkFactory(params) {
99
94
  Logger: createLoggerAPI(log),
100
95
  settings: settings,
101
96
  destroy: function () {
97
+ hasInit = false;
102
98
  return Promise.all(Object.keys(clients).map(function (key) { return clients[key].destroy(); })).then(function () { });
103
99
  }
104
100
  }, extraProps && extraProps(ctx), lazyInit ? { init: init } : init());
@@ -25,7 +25,8 @@ function objectToView(splitObject) {
25
25
  treatments: collectTreatments(splitObject),
26
26
  configs: splitObject.configurations || {},
27
27
  sets: splitObject.sets || [],
28
- defaultTreatment: splitObject.defaultTreatment
28
+ defaultTreatment: splitObject.defaultTreatment,
29
+ trackImpressions: splitObject.trackImpressions !== false
29
30
  };
30
31
  }
31
32
  function objectsToViews(splitObjects) {
@@ -29,3 +29,7 @@ export function decorateHeaders(settings, headers) {
29
29
  }
30
30
  return headers;
31
31
  }
32
+ export function removeNonISO88591(input) {
33
+ // eslint-disable-next-line no-control-regex
34
+ return input.replace(/[^\x00-\xFF]/g, '');
35
+ }
@@ -1,6 +1,6 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
2
  import { ERROR_HTTP, ERROR_CLIENT_CANNOT_GET_READY } from '../logger/constants';
3
- import { decorateHeaders } from './decorateHeaders';
3
+ import { decorateHeaders, removeNonISO88591 } from './decorateHeaders';
4
4
  var messageNoFetch = 'Global fetch API is not available.';
5
5
  /**
6
6
  * Factory of Split HTTP clients, which are HTTP clients with predefined headers for Split endpoints.
@@ -25,7 +25,7 @@ export function splitHttpClientFactory(settings, _a) {
25
25
  if (ip)
26
26
  commonHeaders['SplitSDKMachineIP'] = ip;
27
27
  if (hostname)
28
- commonHeaders['SplitSDKMachineName'] = hostname;
28
+ commonHeaders['SplitSDKMachineName'] = removeNonISO88591(hostname);
29
29
  return function httpClient(url, reqOpts, latencyTracker, logErrorsAsInfo) {
30
30
  if (reqOpts === void 0) { reqOpts = {}; }
31
31
  if (latencyTracker === void 0) { latencyTracker = function () { }; }
@@ -6,12 +6,10 @@ 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 { MySegmentsCacheInMemory } from '../inMemory/MySegmentsCacheInMemory';
10
- import { SplitsCacheInMemory } from '../inMemory/SplitsCacheInMemory';
11
9
  import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../../utils/constants/browser';
12
10
  import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS';
13
11
  import { LOG_PREFIX } from './constants';
14
- import { DEBUG, NONE, STORAGE_LOCALSTORAGE } from '../../utils/constants';
12
+ import { STORAGE_LOCALSTORAGE } from '../../utils/constants';
15
13
  import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
16
14
  import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
17
15
  import { getMatching } from '../../utils/key';
@@ -27,7 +25,7 @@ export function InLocalStorage(options) {
27
25
  params.settings.log.warn(LOG_PREFIX + 'LocalStorage API is unavailable. Falling back to default MEMORY storage');
28
26
  return InMemoryStorageCSFactory(params);
29
27
  }
30
- var settings = params.settings, _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, _c = _a.sync, impressionsMode = _c.impressionsMode, __splitFiltersValidation = _c.__splitFiltersValidation;
28
+ var settings = params.settings, _a = params.settings, log = _a.log, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
31
29
  var matchingKey = getMatching(settings.core.key);
32
30
  var keys = new KeyBuilderCS(prefix, matchingKey);
33
31
  var expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
@@ -39,20 +37,11 @@ export function InLocalStorage(options) {
39
37
  segments: segments,
40
38
  largeSegments: largeSegments,
41
39
  impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
42
- impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
40
+ impressionCounts: new ImpressionCountsCacheInMemory(),
43
41
  events: new EventsCacheInMemory(eventsQueueSize),
44
42
  telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
45
- uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
46
- destroy: function () {
47
- var _a;
48
- this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
49
- this.segments = new MySegmentsCacheInMemory();
50
- this.largeSegments = new MySegmentsCacheInMemory();
51
- this.impressions.clear();
52
- this.impressionCounts && this.impressionCounts.clear();
53
- this.events.clear();
54
- (_a = this.uniqueKeys) === null || _a === void 0 ? void 0 : _a.clear();
55
- },
43
+ uniqueKeys: new UniqueKeysCacheInMemoryCS(),
44
+ destroy: function () { },
56
45
  // When using shared instantiation with MEMORY we reuse everything but segments (they are customer per key).
57
46
  shared: function (matchingKey) {
58
47
  return {
@@ -63,11 +52,8 @@ export function InLocalStorage(options) {
63
52
  impressionCounts: this.impressionCounts,
64
53
  events: this.events,
65
54
  telemetry: this.telemetry,
66
- destroy: function () {
67
- this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
68
- this.segments = new MySegmentsCacheInMemory();
69
- this.largeSegments = new MySegmentsCacheInMemory();
70
- }
55
+ uniqueKeys: this.uniqueKeys,
56
+ destroy: function () { }
71
57
  };
72
58
  },
73
59
  };
@@ -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 { DEBUG, LOCALHOST_MODE, NONE, STORAGE_MEMORY } from '../../utils/constants';
6
+ import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
7
7
  import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
8
8
  import { UniqueKeysCacheInMemory } from './UniqueKeysCacheInMemory';
9
9
  /**
@@ -12,26 +12,18 @@ 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, _c = _a.sync, impressionsMode = _c.impressionsMode, __splitFiltersValidation = _c.__splitFiltersValidation;
15
+ var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, __splitFiltersValidation = _a.sync.__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: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
22
+ impressionCounts: new ImpressionCountsCacheInMemory(),
23
23
  events: new EventsCacheInMemory(eventsQueueSize),
24
24
  telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
25
- uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemory() : undefined,
26
- // When using MEMORY we should clean all the caches to leave them empty
27
- destroy: function () {
28
- this.splits.clear();
29
- this.segments.clear();
30
- this.impressions.clear();
31
- this.impressionCounts && this.impressionCounts.clear();
32
- this.events.clear();
33
- this.uniqueKeys && this.uniqueKeys.clear();
34
- }
25
+ uniqueKeys: new UniqueKeysCacheInMemory(),
26
+ destroy: function () { }
35
27
  };
36
28
  // @TODO revisit storage logic in localhost mode
37
29
  // No tracking data in localhost mode to avoid memory leaks
@@ -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 { DEBUG, LOCALHOST_MODE, NONE, STORAGE_MEMORY } from '../../utils/constants';
6
+ import { LOCALHOST_MODE, 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, _c = _a.sync, impressionsMode = _c.impressionsMode, __splitFiltersValidation = _c.__splitFiltersValidation;
15
+ var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, __splitFiltersValidation = _a.sync.__splitFiltersValidation;
16
16
  var splits = new SplitsCacheInMemory(__splitFiltersValidation);
17
17
  var segments = new MySegmentsCacheInMemory();
18
18
  var largeSegments = new MySegmentsCacheInMemory();
@@ -21,20 +21,11 @@ export function InMemoryStorageCSFactory(params) {
21
21
  segments: segments,
22
22
  largeSegments: largeSegments,
23
23
  impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
24
- impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
24
+ impressionCounts: new ImpressionCountsCacheInMemory(),
25
25
  events: new EventsCacheInMemory(eventsQueueSize),
26
26
  telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
27
- uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
28
- // When using MEMORY we should clean all the caches to leave them empty
29
- destroy: function () {
30
- this.splits.clear();
31
- this.segments.clear();
32
- this.largeSegments.clear();
33
- this.impressions.clear();
34
- this.impressionCounts && this.impressionCounts.clear();
35
- this.events.clear();
36
- this.uniqueKeys && this.uniqueKeys.clear();
37
- },
27
+ uniqueKeys: new UniqueKeysCacheInMemoryCS(),
28
+ destroy: function () { },
38
29
  // When using shared instantiation with MEMORY we reuse everything but segments (they are unique per key)
39
30
  shared: function () {
40
31
  return {
@@ -45,12 +36,8 @@ export function InMemoryStorageCSFactory(params) {
45
36
  impressionCounts: this.impressionCounts,
46
37
  events: this.events,
47
38
  telemetry: this.telemetry,
48
- // Set a new splits cache to clean it for the client without affecting other clients
49
- destroy: function () {
50
- this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
51
- this.segments.clear();
52
- this.largeSegments.clear();
53
- }
39
+ uniqueKeys: this.uniqueKeys,
40
+ destroy: function () { }
54
41
  };
55
42
  },
56
43
  };