@splitsoftware/splitio-commons 1.6.2-rc.0 → 1.6.2-rc.10

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 (265) hide show
  1. package/CHANGES.txt +4 -0
  2. package/cjs/consent/sdkUserConsent.js +2 -2
  3. package/cjs/evaluator/index.js +15 -16
  4. package/cjs/integrations/ga/GaToSplit.js +8 -5
  5. package/cjs/listeners/browser.js +2 -1
  6. package/cjs/logger/constants.js +2 -1
  7. package/cjs/sdkClient/client.js +19 -7
  8. package/cjs/sdkClient/sdkClient.js +3 -1
  9. package/cjs/sdkFactory/index.js +24 -7
  10. package/cjs/sdkManager/index.js +3 -11
  11. package/cjs/services/splitApi.js +24 -4
  12. package/cjs/storages/AbstractSplitsCacheAsync.js +8 -10
  13. package/cjs/storages/AbstractSplitsCacheSync.js +8 -10
  14. package/cjs/storages/KeyBuilderSS.js +54 -9
  15. package/cjs/storages/dataLoader.js +1 -1
  16. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +5 -7
  17. package/cjs/storages/inLocalStorage/index.js +5 -1
  18. package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +12 -1
  19. package/cjs/storages/inMemory/InMemoryStorage.js +6 -2
  20. package/cjs/storages/inMemory/InMemoryStorageCS.js +6 -2
  21. package/cjs/storages/inMemory/SplitsCacheInMemory.js +7 -10
  22. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +10 -5
  23. package/cjs/storages/inMemory/UniqueKeysCacheInMemory.js +73 -0
  24. package/cjs/storages/inMemory/UniqueKeysCacheInMemoryCS.js +78 -0
  25. package/cjs/storages/inRedis/EventsCacheInRedis.js +1 -1
  26. package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +50 -0
  27. package/cjs/storages/inRedis/SplitsCacheInRedis.js +15 -9
  28. package/cjs/storages/inRedis/TelemetryCacheInRedis.js +100 -0
  29. package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +59 -0
  30. package/cjs/storages/inRedis/constants.js +4 -1
  31. package/cjs/storages/inRedis/index.js +17 -2
  32. package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +43 -0
  33. package/cjs/storages/pluggable/SplitsCachePluggable.js +14 -9
  34. package/cjs/storages/pluggable/TelemetryCachePluggable.js +126 -0
  35. package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +50 -0
  36. package/cjs/storages/pluggable/index.js +42 -17
  37. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
  38. package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -1
  39. package/cjs/sync/submitters/submitterManager.js +3 -0
  40. package/cjs/sync/submitters/telemetrySubmitter.js +8 -4
  41. package/cjs/sync/submitters/uniqueKeysSubmitter.js +27 -0
  42. package/cjs/trackers/impressionsTracker.js +22 -41
  43. package/cjs/trackers/strategy/strategyDebug.js +25 -0
  44. package/cjs/trackers/strategy/strategyNone.js +29 -0
  45. package/cjs/trackers/strategy/strategyOptimized.js +35 -0
  46. package/cjs/trackers/telemetryTracker.js +6 -0
  47. package/cjs/trackers/uniqueKeysTracker.js +38 -0
  48. package/cjs/utils/constants/index.js +4 -2
  49. package/cjs/utils/lang/maps.js +15 -7
  50. package/cjs/utils/redis/RedisMock.js +31 -0
  51. package/cjs/utils/settingsValidation/impressionsMode.js +2 -2
  52. package/esm/consent/sdkUserConsent.js +2 -2
  53. package/esm/evaluator/index.js +15 -16
  54. package/esm/integrations/ga/GaToSplit.js +8 -5
  55. package/esm/listeners/browser.js +3 -2
  56. package/esm/logger/constants.js +1 -0
  57. package/esm/sdkClient/client.js +19 -7
  58. package/esm/sdkClient/sdkClient.js +3 -1
  59. package/esm/sdkFactory/index.js +24 -7
  60. package/esm/sdkManager/index.js +3 -11
  61. package/esm/services/splitApi.js +24 -4
  62. package/esm/storages/AbstractSplitsCacheAsync.js +8 -10
  63. package/esm/storages/AbstractSplitsCacheSync.js +8 -10
  64. package/esm/storages/KeyBuilderSS.js +50 -8
  65. package/esm/storages/dataLoader.js +1 -1
  66. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +5 -7
  67. package/esm/storages/inLocalStorage/index.js +6 -2
  68. package/esm/storages/inMemory/ImpressionCountsCacheInMemory.js +12 -1
  69. package/esm/storages/inMemory/InMemoryStorage.js +8 -4
  70. package/esm/storages/inMemory/InMemoryStorageCS.js +7 -3
  71. package/esm/storages/inMemory/SplitsCacheInMemory.js +7 -10
  72. package/esm/storages/inMemory/TelemetryCacheInMemory.js +9 -5
  73. package/esm/storages/inMemory/UniqueKeysCacheInMemory.js +70 -0
  74. package/esm/storages/inMemory/UniqueKeysCacheInMemoryCS.js +75 -0
  75. package/esm/storages/inRedis/EventsCacheInRedis.js +1 -1
  76. package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +47 -0
  77. package/esm/storages/inRedis/SplitsCacheInRedis.js +15 -9
  78. package/esm/storages/inRedis/TelemetryCacheInRedis.js +100 -0
  79. package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +56 -0
  80. package/esm/storages/inRedis/constants.js +3 -0
  81. package/esm/storages/inRedis/index.js +18 -3
  82. package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +40 -0
  83. package/esm/storages/pluggable/SplitsCachePluggable.js +14 -9
  84. package/esm/storages/pluggable/TelemetryCachePluggable.js +126 -0
  85. package/esm/storages/pluggable/UniqueKeysCachePluggable.js +47 -0
  86. package/esm/storages/pluggable/index.js +43 -18
  87. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
  88. package/esm/sync/polling/updaters/splitChangesUpdater.js +1 -1
  89. package/esm/sync/submitters/submitterManager.js +3 -0
  90. package/esm/sync/submitters/telemetrySubmitter.js +9 -5
  91. package/esm/sync/submitters/uniqueKeysSubmitter.js +23 -0
  92. package/esm/trackers/impressionsTracker.js +22 -41
  93. package/esm/trackers/strategy/strategyDebug.js +21 -0
  94. package/esm/trackers/strategy/strategyNone.js +25 -0
  95. package/esm/trackers/strategy/strategyOptimized.js +31 -0
  96. package/esm/trackers/telemetryTracker.js +6 -0
  97. package/esm/trackers/uniqueKeysTracker.js +34 -0
  98. package/esm/utils/constants/index.js +2 -0
  99. package/esm/utils/lang/maps.js +15 -7
  100. package/esm/utils/redis/RedisMock.js +28 -0
  101. package/esm/utils/settingsValidation/impressionsMode.js +3 -3
  102. package/package.json +1 -2
  103. package/src/consent/sdkUserConsent.ts +2 -2
  104. package/src/evaluator/index.ts +14 -15
  105. package/src/integrations/ga/GaToSplit.ts +9 -5
  106. package/src/integrations/types.ts +2 -1
  107. package/src/listeners/browser.ts +3 -2
  108. package/src/logger/constants.ts +1 -0
  109. package/src/sdkClient/client.ts +21 -8
  110. package/src/sdkClient/sdkClient.ts +3 -1
  111. package/src/sdkFactory/index.ts +28 -8
  112. package/src/sdkFactory/types.ts +7 -4
  113. package/src/sdkManager/index.ts +3 -12
  114. package/src/services/splitApi.ts +26 -4
  115. package/src/services/types.ts +8 -2
  116. package/src/storages/AbstractSplitsCacheAsync.ts +13 -15
  117. package/src/storages/AbstractSplitsCacheSync.ts +15 -17
  118. package/src/storages/KeyBuilderSS.ts +61 -9
  119. package/src/storages/dataLoader.ts +1 -1
  120. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +8 -11
  121. package/src/storages/inLocalStorage/index.ts +5 -2
  122. package/src/storages/inMemory/ImpressionCountsCacheInMemory.ts +16 -1
  123. package/src/storages/inMemory/InMemoryStorage.ts +7 -4
  124. package/src/storages/inMemory/InMemoryStorageCS.ts +6 -3
  125. package/src/storages/inMemory/SplitsCacheInMemory.ts +10 -14
  126. package/src/storages/inMemory/TelemetryCacheInMemory.ts +10 -6
  127. package/src/storages/inMemory/UniqueKeysCacheInMemory.ts +82 -0
  128. package/src/storages/inMemory/UniqueKeysCacheInMemoryCS.ts +88 -0
  129. package/src/storages/inRedis/EventsCacheInRedis.ts +1 -1
  130. package/src/storages/inRedis/ImpressionCountsCacheInRedis.ts +53 -0
  131. package/src/storages/inRedis/SplitsCacheInRedis.ts +21 -17
  132. package/src/storages/inRedis/TelemetryCacheInRedis.ts +122 -2
  133. package/src/storages/inRedis/UniqueKeysCacheInRedis.ts +65 -0
  134. package/src/storages/inRedis/constants.ts +3 -0
  135. package/src/storages/inRedis/index.ts +15 -5
  136. package/src/storages/pluggable/ImpressionCountsCachePluggable.ts +47 -0
  137. package/src/storages/pluggable/SplitsCachePluggable.ts +20 -17
  138. package/src/storages/pluggable/TelemetryCachePluggable.ts +147 -2
  139. package/src/storages/pluggable/UniqueKeysCachePluggable.ts +56 -0
  140. package/src/storages/pluggable/index.ts +44 -19
  141. package/src/storages/types.ts +50 -29
  142. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +5 -6
  143. package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -2
  144. package/src/sync/submitters/submitterManager.ts +2 -0
  145. package/src/sync/submitters/telemetrySubmitter.ts +15 -8
  146. package/src/sync/submitters/types.ts +38 -7
  147. package/src/sync/submitters/uniqueKeysSubmitter.ts +36 -0
  148. package/src/trackers/impressionsTracker.ts +27 -48
  149. package/src/trackers/strategy/strategyDebug.ts +28 -0
  150. package/src/trackers/strategy/strategyNone.ts +34 -0
  151. package/src/trackers/strategy/strategyOptimized.ts +42 -0
  152. package/src/trackers/telemetryTracker.ts +7 -2
  153. package/src/trackers/types.ts +32 -0
  154. package/src/trackers/uniqueKeysTracker.ts +48 -0
  155. package/src/types.ts +1 -1
  156. package/src/utils/constants/index.ts +2 -0
  157. package/src/utils/lang/maps.ts +20 -8
  158. package/src/utils/redis/RedisMock.ts +33 -0
  159. package/src/utils/settingsValidation/impressionsMode.ts +3 -3
  160. package/src/utils/settingsValidation/index.ts +1 -0
  161. package/types/integrations/types.d.ts +2 -1
  162. package/types/logger/browser/{debugLogger.d.ts → DebugLogger.d.ts} +0 -0
  163. package/types/logger/browser/{errorLogger.d.ts → ErrorLogger.d.ts} +0 -0
  164. package/types/logger/browser/{infoLogger.d.ts → InfoLogger.d.ts} +0 -0
  165. package/types/logger/browser/{warnLogger.d.ts → WarnLogger.d.ts} +0 -0
  166. package/types/logger/constants.d.ts +1 -0
  167. package/types/sdkFactory/types.d.ts +4 -2
  168. package/types/services/types.d.ts +6 -2
  169. package/types/storages/AbstractSplitsCacheAsync.d.ts +7 -6
  170. package/types/storages/AbstractSplitsCacheSync.d.ts +6 -6
  171. package/types/storages/KeyBuilderSS.d.ts +9 -2
  172. package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +3 -4
  173. package/types/storages/inMemory/ImpressionCountsCacheInMemory.d.ts +5 -1
  174. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +3 -2
  175. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -3
  176. package/types/storages/inMemory/uniqueKeysCacheInMemory.d.ts +35 -0
  177. package/types/storages/inMemory/uniqueKeysCacheInMemoryCS.d.ts +37 -0
  178. package/types/storages/inRedis/EventsCacheInRedis.d.ts +1 -1
  179. package/types/storages/inRedis/ImpressionCountsCacheInRedis.d.ts +14 -0
  180. package/types/storages/inRedis/SplitsCacheInRedis.d.ts +6 -5
  181. package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +16 -1
  182. package/types/storages/inRedis/constants.d.ts +3 -0
  183. package/types/storages/inRedis/uniqueKeysCacheInRedis.d.ts +15 -0
  184. package/types/storages/pluggable/ImpressionCountsCachePluggable.d.ts +14 -0
  185. package/types/storages/pluggable/SplitsCachePluggable.d.ts +6 -5
  186. package/types/storages/pluggable/TelemetryCachePluggable.d.ts +17 -1
  187. package/types/storages/pluggable/UniqueKeysCachePluggable.d.ts +14 -0
  188. package/types/storages/types.d.ts +38 -25
  189. package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -1
  190. package/types/sync/submitters/telemetrySubmitter.d.ts +1 -1
  191. package/types/sync/submitters/types.d.ts +30 -7
  192. package/types/sync/submitters/uniqueKeysSubmitter.d.ts +0 -8
  193. package/types/trackers/impressionsTracker.d.ts +4 -6
  194. package/types/trackers/types.d.ts +27 -0
  195. package/types/trackers/uniqueKeysTracker.d.ts +3 -3
  196. package/types/types.d.ts +1 -1
  197. package/types/utils/constants/index.d.ts +2 -0
  198. package/types/utils/lang/maps.d.ts +6 -2
  199. package/types/utils/redis/RedisMock.d.ts +4 -0
  200. package/src/splitio.d.ts +0 -1602
  201. package/types/integrations/ga/GaToSplitPlugin.d.ts +0 -3
  202. package/types/integrations/ga/SplitToGaPlugin.d.ts +0 -4
  203. package/types/integrations/ga/autoRequire.d.ts +0 -4
  204. package/types/logger/codes.d.ts +0 -2
  205. package/types/logger/codesConstants.d.ts +0 -117
  206. package/types/logger/codesConstantsBrowser.d.ts +0 -2
  207. package/types/logger/codesConstantsNode.d.ts +0 -14
  208. package/types/logger/codesDebug.d.ts +0 -1
  209. package/types/logger/codesDebugBrowser.d.ts +0 -1
  210. package/types/logger/codesDebugNode.d.ts +0 -1
  211. package/types/logger/codesError.d.ts +0 -1
  212. package/types/logger/codesErrorNode.d.ts +0 -1
  213. package/types/logger/codesInfo.d.ts +0 -1
  214. package/types/logger/codesWarn.d.ts +0 -1
  215. package/types/logger/codesWarnNode.d.ts +0 -1
  216. package/types/logger/debugLogger.d.ts +0 -2
  217. package/types/logger/errorLogger.d.ts +0 -2
  218. package/types/logger/infoLogger.d.ts +0 -2
  219. package/types/logger/messages/debugBrowser.d.ts +0 -1
  220. package/types/logger/messages/debugNode.d.ts +0 -1
  221. package/types/logger/messages/errorNode.d.ts +0 -1
  222. package/types/logger/messages/warnNode.d.ts +0 -1
  223. package/types/logger/noopLogger.d.ts +0 -2
  224. package/types/logger/warnLogger.d.ts +0 -2
  225. package/types/sdkClient/types.d.ts +0 -18
  226. package/types/sdkFactory/userConsentProps.d.ts +0 -6
  227. package/types/sdkManager/sdkManagerMethod.d.ts +0 -6
  228. package/types/storages/getRegisteredSegments.d.ts +0 -10
  229. package/types/storages/inMemory/CountsCacheInMemory.d.ts +0 -20
  230. package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +0 -20
  231. package/types/storages/inMemory/index.d.ts +0 -10
  232. package/types/storages/inRedis/CountsCacheInRedis.d.ts +0 -9
  233. package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +0 -9
  234. package/types/storages/parseSegments.d.ts +0 -6
  235. package/types/sync/offline/LocalhostFromFile.d.ts +0 -2
  236. package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +0 -2
  237. package/types/sync/polling/syncTasks/splitsSyncTask.copy.d.ts +0 -35
  238. package/types/sync/polling/syncTasks/splitsSyncTask.morelikeoriginal.d.ts +0 -35
  239. package/types/sync/streaming/AuthClient/indexV1.d.ts +0 -12
  240. package/types/sync/streaming/AuthClient/indexV2.d.ts +0 -8
  241. package/types/sync/streaming/pushManagerCS.d.ts +0 -1
  242. package/types/sync/streaming/pushManagerNoUsers.d.ts +0 -13
  243. package/types/sync/streaming/pushManagerSS.d.ts +0 -1
  244. package/types/sync/submitters/eventsSyncTask.d.ts +0 -8
  245. package/types/sync/submitters/impressionCountsSyncTask.d.ts +0 -13
  246. package/types/sync/submitters/impressionsSyncTask.d.ts +0 -14
  247. package/types/sync/submitters/metricsSyncTask.d.ts +0 -12
  248. package/types/sync/submitters/submitterSyncTask.d.ts +0 -10
  249. package/types/sync/submitters/telemetrySyncTask.d.ts +0 -0
  250. package/types/sync/syncManagerFromFile.d.ts +0 -2
  251. package/types/sync/syncManagerFromObject.d.ts +0 -2
  252. package/types/sync/syncManagerOffline.d.ts +0 -9
  253. package/types/sync/syncTaskComposite.d.ts +0 -5
  254. package/types/trackers/telemetryRecorder.d.ts +0 -0
  255. package/types/utils/EventEmitter.d.ts +0 -4
  256. package/types/utils/consent.d.ts +0 -2
  257. package/types/utils/lang/errors.d.ts +0 -10
  258. package/types/utils/murmur3/commons.d.ts +0 -12
  259. package/types/utils/settingsValidation/buildMetadata.d.ts +0 -3
  260. package/types/utils/settingsValidation/localhost/index.d.ts +0 -9
  261. package/types/utils/settingsValidation/logger.d.ts +0 -11
  262. package/types/utils/settingsValidation/runtime/browser.d.ts +0 -2
  263. package/types/utils/settingsValidation/runtime/node.d.ts +0 -2
  264. package/types/utils/settingsValidation/userConsent.d.ts +0 -5
  265. package/types/utils/timeTracker/index.d.ts +0 -1
@@ -1,4 +1,10 @@
1
+ import { parseExceptionField, parseLatencyField, parseMetadata } from '../KeyBuilderSS';
1
2
  import { findLatencyIndex } from '../findLatencyIndex';
3
+ import { getTelemetryConfigStats } from '../../sync/submitters/telemetrySubmitter';
4
+ import { CONSUMER_MODE, STORAGE_PLUGGABLE } from '../../utils/constants';
5
+ import { isString, isNaNNumber } from '../../utils/lang';
6
+ import { _Map } from '../../utils/lang/maps';
7
+ import { MAX_LATENCY_BUCKET_COUNT, newBuckets } from '../inMemory/TelemetryCacheInMemory';
2
8
  var TelemetryCachePluggable = /** @class */ (function () {
3
9
  /**
4
10
  * Create a Telemetry cache that uses a storage wrapper.
@@ -19,6 +25,126 @@ var TelemetryCachePluggable = /** @class */ (function () {
19
25
  return this.wrapper.incr(this.keys.buildExceptionKey(method))
20
26
  .catch(function () { });
21
27
  };
28
+ TelemetryCachePluggable.prototype.recordConfig = function () {
29
+ var value = JSON.stringify(getTelemetryConfigStats(CONSUMER_MODE, STORAGE_PLUGGABLE));
30
+ return this.wrapper.set(this.keys.buildInitKey(), value).catch(function () { });
31
+ };
32
+ /**
33
+ * Pop telemetry latencies.
34
+ * The returned promise rejects if wrapper operations fail.
35
+ */
36
+ TelemetryCachePluggable.prototype.popLatencies = function () {
37
+ var _this = this;
38
+ return this.wrapper.getKeysByPrefix(this.keys.latencyPrefix).then(function (latencyKeys) {
39
+ return latencyKeys.length ?
40
+ _this.wrapper.getMany(latencyKeys).then(function (latencies) {
41
+ var result = new _Map();
42
+ for (var i = 0; i < latencyKeys.length; i++) {
43
+ var field = latencyKeys[i].split('::')[1];
44
+ var parsedField = parseLatencyField(field);
45
+ if (isString(parsedField)) {
46
+ _this.log.error("Ignoring invalid latency field: " + field + ": " + parsedField);
47
+ continue;
48
+ }
49
+ // @ts-ignore
50
+ var count = parseInt(latencies[i]);
51
+ if (isNaNNumber(count)) {
52
+ _this.log.error("Ignoring latency with invalid count: " + latencies[i]);
53
+ continue;
54
+ }
55
+ var metadata = parsedField[0], method = parsedField[1], bucket = parsedField[2];
56
+ if (bucket >= MAX_LATENCY_BUCKET_COUNT) {
57
+ _this.log.error("Ignoring latency with invalid bucket: " + bucket);
58
+ continue;
59
+ }
60
+ if (!result.has(metadata))
61
+ result.set(metadata, {
62
+ t: newBuckets(),
63
+ ts: newBuckets(),
64
+ tc: newBuckets(),
65
+ tcs: newBuckets(),
66
+ tr: newBuckets(),
67
+ });
68
+ result.get(metadata)[method][bucket] = count;
69
+ }
70
+ return Promise.all(latencyKeys.map(function (latencyKey) { return _this.wrapper.del(latencyKey); })).then(function () { return result; });
71
+ }) :
72
+ // If latencyKeys is empty, return an empty map.
73
+ new _Map();
74
+ });
75
+ };
76
+ /**
77
+ * Pop telemetry exceptions.
78
+ * The returned promise rejects if wrapper operations fail.
79
+ */
80
+ TelemetryCachePluggable.prototype.popExceptions = function () {
81
+ var _this = this;
82
+ return this.wrapper.getKeysByPrefix(this.keys.exceptionPrefix).then(function (exceptionKeys) {
83
+ return exceptionKeys.length ?
84
+ _this.wrapper.getMany(exceptionKeys).then(function (exceptions) {
85
+ var result = new _Map();
86
+ for (var i = 0; i < exceptionKeys.length; i++) {
87
+ var field = exceptionKeys[i].split('::')[1];
88
+ var parsedField = parseExceptionField(field);
89
+ if (isString(parsedField)) {
90
+ _this.log.error("Ignoring invalid exception field: " + field + ": " + parsedField);
91
+ continue;
92
+ }
93
+ // @ts-ignore
94
+ var count = parseInt(exceptions[i]);
95
+ if (isNaNNumber(count)) {
96
+ _this.log.error("Ignoring exception with invalid count: " + exceptions[i]);
97
+ continue;
98
+ }
99
+ var metadata = parsedField[0], method = parsedField[1];
100
+ if (!result.has(metadata))
101
+ result.set(metadata, {
102
+ t: 0,
103
+ ts: 0,
104
+ tc: 0,
105
+ tcs: 0,
106
+ tr: 0,
107
+ });
108
+ result.get(metadata)[method] = count;
109
+ }
110
+ return Promise.all(exceptionKeys.map(function (exceptionKey) { return _this.wrapper.del(exceptionKey); })).then(function () { return result; });
111
+ }) :
112
+ // If exceptionKeys is empty, return an empty map.
113
+ new _Map();
114
+ });
115
+ };
116
+ /**
117
+ * Pop telemetry configs.
118
+ * The returned promise rejects if wrapper operations fail.
119
+ */
120
+ TelemetryCachePluggable.prototype.popConfigs = function () {
121
+ var _this = this;
122
+ return this.wrapper.getKeysByPrefix(this.keys.initPrefix).then(function (configKeys) {
123
+ return configKeys.length ?
124
+ _this.wrapper.getMany(configKeys).then(function (configs) {
125
+ var result = new _Map();
126
+ for (var i = 0; i < configKeys.length; i++) {
127
+ var field = configKeys[i].split('::')[1];
128
+ var parsedField = parseMetadata(field);
129
+ if (isString(parsedField)) {
130
+ _this.log.error("Ignoring invalid config field: " + field + ": " + parsedField);
131
+ continue;
132
+ }
133
+ var metadata = parsedField[0];
134
+ try { // @ts-ignore
135
+ var config = JSON.parse(configs[i]);
136
+ result.set(metadata, config);
137
+ }
138
+ catch (e) {
139
+ _this.log.error("Ignoring invalid config: " + configs[i]);
140
+ }
141
+ }
142
+ return Promise.all(configKeys.map(function (configKey) { return _this.wrapper.del(configKey); })).then(function () { return result; });
143
+ }) :
144
+ // If configKeys is empty, return an empty map.
145
+ new _Map();
146
+ });
147
+ };
22
148
  return TelemetryCachePluggable;
23
149
  }());
24
150
  export { TelemetryCachePluggable };
@@ -0,0 +1,47 @@
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
+ return UniqueKeysCachePluggable;
46
+ }(UniqueKeysCacheInMemory));
47
+ export { UniqueKeysCachePluggable };
@@ -7,10 +7,16 @@ 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
+ import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
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';
14
20
  var NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.';
15
21
  var NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.';
16
22
  /**
@@ -27,15 +33,6 @@ function validatePluggableStorageOptions(options) {
27
33
  if (missingMethods.length)
28
34
  throw new Error(NO_VALID_WRAPPER_INTERFACE + " The following methods are missing or invalid: " + missingMethods);
29
35
  }
30
- // subscription to wrapper connect event in order to emit SDK_READY event
31
- function wrapperConnect(wrapper, onReadyCb) {
32
- wrapper.connect().then(function () {
33
- onReadyCb();
34
- // At the moment, we don't synchronize config with pluggable storage
35
- }).catch(function (e) {
36
- onReadyCb(e || new Error('Error connecting wrapper'));
37
- });
38
- }
39
36
  // Async return type in `client.track` method on consumer partial mode
40
37
  // No need to promisify impressions cache
41
38
  function promisifyEventsTrack(events) {
@@ -51,28 +48,56 @@ function promisifyEventsTrack(events) {
51
48
  export function PluggableStorage(options) {
52
49
  validatePluggableStorageOptions(options);
53
50
  var prefix = validatePrefix(options.prefix);
54
- function PluggableStorageFactory(_a) {
55
- var log = _a.log, metadata = _a.metadata, onReadyCb = _a.onReadyCb, mode = _a.mode, eventsQueueSize = _a.eventsQueueSize, impressionsQueueSize = _a.impressionsQueueSize, optimize = _a.optimize;
51
+ function PluggableStorageFactory(params) {
52
+ var log = params.log, metadata = params.metadata, onReadyCb = params.onReadyCb, mode = params.mode, eventsQueueSize = params.eventsQueueSize, impressionsQueueSize = params.impressionsQueueSize, impressionsMode = params.impressionsMode, matchingKey = params.matchingKey;
56
53
  var keys = new KeyBuilderSS(prefix, metadata);
57
54
  var wrapper = wrapperAdapter(log, options.wrapper);
58
55
  var isPartialConsumer = mode === CONSUMER_PARTIAL_MODE;
56
+ var telemetry = shouldRecordTelemetry(params) ?
57
+ isPartialConsumer ? new TelemetryCacheInMemory() : new TelemetryCachePluggable(log, keys, wrapper) :
58
+ undefined;
59
+ var impressionCountsCache = impressionsMode !== DEBUG ?
60
+ isPartialConsumer ? new ImpressionCountsCacheInMemory() : new ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper) :
61
+ undefined;
62
+ var uniqueKeysCache = impressionsMode === NONE ?
63
+ isPartialConsumer ?
64
+ matchingKey === undefined ? new UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS() :
65
+ new UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper) :
66
+ undefined;
59
67
  // Connects to wrapper and emits SDK_READY event on main client
60
- wrapperConnect(wrapper, onReadyCb);
68
+ var connectPromise = wrapper.connect().then(function () {
69
+ onReadyCb();
70
+ // Start periodic flush of async storages
71
+ if (impressionCountsCache && impressionCountsCache.start)
72
+ impressionCountsCache.start();
73
+ if (uniqueKeysCache && uniqueKeysCache.start)
74
+ uniqueKeysCache.start();
75
+ // If mode is not defined, it means that the synchronizer is running and so we don't have to record telemetry
76
+ if (telemetry && telemetry.recordConfig && mode)
77
+ telemetry.recordConfig();
78
+ }).catch(function (e) {
79
+ e = e || new Error('Error connecting wrapper');
80
+ onReadyCb(e);
81
+ return e;
82
+ });
61
83
  return {
62
84
  splits: new SplitsCachePluggable(log, keys, wrapper),
63
85
  segments: new SegmentsCachePluggable(log, keys, wrapper),
64
86
  impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
65
- impressionCounts: optimize ? new ImpressionCountsCacheInMemory() : undefined,
87
+ impressionCounts: impressionCountsCache,
66
88
  events: isPartialConsumer ? promisifyEventsTrack(new EventsCacheInMemory(eventsQueueSize)) : new EventsCachePluggable(log, keys.buildEventsKey(), wrapper, metadata),
67
- // @TODO Not using TelemetryCachePluggable yet because it's not supported by the Split Synchronizer, and needs to drop or queue operations while the wrapper is not ready
68
- // telemetry: isPartialConsumer ? new TelemetryCacheInMemory() : new TelemetryCachePluggable(log, keys, wrapper),
89
+ telemetry: telemetry,
90
+ uniqueKeys: uniqueKeysCache,
69
91
  // Disconnect the underlying storage
70
92
  destroy: function () {
71
- return wrapper.disconnect();
93
+ return Promise.all([
94
+ impressionCountsCache && impressionCountsCache.stop && impressionCountsCache.stop(),
95
+ uniqueKeysCache && uniqueKeysCache.stop && uniqueKeysCache.stop(),
96
+ ]).then(function () { return wrapper.disconnect(); });
72
97
  },
73
98
  // emits SDK_READY event on shared clients and returns a reference to the storage
74
99
  shared: function (_, onReadyCb) {
75
- wrapperConnect(wrapper, onReadyCb);
100
+ connectPromise.then(onReadyCb);
76
101
  return __assign(__assign({}, this), {
77
102
  // no-op destroy, to disconnect the wrapper only when the main client is destroyed
78
103
  destroy: function () { } });
@@ -24,8 +24,7 @@ export function fromObjectUpdaterFactory(splitsParser, storage, readiness, setti
24
24
  log.debug(SYNC_OFFLINE_DATA, [JSON.stringify(splitsMock)]);
25
25
  forOwn(splitsMock, function (val, name) {
26
26
  splits.push([
27
- name,
28
- JSON.stringify({
27
+ name, {
29
28
  name: name,
30
29
  status: 'ACTIVE',
31
30
  killed: false,
@@ -34,7 +33,7 @@ export function fromObjectUpdaterFactory(splitsParser, storage, readiness, setti
34
33
  conditions: val.conditions || [],
35
34
  configurations: val.configurations,
36
35
  trafficTypeName: val.trafficTypeName
37
- })
36
+ }
38
37
  ]);
39
38
  });
40
39
  return Promise.all([
@@ -37,7 +37,7 @@ export function computeSplitsMutation(entries) {
37
37
  var segments = new _Set();
38
38
  var computed = entries.reduce(function (accum, split) {
39
39
  if (split.status === 'ACTIVE') {
40
- accum.added.push([split.name, JSON.stringify(split)]);
40
+ accum.added.push([split.name, split]);
41
41
  parseSegments(split).forEach(function (segmentName) {
42
42
  segments.add(segmentName);
43
43
  });
@@ -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.uniqueKeysTracker)
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,11 +1,12 @@
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 { QUEUED, DEDUPED, DROPPED, 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';
9
10
  /**
10
11
  * Converts data from telemetry cache into /metrics/usage request payload.
11
12
  */
@@ -26,9 +27,9 @@ export function telemetryCacheStatsAdapter(telemetry, splits, segments) {
26
27
  iQ: telemetry.getImpressionStats(QUEUED),
27
28
  iDe: telemetry.getImpressionStats(DEDUPED),
28
29
  iDr: telemetry.getImpressionStats(DROPPED),
29
- spC: splits.getSplitNames().length,
30
- seC: segments.getRegisteredSegments().length,
31
- skC: segments.getKeysCount(),
30
+ spC: splits && splits.getSplitNames().length,
31
+ seC: segments && segments.getRegisteredSegments().length,
32
+ skC: segments && segments.getKeysCount(),
32
33
  sL: telemetry.getSessionLength(),
33
34
  eQ: telemetry.getEventStats(QUEUED),
34
35
  eD: telemetry.getEventStats(DROPPED),
@@ -46,6 +47,7 @@ var OPERATION_MODE_MAP = (_a = {},
46
47
  var IMPRESSIONS_MODE_MAP = (_b = {},
47
48
  _b[OPTIMIZED] = OPTIMIZED_ENUM,
48
49
  _b[DEBUG] = DEBUG_ENUM,
50
+ _b[NONE] = NONE_ENUM,
49
51
  _b);
50
52
  var USER_CONSENT_MAP = (_c = {},
51
53
  _c[CONSENT_UNKNOWN] = 1,
@@ -119,7 +121,9 @@ export function telemetrySubmitterFactory(params) {
119
121
  return; // No submitter created if telemetry cache is not defined
120
122
  var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, readiness = params.readiness, sdkReadinessManager = params.sdkReadinessManager;
121
123
  var startTime = timer(now);
122
- var submitter = firstPushWindowDecorator(submitterFactory(log, splitApi.postMetricsUsage, telemetryCacheStatsAdapter(telemetry, splits, segments), telemetryRefreshRate, 'telemetry stats', undefined, 0, true), telemetryRefreshRate);
124
+ var submitter = firstPushWindowDecorator(submitterFactory(log, splitApi.postMetricsUsage,
125
+ // @TODO cannot provide splits and segments cache if they are async, because `submitterFactory` expects a sync storage source
126
+ isStorageSync(params.settings) ? telemetryCacheStatsAdapter(telemetry, splits, segments) : telemetryCacheStatsAdapter(telemetry), telemetryRefreshRate, 'telemetry stats', undefined, 0, true), telemetryRefreshRate);
123
127
  readiness.gate.once(SDK_READY_FROM_CACHE, function () {
124
128
  telemetry.recordTimeUntilReadyFromCache(startTime());
125
129
  });
@@ -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,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
+ }
@@ -46,6 +46,11 @@ export function telemetryTrackerFactory(telemetryCache, now) {
46
46
  if (e === TOKEN_REFRESH)
47
47
  telemetryCache.recordTokenRefreshes();
48
48
  }
49
+ },
50
+ addTag: function (tag) {
51
+ // @ts-ignore
52
+ if (telemetryCache.addTag)
53
+ telemetryCache.addTag(tag);
49
54
  }
50
55
  };
51
56
  }
@@ -56,6 +61,7 @@ export function telemetryTrackerFactory(telemetryCache, now) {
56
61
  trackHttp: noopTrack,
57
62
  sessionLength: function () { },
58
63
  streamingEvent: function () { },
64
+ addTag: function () { }
59
65
  };
60
66
  }
61
67
  }
@@ -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
+ }