@splitsoftware/splitio-commons 1.6.2-rc.1 → 1.6.2-rc.11

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 (197) 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/sdkClient/client.js +19 -7
  6. package/cjs/sdkClient/sdkClient.js +3 -1
  7. package/cjs/sdkFactory/index.js +15 -6
  8. package/cjs/sdkManager/index.js +3 -11
  9. package/cjs/services/splitApi.js +6 -6
  10. package/cjs/storages/AbstractSplitsCacheAsync.js +8 -10
  11. package/cjs/storages/AbstractSplitsCacheSync.js +8 -10
  12. package/cjs/storages/KeyBuilderSS.js +54 -9
  13. package/cjs/storages/dataLoader.js +1 -1
  14. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +5 -7
  15. package/cjs/storages/inLocalStorage/index.js +5 -1
  16. package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +12 -1
  17. package/cjs/storages/inMemory/InMemoryStorage.js +6 -2
  18. package/cjs/storages/inMemory/InMemoryStorageCS.js +6 -2
  19. package/cjs/storages/inMemory/SplitsCacheInMemory.js +7 -10
  20. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +10 -5
  21. package/cjs/storages/inMemory/UniqueKeysCacheInMemory.js +72 -0
  22. package/cjs/storages/inMemory/UniqueKeysCacheInMemoryCS.js +76 -0
  23. package/cjs/storages/inRedis/EventsCacheInRedis.js +1 -1
  24. package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +85 -0
  25. package/cjs/storages/inRedis/SplitsCacheInRedis.js +15 -9
  26. package/cjs/storages/inRedis/TelemetryCacheInRedis.js +100 -0
  27. package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +71 -0
  28. package/cjs/storages/inRedis/constants.js +4 -1
  29. package/cjs/storages/inRedis/index.js +17 -2
  30. package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +81 -0
  31. package/cjs/storages/pluggable/SplitsCachePluggable.js +14 -9
  32. package/cjs/storages/pluggable/TelemetryCachePluggable.js +126 -0
  33. package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +61 -0
  34. package/cjs/storages/pluggable/index.js +46 -17
  35. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
  36. package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -1
  37. package/cjs/sync/submitters/telemetrySubmitter.js +8 -4
  38. package/cjs/sync/submitters/uniqueKeysSubmitter.js +16 -59
  39. package/cjs/trackers/impressionsTracker.js +17 -15
  40. package/cjs/trackers/strategy/strategyNone.js +1 -1
  41. package/cjs/trackers/strategy/strategyOptimized.js +2 -1
  42. package/cjs/trackers/telemetryTracker.js +6 -0
  43. package/cjs/trackers/uniqueKeysTracker.js +11 -42
  44. package/cjs/utils/constants/index.js +3 -2
  45. package/cjs/utils/lang/maps.js +15 -7
  46. package/cjs/utils/redis/RedisMock.js +31 -0
  47. package/cjs/utils/settingsValidation/index.js +0 -3
  48. package/esm/consent/sdkUserConsent.js +2 -2
  49. package/esm/evaluator/index.js +15 -16
  50. package/esm/integrations/ga/GaToSplit.js +8 -5
  51. package/esm/sdkClient/client.js +19 -7
  52. package/esm/sdkClient/sdkClient.js +3 -1
  53. package/esm/sdkFactory/index.js +16 -7
  54. package/esm/sdkManager/index.js +3 -11
  55. package/esm/services/splitApi.js +6 -6
  56. package/esm/storages/AbstractSplitsCacheAsync.js +8 -10
  57. package/esm/storages/AbstractSplitsCacheSync.js +8 -10
  58. package/esm/storages/KeyBuilderSS.js +50 -8
  59. package/esm/storages/dataLoader.js +1 -1
  60. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +5 -7
  61. package/esm/storages/inLocalStorage/index.js +6 -2
  62. package/esm/storages/inMemory/ImpressionCountsCacheInMemory.js +12 -1
  63. package/esm/storages/inMemory/InMemoryStorage.js +8 -4
  64. package/esm/storages/inMemory/InMemoryStorageCS.js +7 -3
  65. package/esm/storages/inMemory/SplitsCacheInMemory.js +7 -10
  66. package/esm/storages/inMemory/TelemetryCacheInMemory.js +9 -5
  67. package/esm/storages/inMemory/UniqueKeysCacheInMemory.js +68 -0
  68. package/esm/storages/inMemory/UniqueKeysCacheInMemoryCS.js +73 -0
  69. package/esm/storages/inRedis/EventsCacheInRedis.js +1 -1
  70. package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +82 -0
  71. package/esm/storages/inRedis/SplitsCacheInRedis.js +15 -9
  72. package/esm/storages/inRedis/TelemetryCacheInRedis.js +100 -0
  73. package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +68 -0
  74. package/esm/storages/inRedis/constants.js +3 -0
  75. package/esm/storages/inRedis/index.js +18 -3
  76. package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +78 -0
  77. package/esm/storages/pluggable/SplitsCachePluggable.js +14 -9
  78. package/esm/storages/pluggable/TelemetryCachePluggable.js +126 -0
  79. package/esm/storages/pluggable/UniqueKeysCachePluggable.js +58 -0
  80. package/esm/storages/pluggable/index.js +47 -18
  81. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
  82. package/esm/sync/polling/updaters/splitChangesUpdater.js +1 -1
  83. package/esm/sync/submitters/telemetrySubmitter.js +9 -5
  84. package/esm/sync/submitters/uniqueKeysSubmitter.js +15 -56
  85. package/esm/trackers/impressionsTracker.js +17 -15
  86. package/esm/trackers/strategy/strategyNone.js +1 -1
  87. package/esm/trackers/strategy/strategyOptimized.js +2 -1
  88. package/esm/trackers/telemetryTracker.js +6 -0
  89. package/esm/trackers/uniqueKeysTracker.js +11 -42
  90. package/esm/utils/constants/index.js +1 -0
  91. package/esm/utils/lang/maps.js +15 -7
  92. package/esm/utils/redis/RedisMock.js +28 -0
  93. package/esm/utils/settingsValidation/index.js +0 -3
  94. package/package.json +1 -2
  95. package/src/consent/sdkUserConsent.ts +2 -2
  96. package/src/evaluator/index.ts +14 -15
  97. package/src/integrations/ga/GaToSplit.ts +9 -5
  98. package/src/integrations/types.ts +2 -1
  99. package/src/logger/.DS_Store +0 -0
  100. package/src/sdkClient/client.ts +21 -8
  101. package/src/sdkClient/sdkClient.ts +3 -1
  102. package/src/sdkFactory/index.ts +17 -7
  103. package/src/sdkManager/index.ts +3 -12
  104. package/src/services/splitApi.ts +6 -6
  105. package/src/services/types.ts +2 -2
  106. package/src/storages/AbstractSplitsCacheAsync.ts +13 -15
  107. package/src/storages/AbstractSplitsCacheSync.ts +15 -17
  108. package/src/storages/KeyBuilderSS.ts +61 -9
  109. package/src/storages/dataLoader.ts +1 -1
  110. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +8 -11
  111. package/src/storages/inLocalStorage/index.ts +5 -2
  112. package/src/storages/inMemory/ImpressionCountsCacheInMemory.ts +16 -1
  113. package/src/storages/inMemory/InMemoryStorage.ts +7 -4
  114. package/src/storages/inMemory/InMemoryStorageCS.ts +6 -3
  115. package/src/storages/inMemory/SplitsCacheInMemory.ts +10 -14
  116. package/src/storages/inMemory/TelemetryCacheInMemory.ts +10 -6
  117. package/src/storages/inMemory/UniqueKeysCacheInMemory.ts +80 -0
  118. package/src/storages/inMemory/UniqueKeysCacheInMemoryCS.ts +86 -0
  119. package/src/storages/inRedis/EventsCacheInRedis.ts +1 -1
  120. package/src/storages/inRedis/ImpressionCountsCacheInRedis.ts +95 -0
  121. package/src/storages/inRedis/SplitsCacheInRedis.ts +21 -17
  122. package/src/storages/inRedis/TelemetryCacheInRedis.ts +122 -2
  123. package/src/storages/inRedis/UniqueKeysCacheInRedis.ts +77 -0
  124. package/src/storages/inRedis/constants.ts +3 -0
  125. package/src/storages/inRedis/index.ts +15 -5
  126. package/src/storages/pluggable/ImpressionCountsCachePluggable.ts +92 -0
  127. package/src/storages/pluggable/SplitsCachePluggable.ts +20 -17
  128. package/src/storages/pluggable/TelemetryCachePluggable.ts +147 -2
  129. package/src/storages/pluggable/UniqueKeysCachePluggable.ts +67 -0
  130. package/src/storages/pluggable/index.ts +51 -19
  131. package/src/storages/types.ts +38 -30
  132. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +5 -6
  133. package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -2
  134. package/src/sync/submitters/telemetrySubmitter.ts +15 -8
  135. package/src/sync/submitters/types.ts +26 -12
  136. package/src/sync/submitters/uniqueKeysSubmitter.ts +18 -61
  137. package/src/trackers/impressionsTracker.ts +16 -15
  138. package/src/trackers/strategy/strategyNone.ts +1 -1
  139. package/src/trackers/strategy/strategyOptimized.ts +1 -1
  140. package/src/trackers/telemetryTracker.ts +7 -2
  141. package/src/trackers/types.ts +9 -7
  142. package/src/trackers/uniqueKeysTracker.ts +15 -47
  143. package/src/types.ts +0 -1
  144. package/src/utils/constants/index.ts +1 -0
  145. package/src/utils/lang/maps.ts +20 -8
  146. package/src/utils/redis/RedisMock.ts +33 -0
  147. package/src/utils/settingsValidation/index.ts +1 -4
  148. package/types/integrations/types.d.ts +2 -1
  149. package/types/services/types.d.ts +2 -2
  150. package/types/storages/AbstractSplitsCacheAsync.d.ts +7 -6
  151. package/types/storages/AbstractSplitsCacheSync.d.ts +6 -6
  152. package/types/storages/KeyBuilderSS.d.ts +9 -2
  153. package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +3 -4
  154. package/types/storages/inMemory/ImpressionCountsCacheInMemory.d.ts +5 -1
  155. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +3 -2
  156. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -3
  157. package/types/storages/inMemory/uniqueKeysCacheInMemory.d.ts +35 -0
  158. package/types/storages/inMemory/uniqueKeysCacheInMemoryCS.d.ts +35 -0
  159. package/types/storages/inRedis/EventsCacheInRedis.d.ts +1 -1
  160. package/types/storages/inRedis/ImpressionCountsCacheInRedis.d.ts +16 -0
  161. package/types/storages/inRedis/SplitsCacheInRedis.d.ts +6 -5
  162. package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +16 -1
  163. package/types/storages/inRedis/constants.d.ts +3 -0
  164. package/types/storages/inRedis/uniqueKeysCacheInRedis.d.ts +21 -0
  165. package/types/storages/pluggable/ImpressionCountsCachePluggable.d.ts +16 -0
  166. package/types/storages/pluggable/SplitsCachePluggable.d.ts +6 -5
  167. package/types/storages/pluggable/TelemetryCachePluggable.d.ts +17 -1
  168. package/types/storages/pluggable/UniqueKeysCachePluggable.d.ts +20 -0
  169. package/types/storages/types.d.ts +35 -35
  170. package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -1
  171. package/types/sync/submitters/telemetrySubmitter.d.ts +1 -1
  172. package/types/sync/submitters/types.d.ts +19 -12
  173. package/types/sync/submitters/uniqueKeysSubmitter.d.ts +0 -14
  174. package/types/trackers/types.d.ts +9 -11
  175. package/types/trackers/uniqueKeysTracker.d.ts +3 -3
  176. package/types/types.d.ts +0 -1
  177. package/types/utils/constants/index.d.ts +1 -0
  178. package/types/utils/lang/maps.d.ts +6 -2
  179. package/types/utils/redis/RedisMock.d.ts +4 -0
  180. package/types/utils/settingsValidation/index.d.ts +0 -1
  181. package/types/sdkClient/types.d.ts +0 -18
  182. package/types/storages/inMemory/CountsCacheInMemory.d.ts +0 -20
  183. package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +0 -20
  184. package/types/storages/inRedis/CountsCacheInRedis.d.ts +0 -9
  185. package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +0 -9
  186. package/types/sync/offline/LocalhostFromFile.d.ts +0 -2
  187. package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +0 -2
  188. package/types/sync/submitters/eventsSyncTask.d.ts +0 -8
  189. package/types/sync/submitters/impressionCountsSyncTask.d.ts +0 -13
  190. package/types/sync/submitters/impressionsSyncTask.d.ts +0 -14
  191. package/types/sync/submitters/metricsSyncTask.d.ts +0 -12
  192. package/types/sync/submitters/submitterSyncTask.d.ts +0 -10
  193. package/types/sync/syncTaskComposite.d.ts +0 -5
  194. package/types/trackers/filter/bloomFilter.d.ts +0 -10
  195. package/types/trackers/filter/dictionaryFilter.d.ts +0 -8
  196. package/types/trackers/filter/types.d.ts +0 -5
  197. package/types/utils/timeTracker/index.d.ts +0 -70
@@ -30,26 +30,27 @@ export function impressionsTrackerFactory(
30
30
  if (settings.userConsent === CONSENT_DECLINED) return;
31
31
 
32
32
  const impressionsCount = impressions.length;
33
-
34
33
  const { impressionsToStore, impressionsToListener, deduped } = strategy.process(impressions);
35
34
 
36
35
  const impressionsToListenerCount = impressionsToListener.length;
37
36
 
38
- const res = impressionsCache.track(impressionsToStore);
37
+ if ( impressionsToStore.length>0 ){
38
+ const res = impressionsCache.track(impressionsToStore);
39
39
 
40
- // If we're on an async storage, handle error and log it.
41
- if (thenable(res)) {
42
- res.then(() => {
43
- log.info(IMPRESSIONS_TRACKER_SUCCESS, [impressionsCount]);
44
- }).catch(err => {
45
- log.error(ERROR_IMPRESSIONS_TRACKER, [impressionsCount, err]);
46
- });
47
- } else {
48
- // Record when impressionsCache is sync only (standalone mode)
49
- // @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
50
- if (telemetryCache) {
51
- (telemetryCache as ITelemetryCacheSync).recordImpressionStats(QUEUED, impressionsToStore.length);
52
- (telemetryCache as ITelemetryCacheSync).recordImpressionStats(DEDUPED, deduped);
40
+ // If we're on an async storage, handle error and log it.
41
+ if (thenable(res)) {
42
+ res.then(() => {
43
+ log.info(IMPRESSIONS_TRACKER_SUCCESS, [impressionsCount]);
44
+ }).catch(err => {
45
+ log.error(ERROR_IMPRESSIONS_TRACKER, [impressionsCount, err]);
46
+ });
47
+ } else {
48
+ // Record when impressionsCache is sync only (standalone mode)
49
+ // @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
50
+ if (telemetryCache) {
51
+ (telemetryCache as ITelemetryCacheSync).recordImpressionStats(QUEUED, impressionsToStore.length);
52
+ (telemetryCache as ITelemetryCacheSync).recordImpressionStats(DEDUPED, deduped);
53
+ }
53
54
  }
54
55
  }
55
56
 
@@ -21,7 +21,7 @@ export function strategyNoneFactory(
21
21
  // Increments impression counter per featureName
22
22
  impressionsCounter.track(impression.feature, now, 1);
23
23
  // Keep track by unique key
24
- uniqueKeysTracker.track(impression.feature, impression.keyName);
24
+ uniqueKeysTracker.track(impression.keyName, impression.feature);
25
25
  });
26
26
 
27
27
  return {
@@ -25,7 +25,7 @@ export function strategyOptimizedFactory(
25
25
  const now = Date.now();
26
26
 
27
27
  // Increments impression counter per featureName
28
- impressionsCounter.track(impression.feature, now, 1);
28
+ if (impression.pt) impressionsCounter.track(impression.feature, now, 1);
29
29
 
30
30
  // Checks if the impression should be added in queue to be sent
31
31
  if (!impression.pt || impression.pt < truncateTimeFrame(now)) {
@@ -48,6 +48,10 @@ export function telemetryTrackerFactory(
48
48
  });
49
49
  if (e === TOKEN_REFRESH) (telemetryCache as ITelemetryCacheSync).recordTokenRefreshes();
50
50
  }
51
+ },
52
+ addTag(tag: string) {
53
+ // @ts-ignore
54
+ if (telemetryCache.addTag) telemetryCache.addTag(tag);
51
55
  }
52
56
  };
53
57
 
@@ -56,8 +60,9 @@ export function telemetryTrackerFactory(
56
60
  return {
57
61
  trackEval: noopTrack,
58
62
  trackHttp: noopTrack,
59
- sessionLength: () => { },
60
- streamingEvent: () => { },
63
+ sessionLength() { },
64
+ streamingEvent() { },
65
+ addTag() { }
61
66
  };
62
67
  }
63
68
  }
@@ -2,7 +2,6 @@ import { SplitIO, ImpressionDTO } from '../types';
2
2
  import { StreamingEventType, Method, OperationType } from '../sync/submitters/types';
3
3
  import { IEventsCacheBase } from '../storages/types';
4
4
  import { NetworkError } from '../services/types';
5
- import { ISet } from '../utils/lang/sets';
6
5
 
7
6
  /** Events tracker */
8
7
 
@@ -42,12 +41,17 @@ export interface ITelemetryTracker {
42
41
  * Records streaming event
43
42
  */
44
43
  streamingEvent(e: StreamingEventType | AUTH_REJECTION, d?: number): void
44
+ /**
45
+ * Records tag
46
+ */
47
+ addTag(tag: string): void
45
48
  }
46
49
 
47
50
  export interface IFilterAdapter {
48
- add(featureName: string, key: string): boolean;
49
- contains(featureName: string, key: string): boolean;
51
+ add(key: string, featureName: string): boolean;
52
+ contains(key: string, featureName: string): boolean;
50
53
  clear(): void;
54
+ refreshRate?: number;
51
55
  }
52
56
 
53
57
  export interface IImpressionSenderAdapter {
@@ -57,10 +61,8 @@ export interface IImpressionSenderAdapter {
57
61
 
58
62
  /** Unique keys tracker */
59
63
  export interface IUniqueKeysTracker {
60
- track(featureName: string, key: string): void;
61
- pop(toMerge?: { [featureName: string]: ISet<string> }): { [featureName: string]: ISet<string>; };
62
- clear(): void;
63
- isEmpty(): boolean;
64
+ stop(): void;
65
+ track(key: string, featureName: string): void;
64
66
  }
65
67
 
66
68
  export interface IStrategyResult {
@@ -1,6 +1,6 @@
1
1
  import { LOG_PREFIX_UNIQUE_KEYS_TRACKER } from '../logger/constants';
2
2
  import { ILogger } from '../logger/types';
3
- import { ISet, _Set } from '../utils/lang/sets';
3
+ import { IUniqueKeysCacheBase } from '../storages/types';
4
4
  import { IFilterAdapter, IUniqueKeysTracker } from './types';
5
5
 
6
6
  const noopFilterAdapter = {
@@ -9,70 +9,38 @@ const noopFilterAdapter = {
9
9
  clear() {}
10
10
  };
11
11
 
12
- const DEFAULT_CACHE_SIZE = 30000;
13
12
  /**
14
13
  * Trackes uniques keys
15
14
  * Unique Keys Tracker will be in charge of checking if the MTK was already sent to the BE in the last period
16
15
  * or schedule to be sent; if not it will be added in an internal cache and sent in the next post.
17
16
  *
18
17
  * @param log Logger instance
18
+ * @param uniqueKeysCache cache to save unique keys
19
19
  * @param filterAdapter filter adapter
20
- * @param cacheSize optional internal cache size
21
- * @param maxBulkSize optional max MTKs bulk size
22
20
  */
23
21
  export function uniqueKeysTrackerFactory(
24
22
  log: ILogger,
23
+ uniqueKeysCache: IUniqueKeysCacheBase,
25
24
  filterAdapter: IFilterAdapter = noopFilterAdapter,
26
- cacheSize = DEFAULT_CACHE_SIZE,
27
- // @TODO
28
- // maxBulkSize: number = 5000,
29
25
  ): IUniqueKeysTracker {
30
-
31
- let uniqueKeysTracker: { [featureName: string]: ISet<string> } = {};
32
- let uniqueTrackerSize = 0;
33
-
26
+ let intervalId: any;
27
+
28
+ if (filterAdapter.refreshRate) {
29
+ intervalId = setInterval(filterAdapter.clear, filterAdapter.refreshRate);
30
+ }
31
+
34
32
  return {
35
- track(featureName: string, key: string): void {
36
- if (!filterAdapter.add(featureName, key)) {
33
+
34
+ track(key: string, featureName: string): void {
35
+ if (!filterAdapter.add(key, featureName)) {
37
36
  log.debug(`${LOG_PREFIX_UNIQUE_KEYS_TRACKER}The feature ${featureName} and key ${key} exist in the filter`);
38
37
  return;
39
38
  }
40
- if (!uniqueKeysTracker[featureName]) uniqueKeysTracker[featureName] = new _Set();
41
- const tracker = uniqueKeysTracker[featureName];
42
- if (!tracker.has(key)) {
43
- tracker.add(key);
44
- log.debug(`${LOG_PREFIX_UNIQUE_KEYS_TRACKER}Key ${key} added to feature ${featureName}`);
45
- uniqueTrackerSize++;
46
- }
47
-
48
- if (uniqueTrackerSize >= cacheSize) {
49
- log.warn(`${LOG_PREFIX_UNIQUE_KEYS_TRACKER}The UniqueKeysTracker size reached the maximum limit`);
50
- // @TODO trigger event to submitter to send mtk
51
- uniqueTrackerSize = 0;
52
- }
53
- },
54
-
55
- /**
56
- * Pop the collected data, used as payload for posting.
57
- */
58
- pop() {
59
- const data = uniqueKeysTracker;
60
- uniqueKeysTracker = {};
61
- return data;
62
- },
63
-
64
- /**
65
- * Clear the data stored on the cache.
66
- */
67
- clear() {
68
- uniqueKeysTracker = {};
39
+ uniqueKeysCache.track(key, featureName);
69
40
  },
70
41
 
71
- /**
72
- * Check if the cache is empty.
73
- */
74
- isEmpty() {
75
- return Object.keys(uniqueKeysTracker).length === 0;
42
+ stop(): void {
43
+ clearInterval(intervalId);
76
44
  }
77
45
 
78
46
  };
package/src/types.ts CHANGED
@@ -80,7 +80,6 @@ export interface ISettings {
80
80
  featuresRefreshRate: number,
81
81
  impressionsRefreshRate: number,
82
82
  impressionsQueueSize: number,
83
- uniqueKeysRefreshRate: number,
84
83
  /**
85
84
  * @deprecated
86
85
  */
@@ -50,6 +50,7 @@ export const CONSUMER_PARTIAL_ENUM = 2;
50
50
 
51
51
  export const OPTIMIZED_ENUM = 0;
52
52
  export const DEBUG_ENUM = 1;
53
+ export const NONE_ENUM = 2;
53
54
 
54
55
  export const SPLITS = 'sp';
55
56
  export const IMPRESSIONS = 'im';
@@ -24,10 +24,12 @@ THE SOFTWARE.
24
24
  **/
25
25
 
26
26
  export interface IMap<K, V> {
27
- set(key: K, value: V): this;
28
27
  clear(): void;
29
28
  delete(key: K): boolean;
29
+ forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
30
30
  get(key: K): V | undefined;
31
+ has(key: K): boolean;
32
+ set(key: K, value: V): this;
31
33
  readonly size: number;
32
34
  }
33
35
 
@@ -46,13 +48,6 @@ export class MapPoly<K, V> implements IMap<K, V>{
46
48
  this.__mapValuesData__.length = 0;
47
49
  }
48
50
 
49
- set(key: K, value: V) {
50
- let index = this.__mapKeysData__.indexOf(key);
51
- if (index === -1) index = this.__mapKeysData__.push(key) - 1;
52
- this.__mapValuesData__[index] = value;
53
- return this;
54
- }
55
-
56
51
  delete(key: K) {
57
52
  const index = this.__mapKeysData__.indexOf(key);
58
53
  if (index === -1) return false;
@@ -61,12 +56,29 @@ export class MapPoly<K, V> implements IMap<K, V>{
61
56
  return true;
62
57
  }
63
58
 
59
+ forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any) {
60
+ for (let i = 0; i < this.__mapKeysData__.length; i++) {
61
+ callbackfn.call(thisArg, this.__mapValuesData__[i], this.__mapKeysData__[i], this as any);
62
+ }
63
+ }
64
+
64
65
  get(key: K) {
65
66
  const index = this.__mapKeysData__.indexOf(key);
66
67
  if (index === -1) return;
67
68
  return this.__mapValuesData__[index];
68
69
  }
69
70
 
71
+ has(key: K): boolean {
72
+ return this.__mapKeysData__.indexOf(key) !== -1;
73
+ }
74
+
75
+ set(key: K, value: V) {
76
+ let index = this.__mapKeysData__.indexOf(key);
77
+ if (index === -1) index = this.__mapKeysData__.push(key) - 1;
78
+ this.__mapValuesData__[index] = value;
79
+ return this;
80
+ }
81
+
70
82
  get size() {
71
83
  return this.__mapKeysData__.length;
72
84
  }
@@ -0,0 +1,33 @@
1
+ //@ts-nocheck
2
+ function identityFunction(data: any): any {
3
+ return data;
4
+ }
5
+
6
+ function asyncFunction(data: any): Promise<any> {
7
+ return Promise.resolve(data);
8
+ }
9
+
10
+ const IDENTITY_METHODS: string[] = [];
11
+ const ASYNC_METHODS = ['rpush', 'hincrby'];
12
+ const PIPELINE_METHODS = ['rpush', 'hincrby'];
13
+
14
+ export class RedisMock {
15
+
16
+ private pipelineMethods: any = { exec: jest.fn(asyncFunction) }
17
+
18
+ constructor() {
19
+ IDENTITY_METHODS.forEach(method => {
20
+ this[method] = jest.fn(identityFunction);
21
+ });
22
+ ASYNC_METHODS.forEach(method => {
23
+ this[method] = jest.fn(asyncFunction);
24
+ });
25
+ PIPELINE_METHODS.forEach(method => {
26
+ this.pipelineMethods[method] = this[method];
27
+ });
28
+
29
+ this.pipeline = jest.fn(() => {return this.pipelineMethods;});
30
+ }
31
+
32
+
33
+ }
@@ -36,8 +36,6 @@ export const base = {
36
36
  telemetryRefreshRate: 3600,
37
37
  // publish evaluations each 300 sec (default value for OPTIMIZED impressions mode)
38
38
  impressionsRefreshRate: 300,
39
- // publish unique Keys each 900 sec (15 min)
40
- uniqueKeysRefreshRate: 900,
41
39
  // fetch offline changes each 15 sec
42
40
  offlineRefreshRate: 15,
43
41
  // publish events every 60 seconds after the first flush
@@ -132,13 +130,12 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
132
130
  scheduler.segmentsRefreshRate = fromSecondsToMillis(scheduler.segmentsRefreshRate);
133
131
  scheduler.offlineRefreshRate = fromSecondsToMillis(scheduler.offlineRefreshRate);
134
132
  scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate);
135
- scheduler.uniqueKeysRefreshRate = fromSecondsToMillis(scheduler.uniqueKeysRefreshRate);
136
133
  scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
137
134
 
138
135
  // Default impressionsRefreshRate for DEBUG mode is 60 secs
139
136
  if (get(config, 'scheduler.impressionsRefreshRate') === undefined && withDefaults.sync.impressionsMode === DEBUG) scheduler.impressionsRefreshRate = 60;
140
137
  scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
141
-
138
+
142
139
 
143
140
  // Log deprecation for old telemetry param
144
141
  if (scheduler.metricsRefreshRate) log.warn('`metricsRefreshRate` will be deprecated soon. For configuring telemetry rates, update `telemetryRefreshRate` value in configs');
@@ -1,5 +1,5 @@
1
1
  import { IEventsCacheBase } from '../storages/types';
2
- import { IEventsHandler, IImpressionsHandler } from '../trackers/types';
2
+ import { IEventsHandler, IImpressionsHandler, ITelemetryTracker } from '../trackers/types';
3
3
  import { ISettings, SplitIO } from '../types';
4
4
  export interface IIntegration {
5
5
  queue(data: SplitIO.IntegrationData): void;
@@ -10,6 +10,7 @@ export interface IIntegrationFactoryParams {
10
10
  events: IEventsCacheBase;
11
11
  };
12
12
  settings: ISettings;
13
+ telemetryTracker: ITelemetryTracker;
13
14
  }
14
15
  export declare type IntegrationFactory = {
15
16
  readonly type: string;
@@ -24,8 +24,8 @@ export declare type IPostUniqueKeysBulkCs = (body: string, headers?: Record<stri
24
24
  export declare type IPostUniqueKeysBulkSs = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
25
25
  export declare type IPostTestImpressionsBulk = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
26
26
  export declare type IPostTestImpressionsCount = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
27
- export declare type IPostMetricsConfig = (body: string) => Promise<IResponse>;
28
- export declare type IPostMetricsUsage = (body: string) => Promise<IResponse>;
27
+ export declare type IPostMetricsConfig = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
28
+ export declare type IPostMetricsUsage = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
29
29
  export interface ISplitApi {
30
30
  getSdkAPIHealthCheck: IHealthCheckAPI;
31
31
  getEventsAPIHealthCheck: IHealthCheckAPI;
@@ -1,17 +1,18 @@
1
1
  import { ISplitsCacheAsync } from './types';
2
+ import { ISplit } from '../dtos/types';
2
3
  /**
3
4
  * This class provides a skeletal implementation of the ISplitsCacheAsync interface
4
5
  * to minimize the effort required to implement this interface.
5
6
  */
6
7
  export declare abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
7
- abstract addSplit(name: string, split: string): Promise<boolean>;
8
- abstract addSplits(entries: [string, string][]): Promise<boolean[] | void>;
8
+ abstract addSplit(name: string, split: ISplit): Promise<boolean>;
9
+ abstract addSplits(entries: [string, ISplit][]): Promise<boolean[] | void>;
9
10
  abstract removeSplits(names: string[]): Promise<boolean[] | void>;
10
- abstract getSplit(name: string): Promise<string | null>;
11
- abstract getSplits(names: string[]): Promise<Record<string, string | null>>;
11
+ abstract getSplit(name: string): Promise<ISplit | null>;
12
+ abstract getSplits(names: string[]): Promise<Record<string, ISplit | null>>;
12
13
  abstract setChangeNumber(changeNumber: number): Promise<boolean | void>;
13
14
  abstract getChangeNumber(): Promise<number>;
14
- abstract getAll(): Promise<string[]>;
15
+ abstract getAll(): Promise<ISplit[]>;
15
16
  abstract getSplitNames(): Promise<string[]>;
16
17
  abstract trafficTypeExists(trafficType: string): Promise<boolean>;
17
18
  abstract clear(): Promise<boolean | void>;
@@ -28,7 +29,7 @@ export declare abstract class AbstractSplitsCacheAsync implements ISplitsCacheAs
28
29
  * @param {string} name
29
30
  * @param {string} defaultTreatment
30
31
  * @param {number} changeNumber
31
- * @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,
32
+ * @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,
32
33
  * 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.
33
34
  * The promise will never be rejected.
34
35
  */
@@ -5,15 +5,15 @@ import { ISplit } from '../dtos/types';
5
5
  * to minimize the effort required to implement this interface.
6
6
  */
7
7
  export declare abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
8
- abstract addSplit(name: string, split: string): boolean;
9
- addSplits(entries: [string, string][]): boolean[];
8
+ abstract addSplit(name: string, split: ISplit): boolean;
9
+ addSplits(entries: [string, ISplit][]): boolean[];
10
10
  abstract removeSplit(name: string): boolean;
11
11
  removeSplits(names: string[]): boolean[];
12
- abstract getSplit(name: string): string | null;
13
- getSplits(names: string[]): Record<string, string | null>;
12
+ abstract getSplit(name: string): ISplit | null;
13
+ getSplits(names: string[]): Record<string, ISplit | null>;
14
14
  abstract setChangeNumber(changeNumber: number): boolean;
15
15
  abstract getChangeNumber(): number;
16
- getAll(): string[];
16
+ getAll(): ISplit[];
17
17
  abstract getSplitNames(): string[];
18
18
  abstract trafficTypeExists(trafficType: string): boolean;
19
19
  abstract usesSegments(): boolean;
@@ -30,7 +30,7 @@ export declare abstract class AbstractSplitsCacheSync implements ISplitsCacheSyn
30
30
  * @param {string} name
31
31
  * @param {string} defaultTreatment
32
32
  * @param {number} changeNumber
33
- * @returns {Promise} a promise that is resolved once the split kill is performed. The fulfillment value is a boolean: `true` if the kill success updating the split or `false` if no split is updated,
33
+ * @returns {boolean} `true` if the operation successed updating the split, or `false` if no split is updated,
34
34
  * 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.
35
35
  */
36
36
  killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean;
@@ -2,14 +2,21 @@ import { KeyBuilder } from './KeyBuilder';
2
2
  import { IMetadata } from '../dtos/types';
3
3
  import { Method } from '../sync/submitters/types';
4
4
  export declare class KeyBuilderSS extends KeyBuilder {
5
- protected readonly metadata: IMetadata;
5
+ latencyPrefix: string;
6
+ exceptionPrefix: string;
7
+ initPrefix: string;
8
+ private versionablePrefix;
6
9
  constructor(prefix: string, metadata: IMetadata);
7
10
  buildRegisteredSegmentsKey(): string;
8
11
  buildImpressionsKey(): string;
12
+ buildImpressionsCountKey(): string;
13
+ buildUniqueKeysKey(): string;
9
14
  buildEventsKey(): string;
10
15
  searchPatternForSplitKeys(): string;
11
16
  buildLatencyKey(method: Method, bucket: number): string;
12
17
  buildExceptionKey(method: Method): string;
13
18
  buildInitKey(): string;
14
- private buildVersionablePrefix;
15
19
  }
20
+ export declare function parseMetadata(field: string): [metadata: string] | string;
21
+ export declare function parseExceptionField(field: string): [metadata: string, method: Method] | string;
22
+ export declare function parseLatencyField(field: string): [metadata: string, method: Method, bucket: number] | string;
@@ -1,4 +1,4 @@
1
- import { ISplitFiltersValidation } from '../../dtos/types';
1
+ import { ISplit, ISplitFiltersValidation } from '../../dtos/types';
2
2
  import { AbstractSplitsCacheSync } from '../AbstractSplitsCacheSync';
3
3
  import { KeyBuilderCS } from '../KeyBuilderCS';
4
4
  import { ILogger } from '../../logger/types';
@@ -26,9 +26,9 @@ export declare class SplitsCacheInLocal extends AbstractSplitsCacheSync {
26
26
  * We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
27
27
  */
28
28
  clear(): void;
29
- addSplit(name: string, split: string): boolean;
29
+ addSplit(name: string, split: ISplit): boolean;
30
30
  removeSplit(name: string): boolean;
31
- getSplit(name: string): string | null;
31
+ getSplit(name: string): any;
32
32
  setChangeNumber(changeNumber: number): boolean;
33
33
  getChangeNumber(): number;
34
34
  getSplitNames(): string[];
@@ -42,7 +42,6 @@ export declare class SplitsCacheInLocal extends AbstractSplitsCacheSync {
42
42
  checkCache(): boolean;
43
43
  /**
44
44
  * Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
45
- * Clean operation (clear) also updates `lastUpdated` timestamp with current time.
46
45
  *
47
46
  * @param {number | undefined} expirationTimestamp if the value is not a number, data will not be cleaned
48
47
  */
@@ -1,6 +1,10 @@
1
1
  import { IImpressionCountsCacheSync } from '../types';
2
2
  export declare class ImpressionCountsCacheInMemory implements IImpressionCountsCacheSync {
3
- private cache;
3
+ protected cache: Record<string, number>;
4
+ private readonly maxStorage;
5
+ protected onFullQueue?: () => void;
6
+ private cacheSize;
7
+ constructor(impressionCountsCacheSize?: number);
4
8
  /**
5
9
  * Builds key to be stored in the cache with the featureName and the timeFrame truncated.
6
10
  */
@@ -1,3 +1,4 @@
1
+ import { ISplit } from '../../dtos/types';
1
2
  import { AbstractSplitsCacheSync } from '../AbstractSplitsCacheSync';
2
3
  /**
3
4
  * Default ISplitsCacheSync implementation that stores split definitions in memory.
@@ -9,9 +10,9 @@ export declare class SplitsCacheInMemory extends AbstractSplitsCacheSync {
9
10
  private changeNumber;
10
11
  private splitsWithSegmentsCount;
11
12
  clear(): void;
12
- addSplit(name: string, split: string): boolean;
13
+ addSplit(name: string, split: ISplit): boolean;
13
14
  removeSplit(name: string): boolean;
14
- getSplit(name: string): string | null;
15
+ getSplit(name: string): ISplit | null;
15
16
  setChangeNumber(changeNumber: number): boolean;
16
17
  getChangeNumber(): number;
17
18
  getSplitNames(): string[];
@@ -1,9 +1,12 @@
1
1
  import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies } from '../../sync/submitters/types';
2
- import { ITelemetryCacheSync } from '../types';
2
+ import { IStorageFactoryParams, ITelemetryCacheSync } from '../types';
3
+ export declare const MAX_LATENCY_BUCKET_COUNT = 23;
4
+ export declare function newBuckets(): number[];
3
5
  /**
4
- * Used on client-side. 0.1% of instances will track telemetry
6
+ * Record telemetry if mode is not localhost.
7
+ * All factory instances track telemetry on server-side, and 0.1% on client-side.
5
8
  */
6
- export declare function shouldRecordTelemetry(): boolean;
9
+ export declare function shouldRecordTelemetry(params: IStorageFactoryParams): boolean;
7
10
  export declare class TelemetryCacheInMemory implements ITelemetryCacheSync {
8
11
  private timeUntilReady?;
9
12
  getTimeUntilReady(): number | undefined;
@@ -0,0 +1,35 @@
1
+ import { IUniqueKeysCacheBase } from '../types';
2
+ import { ISet } from '../../utils/lang/sets';
3
+ import { UniqueKeysPayloadSs } from '../../sync/submitters/types';
4
+ /**
5
+ * Converts `uniqueKeys` data from cache into request payload for SS.
6
+ */
7
+ export declare function fromUniqueKeysCollector(uniqueKeys: {
8
+ [featureName: string]: ISet<string>;
9
+ }): UniqueKeysPayloadSs;
10
+ export declare class UniqueKeysCacheInMemory implements IUniqueKeysCacheBase {
11
+ protected onFullQueue?: () => void;
12
+ private readonly maxStorage;
13
+ private uniqueTrackerSize;
14
+ protected uniqueKeysTracker: {
15
+ [featureName: string]: ISet<string>;
16
+ };
17
+ constructor(uniqueKeysQueueSize?: number);
18
+ setOnFullQueueCb(cb: () => void): void;
19
+ /**
20
+ * Store unique keys per feature.
21
+ */
22
+ track(userKey: string, featureName: string): void;
23
+ /**
24
+ * Clear the data stored on the cache.
25
+ */
26
+ clear(): void;
27
+ /**
28
+ * Pop the collected data, used as payload for posting.
29
+ */
30
+ pop(): UniqueKeysPayloadSs;
31
+ /**
32
+ * Check if the cache is empty.
33
+ */
34
+ isEmpty(): boolean;
35
+ }
@@ -0,0 +1,35 @@
1
+ import { IUniqueKeysCacheBase } from '../types';
2
+ import { UniqueKeysPayloadCs } from '../../sync/submitters/types';
3
+ export declare class UniqueKeysCacheInMemoryCS implements IUniqueKeysCacheBase {
4
+ private onFullQueue?;
5
+ private readonly maxStorage;
6
+ private uniqueTrackerSize;
7
+ private uniqueKeysTracker;
8
+ /**
9
+ *
10
+ * @param impressionsQueueSize number of queued impressions to call onFullQueueCb.
11
+ * Default value is 0, that means no maximum value, in case we want to avoid this being triggered.
12
+ */
13
+ constructor(uniqueKeysQueueSize?: number);
14
+ setOnFullQueueCb(cb: () => void): void;
15
+ /**
16
+ * Store unique keys per feature.
17
+ */
18
+ track(userKey: string, featureName: string): void;
19
+ /**
20
+ * Clear the data stored on the cache.
21
+ */
22
+ clear(): void;
23
+ /**
24
+ * Pop the collected data, used as payload for posting.
25
+ */
26
+ pop(): UniqueKeysPayloadCs;
27
+ /**
28
+ * Check if the cache is empty.
29
+ */
30
+ isEmpty(): boolean;
31
+ /**
32
+ * Converts `uniqueKeys` data from cache into request payload.
33
+ */
34
+ private fromUniqueKeysCollector;
35
+ }
@@ -23,7 +23,7 @@ export declare class EventsCacheInRedis implements IEventsCacheAsync {
23
23
  drop(count?: number): Promise<any>;
24
24
  /**
25
25
  * Pop the given number of events from the storage.
26
- * The returned promise rejects if the wrapper operation fails.
26
+ * The returned promise rejects if the redis operation fails.
27
27
  *
28
28
  * NOTE: this method doesn't take into account MAX_EVENT_SIZE or MAX_QUEUE_BYTE_SIZE limits.
29
29
  * It is the submitter responsability to handle that.
@@ -0,0 +1,16 @@
1
+ import { Redis } from 'ioredis';
2
+ import { ILogger } from '../../logger/types';
3
+ import { ImpressionCountsPayload } from '../../sync/submitters/types';
4
+ import { ImpressionCountsCacheInMemory } from '../inMemory/ImpressionCountsCacheInMemory';
5
+ export declare class ImpressionCountsCacheInRedis extends ImpressionCountsCacheInMemory {
6
+ private readonly log;
7
+ private readonly key;
8
+ private readonly redis;
9
+ private readonly refreshRate;
10
+ private intervalId;
11
+ constructor(log: ILogger, key: string, redis: Redis, impressionCountsCacheSize?: number, refreshRate?: number);
12
+ private postImpressionCountsInRedis;
13
+ start(): void;
14
+ stop(): Promise<boolean | import("ioredis").BooleanResponse | undefined>;
15
+ getImpressionsCount(): Promise<ImpressionCountsPayload | undefined>;
16
+ }