@splitsoftware/splitio-commons 1.6.2-rc.9 → 1.7.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 (176) hide show
  1. package/CHANGES.txt +6 -1
  2. package/cjs/consent/sdkUserConsent.js +2 -2
  3. package/cjs/listeners/browser.js +11 -12
  4. package/cjs/logger/constants.js +2 -1
  5. package/cjs/sdkClient/sdkClient.js +3 -1
  6. package/cjs/sdkFactory/index.js +26 -26
  7. package/cjs/services/splitApi.js +20 -0
  8. package/cjs/storages/AbstractSplitsCacheAsync.js +1 -1
  9. package/cjs/storages/AbstractSplitsCacheSync.js +1 -1
  10. package/cjs/storages/KeyBuilderSS.js +10 -43
  11. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +0 -1
  12. package/cjs/storages/inLocalStorage/index.js +17 -9
  13. package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +12 -1
  14. package/cjs/storages/inMemory/InMemoryStorage.js +13 -6
  15. package/cjs/storages/inMemory/InMemoryStorageCS.js +13 -6
  16. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +60 -35
  17. package/cjs/storages/inMemory/UniqueKeysCacheInMemory.js +72 -0
  18. package/cjs/storages/inMemory/UniqueKeysCacheInMemoryCS.js +76 -0
  19. package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +85 -0
  20. package/cjs/storages/inRedis/ImpressionsCacheInRedis.js +2 -19
  21. package/cjs/storages/inRedis/TelemetryCacheInRedis.js +4 -4
  22. package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +71 -0
  23. package/cjs/storages/inRedis/constants.js +4 -1
  24. package/cjs/storages/inRedis/index.js +20 -3
  25. package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +81 -0
  26. package/cjs/storages/pluggable/ImpressionsCachePluggable.js +2 -19
  27. package/cjs/storages/pluggable/TelemetryCachePluggable.js +4 -4
  28. package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +61 -0
  29. package/cjs/storages/pluggable/inMemoryWrapper.js +8 -6
  30. package/cjs/storages/pluggable/index.js +38 -9
  31. package/cjs/storages/utils.js +73 -0
  32. package/cjs/sync/submitters/submitterManager.js +3 -0
  33. package/cjs/sync/submitters/telemetrySubmitter.js +5 -40
  34. package/cjs/sync/submitters/uniqueKeysSubmitter.js +27 -0
  35. package/cjs/trackers/impressionObserver/utils.js +1 -17
  36. package/cjs/trackers/impressionsTracker.js +22 -41
  37. package/cjs/trackers/strategy/strategyDebug.js +25 -0
  38. package/cjs/trackers/strategy/strategyNone.js +29 -0
  39. package/cjs/trackers/strategy/strategyOptimized.js +35 -0
  40. package/cjs/trackers/uniqueKeysTracker.js +38 -0
  41. package/cjs/utils/constants/index.js +4 -2
  42. package/cjs/utils/redis/RedisMock.js +31 -0
  43. package/cjs/utils/settingsValidation/impressionsMode.js +2 -2
  44. package/cjs/utils/settingsValidation/index.js +9 -3
  45. package/esm/consent/sdkUserConsent.js +2 -2
  46. package/esm/listeners/browser.js +12 -13
  47. package/esm/logger/constants.js +1 -0
  48. package/esm/sdkClient/sdkClient.js +3 -1
  49. package/esm/sdkFactory/index.js +26 -26
  50. package/esm/services/splitApi.js +20 -0
  51. package/esm/storages/AbstractSplitsCacheAsync.js +1 -1
  52. package/esm/storages/AbstractSplitsCacheSync.js +1 -1
  53. package/esm/storages/KeyBuilderSS.js +7 -37
  54. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +0 -1
  55. package/esm/storages/inLocalStorage/index.js +18 -10
  56. package/esm/storages/inMemory/ImpressionCountsCacheInMemory.js +12 -1
  57. package/esm/storages/inMemory/InMemoryStorage.js +14 -7
  58. package/esm/storages/inMemory/InMemoryStorageCS.js +14 -7
  59. package/esm/storages/inMemory/TelemetryCacheInMemory.js +61 -36
  60. package/esm/storages/inMemory/UniqueKeysCacheInMemory.js +68 -0
  61. package/esm/storages/inMemory/UniqueKeysCacheInMemoryCS.js +73 -0
  62. package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +82 -0
  63. package/esm/storages/inRedis/ImpressionsCacheInRedis.js +2 -19
  64. package/esm/storages/inRedis/TelemetryCacheInRedis.js +1 -1
  65. package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +68 -0
  66. package/esm/storages/inRedis/constants.js +3 -0
  67. package/esm/storages/inRedis/index.js +21 -4
  68. package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +78 -0
  69. package/esm/storages/pluggable/ImpressionsCachePluggable.js +2 -19
  70. package/esm/storages/pluggable/TelemetryCachePluggable.js +1 -1
  71. package/esm/storages/pluggable/UniqueKeysCachePluggable.js +58 -0
  72. package/esm/storages/pluggable/inMemoryWrapper.js +8 -6
  73. package/esm/storages/pluggable/index.js +39 -10
  74. package/esm/storages/utils.js +65 -0
  75. package/esm/sync/submitters/submitterManager.js +3 -0
  76. package/esm/sync/submitters/telemetrySubmitter.js +5 -39
  77. package/esm/sync/submitters/uniqueKeysSubmitter.js +23 -0
  78. package/esm/trackers/impressionObserver/utils.js +1 -15
  79. package/esm/trackers/impressionsTracker.js +22 -41
  80. package/esm/trackers/strategy/strategyDebug.js +21 -0
  81. package/esm/trackers/strategy/strategyNone.js +25 -0
  82. package/esm/trackers/strategy/strategyOptimized.js +31 -0
  83. package/esm/trackers/uniqueKeysTracker.js +34 -0
  84. package/esm/utils/constants/index.js +2 -0
  85. package/esm/utils/redis/RedisMock.js +28 -0
  86. package/esm/utils/settingsValidation/impressionsMode.js +3 -3
  87. package/esm/utils/settingsValidation/index.js +9 -3
  88. package/package.json +1 -2
  89. package/src/consent/sdkUserConsent.ts +2 -2
  90. package/src/listeners/browser.ts +12 -15
  91. package/src/logger/constants.ts +1 -0
  92. package/src/sdkClient/sdkClient.ts +3 -1
  93. package/src/sdkFactory/index.ts +29 -31
  94. package/src/sdkFactory/types.ts +7 -4
  95. package/src/services/splitApi.ts +22 -0
  96. package/src/services/types.ts +6 -0
  97. package/src/storages/AbstractSplitsCacheAsync.ts +1 -1
  98. package/src/storages/AbstractSplitsCacheSync.ts +1 -1
  99. package/src/storages/KeyBuilderSS.ts +9 -43
  100. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +0 -1
  101. package/src/storages/inLocalStorage/index.ts +18 -10
  102. package/src/storages/inMemory/AttributesCacheInMemory.ts +7 -7
  103. package/src/storages/inMemory/ImpressionCountsCacheInMemory.ts +16 -1
  104. package/src/storages/inMemory/InMemoryStorage.ts +14 -7
  105. package/src/storages/inMemory/InMemoryStorageCS.ts +14 -7
  106. package/src/storages/inMemory/TelemetryCacheInMemory.ts +69 -34
  107. package/src/storages/inMemory/UniqueKeysCacheInMemory.ts +80 -0
  108. package/src/storages/inMemory/UniqueKeysCacheInMemoryCS.ts +86 -0
  109. package/src/storages/inRedis/ImpressionCountsCacheInRedis.ts +95 -0
  110. package/src/storages/inRedis/ImpressionsCacheInRedis.ts +2 -22
  111. package/src/storages/inRedis/TelemetryCacheInRedis.ts +3 -2
  112. package/src/storages/inRedis/UniqueKeysCacheInRedis.ts +77 -0
  113. package/src/storages/inRedis/constants.ts +3 -0
  114. package/src/storages/inRedis/index.ts +18 -5
  115. package/src/storages/pluggable/ImpressionCountsCachePluggable.ts +92 -0
  116. package/src/storages/pluggable/ImpressionsCachePluggable.ts +3 -23
  117. package/src/storages/pluggable/TelemetryCachePluggable.ts +3 -2
  118. package/src/storages/pluggable/UniqueKeysCachePluggable.ts +67 -0
  119. package/src/storages/pluggable/inMemoryWrapper.ts +6 -6
  120. package/src/storages/pluggable/index.ts +41 -9
  121. package/src/storages/types.ts +56 -55
  122. package/src/storages/utils.ts +78 -0
  123. package/src/sync/submitters/submitter.ts +2 -2
  124. package/src/sync/submitters/submitterManager.ts +2 -0
  125. package/src/sync/submitters/telemetrySubmitter.ts +8 -43
  126. package/src/sync/submitters/types.ts +29 -27
  127. package/src/sync/submitters/uniqueKeysSubmitter.ts +36 -0
  128. package/src/trackers/impressionObserver/utils.ts +1 -16
  129. package/src/trackers/impressionsTracker.ts +25 -46
  130. package/src/trackers/strategy/strategyDebug.ts +28 -0
  131. package/src/trackers/strategy/strategyNone.ts +34 -0
  132. package/src/trackers/strategy/strategyOptimized.ts +42 -0
  133. package/src/trackers/types.ts +28 -0
  134. package/src/trackers/uniqueKeysTracker.ts +48 -0
  135. package/src/types.ts +1 -1
  136. package/src/utils/constants/index.ts +2 -0
  137. package/src/utils/redis/RedisMock.ts +33 -0
  138. package/src/utils/settingsValidation/impressionsMode.ts +3 -3
  139. package/src/utils/settingsValidation/index.ts +7 -3
  140. package/types/logger/constants.d.ts +1 -0
  141. package/types/sdkFactory/types.d.ts +4 -2
  142. package/types/services/types.d.ts +4 -0
  143. package/types/storages/AbstractSplitsCacheAsync.d.ts +1 -1
  144. package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
  145. package/types/storages/KeyBuilderSS.d.ts +3 -3
  146. package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +0 -1
  147. package/types/storages/inMemory/ImpressionCountsCacheInMemory.d.ts +5 -1
  148. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +20 -9
  149. package/types/storages/inMemory/uniqueKeysCacheInMemory.d.ts +35 -0
  150. package/types/storages/inMemory/uniqueKeysCacheInMemoryCS.d.ts +35 -0
  151. package/types/storages/inRedis/ImpressionCountsCacheInRedis.d.ts +16 -0
  152. package/types/storages/inRedis/ImpressionsCacheInRedis.d.ts +0 -1
  153. package/types/storages/inRedis/constants.d.ts +3 -0
  154. package/types/storages/inRedis/uniqueKeysCacheInRedis.d.ts +21 -0
  155. package/types/storages/pluggable/ImpressionCountsCachePluggable.d.ts +16 -0
  156. package/types/storages/pluggable/ImpressionsCachePluggable.d.ts +1 -2
  157. package/types/storages/pluggable/UniqueKeysCachePluggable.d.ts +20 -0
  158. package/types/storages/types.d.ts +39 -38
  159. package/types/storages/utils.d.ts +8 -0
  160. package/types/sync/submitters/submitter.d.ts +2 -2
  161. package/types/sync/submitters/telemetrySubmitter.d.ts +2 -10
  162. package/types/sync/submitters/types.d.ts +27 -7
  163. package/types/sync/submitters/uniqueKeysSubmitter.d.ts +5 -0
  164. package/types/trackers/impressionObserver/utils.d.ts +0 -8
  165. package/types/trackers/impressionsTracker.d.ts +4 -6
  166. package/types/trackers/strategy/strategyDebug.d.ts +9 -0
  167. package/types/trackers/strategy/strategyNone.d.ts +10 -0
  168. package/types/trackers/strategy/strategyOptimized.d.ts +11 -0
  169. package/types/trackers/types.d.ts +23 -0
  170. package/types/trackers/uniqueKeysTracker.d.ts +13 -0
  171. package/types/types.d.ts +1 -1
  172. package/types/utils/constants/index.d.ts +2 -0
  173. package/types/utils/redis/RedisMock.d.ts +4 -0
  174. package/cjs/storages/metadataBuilder.js +0 -12
  175. package/esm/storages/metadataBuilder.js +0 -8
  176. package/src/storages/metadataBuilder.ts +0 -11
@@ -1,6 +1,5 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
2
  import { thenable } from '../utils/promise/thenable';
3
- import { truncateTimeFrame } from '../utils/time';
4
3
  import { IMPRESSIONS_TRACKER_SUCCESS, ERROR_IMPRESSIONS_TRACKER, ERROR_IMPRESSIONS_LISTENER } from '../logger/constants';
5
4
  import { CONSENT_DECLINED, DEDUPED, QUEUED } from '../utils/constants';
6
5
  /**
@@ -10,52 +9,34 @@ import { CONSENT_DECLINED, DEDUPED, QUEUED } from '../utils/constants';
10
9
  * @param metadata runtime metadata (ip, hostname and version)
11
10
  * @param impressionListener optional impression listener
12
11
  * @param integrationsManager optional integrations manager
13
- * @param observer optional impression observer. If provided, previous time (pt property) is included in impression instances
14
- * @param countsCache optional cache to save impressions count. If provided, impressions will be deduped (OPTIMIZED mode)
12
+ * @param strategy strategy for impressions tracking.
15
13
  */
16
- export function impressionsTrackerFactory(settings, impressionsCache, integrationsManager,
17
- // if observer is provided, it implies `shouldAddPreviousTime` flag (i.e., if impressions previous time should be added or not)
18
- observer,
19
- // if countsCache is provided, it implies `isOptimized` flag (i.e., if impressions should be deduped or not)
20
- countsCache, telemetryCache) {
14
+ export function impressionsTrackerFactory(settings, impressionsCache, strategy, integrationsManager, telemetryCache) {
21
15
  var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version;
22
16
  return {
23
17
  track: function (impressions, attributes) {
24
18
  if (settings.userConsent === CONSENT_DECLINED)
25
19
  return;
26
20
  var impressionsCount = impressions.length;
27
- var impressionsToStore = []; // Track only the impressions that are going to be stored
28
- // Wraps impressions to store and adds previousTime if it corresponds
29
- impressions.forEach(function (impression) {
30
- if (observer) {
31
- // Adds previous time if it is enabled
32
- impression.pt = observer.testAndSet(impression);
21
+ var _a = strategy.process(impressions), impressionsToStore = _a.impressionsToStore, impressionsToListener = _a.impressionsToListener, deduped = _a.deduped;
22
+ var impressionsToListenerCount = impressionsToListener.length;
23
+ if (impressionsToStore.length > 0) {
24
+ var res = impressionsCache.track(impressionsToStore);
25
+ // If we're on an async storage, handle error and log it.
26
+ if (thenable(res)) {
27
+ res.then(function () {
28
+ log.info(IMPRESSIONS_TRACKER_SUCCESS, [impressionsCount]);
29
+ }).catch(function (err) {
30
+ log.error(ERROR_IMPRESSIONS_TRACKER, [impressionsCount, err]);
31
+ });
33
32
  }
34
- var now = Date.now();
35
- if (countsCache) {
36
- // Increments impression counter per featureName
37
- countsCache.track(impression.feature, now, 1);
38
- }
39
- // Checks if the impression should be added in queue to be sent
40
- if (!countsCache || !impression.pt || impression.pt < truncateTimeFrame(now)) {
41
- impressionsToStore.push(impression);
42
- }
43
- });
44
- var res = impressionsCache.track(impressionsToStore);
45
- // If we're on an async storage, handle error and log it.
46
- if (thenable(res)) {
47
- res.then(function () {
48
- log.info(IMPRESSIONS_TRACKER_SUCCESS, [impressionsCount]);
49
- }).catch(function (err) {
50
- log.error(ERROR_IMPRESSIONS_TRACKER, [impressionsCount, err]);
51
- });
52
- }
53
- else {
54
- // Record when impressionsCache is sync only (standalone mode)
55
- // @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
56
- if (telemetryCache) {
57
- telemetryCache.recordImpressionStats(QUEUED, impressionsToStore.length);
58
- telemetryCache.recordImpressionStats(DEDUPED, impressions.length - impressionsToStore.length);
33
+ else {
34
+ // Record when impressionsCache is sync only (standalone mode)
35
+ // @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
36
+ if (telemetryCache) {
37
+ telemetryCache.recordImpressionStats(QUEUED, impressionsToStore.length);
38
+ telemetryCache.recordImpressionStats(DEDUPED, deduped);
39
+ }
59
40
  }
60
41
  }
61
42
  // @TODO next block might be handled by the integration manager. In that case, the metadata object doesn't need to be passed in the constructor
@@ -63,7 +44,7 @@ countsCache, telemetryCache) {
63
44
  var _loop_1 = function (i) {
64
45
  var impressionData = {
65
46
  // copy of impression, to avoid unexpected behaviour if modified by integrations or impressionListener
66
- impression: objectAssign({}, impressions[i]),
47
+ impression: objectAssign({}, impressionsToListener[i]),
67
48
  attributes: attributes,
68
49
  ip: ip,
69
50
  hostname: hostname,
@@ -83,7 +64,7 @@ countsCache, telemetryCache) {
83
64
  }
84
65
  }, 0);
85
66
  };
86
- for (var i = 0; i < impressionsCount; i++) {
67
+ for (var i = 0; i < impressionsToListenerCount; i++) {
87
68
  _loop_1(i);
88
69
  }
89
70
  }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Debug strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
3
+ *
4
+ * @param impressionsObserver impression observer. Previous time (pt property) is included in impression instances
5
+ * @returns IStrategyResult
6
+ */
7
+ export function strategyDebugFactory(impressionsObserver) {
8
+ return {
9
+ process: function (impressions) {
10
+ impressions.forEach(function (impression) {
11
+ // Adds previous time if it is enabled
12
+ impression.pt = impressionsObserver.testAndSet(impression);
13
+ });
14
+ return {
15
+ impressionsToStore: impressions,
16
+ impressionsToListener: impressions,
17
+ deduped: 0
18
+ };
19
+ }
20
+ };
21
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * None strategy for impressions tracker.
3
+ *
4
+ * @param impressionsCounter cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
5
+ * @param uniqueKeysTracker unique keys tracker in charge of tracking the unique keys per split.
6
+ * @returns IStrategyResult
7
+ */
8
+ export function strategyNoneFactory(impressionsCounter, uniqueKeysTracker) {
9
+ return {
10
+ process: function (impressions) {
11
+ impressions.forEach(function (impression) {
12
+ var now = Date.now();
13
+ // Increments impression counter per featureName
14
+ impressionsCounter.track(impression.feature, now, 1);
15
+ // Keep track by unique key
16
+ uniqueKeysTracker.track(impression.keyName, impression.feature);
17
+ });
18
+ return {
19
+ impressionsToStore: [],
20
+ impressionsToListener: impressions,
21
+ deduped: 0
22
+ };
23
+ }
24
+ };
25
+ }
@@ -0,0 +1,31 @@
1
+ import { truncateTimeFrame } from '../../utils/time';
2
+ /**
3
+ * Optimized strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
4
+ *
5
+ * @param impressionsObserver impression observer. previous time (pt property) is included in impression instances
6
+ * @param impressionsCounter cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
7
+ * @returns IStrategyResult
8
+ */
9
+ export function strategyOptimizedFactory(impressionsObserver, impressionsCounter) {
10
+ return {
11
+ process: function (impressions) {
12
+ var impressionsToStore = [];
13
+ impressions.forEach(function (impression) {
14
+ impression.pt = impressionsObserver.testAndSet(impression);
15
+ var now = Date.now();
16
+ // Increments impression counter per featureName
17
+ if (impression.pt)
18
+ impressionsCounter.track(impression.feature, now, 1);
19
+ // Checks if the impression should be added in queue to be sent
20
+ if (!impression.pt || impression.pt < truncateTimeFrame(now)) {
21
+ impressionsToStore.push(impression);
22
+ }
23
+ });
24
+ return {
25
+ impressionsToStore: impressionsToStore,
26
+ impressionsToListener: impressions,
27
+ deduped: impressions.length - impressionsToStore.length
28
+ };
29
+ }
30
+ };
31
+ }
@@ -0,0 +1,34 @@
1
+ import { LOG_PREFIX_UNIQUE_KEYS_TRACKER } from '../logger/constants';
2
+ var noopFilterAdapter = {
3
+ add: function () { return true; },
4
+ contains: function () { return true; },
5
+ clear: function () { }
6
+ };
7
+ /**
8
+ * Trackes uniques keys
9
+ * Unique Keys Tracker will be in charge of checking if the MTK was already sent to the BE in the last period
10
+ * or schedule to be sent; if not it will be added in an internal cache and sent in the next post.
11
+ *
12
+ * @param log Logger instance
13
+ * @param uniqueKeysCache cache to save unique keys
14
+ * @param filterAdapter filter adapter
15
+ */
16
+ export function uniqueKeysTrackerFactory(log, uniqueKeysCache, filterAdapter) {
17
+ if (filterAdapter === void 0) { filterAdapter = noopFilterAdapter; }
18
+ var intervalId;
19
+ if (filterAdapter.refreshRate) {
20
+ intervalId = setInterval(filterAdapter.clear, filterAdapter.refreshRate);
21
+ }
22
+ return {
23
+ track: function (key, featureName) {
24
+ if (!filterAdapter.add(key, featureName)) {
25
+ log.debug(LOG_PREFIX_UNIQUE_KEYS_TRACKER + "The feature " + featureName + " and key " + key + " exist in the filter");
26
+ return;
27
+ }
28
+ uniqueKeysCache.track(key, featureName);
29
+ },
30
+ stop: function () {
31
+ clearInterval(intervalId);
32
+ }
33
+ };
34
+ }
@@ -13,6 +13,7 @@ export var SPLIT_EVENT = 'EVENT';
13
13
  // Impression collection modes
14
14
  export var DEBUG = 'DEBUG';
15
15
  export var OPTIMIZED = 'OPTIMIZED';
16
+ export var NONE = 'NONE';
16
17
  // SDK Modes
17
18
  export var LOCALHOST_MODE = 'localhost';
18
19
  export var STANDALONE_MODE = 'standalone';
@@ -37,6 +38,7 @@ export var CONSUMER_ENUM = 1;
37
38
  export var CONSUMER_PARTIAL_ENUM = 2;
38
39
  export var OPTIMIZED_ENUM = 0;
39
40
  export var DEBUG_ENUM = 1;
41
+ export var NONE_ENUM = 2;
40
42
  export var SPLITS = 'sp';
41
43
  export var IMPRESSIONS = 'im';
42
44
  export var IMPRESSIONS_COUNT = 'ic';
@@ -0,0 +1,28 @@
1
+ //@ts-nocheck
2
+ function identityFunction(data) {
3
+ return data;
4
+ }
5
+ function asyncFunction(data) {
6
+ return Promise.resolve(data);
7
+ }
8
+ var IDENTITY_METHODS = [];
9
+ var ASYNC_METHODS = ['rpush', 'hincrby'];
10
+ var PIPELINE_METHODS = ['rpush', 'hincrby'];
11
+ var RedisMock = /** @class */ (function () {
12
+ function RedisMock() {
13
+ var _this = this;
14
+ this.pipelineMethods = { exec: jest.fn(asyncFunction) };
15
+ IDENTITY_METHODS.forEach(function (method) {
16
+ _this[method] = jest.fn(identityFunction);
17
+ });
18
+ ASYNC_METHODS.forEach(function (method) {
19
+ _this[method] = jest.fn(asyncFunction);
20
+ });
21
+ PIPELINE_METHODS.forEach(function (method) {
22
+ _this.pipelineMethods[method] = _this[method];
23
+ });
24
+ this.pipeline = jest.fn(function () { return _this.pipelineMethods; });
25
+ }
26
+ return RedisMock;
27
+ }());
28
+ export { RedisMock };
@@ -1,10 +1,10 @@
1
1
  import { ERROR_INVALID_CONFIG_PARAM } from '../../logger/constants';
2
- import { DEBUG, OPTIMIZED } from '../constants';
2
+ import { DEBUG, OPTIMIZED, NONE } from '../constants';
3
3
  import { stringToUpperCase } from '../lang';
4
4
  export function validImpressionsMode(log, impressionsMode) {
5
5
  impressionsMode = stringToUpperCase(impressionsMode);
6
- if ([DEBUG, OPTIMIZED].indexOf(impressionsMode) > -1)
6
+ if ([DEBUG, OPTIMIZED, NONE].indexOf(impressionsMode) > -1)
7
7
  return impressionsMode;
8
- log.error(ERROR_INVALID_CONFIG_PARAM, ['impressionsMode', [DEBUG, OPTIMIZED], OPTIMIZED]);
8
+ log.error(ERROR_INVALID_CONFIG_PARAM, ['impressionsMode', [DEBUG, OPTIMIZED, NONE], OPTIMIZED]);
9
9
  return OPTIMIZED;
10
10
  }
@@ -23,8 +23,8 @@ export var base = {
23
23
  IPAddressesEnabled: undefined
24
24
  },
25
25
  scheduler: {
26
- // fetch feature updates each 30 sec
27
- featuresRefreshRate: 30,
26
+ // fetch feature updates each 60 sec
27
+ featuresRefreshRate: 60,
28
28
  // fetch segments updates each 60 sec
29
29
  segmentsRefreshRate: 60,
30
30
  // publish telemetry stats each 3600 secs (1 hour)
@@ -129,8 +129,8 @@ export function settingsValidation(config, validationParams) {
129
129
  if (storage)
130
130
  withDefaults.storage = storage(withDefaults);
131
131
  // Validate key and TT (for client-side)
132
+ var maybeKey = withDefaults.core.key;
132
133
  if (validationParams.acceptKey) {
133
- var maybeKey = withDefaults.core.key;
134
134
  // Although `key` is required in client-side, it can be omitted in LOCALHOST mode. In that case, the value `localhost_key` is used.
135
135
  if (withDefaults.mode === LOCALHOST_MODE && maybeKey === undefined) {
136
136
  withDefaults.core.key = 'localhost_key';
@@ -148,6 +148,12 @@ export function settingsValidation(config, validationParams) {
148
148
  }
149
149
  }
150
150
  }
151
+ else {
152
+ // On server-side, key is undefined and used to distinguish from client-side
153
+ if (maybeKey !== undefined)
154
+ log.warn('Provided `key` is ignored in server-side SDK.'); // @ts-ignore
155
+ withDefaults.core.key = undefined;
156
+ }
151
157
  // Current ip/hostname information
152
158
  // @ts-ignore, modify readonly prop
153
159
  withDefaults.runtime = runtime(withDefaults);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "1.6.2-rc.9",
3
+ "version": "1.7.1",
4
4
  "description": "Split Javascript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -71,7 +71,6 @@
71
71
  "ioredis": "^4.28.0",
72
72
  "jest": "^27.2.3",
73
73
  "jest-localstorage-mock": "^2.4.3",
74
- "js-yaml": "^3.13.1",
75
74
  "lodash": "^4.17.21",
76
75
  "node-fetch": "^2.6.7",
77
76
  "redis-server": "1.2.2",
@@ -40,8 +40,8 @@ export function createUserConsentAPI(params: ISdkFactoryContext) {
40
40
 
41
41
  // @ts-ignore, clear method is present in storage for standalone and partial consumer mode
42
42
  if (events.clear) events.clear(); // @ts-ignore
43
- if (impressions.clear) impressions.clear();
44
- if (impressionCounts) impressionCounts.clear();
43
+ if (impressions.clear) impressions.clear(); // @ts-ignore
44
+ if (impressionCounts && impressionCounts.clear) impressionCounts.clear();
45
45
  }
46
46
  } else {
47
47
  log.info(USER_CONSENT_NOT_UPDATED, [newConsentStatus]);
@@ -1,18 +1,17 @@
1
1
  /* eslint-disable no-undef */
2
2
  // @TODO eventually migrate to JS-Browser-SDK package.
3
3
  import { ISignalListener } from './types';
4
- import { IRecorderCacheProducerSync, IStorageSync } from '../storages/types';
4
+ import { IRecorderCacheSync, IStorageSync } from '../storages/types';
5
5
  import { fromImpressionsCollector } from '../sync/submitters/impressionsSubmitter';
6
6
  import { fromImpressionCountsCollector } from '../sync/submitters/impressionCountsSubmitter';
7
7
  import { IResponse, ISplitApi } from '../services/types';
8
8
  import { ImpressionDTO, ISettings } from '../types';
9
9
  import { ImpressionsPayload } from '../sync/submitters/types';
10
- import { OPTIMIZED, DEBUG } from '../utils/constants';
10
+ import { OPTIMIZED, DEBUG, NONE } from '../utils/constants';
11
11
  import { objectAssign } from '../utils/lang/objectAssign';
12
12
  import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
13
13
  import { ISyncManager } from '../sync/types';
14
14
  import { isConsentGranted } from '../consent';
15
- import { telemetryCacheStatsAdapter } from '../sync/submitters/telemetrySubmitter';
16
15
 
17
16
  const VISIBILITYCHANGE_EVENT = 'visibilitychange';
18
17
  const PAGEHIDE_EVENT = 'pagehide';
@@ -84,26 +83,25 @@ export class BrowserSignalListener implements ISignalListener {
84
83
  */
85
84
  flushData() {
86
85
  if (!this.syncManager) return; // In consumer mode there is not sync manager and data to flush
86
+ const { events, telemetry } = this.settings.urls;
87
87
 
88
88
  // Flush impressions & events data if there is user consent
89
89
  if (isConsentGranted(this.settings)) {
90
- const eventsUrl = this.settings.urls.events;
90
+ const sim = this.settings.sync.impressionsMode;
91
91
  const extraMetadata = {
92
92
  // sim stands for Sync/Split Impressions Mode
93
- sim: this.settings.sync.impressionsMode === OPTIMIZED ? OPTIMIZED : DEBUG
93
+ sim: sim === OPTIMIZED ? OPTIMIZED : sim === DEBUG ? DEBUG : NONE
94
94
  };
95
95
 
96
- this._flushData(eventsUrl + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata);
97
- this._flushData(eventsUrl + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
98
- if (this.storage.impressionCounts) this._flushData(eventsUrl + '/testImpressions/count/beacon', this.storage.impressionCounts, this.serviceApi.postTestImpressionsCount, fromImpressionCountsCollector);
96
+ this._flushData(events + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata);
97
+ this._flushData(events + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
98
+ if (this.storage.impressionCounts) this._flushData(events + '/testImpressions/count/beacon', this.storage.impressionCounts, this.serviceApi.postTestImpressionsCount, fromImpressionCountsCollector);
99
+ // @ts-ignore
100
+ if (this.storage.uniqueKeys) this._flushData(telemetry + '/v1/keys/cs/beacon', this.storage.uniqueKeys, this.serviceApi.postUniqueKeysBulkCs);
99
101
  }
100
102
 
101
103
  // Flush telemetry data
102
- if (this.storage.telemetry) {
103
- const telemetryUrl = this.settings.urls.telemetry;
104
- const telemetryCacheAdapter = telemetryCacheStatsAdapter(this.storage.telemetry, this.storage.splits, this.storage.segments);
105
- this._flushData(telemetryUrl + '/v1/metrics/usage/beacon', telemetryCacheAdapter, this.serviceApi.postMetricsUsage);
106
- }
104
+ if (this.storage.telemetry) this._flushData(telemetry + '/v1/metrics/usage/beacon', this.storage.telemetry, this.serviceApi.postMetricsUsage);
107
105
  }
108
106
 
109
107
  flushDataIfHidden() {
@@ -111,14 +109,13 @@ export class BrowserSignalListener implements ISignalListener {
111
109
  if (document.visibilityState === 'hidden') this.flushData(); // On a 'visibilitychange' event, flush data if state is hidden
112
110
  }
113
111
 
114
- private _flushData<T>(url: string, cache: IRecorderCacheProducerSync<T>, postService: (body: string) => Promise<IResponse>, fromCacheToPayload?: (cacheData: T) => any, extraMetadata?: {}) {
112
+ private _flushData<T>(url: string, cache: IRecorderCacheSync<T>, postService: (body: string) => Promise<IResponse>, fromCacheToPayload?: (cacheData: T) => any, extraMetadata?: {}) {
115
113
  // if there is data in cache, send it to backend
116
114
  if (!cache.isEmpty()) {
117
115
  const dataPayload = fromCacheToPayload ? fromCacheToPayload(cache.pop()) : cache.pop();
118
116
  if (!this._sendBeacon(url, dataPayload, extraMetadata)) {
119
117
  postService(JSON.stringify(dataPayload)).catch(() => { }); // no-op just to catch a possible exception
120
118
  }
121
- cache.clear();
122
119
  }
123
120
  }
124
121
 
@@ -143,4 +143,5 @@ export const LOG_PREFIX_SYNC_POLLING = LOG_PREFIX_SYNC + ':polling-manager: ';
143
143
  export const LOG_PREFIX_SYNC_SUBMITTERS = LOG_PREFIX_SYNC + ':submitter: ';
144
144
  export const LOG_PREFIX_IMPRESSIONS_TRACKER = 'impressions-tracker: ';
145
145
  export const LOG_PREFIX_EVENTS_TRACKER = 'events-tracker: ';
146
+ export const LOG_PREFIX_UNIQUE_KEYS_TRACKER = 'unique-keys-tracker: ';
146
147
  export const LOG_PREFIX_CLEANUP = 'cleanup: ';
@@ -9,7 +9,7 @@ import { ISdkFactoryContext } from '../sdkFactory/types';
9
9
  * Creates an Sdk client, i.e., a base client with status and destroy interface
10
10
  */
11
11
  export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: boolean): SplitIO.IClient | SplitIO.IAsyncClient {
12
- const { sdkReadinessManager, syncManager, storage, signalListener, settings, telemetryTracker } = params;
12
+ const { sdkReadinessManager, syncManager, storage, signalListener, settings, telemetryTracker, uniqueKeysTracker } = params;
13
13
 
14
14
  return objectAssign(
15
15
  // Proto-linkage of the readiness Event Emitter
@@ -40,6 +40,8 @@ export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: bo
40
40
  // Release the API Key if it is the main client
41
41
  if (!isSharedClient) releaseApiKey(settings.core.authorizationKey);
42
42
 
43
+ if (uniqueKeysTracker) uniqueKeysTracker.stop();
44
+
43
45
  // Cleanup storage
44
46
  return storage.destroy();
45
47
  });
@@ -3,16 +3,17 @@ import { sdkReadinessManagerFactory } from '../readiness/sdkReadinessManager';
3
3
  import { impressionsTrackerFactory } from '../trackers/impressionsTracker';
4
4
  import { eventTrackerFactory } from '../trackers/eventTracker';
5
5
  import { telemetryTrackerFactory } from '../trackers/telemetryTracker';
6
- import { IStorageFactoryParams } from '../storages/types';
7
6
  import { SplitIO } from '../types';
8
- import { getMatching } from '../utils/key';
9
- import { shouldBeOptimized } from '../trackers/impressionObserver/utils';
10
7
  import { validateAndTrackApiKey } from '../utils/inputValidation/apiKey';
11
8
  import { createLoggerAPI } from '../logger/sdkLogger';
12
9
  import { NEW_FACTORY, RETRIEVE_MANAGER } from '../logger/constants';
13
- import { metadataBuilder } from '../storages/metadataBuilder';
14
10
  import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
15
11
  import { objectAssign } from '../utils/lang/objectAssign';
12
+ import { strategyDebugFactory } from '../trackers/strategy/strategyDebug';
13
+ import { strategyOptimizedFactory } from '../trackers/strategy/strategyOptimized';
14
+ import { strategyNoneFactory } from '../trackers/strategy/strategyNone';
15
+ import { uniqueKeysTrackerFactory } from '../trackers/uniqueKeysTracker';
16
+ import { NONE, OPTIMIZED } from '../utils/constants';
16
17
 
17
18
  /**
18
19
  * Modular SDK factory
@@ -21,8 +22,9 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
21
22
 
22
23
  const { settings, platform, storageFactory, splitApiFactory, extraProps,
23
24
  syncManagerFactory, SignalListener, impressionsObserverFactory,
24
- integrationsManagerFactory, sdkManagerFactory, sdkClientMethodFactory } = params;
25
- const log = settings.log;
25
+ integrationsManagerFactory, sdkManagerFactory, sdkClientMethodFactory,
26
+ filterAdapterFactory } = params;
27
+ const { log, sync: { impressionsMode } } = settings;
26
28
 
27
29
  // @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid API Key, etc.
28
30
  // On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
@@ -33,45 +35,41 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
33
35
  const sdkReadinessManager = sdkReadinessManagerFactory(log, platform.EventEmitter, settings.startup.readyTimeout);
34
36
  const readiness = sdkReadinessManager.readinessManager;
35
37
 
36
- // @TODO consider passing the settings object, so that each storage access only what it needs
37
- const storageFactoryParams: IStorageFactoryParams = {
38
- impressionsQueueSize: settings.scheduler.impressionsQueueSize,
39
- eventsQueueSize: settings.scheduler.eventsQueueSize,
40
- optimize: shouldBeOptimized(settings),
41
-
42
- // ATM, only used by InLocalStorage
43
- matchingKey: getMatching(settings.core.key),
44
- splitFiltersValidation: settings.sync.__splitFiltersValidation,
45
-
46
- // ATM, only used by PluggableStorage
47
- mode: settings.mode,
48
-
49
- // Callback used to emit SDK_READY in consumer mode, where `syncManagerFactory` is undefined,
50
- // or partial consumer mode, where it only has submitters, and therefore it doesn't emit readiness events.
38
+ const storage = storageFactory({
39
+ settings,
51
40
  onReadyCb: (error) => {
52
41
  if (error) return; // Don't emit SDK_READY if storage failed to connect. Error message is logged by wrapperAdapter
53
42
  readiness.splits.emit(SDK_SPLITS_ARRIVED);
54
43
  readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
55
44
  },
56
- metadata: metadataBuilder(settings),
57
- log
58
- };
59
-
60
- const storage = storageFactory(storageFactoryParams);
45
+ });
61
46
  // @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);`
62
47
 
63
48
  const telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
64
49
  const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage, telemetryTracker });
65
50
 
66
- // trackers
67
- const observer = impressionsObserverFactory && impressionsObserverFactory();
68
- const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, integrationsManager, observer, storage.impressionCounts, storage.telemetry);
51
+ const observer = impressionsObserverFactory();
52
+ const uniqueKeysTracker = impressionsMode === NONE ? uniqueKeysTrackerFactory(log, storage.uniqueKeys!, filterAdapterFactory && filterAdapterFactory()) : undefined;
53
+
54
+ let strategy;
55
+ switch (impressionsMode) {
56
+ case OPTIMIZED:
57
+ strategy = strategyOptimizedFactory(observer, storage.impressionCounts!);
58
+ break;
59
+ case NONE:
60
+ strategy = strategyNoneFactory(storage.impressionCounts!, uniqueKeysTracker!);
61
+ break;
62
+ default:
63
+ strategy = strategyDebugFactory(observer);
64
+ }
65
+
66
+ const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, strategy, integrationsManager, storage.telemetry);
69
67
  const eventTracker = eventTrackerFactory(settings, storage.events, integrationsManager, storage.telemetry);
70
68
 
71
69
  // splitApi is used by SyncManager and Browser signal listener
72
70
  const splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
73
71
 
74
- const ctx: ISdkFactoryContext = { splitApi, eventTracker, impressionsTracker, telemetryTracker, sdkReadinessManager, readiness, settings, storage, platform };
72
+ const ctx: ISdkFactoryContext = { splitApi, eventTracker, impressionsTracker, telemetryTracker, uniqueKeysTracker, sdkReadinessManager, readiness, settings, storage, platform };
75
73
 
76
74
  const syncManager = syncManagerFactory && syncManagerFactory(ctx as ISdkFactoryContextSync);
77
75
  ctx.syncManager = syncManager;
@@ -100,7 +98,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
100
98
  },
101
99
 
102
100
  // Logger wrapper API
103
- Logger: createLoggerAPI(settings.log),
101
+ Logger: createLoggerAPI(log),
104
102
 
105
103
  settings,
106
104
  }, extraProps && extraProps(ctx));
@@ -6,7 +6,7 @@ import { IFetch, ISplitApi, IEventSourceConstructor } from '../services/types';
6
6
  import { IStorageAsync, IStorageSync, ISplitsCacheSync, ISplitsCacheAsync, IStorageFactoryParams } from '../storages/types';
7
7
  import { ISyncManager } from '../sync/types';
8
8
  import { IImpressionObserver } from '../trackers/impressionObserver/types';
9
- import { IImpressionsTracker, IEventTracker, ITelemetryTracker } from '../trackers/types';
9
+ import { IImpressionsTracker, IEventTracker, ITelemetryTracker, IFilterAdapter, IUniqueKeysTracker } from '../trackers/types';
10
10
  import { SplitIO, ISettings, IEventEmitter } from '../types';
11
11
 
12
12
  /**
@@ -44,6 +44,7 @@ export interface ISdkFactoryContext {
44
44
  eventTracker: IEventTracker,
45
45
  telemetryTracker: ITelemetryTracker,
46
46
  storage: IStorageSync | IStorageAsync,
47
+ uniqueKeysTracker?: IUniqueKeysTracker,
47
48
  signalListener?: ISignalListener
48
49
  splitApi?: ISplitApi
49
50
  syncManager?: ISyncManager,
@@ -96,6 +97,11 @@ export interface ISdkFactoryParams {
96
97
  // It Allows to distinguish SDK clients with the client-side API (`ICsSDK`) or server-side API (`ISDK` or `IAsyncSDK`).
97
98
  sdkClientMethodFactory: (params: ISdkFactoryContext) => ({ (): SplitIO.ICsClient; (key: SplitIO.SplitKey, trafficType?: string | undefined): SplitIO.ICsClient; } | (() => SplitIO.IClient) | (() => SplitIO.IAsyncClient))
98
99
 
100
+ // Impression observer factory.
101
+ impressionsObserverFactory: () => IImpressionObserver
102
+
103
+ filterAdapterFactory?: () => IFilterAdapter
104
+
99
105
  // Optional signal listener constructor. Used to handle special app states, like shutdown, app paused or resumed.
100
106
  // Pass only if `syncManager` (used by Node listener) and `splitApi` (used by Browser listener) are passed.
101
107
  SignalListener?: new (
@@ -107,9 +113,6 @@ export interface ISdkFactoryParams {
107
113
  // @TODO review impressionListener and integrations interfaces. What about handling impressionListener as an integration ?
108
114
  integrationsManagerFactory?: (params: IIntegrationFactoryParams) => IIntegrationManager | undefined,
109
115
 
110
- // Impression observer factory. If provided, will be used for impressions dedupe
111
- impressionsObserverFactory?: () => IImpressionObserver
112
-
113
116
  // Optional function to assign additional properties to the factory instance
114
117
  extraProps?: (params: ISdkFactoryContext) => object
115
118
  }
@@ -107,6 +107,28 @@ export function splitApiFactory(
107
107
  return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(IMPRESSIONS_COUNT));
108
108
  },
109
109
 
110
+ /**
111
+ * Post unique keys for client side.
112
+ *
113
+ * @param body unique keys payload
114
+ * @param headers Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
115
+ */
116
+ postUniqueKeysBulkCs(body: string, headers?: Record<string, string>) {
117
+ const url = `${urls.telemetry}/v1/keys/cs`;
118
+ return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(TELEMETRY));
119
+ },
120
+
121
+ /**
122
+ * Post unique keys for server side.
123
+ *
124
+ * @param body unique keys payload
125
+ * @param headers Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
126
+ */
127
+ postUniqueKeysBulkSs(body: string, headers?: Record<string, string>) {
128
+ const url = `${urls.telemetry}/v1/keys/ss`;
129
+ return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(TELEMETRY));
130
+ },
131
+
110
132
  postMetricsConfig(body: string, headers?: Record<string, string>) {
111
133
  const url = `${urls.telemetry}/v1/metrics/config`;
112
134
  return splitHttpClient(url, { method: 'POST', body, headers }, telemetryTracker.trackHttp(TELEMETRY), true);
@@ -43,6 +43,10 @@ export type IFetchMySegments = (userMatchingKey: string, noCache?: boolean) => P
43
43
 
44
44
  export type IPostEventsBulk = (body: string, headers?: Record<string, string>) => Promise<IResponse>
45
45
 
46
+ export type IPostUniqueKeysBulkCs = (body: string, headers?: Record<string, string>) => Promise<IResponse>
47
+
48
+ export type IPostUniqueKeysBulkSs = (body: string, headers?: Record<string, string>) => Promise<IResponse>
49
+
46
50
  export type IPostTestImpressionsBulk = (body: string, headers?: Record<string, string>) => Promise<IResponse>
47
51
 
48
52
  export type IPostTestImpressionsCount = (body: string, headers?: Record<string, string>) => Promise<IResponse>
@@ -59,6 +63,8 @@ export interface ISplitApi {
59
63
  fetchSegmentChanges: IFetchSegmentChanges
60
64
  fetchMySegments: IFetchMySegments
61
65
  postEventsBulk: IPostEventsBulk
66
+ postUniqueKeysBulkCs: IPostUniqueKeysBulkCs
67
+ postUniqueKeysBulkSs: IPostUniqueKeysBulkSs
62
68
  postTestImpressionsBulk: IPostTestImpressionsBulk
63
69
  postTestImpressionsCount: IPostTestImpressionsCount
64
70
  postMetricsConfig: IPostMetricsConfig
@@ -41,7 +41,7 @@ export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
41
41
  * @param {string} name
42
42
  * @param {string} defaultTreatment
43
43
  * @param {number} changeNumber
44
- * @returns {Promise} a promise that is resolved once the split kill operation is performed. The fulfillment value is a boolean: `true` if the kill success updating the split or `false` if no split is updated,
44
+ * @returns {Promise} a promise that is resolved once the split kill operation is performed. The fulfillment value is a boolean: `true` if the operation successed updating the split or `false` if no split is updated,
45
45
  * for instance, if the `changeNumber` is old, or if the split is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
46
46
  * The promise will never be rejected.
47
47
  */