@splitsoftware/splitio-commons 1.6.2-rc.9 → 1.7.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 (176) hide show
  1. package/CHANGES.txt +3 -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 +7 -1
  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 +7 -1
  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 +5 -1
  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
@@ -0,0 +1,68 @@
1
+ import { __extends } from "tslib";
2
+ import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
3
+ import { setToArray } from '../../utils/lang/sets';
4
+ import { DEFAULT_CACHE_SIZE, REFRESH_RATE, TTL_REFRESH } from './constants';
5
+ import { LOG_PREFIX } from './constants';
6
+ var UniqueKeysCacheInRedis = /** @class */ (function (_super) {
7
+ __extends(UniqueKeysCacheInRedis, _super);
8
+ function UniqueKeysCacheInRedis(log, key, redis, uniqueKeysQueueSize, refreshRate) {
9
+ if (uniqueKeysQueueSize === void 0) { uniqueKeysQueueSize = DEFAULT_CACHE_SIZE; }
10
+ if (refreshRate === void 0) { refreshRate = REFRESH_RATE; }
11
+ var _this = _super.call(this, uniqueKeysQueueSize) || this;
12
+ _this.log = log;
13
+ _this.key = key;
14
+ _this.redis = redis;
15
+ _this.refreshRate = refreshRate;
16
+ _this.onFullQueue = function () { _this.postUniqueKeysInRedis(); };
17
+ return _this;
18
+ }
19
+ UniqueKeysCacheInRedis.prototype.postUniqueKeysInRedis = function () {
20
+ var _this = this;
21
+ var featureNames = Object.keys(this.uniqueKeysTracker);
22
+ if (!featureNames.length)
23
+ return Promise.resolve(false);
24
+ var pipeline = this.redis.pipeline();
25
+ for (var i = 0; i < featureNames.length; i++) {
26
+ var featureName = featureNames[i];
27
+ var featureKeys = setToArray(this.uniqueKeysTracker[featureName]);
28
+ var uniqueKeysPayload = {
29
+ f: featureName,
30
+ ks: featureKeys
31
+ };
32
+ pipeline.rpush(this.key, JSON.stringify(uniqueKeysPayload));
33
+ }
34
+ this.clear();
35
+ return pipeline.exec()
36
+ .then(function (data) {
37
+ // If this is the creation of the key on Redis, set the expiration for it in 3600 seconds.
38
+ if (data.length && data.length === featureNames.length) {
39
+ return _this.redis.expire(_this.key, TTL_REFRESH);
40
+ }
41
+ })
42
+ .catch(function (err) {
43
+ _this.log.error(LOG_PREFIX + "Error in uniqueKeys pipeline: " + err + ".");
44
+ return false;
45
+ });
46
+ };
47
+ UniqueKeysCacheInRedis.prototype.start = function () {
48
+ this.intervalId = setInterval(this.postUniqueKeysInRedis.bind(this), this.refreshRate);
49
+ };
50
+ UniqueKeysCacheInRedis.prototype.stop = function () {
51
+ clearInterval(this.intervalId);
52
+ return this.postUniqueKeysInRedis();
53
+ };
54
+ /**
55
+ * Async consumer API, used by synchronizer.
56
+ * @param count number of items to pop from the queue. If not provided or equal 0, all items will be popped.
57
+ */
58
+ UniqueKeysCacheInRedis.prototype.popNRaw = function (count) {
59
+ var _this = this;
60
+ if (count === void 0) { count = 0; }
61
+ return this.redis.lrange(this.key, 0, count - 1).then(function (uniqueKeyItems) {
62
+ return _this.redis.ltrim(_this.key, uniqueKeyItems.length, -1)
63
+ .then(function () { return uniqueKeyItems.map(function (uniqueKeyItem) { return JSON.parse(uniqueKeyItem); }); });
64
+ });
65
+ };
66
+ return UniqueKeysCacheInRedis;
67
+ }(UniqueKeysCacheInMemory));
68
+ export { UniqueKeysCacheInRedis };
@@ -1 +1,4 @@
1
1
  export var LOG_PREFIX = 'storage:redis: ';
2
+ export var DEFAULT_CACHE_SIZE = 30000;
3
+ export var REFRESH_RATE = 300000; // 300.000 ms = start after 5 mins
4
+ export var TTL_REFRESH = 3600; // 1hr
@@ -5,8 +5,11 @@ import { SplitsCacheInRedis } from './SplitsCacheInRedis';
5
5
  import { SegmentsCacheInRedis } from './SegmentsCacheInRedis';
6
6
  import { ImpressionsCacheInRedis } from './ImpressionsCacheInRedis';
7
7
  import { EventsCacheInRedis } from './EventsCacheInRedis';
8
- import { STORAGE_REDIS } from '../../utils/constants';
8
+ import { DEBUG, NONE, STORAGE_REDIS } from '../../utils/constants';
9
9
  import { TelemetryCacheInRedis } from './TelemetryCacheInRedis';
10
+ import { UniqueKeysCacheInRedis } from './UniqueKeysCacheInRedis';
11
+ import { ImpressionCountsCacheInRedis } from './ImpressionCountsCacheInRedis';
12
+ import { metadataBuilder } from '../utils';
10
13
  /**
11
14
  * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.
12
15
  * @see {@link https://www.npmjs.com/package/ioredis}
@@ -14,14 +17,21 @@ import { TelemetryCacheInRedis } from './TelemetryCacheInRedis';
14
17
  export function InRedisStorage(options) {
15
18
  if (options === void 0) { options = {}; }
16
19
  var prefix = validatePrefix(options.prefix);
17
- function InRedisStorageFactory(_a) {
18
- var log = _a.log, metadata = _a.metadata, onReadyCb = _a.onReadyCb;
20
+ function InRedisStorageFactory(params) {
21
+ var onReadyCb = params.onReadyCb, settings = params.settings, _a = params.settings, log = _a.log, impressionsMode = _a.sync.impressionsMode;
22
+ var metadata = metadataBuilder(settings);
19
23
  var keys = new KeyBuilderSS(prefix, metadata);
20
24
  var redisClient = new RedisAdapter(log, options.options || {});
21
25
  var telemetry = new TelemetryCacheInRedis(log, keys, redisClient);
26
+ var impressionCountsCache = impressionsMode !== DEBUG ? new ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient) : undefined;
27
+ var uniqueKeysCache = impressionsMode === NONE ? new UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient) : undefined;
22
28
  // subscription to Redis connect event in order to emit SDK_READY event on consumer mode
23
29
  redisClient.on('connect', function () {
24
30
  onReadyCb();
31
+ if (impressionCountsCache)
32
+ impressionCountsCache.start();
33
+ if (uniqueKeysCache)
34
+ uniqueKeysCache.start();
25
35
  // Synchronize config
26
36
  telemetry.recordConfig();
27
37
  });
@@ -29,12 +39,19 @@ export function InRedisStorage(options) {
29
39
  splits: new SplitsCacheInRedis(log, keys, redisClient),
30
40
  segments: new SegmentsCacheInRedis(log, keys, redisClient),
31
41
  impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
42
+ impressionCounts: impressionCountsCache,
32
43
  events: new EventsCacheInRedis(log, keys.buildEventsKey(), redisClient, metadata),
33
44
  telemetry: telemetry,
45
+ uniqueKeys: uniqueKeysCache,
34
46
  // When using REDIS we should:
35
47
  // 1- Disconnect from the storage
36
48
  destroy: function () {
37
- redisClient.disconnect();
49
+ var promises = [];
50
+ if (impressionCountsCache)
51
+ promises.push(impressionCountsCache.stop());
52
+ if (uniqueKeysCache)
53
+ promises.push(uniqueKeysCache.stop());
54
+ return Promise.all(promises).then(function () { redisClient.disconnect(); });
38
55
  // @TODO check that caches works as expected when redisClient is disconnected
39
56
  }
40
57
  };
@@ -0,0 +1,78 @@
1
+ import { __extends } from "tslib";
2
+ import { ImpressionCountsCacheInMemory } from '../inMemory/ImpressionCountsCacheInMemory';
3
+ import { REFRESH_RATE } from '../inRedis/constants';
4
+ import { LOG_PREFIX } from './constants';
5
+ var ImpressionCountsCachePluggable = /** @class */ (function (_super) {
6
+ __extends(ImpressionCountsCachePluggable, _super);
7
+ function ImpressionCountsCachePluggable(log, key, wrapper, impressionCountsCacheSize, refreshRate) {
8
+ if (refreshRate === void 0) { refreshRate = REFRESH_RATE; }
9
+ var _this = _super.call(this, impressionCountsCacheSize) || this;
10
+ _this.log = log;
11
+ _this.key = key;
12
+ _this.wrapper = wrapper;
13
+ _this.refreshRate = refreshRate;
14
+ _this.onFullQueue = function () { _this.storeImpressionCounts(); };
15
+ return _this;
16
+ }
17
+ ImpressionCountsCachePluggable.prototype.storeImpressionCounts = function () {
18
+ var _this = this;
19
+ var counts = this.pop();
20
+ var keys = Object.keys(counts);
21
+ if (!keys.length)
22
+ return Promise.resolve(false);
23
+ var pipeline = keys.reduce(function (pipeline, key) {
24
+ return pipeline.then(function () { return _this.wrapper.incr(_this.key + "::" + key, counts[key]); });
25
+ }, Promise.resolve());
26
+ return pipeline.catch(function (err) {
27
+ _this.log.error(LOG_PREFIX + "Error in impression counts pipeline: " + err + ".");
28
+ return false;
29
+ });
30
+ };
31
+ ImpressionCountsCachePluggable.prototype.start = function () {
32
+ this.intervalId = setInterval(this.storeImpressionCounts.bind(this), this.refreshRate);
33
+ };
34
+ ImpressionCountsCachePluggable.prototype.stop = function () {
35
+ clearInterval(this.intervalId);
36
+ return this.storeImpressionCounts();
37
+ };
38
+ // Async consumer API, used by synchronizer
39
+ ImpressionCountsCachePluggable.prototype.getImpressionsCount = function () {
40
+ var _this = this;
41
+ return this.wrapper.getKeysByPrefix(this.key)
42
+ .then(function (keys) {
43
+ return keys.length ? Promise.all(keys.map(function (key) { return _this.wrapper.get(key); }))
44
+ .then(function (counts) {
45
+ keys.forEach(function (key) { return _this.wrapper.del(key).catch(function () { }); });
46
+ var pf = [];
47
+ for (var i = 0; i < keys.length; i++) {
48
+ var key = keys[i];
49
+ var count = counts[i];
50
+ var keyFeatureNameAndTime = key.split('::');
51
+ if (keyFeatureNameAndTime.length !== 3) {
52
+ _this.log.error(LOG_PREFIX + "Error spliting key " + key);
53
+ continue;
54
+ }
55
+ var timeFrame = parseInt(keyFeatureNameAndTime[2]);
56
+ if (isNaN(timeFrame)) {
57
+ _this.log.error(LOG_PREFIX + "Error parsing time frame " + keyFeatureNameAndTime[2]);
58
+ continue;
59
+ }
60
+ // @ts-ignore
61
+ var rawCount = parseInt(count);
62
+ if (isNaN(rawCount)) {
63
+ _this.log.error(LOG_PREFIX + "Error parsing raw count " + count);
64
+ continue;
65
+ }
66
+ pf.push({
67
+ f: keyFeatureNameAndTime[1],
68
+ m: timeFrame,
69
+ rc: rawCount,
70
+ });
71
+ }
72
+ return { pf: pf };
73
+ }) : undefined;
74
+ });
75
+ };
76
+ return ImpressionCountsCachePluggable;
77
+ }(ImpressionCountsCacheInMemory));
78
+ export { ImpressionCountsCachePluggable };
@@ -1,3 +1,4 @@
1
+ import { impressionsToJSON } from '../utils';
1
2
  var ImpressionsCachePluggable = /** @class */ (function () {
2
3
  function ImpressionsCachePluggable(log, key, wrapper, metadata) {
3
4
  this.log = log;
@@ -12,25 +13,7 @@ var ImpressionsCachePluggable = /** @class */ (function () {
12
13
  * or rejected if the wrapper operation fails.
13
14
  */
14
15
  ImpressionsCachePluggable.prototype.track = function (impressions) {
15
- return this.wrapper.pushItems(this.key, this._toJSON(impressions));
16
- };
17
- ImpressionsCachePluggable.prototype._toJSON = function (impressions) {
18
- var _this = this;
19
- return impressions.map(function (impression) {
20
- var keyName = impression.keyName, bucketingKey = impression.bucketingKey, feature = impression.feature, treatment = impression.treatment, label = impression.label, time = impression.time, changeNumber = impression.changeNumber;
21
- return JSON.stringify({
22
- m: _this.metadata,
23
- i: {
24
- k: keyName,
25
- b: bucketingKey,
26
- f: feature,
27
- t: treatment,
28
- r: label,
29
- c: changeNumber,
30
- m: time
31
- }
32
- });
33
- });
16
+ return this.wrapper.pushItems(this.key, impressionsToJSON(impressions, this.metadata));
34
17
  };
35
18
  /**
36
19
  * Returns a promise that resolves with the count of stored impressions, or 0 if there was some error.
@@ -1,10 +1,10 @@
1
- import { parseExceptionField, parseLatencyField, parseMetadata } from '../KeyBuilderSS';
2
1
  import { findLatencyIndex } from '../findLatencyIndex';
3
2
  import { getTelemetryConfigStats } from '../../sync/submitters/telemetrySubmitter';
4
3
  import { CONSUMER_MODE, STORAGE_PLUGGABLE } from '../../utils/constants';
5
4
  import { isString, isNaNNumber } from '../../utils/lang';
6
5
  import { _Map } from '../../utils/lang/maps';
7
6
  import { MAX_LATENCY_BUCKET_COUNT, newBuckets } from '../inMemory/TelemetryCacheInMemory';
7
+ import { parseLatencyField, parseExceptionField, parseMetadata } from '../utils';
8
8
  var TelemetryCachePluggable = /** @class */ (function () {
9
9
  /**
10
10
  * Create a Telemetry cache that uses a storage wrapper.
@@ -0,0 +1,58 @@
1
+ import { __extends } from "tslib";
2
+ import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
3
+ import { setToArray } from '../../utils/lang/sets';
4
+ import { DEFAULT_CACHE_SIZE, REFRESH_RATE } from '../inRedis/constants';
5
+ import { LOG_PREFIX } from './constants';
6
+ var UniqueKeysCachePluggable = /** @class */ (function (_super) {
7
+ __extends(UniqueKeysCachePluggable, _super);
8
+ function UniqueKeysCachePluggable(log, key, wrapper, uniqueKeysQueueSize, refreshRate) {
9
+ if (uniqueKeysQueueSize === void 0) { uniqueKeysQueueSize = DEFAULT_CACHE_SIZE; }
10
+ if (refreshRate === void 0) { refreshRate = REFRESH_RATE; }
11
+ var _this = _super.call(this, uniqueKeysQueueSize) || this;
12
+ _this.log = log;
13
+ _this.key = key;
14
+ _this.wrapper = wrapper;
15
+ _this.refreshRate = refreshRate;
16
+ _this.onFullQueue = function () { _this.storeUniqueKeys(); };
17
+ return _this;
18
+ }
19
+ UniqueKeysCachePluggable.prototype.storeUniqueKeys = function () {
20
+ var _this = this;
21
+ var featureNames = Object.keys(this.uniqueKeysTracker);
22
+ if (!featureNames.length)
23
+ return Promise.resolve(false);
24
+ var pipeline = featureNames.reduce(function (pipeline, featureName) {
25
+ var featureKeys = setToArray(_this.uniqueKeysTracker[featureName]);
26
+ var uniqueKeysPayload = {
27
+ f: featureName,
28
+ ks: featureKeys
29
+ };
30
+ return pipeline.then(function () { return _this.wrapper.pushItems(_this.key, [JSON.stringify(uniqueKeysPayload)]); });
31
+ }, Promise.resolve());
32
+ this.clear();
33
+ return pipeline.catch(function (err) {
34
+ _this.log.error(LOG_PREFIX + "Error in uniqueKeys pipeline: " + err + ".");
35
+ return false;
36
+ });
37
+ };
38
+ UniqueKeysCachePluggable.prototype.start = function () {
39
+ this.intervalId = setInterval(this.storeUniqueKeys.bind(this), this.refreshRate);
40
+ };
41
+ UniqueKeysCachePluggable.prototype.stop = function () {
42
+ clearInterval(this.intervalId);
43
+ return this.storeUniqueKeys();
44
+ };
45
+ /**
46
+ * Async consumer API, used by synchronizer.
47
+ * @param count number of items to pop from the queue. If not provided or equal 0, all items will be popped.
48
+ */
49
+ UniqueKeysCachePluggable.prototype.popNRaw = function (count) {
50
+ var _this = this;
51
+ if (count === void 0) { count = 0; }
52
+ return Promise.resolve(count || this.wrapper.getItemsCount(this.key))
53
+ .then(function (count) { return _this.wrapper.popItems(_this.key, count); })
54
+ .then(function (uniqueKeyItems) { return uniqueKeyItems.map(function (uniqueKeyItem) { return JSON.parse(uniqueKeyItem); }); });
55
+ };
56
+ return UniqueKeysCachePluggable;
57
+ }(UniqueKeysCacheInMemory));
58
+ export { UniqueKeysCachePluggable };
@@ -34,29 +34,31 @@ export function inMemoryWrapperFactory(connDelay) {
34
34
  getKeysByPrefix: function (prefix) {
35
35
  return Promise.resolve(Object.keys(_cache).filter(function (key) { return startsWith(key, prefix); }));
36
36
  },
37
- incr: function (key) {
37
+ incr: function (key, increment) {
38
+ if (increment === void 0) { increment = 1; }
38
39
  if (key in _cache) {
39
- var count = toNumber(_cache[key]) + 1;
40
+ var count = toNumber(_cache[key]) + increment;
40
41
  if (isNaN(count))
41
42
  return Promise.reject('Given key is not a number');
42
43
  _cache[key] = count + '';
43
44
  return Promise.resolve(count);
44
45
  }
45
46
  else {
46
- _cache[key] = '1';
47
+ _cache[key] = '' + increment;
47
48
  return Promise.resolve(1);
48
49
  }
49
50
  },
50
- decr: function (key) {
51
+ decr: function (key, decrement) {
52
+ if (decrement === void 0) { decrement = 1; }
51
53
  if (key in _cache) {
52
- var count = toNumber(_cache[key]) - 1;
54
+ var count = toNumber(_cache[key]) - decrement;
53
55
  if (isNaN(count))
54
56
  return Promise.reject('Given key is not a number');
55
57
  _cache[key] = count + '';
56
58
  return Promise.resolve(count);
57
59
  }
58
60
  else {
59
- _cache[key] = '-1';
61
+ _cache[key] = '-' + decrement;
60
62
  return Promise.resolve(-1);
61
63
  }
62
64
  },
@@ -7,12 +7,17 @@ import { EventsCachePluggable } from './EventsCachePluggable';
7
7
  import { wrapperAdapter, METHODS_TO_PROMISE_WRAP } from './wrapperAdapter';
8
8
  import { isObject } from '../../utils/lang';
9
9
  import { validatePrefix } from '../KeyBuilder';
10
- import { CONSUMER_PARTIAL_MODE, STORAGE_PLUGGABLE } from '../../utils/constants';
10
+ import { CONSUMER_PARTIAL_MODE, DEBUG, NONE, STORAGE_PLUGGABLE } from '../../utils/constants';
11
11
  import { ImpressionsCacheInMemory } from '../inMemory/ImpressionsCacheInMemory';
12
12
  import { EventsCacheInMemory } from '../inMemory/EventsCacheInMemory';
13
13
  import { ImpressionCountsCacheInMemory } from '../inMemory/ImpressionCountsCacheInMemory';
14
14
  import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
15
15
  import { TelemetryCachePluggable } from './TelemetryCachePluggable';
16
+ import { ImpressionCountsCachePluggable } from './ImpressionCountsCachePluggable';
17
+ import { UniqueKeysCachePluggable } from './UniqueKeysCachePluggable';
18
+ import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
19
+ import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
20
+ import { metadataBuilder } from '../utils';
16
21
  var NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.';
17
22
  var NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.';
18
23
  /**
@@ -45,19 +50,39 @@ export function PluggableStorage(options) {
45
50
  validatePluggableStorageOptions(options);
46
51
  var prefix = validatePrefix(options.prefix);
47
52
  function PluggableStorageFactory(params) {
48
- var log = params.log, metadata = params.metadata, onReadyCb = params.onReadyCb, mode = params.mode, eventsQueueSize = params.eventsQueueSize, impressionsQueueSize = params.impressionsQueueSize, optimize = params.optimize;
53
+ 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;
54
+ var metadata = metadataBuilder(settings);
49
55
  var keys = new KeyBuilderSS(prefix, metadata);
50
56
  var wrapper = wrapperAdapter(log, options.wrapper);
57
+ var isSyncronizer = mode === undefined; // If mode is not defined, the synchronizer is running
51
58
  var isPartialConsumer = mode === CONSUMER_PARTIAL_MODE;
52
- var telemetry = shouldRecordTelemetry(params) ?
53
- isPartialConsumer ? new TelemetryCacheInMemory() : new TelemetryCachePluggable(log, keys, wrapper) :
59
+ var telemetry = shouldRecordTelemetry(params) || isSyncronizer ?
60
+ isPartialConsumer ?
61
+ new TelemetryCacheInMemory() :
62
+ new TelemetryCachePluggable(log, keys, wrapper) :
63
+ undefined;
64
+ var impressionCountsCache = impressionsMode !== DEBUG || isSyncronizer ?
65
+ isPartialConsumer ?
66
+ new ImpressionCountsCacheInMemory() :
67
+ new ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper) :
68
+ undefined;
69
+ var uniqueKeysCache = impressionsMode === NONE || isSyncronizer ?
70
+ isPartialConsumer ?
71
+ settings.core.key === undefined ? new UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS() :
72
+ new UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper) :
54
73
  undefined;
55
74
  // Connects to wrapper and emits SDK_READY event on main client
56
75
  var connectPromise = wrapper.connect().then(function () {
57
76
  onReadyCb();
58
- // If mode is not defined, it means that the synchronizer is running and so we don't have to record telemetry
59
- if (telemetry && telemetry.recordConfig && mode)
60
- telemetry.recordConfig();
77
+ // Start periodic flush of async storages if not running synchronizer (producer mode)
78
+ if (!isSyncronizer) {
79
+ if (impressionCountsCache && impressionCountsCache.start)
80
+ impressionCountsCache.start();
81
+ if (uniqueKeysCache && uniqueKeysCache.start)
82
+ uniqueKeysCache.start();
83
+ if (telemetry && telemetry.recordConfig)
84
+ telemetry.recordConfig();
85
+ }
61
86
  }).catch(function (e) {
62
87
  e = e || new Error('Error connecting wrapper');
63
88
  onReadyCb(e);
@@ -67,12 +92,16 @@ export function PluggableStorage(options) {
67
92
  splits: new SplitsCachePluggable(log, keys, wrapper),
68
93
  segments: new SegmentsCachePluggable(log, keys, wrapper),
69
94
  impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
70
- impressionCounts: optimize ? new ImpressionCountsCacheInMemory() : undefined,
95
+ impressionCounts: impressionCountsCache,
71
96
  events: isPartialConsumer ? promisifyEventsTrack(new EventsCacheInMemory(eventsQueueSize)) : new EventsCachePluggable(log, keys.buildEventsKey(), wrapper, metadata),
72
97
  telemetry: telemetry,
73
- // Disconnect the underlying storage
98
+ uniqueKeys: uniqueKeysCache,
99
+ // Stop periodic flush and disconnect the underlying storage
74
100
  destroy: function () {
75
- return wrapper.disconnect();
101
+ return Promise.all(isSyncronizer ? [] : [
102
+ impressionCountsCache && impressionCountsCache.stop && impressionCountsCache.stop(),
103
+ uniqueKeysCache && uniqueKeysCache.stop && uniqueKeysCache.stop(),
104
+ ]).then(function () { return wrapper.disconnect(); });
76
105
  },
77
106
  // emits SDK_READY event on shared clients and returns a reference to the storage
78
107
  shared: function (_, onReadyCb) {
@@ -0,0 +1,65 @@
1
+ // Shared utils for Redis and Pluggable storage
2
+ import { UNKNOWN } from '../utils/constants';
3
+ import { MAX_LATENCY_BUCKET_COUNT } from './inMemory/TelemetryCacheInMemory';
4
+ import { METHOD_NAMES } from './KeyBuilderSS';
5
+ export function metadataBuilder(settings) {
6
+ return {
7
+ s: settings.version,
8
+ i: settings.runtime.ip || UNKNOWN,
9
+ n: settings.runtime.hostname || UNKNOWN,
10
+ };
11
+ }
12
+ // Converts impressions to be stored in Redis or pluggable storage.
13
+ export function impressionsToJSON(impressions, metadata) {
14
+ return impressions.map(function (impression) {
15
+ var impressionWithMetadata = {
16
+ m: metadata,
17
+ i: {
18
+ k: impression.keyName,
19
+ b: impression.bucketingKey,
20
+ f: impression.feature,
21
+ t: impression.treatment,
22
+ r: impression.label,
23
+ c: impression.changeNumber,
24
+ m: impression.time,
25
+ pt: impression.pt,
26
+ }
27
+ };
28
+ return JSON.stringify(impressionWithMetadata);
29
+ });
30
+ }
31
+ // Utilities used by TelemetryCacheInRedis and TelemetryCachePluggable
32
+ var REVERSE_METHOD_NAMES = Object.keys(METHOD_NAMES).reduce(function (acc, key) {
33
+ acc[METHOD_NAMES[key]] = key;
34
+ return acc;
35
+ }, {});
36
+ export function parseMetadata(field) {
37
+ var parts = field.split('/');
38
+ if (parts.length !== 3)
39
+ return "invalid subsection count. Expected 3, got: " + parts.length;
40
+ var s = parts[0] /* metadata.s */, n = parts[1] /* metadata.n */, i = parts[2] /* metadata.i */;
41
+ return [JSON.stringify({ s: s, n: n, i: i })];
42
+ }
43
+ export function parseExceptionField(field) {
44
+ var parts = field.split('/');
45
+ if (parts.length !== 4)
46
+ return "invalid subsection count. Expected 4, got: " + parts.length;
47
+ var s = parts[0] /* metadata.s */, n = parts[1] /* metadata.n */, i = parts[2] /* metadata.i */, m = parts[3];
48
+ var method = REVERSE_METHOD_NAMES[m];
49
+ if (!method)
50
+ return "unknown method '" + m + "'";
51
+ return [JSON.stringify({ s: s, n: n, i: i }), method];
52
+ }
53
+ export function parseLatencyField(field) {
54
+ var parts = field.split('/');
55
+ if (parts.length !== 5)
56
+ return "invalid subsection count. Expected 5, got: " + parts.length;
57
+ var s = parts[0] /* metadata.s */, n = parts[1] /* metadata.n */, i = parts[2] /* metadata.i */, m = parts[3], b = parts[4];
58
+ var method = REVERSE_METHOD_NAMES[m];
59
+ if (!method)
60
+ return "unknown method '" + m + "'";
61
+ var bucket = parseInt(b);
62
+ if (isNaN(bucket) || bucket >= MAX_LATENCY_BUCKET_COUNT)
63
+ return "invalid bucket. Expected a number between 0 and " + (MAX_LATENCY_BUCKET_COUNT - 1) + ", got: " + b;
64
+ return [JSON.stringify({ s: s, n: n, i: i }), method, bucket];
65
+ }
@@ -2,6 +2,7 @@ import { eventsSubmitterFactory } from './eventsSubmitter';
2
2
  import { impressionsSubmitterFactory } from './impressionsSubmitter';
3
3
  import { impressionCountsSubmitterFactory } from './impressionCountsSubmitter';
4
4
  import { telemetrySubmitterFactory } from './telemetrySubmitter';
5
+ import { uniqueKeysSubmitterFactory } from './uniqueKeysSubmitter';
5
6
  export function submitterManagerFactory(params) {
6
7
  var submitters = [
7
8
  impressionsSubmitterFactory(params),
@@ -11,6 +12,8 @@ export function submitterManagerFactory(params) {
11
12
  if (impressionCountsSubmitter)
12
13
  submitters.push(impressionCountsSubmitter);
13
14
  var telemetrySubmitter = telemetrySubmitterFactory(params);
15
+ if (params.storage.uniqueKeys)
16
+ submitters.push(uniqueKeysSubmitterFactory(params));
14
17
  return {
15
18
  // `onlyTelemetry` true if SDK is created with userConsent not GRANTED
16
19
  start: function (onlyTelemetry) {
@@ -1,44 +1,11 @@
1
1
  var _a, _b, _c;
2
2
  import { submitterFactory, firstPushWindowDecorator } from './submitter';
3
- import { QUEUED, DEDUPED, DROPPED, CONSUMER_MODE, CONSUMER_ENUM, STANDALONE_MODE, CONSUMER_PARTIAL_MODE, STANDALONE_ENUM, CONSUMER_PARTIAL_ENUM, OPTIMIZED, DEBUG, DEBUG_ENUM, OPTIMIZED_ENUM, CONSENT_GRANTED, CONSENT_DECLINED, CONSENT_UNKNOWN } from '../../utils/constants';
3
+ import { CONSUMER_MODE, CONSUMER_ENUM, STANDALONE_MODE, CONSUMER_PARTIAL_MODE, STANDALONE_ENUM, CONSUMER_PARTIAL_ENUM, OPTIMIZED, DEBUG, NONE, DEBUG_ENUM, OPTIMIZED_ENUM, NONE_ENUM, CONSENT_GRANTED, CONSENT_DECLINED, CONSENT_UNKNOWN } from '../../utils/constants';
4
4
  import { SDK_READY, SDK_READY_FROM_CACHE } from '../../readiness/constants';
5
5
  import { base } from '../../utils/settingsValidation';
6
6
  import { usedKeysMap } from '../../utils/inputValidation/apiKey';
7
7
  import { timer } from '../../utils/timeTracker/timer';
8
8
  import { objectAssign } from '../../utils/lang/objectAssign';
9
- import { isStorageSync } from '../../trackers/impressionObserver/utils';
10
- /**
11
- * Converts data from telemetry cache into /metrics/usage request payload.
12
- */
13
- export function telemetryCacheStatsAdapter(telemetry, splits, segments) {
14
- return {
15
- isEmpty: function () { return false; },
16
- clear: function () { },
17
- // @TODO consider moving inside telemetry cache for code size reduction
18
- pop: function () {
19
- return {
20
- lS: telemetry.getLastSynchronization(),
21
- mL: telemetry.popLatencies(),
22
- mE: telemetry.popExceptions(),
23
- hE: telemetry.popHttpErrors(),
24
- hL: telemetry.popHttpLatencies(),
25
- tR: telemetry.popTokenRefreshes(),
26
- aR: telemetry.popAuthRejections(),
27
- iQ: telemetry.getImpressionStats(QUEUED),
28
- iDe: telemetry.getImpressionStats(DEDUPED),
29
- iDr: telemetry.getImpressionStats(DROPPED),
30
- spC: splits && splits.getSplitNames().length,
31
- seC: segments && segments.getRegisteredSegments().length,
32
- skC: segments && segments.getKeysCount(),
33
- sL: telemetry.getSessionLength(),
34
- eQ: telemetry.getEventStats(QUEUED),
35
- eD: telemetry.getEventStats(DROPPED),
36
- sE: telemetry.popStreamingEvents(),
37
- t: telemetry.popTags(),
38
- };
39
- }
40
- };
41
- }
42
9
  var OPERATION_MODE_MAP = (_a = {},
43
10
  _a[STANDALONE_MODE] = STANDALONE_ENUM,
44
11
  _a[CONSUMER_MODE] = CONSUMER_ENUM,
@@ -47,6 +14,7 @@ var OPERATION_MODE_MAP = (_a = {},
47
14
  var IMPRESSIONS_MODE_MAP = (_b = {},
48
15
  _b[OPTIMIZED] = OPTIMIZED_ENUM,
49
16
  _b[DEBUG] = DEBUG_ENUM,
17
+ _b[NONE] = NONE_ENUM,
50
18
  _b);
51
19
  var USER_CONSENT_MAP = (_c = {},
52
20
  _c[CONSENT_UNKNOWN] = 1,
@@ -115,14 +83,12 @@ export function telemetryCacheConfigAdapter(telemetry, settings) {
115
83
  * Submitter that periodically posts telemetry data
116
84
  */
117
85
  export function telemetrySubmitterFactory(params) {
118
- var _a = params.storage, splits = _a.splits, segments = _a.segments, telemetry = _a.telemetry, now = params.platform.now;
86
+ var telemetry = params.storage.telemetry, now = params.platform.now;
119
87
  if (!telemetry || !now)
120
88
  return; // No submitter created if telemetry cache is not defined
121
- var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, readiness = params.readiness, sdkReadinessManager = params.sdkReadinessManager;
89
+ var settings = params.settings, _a = params.settings, log = _a.log, telemetryRefreshRate = _a.scheduler.telemetryRefreshRate, splitApi = params.splitApi, readiness = params.readiness, sdkReadinessManager = params.sdkReadinessManager;
122
90
  var startTime = timer(now);
123
- var submitter = firstPushWindowDecorator(submitterFactory(log, splitApi.postMetricsUsage,
124
- // @TODO cannot provide splits and segments cache if they are async, because `submitterFactory` expects a sync storage source
125
- isStorageSync(params.settings) ? telemetryCacheStatsAdapter(telemetry, splits, segments) : telemetryCacheStatsAdapter(telemetry), telemetryRefreshRate, 'telemetry stats', undefined, 0, true), telemetryRefreshRate);
91
+ var submitter = firstPushWindowDecorator(submitterFactory(log, splitApi.postMetricsUsage, telemetry, telemetryRefreshRate, 'telemetry stats', undefined, 0, true), telemetryRefreshRate);
126
92
  readiness.gate.once(SDK_READY_FROM_CACHE, function () {
127
93
  telemetry.recordTimeUntilReadyFromCache(startTime());
128
94
  });
@@ -0,0 +1,23 @@
1
+ import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
2
+ import { submitterFactory } from './submitter';
3
+ var DATA_NAME = 'unique keys';
4
+ var UNIQUE_KEYS_RATE = 900000; // 15 minutes
5
+ /**
6
+ * Submitter that periodically posts impression counts
7
+ */
8
+ export function uniqueKeysSubmitterFactory(params) {
9
+ var _a = params.settings, log = _a.log, key = _a.core.key, _b = params.splitApi, postUniqueKeysBulkCs = _b.postUniqueKeysBulkCs, postUniqueKeysBulkSs = _b.postUniqueKeysBulkSs, uniqueKeys = params.storage.uniqueKeys;
10
+ var isClientSide = key !== undefined;
11
+ var postUniqueKeysBulk = isClientSide ? postUniqueKeysBulkCs : postUniqueKeysBulkSs;
12
+ var syncTask = submitterFactory(log, postUniqueKeysBulk, uniqueKeys, UNIQUE_KEYS_RATE, DATA_NAME);
13
+ // register unique keys submitter to be executed when uniqueKeys cache is full
14
+ uniqueKeys.setOnFullQueueCb(function () {
15
+ if (syncTask.isRunning()) {
16
+ log.info(SUBMITTERS_PUSH_FULL_QUEUE, [DATA_NAME]);
17
+ syncTask.execute();
18
+ }
19
+ // If submitter is stopped (e.g., user consent declined or unknown, or app state offline), we don't send the data.
20
+ // Data will be sent when submitter is resumed.
21
+ });
22
+ return syncTask;
23
+ }
@@ -1,18 +1,4 @@
1
- import { CONSUMER_MODE, CONSUMER_PARTIAL_MODE, OPTIMIZED, PRODUCER_MODE, STANDALONE_MODE } from '../../utils/constants';
2
- /**
3
- * Checks if impressions previous time should be added or not.
4
- */
5
- export function shouldAddPt(settings) {
6
- return [PRODUCER_MODE, STANDALONE_MODE, CONSUMER_PARTIAL_MODE].indexOf(settings.mode) > -1 ? true : false;
7
- }
8
- /**
9
- * Checks if it should dedupe impressions or not.
10
- */
11
- export function shouldBeOptimized(settings) {
12
- if (!shouldAddPt(settings))
13
- return false;
14
- return settings.sync.impressionsMode === OPTIMIZED ? true : false;
15
- }
1
+ import { CONSUMER_MODE, CONSUMER_PARTIAL_MODE } from '../../utils/constants';
16
2
  /**
17
3
  * Storage is async if mode is consumer or partial consumer
18
4
  */