@splitsoftware/splitio-commons 1.6.2-rc.8 → 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 (177) hide show
  1. package/CHANGES.txt +4 -1
  2. package/cjs/evaluator/index.js +5 -5
  3. package/cjs/listeners/browser.js +9 -11
  4. package/cjs/sdkClient/client.js +19 -7
  5. package/cjs/sdkFactory/index.js +7 -25
  6. package/cjs/services/splitApi.js +4 -4
  7. package/cjs/storages/AbstractSplitsCacheAsync.js +1 -1
  8. package/cjs/storages/AbstractSplitsCacheSync.js +1 -1
  9. package/cjs/storages/KeyBuilderSS.js +9 -9
  10. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +0 -1
  11. package/cjs/storages/inLocalStorage/index.js +15 -11
  12. package/cjs/storages/inMemory/InMemoryStorage.js +11 -8
  13. package/cjs/storages/inMemory/InMemoryStorageCS.js +11 -8
  14. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +65 -37
  15. package/cjs/storages/inMemory/{uniqueKeysCacheInMemory.js → UniqueKeysCacheInMemory.js} +24 -25
  16. package/cjs/storages/inMemory/{uniqueKeysCacheInMemoryCS.js → UniqueKeysCacheInMemoryCS.js} +10 -12
  17. package/cjs/storages/inRedis/EventsCacheInRedis.js +1 -1
  18. package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +37 -2
  19. package/cjs/storages/inRedis/ImpressionsCacheInRedis.js +2 -19
  20. package/cjs/storages/inRedis/TelemetryCacheInRedis.js +100 -0
  21. package/cjs/storages/inRedis/{uniqueKeysCacheInRedis.js → UniqueKeysCacheInRedis.js} +16 -4
  22. package/cjs/storages/inRedis/index.js +6 -4
  23. package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +81 -0
  24. package/cjs/storages/pluggable/ImpressionsCachePluggable.js +2 -19
  25. package/cjs/storages/pluggable/TelemetryCachePluggable.js +126 -0
  26. package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +61 -0
  27. package/cjs/storages/pluggable/inMemoryWrapper.js +8 -6
  28. package/cjs/storages/pluggable/index.js +51 -18
  29. package/cjs/storages/utils.js +73 -0
  30. package/cjs/sync/submitters/submitterManager.js +1 -1
  31. package/cjs/sync/submitters/telemetrySubmitter.js +4 -37
  32. package/cjs/sync/submitters/uniqueKeysSubmitter.js +4 -3
  33. package/cjs/trackers/impressionObserver/utils.js +1 -17
  34. package/cjs/trackers/uniqueKeysTracker.js +1 -1
  35. package/cjs/utils/lang/maps.js +15 -7
  36. package/cjs/utils/redis/RedisMock.js +31 -0
  37. package/cjs/utils/settingsValidation/index.js +7 -4
  38. package/esm/evaluator/index.js +5 -5
  39. package/esm/listeners/browser.js +9 -11
  40. package/esm/sdkClient/client.js +19 -7
  41. package/esm/sdkFactory/index.js +7 -25
  42. package/esm/services/splitApi.js +4 -4
  43. package/esm/storages/AbstractSplitsCacheAsync.js +1 -1
  44. package/esm/storages/AbstractSplitsCacheSync.js +1 -1
  45. package/esm/storages/KeyBuilderSS.js +8 -8
  46. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +0 -1
  47. package/esm/storages/inLocalStorage/index.js +16 -12
  48. package/esm/storages/inMemory/InMemoryStorage.js +13 -10
  49. package/esm/storages/inMemory/InMemoryStorageCS.js +12 -9
  50. package/esm/storages/inMemory/TelemetryCacheInMemory.js +64 -37
  51. package/esm/storages/inMemory/{uniqueKeysCacheInMemory.js → UniqueKeysCacheInMemory.js} +22 -24
  52. package/esm/storages/inMemory/{uniqueKeysCacheInMemoryCS.js → UniqueKeysCacheInMemoryCS.js} +10 -12
  53. package/esm/storages/inRedis/EventsCacheInRedis.js +1 -1
  54. package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +37 -2
  55. package/esm/storages/inRedis/ImpressionsCacheInRedis.js +2 -19
  56. package/esm/storages/inRedis/TelemetryCacheInRedis.js +100 -0
  57. package/esm/storages/inRedis/{uniqueKeysCacheInRedis.js → UniqueKeysCacheInRedis.js} +15 -3
  58. package/esm/storages/inRedis/index.js +5 -3
  59. package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +78 -0
  60. package/esm/storages/pluggable/ImpressionsCachePluggable.js +2 -19
  61. package/esm/storages/pluggable/TelemetryCachePluggable.js +126 -0
  62. package/esm/storages/pluggable/UniqueKeysCachePluggable.js +58 -0
  63. package/esm/storages/pluggable/inMemoryWrapper.js +8 -6
  64. package/esm/storages/pluggable/index.js +52 -19
  65. package/esm/storages/utils.js +65 -0
  66. package/esm/sync/submitters/submitterManager.js +1 -1
  67. package/esm/sync/submitters/telemetrySubmitter.js +4 -36
  68. package/esm/sync/submitters/uniqueKeysSubmitter.js +4 -3
  69. package/esm/trackers/impressionObserver/utils.js +1 -15
  70. package/esm/trackers/uniqueKeysTracker.js +1 -1
  71. package/esm/utils/lang/maps.js +15 -7
  72. package/esm/utils/redis/RedisMock.js +28 -0
  73. package/esm/utils/settingsValidation/index.js +7 -4
  74. package/package.json +2 -2
  75. package/src/consent/sdkUserConsent.ts +1 -1
  76. package/src/evaluator/index.ts +6 -6
  77. package/src/listeners/browser.ts +9 -13
  78. package/src/logger/.DS_Store +0 -0
  79. package/src/sdkClient/client.ts +21 -8
  80. package/src/sdkClient/sdkClient.ts +1 -1
  81. package/src/sdkFactory/index.ts +10 -33
  82. package/src/sdkFactory/types.ts +2 -2
  83. package/src/services/splitApi.ts +6 -6
  84. package/src/services/types.ts +2 -2
  85. package/src/storages/AbstractSplitsCacheAsync.ts +1 -1
  86. package/src/storages/AbstractSplitsCacheSync.ts +1 -1
  87. package/src/storages/KeyBuilderSS.ts +13 -11
  88. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +0 -1
  89. package/src/storages/inLocalStorage/index.ts +17 -12
  90. package/src/storages/inMemory/AttributesCacheInMemory.ts +7 -7
  91. package/src/storages/inMemory/ImpressionCountsCacheInMemory.ts +2 -2
  92. package/src/storages/inMemory/InMemoryStorage.ts +14 -10
  93. package/src/storages/inMemory/InMemoryStorageCS.ts +13 -10
  94. package/src/storages/inMemory/TelemetryCacheInMemory.ts +72 -35
  95. package/src/storages/inMemory/{uniqueKeysCacheInMemory.ts → UniqueKeysCacheInMemory.ts} +26 -28
  96. package/src/storages/inMemory/{uniqueKeysCacheInMemoryCS.ts → UniqueKeysCacheInMemoryCS.ts} +15 -17
  97. package/src/storages/inRedis/EventsCacheInRedis.ts +1 -1
  98. package/src/storages/inRedis/ImpressionCountsCacheInRedis.ts +51 -8
  99. package/src/storages/inRedis/ImpressionsCacheInRedis.ts +2 -22
  100. package/src/storages/inRedis/TelemetryCacheInRedis.ts +122 -1
  101. package/src/storages/inRedis/{uniqueKeysCacheInRedis.ts → UniqueKeysCacheInRedis.ts} +25 -12
  102. package/src/storages/inRedis/index.ts +6 -3
  103. package/src/storages/pluggable/ImpressionCountsCachePluggable.ts +92 -0
  104. package/src/storages/pluggable/ImpressionsCachePluggable.ts +3 -23
  105. package/src/storages/pluggable/TelemetryCachePluggable.ts +147 -1
  106. package/src/storages/pluggable/UniqueKeysCachePluggable.ts +67 -0
  107. package/src/storages/pluggable/inMemoryWrapper.ts +6 -6
  108. package/src/storages/pluggable/index.ts +56 -20
  109. package/src/storages/types.ts +53 -70
  110. package/src/storages/utils.ts +78 -0
  111. package/src/sync/submitters/submitter.ts +2 -2
  112. package/src/sync/submitters/submitterManager.ts +1 -1
  113. package/src/sync/submitters/telemetrySubmitter.ts +9 -39
  114. package/src/sync/submitters/types.ts +33 -17
  115. package/src/sync/submitters/uniqueKeysSubmitter.ts +6 -5
  116. package/src/trackers/impressionObserver/utils.ts +1 -16
  117. package/src/trackers/impressionsTracker.ts +2 -2
  118. package/src/trackers/strategy/strategyDebug.ts +4 -4
  119. package/src/trackers/strategy/strategyNone.ts +9 -9
  120. package/src/trackers/strategy/strategyOptimized.ts +9 -9
  121. package/src/trackers/uniqueKeysTracker.ts +6 -6
  122. package/src/types.ts +0 -2
  123. package/src/utils/lang/maps.ts +20 -8
  124. package/src/utils/redis/RedisMock.ts +33 -0
  125. package/src/utils/settingsValidation/index.ts +5 -5
  126. package/types/services/types.d.ts +2 -2
  127. package/types/storages/AbstractSplitsCacheAsync.d.ts +1 -1
  128. package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
  129. package/types/storages/KeyBuilderSS.d.ts +5 -2
  130. package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +0 -1
  131. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +23 -9
  132. package/types/storages/inMemory/uniqueKeysCacheInMemory.d.ts +9 -9
  133. package/types/storages/inMemory/uniqueKeysCacheInMemoryCS.d.ts +2 -4
  134. package/types/storages/inRedis/EventsCacheInRedis.d.ts +1 -1
  135. package/types/storages/inRedis/ImpressionCountsCacheInRedis.d.ts +3 -1
  136. package/types/storages/inRedis/ImpressionsCacheInRedis.d.ts +0 -1
  137. package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +16 -1
  138. package/types/storages/inRedis/uniqueKeysCacheInRedis.d.ts +8 -2
  139. package/types/storages/pluggable/ImpressionCountsCachePluggable.d.ts +16 -0
  140. package/types/storages/pluggable/ImpressionsCachePluggable.d.ts +1 -2
  141. package/types/storages/pluggable/TelemetryCachePluggable.d.ts +17 -1
  142. package/types/storages/pluggable/UniqueKeysCachePluggable.d.ts +20 -0
  143. package/types/storages/types.d.ts +42 -49
  144. package/types/storages/utils.d.ts +8 -0
  145. package/types/sync/submitters/submitter.d.ts +2 -2
  146. package/types/sync/submitters/telemetrySubmitter.d.ts +2 -10
  147. package/types/sync/submitters/types.d.ts +27 -18
  148. package/types/trackers/impressionObserver/utils.d.ts +0 -8
  149. package/types/trackers/strategy/strategyNone.d.ts +2 -2
  150. package/types/trackers/strategy/strategyOptimized.d.ts +2 -2
  151. package/types/trackers/uniqueKeysTracker.d.ts +1 -1
  152. package/types/types.d.ts +0 -2
  153. package/types/utils/lang/maps.d.ts +6 -2
  154. package/types/utils/redis/RedisMock.d.ts +4 -0
  155. package/types/utils/settingsValidation/index.d.ts +0 -1
  156. package/cjs/storages/metadataBuilder.js +0 -12
  157. package/esm/storages/metadataBuilder.js +0 -8
  158. package/src/storages/metadataBuilder.ts +0 -11
  159. package/types/sdkClient/types.d.ts +0 -18
  160. package/types/storages/inMemory/CountsCacheInMemory.d.ts +0 -20
  161. package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +0 -20
  162. package/types/storages/inRedis/CountsCacheInRedis.d.ts +0 -9
  163. package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +0 -9
  164. package/types/sync/offline/LocalhostFromFile.d.ts +0 -2
  165. package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +0 -2
  166. package/types/sync/submitters/eventsSyncTask.d.ts +0 -8
  167. package/types/sync/submitters/impressionCountsSubmitterInRedis.d.ts +0 -5
  168. package/types/sync/submitters/impressionCountsSyncTask.d.ts +0 -13
  169. package/types/sync/submitters/impressionsSyncTask.d.ts +0 -14
  170. package/types/sync/submitters/metricsSyncTask.d.ts +0 -12
  171. package/types/sync/submitters/submitterSyncTask.d.ts +0 -10
  172. package/types/sync/submitters/uniqueKeysSubmitterInRedis.d.ts +0 -5
  173. package/types/sync/syncTaskComposite.d.ts +0 -5
  174. package/types/trackers/filter/bloomFilter.d.ts +0 -10
  175. package/types/trackers/filter/dictionaryFilter.d.ts +0 -8
  176. package/types/trackers/filter/types.d.ts +0 -5
  177. package/types/utils/timeTracker/index.d.ts +0 -70
@@ -1,5 +1,7 @@
1
+ /* eslint-disable no-use-before-define */
1
2
  import { IMetadata } from '../../dtos/types';
2
3
  import { SplitIO } from '../../types';
4
+ import { IMap } from '../../utils/lang/maps';
3
5
  import { ISyncTask } from '../types';
4
6
 
5
7
  export type ImpressionsPayload = {
@@ -35,13 +37,15 @@ export type ImpressionCountsPayload = {
35
37
  }[]
36
38
  }
37
39
 
40
+ export type UniqueKeysItemSs = {
41
+ /** Split name */
42
+ f: string
43
+ /** keyNames */
44
+ ks: string[]
45
+ }
46
+
38
47
  export type UniqueKeysPayloadSs = {
39
- keys: {
40
- /** Split name */
41
- f: string
42
- /** keyNames */
43
- ks: string[]
44
- }[]
48
+ keys: UniqueKeysItemSs[]
45
49
  }
46
50
 
47
51
  export type UniqueKeysPayloadCs = {
@@ -72,6 +76,8 @@ export type StoredImpressionWithMetadata = {
72
76
  c: number,
73
77
  /** time */
74
78
  m: number
79
+ /** previous time */
80
+ pt?: number
75
81
  }
76
82
  }
77
83
 
@@ -82,6 +88,12 @@ export type StoredEventWithMetadata = {
82
88
  e: SplitIO.EventData
83
89
  }
84
90
 
91
+ export type MultiMethodLatencies = IMap<string, MethodLatencies>
92
+
93
+ export type MultiMethodExceptions = IMap<string, MethodExceptions>
94
+
95
+ export type MultiConfigs = IMap<string, TelemetryConfigStats>
96
+
85
97
  /**
86
98
  * Telemetry usage stats
87
99
  */
@@ -102,9 +114,9 @@ export type SEGMENT = 'se';
102
114
  export type MY_SEGMENT = 'ms';
103
115
  export type OperationType = SPLITS | IMPRESSIONS | IMPRESSIONS_COUNT | EVENTS | TELEMETRY | TOKEN | SEGMENT | MY_SEGMENT;
104
116
 
105
- export type LastSync = Record<OperationType, number | undefined>
106
- export type HttpErrors = Record<OperationType, { [statusCode: string]: number }>
107
- export type HttpLatencies = Record<OperationType, Array<number>>
117
+ export type LastSync = Partial<Record<OperationType, number | undefined>>
118
+ export type HttpErrors = Partial<Record<OperationType, { [statusCode: string]: number }>>
119
+ export type HttpLatencies = Partial<Record<OperationType, Array<number>>>
108
120
 
109
121
  export type TREATMENT = 't';
110
122
  export type TREATMENTS = 'ts';
@@ -113,9 +125,9 @@ export type TREATMENTS_WITH_CONFIG = 'tcs';
113
125
  export type TRACK = 'tr';
114
126
  export type Method = TREATMENT | TREATMENTS | TREATMENT_WITH_CONFIG | TREATMENTS_WITH_CONFIG | TRACK;
115
127
 
116
- export type MethodLatencies = Record<Method, Array<number>>;
128
+ export type MethodLatencies = Partial<Record<Method, Array<number>>>;
117
129
 
118
- export type MethodExceptions = Record<Method, number>;
130
+ export type MethodExceptions = Partial<Record<Method, number>>;
119
131
 
120
132
  export type CONNECTION_ESTABLISHED = 0;
121
133
  export type OCCUPANCY_PRI = 10;
@@ -133,11 +145,15 @@ export type StreamingEvent = {
133
145
  t: number, // timestamp
134
146
  }
135
147
 
148
+ // 'telemetry.latencias' and 'telemetry.exceptions' Redis/Pluggable keys
149
+ export type TelemetryUsageStats = {
150
+ mL?: MethodLatencies, // clientMethodLatencies
151
+ mE?: MethodExceptions, // methodExceptions
152
+ }
153
+
136
154
  // 'metrics/usage' JSON request body
137
- export type TelemetryUsageStatsPayload = {
155
+ export type TelemetryUsageStatsPayload = TelemetryUsageStats & {
138
156
  lS: LastSync, // lastSynchronization
139
- mL: MethodLatencies, // clientMethodLatencies
140
- mE: MethodExceptions, // methodExceptions
141
157
  hE: HttpErrors, // httpErrors
142
158
  hL: HttpLatencies, // httpLatencies
143
159
  tR: number, // tokenRefreshes
@@ -145,9 +161,9 @@ export type TelemetryUsageStatsPayload = {
145
161
  iQ: number, // impressionsQueued
146
162
  iDe: number, // impressionsDeduped
147
163
  iDr: number, // impressionsDropped
148
- spC: number, // splitCount
149
- seC: number, // segmentCount
150
- skC: number, // segmentKeyCount
164
+ spC?: number, // splitCount
165
+ seC?: number, // segmentCount
166
+ skC?: number, // segmentKeyCount
151
167
  sL?: number, // sessionLengthMs
152
168
  eQ: number, // eventsQueued
153
169
  eD: number, // eventsDropped
@@ -2,7 +2,8 @@ import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
2
2
  import { ISdkFactoryContextSync } from '../../sdkFactory/types';
3
3
  import { submitterFactory } from './submitter';
4
4
 
5
- const DATA_NAME = 'uniqueKeys';
5
+ const DATA_NAME = 'unique keys';
6
+ const UNIQUE_KEYS_RATE = 900000; // 15 minutes
6
7
 
7
8
  /**
8
9
  * Submitter that periodically posts impression counts
@@ -10,15 +11,15 @@ const DATA_NAME = 'uniqueKeys';
10
11
  export function uniqueKeysSubmitterFactory(params: ISdkFactoryContextSync) {
11
12
 
12
13
  const {
13
- settings: { log, scheduler: { uniqueKeysRefreshRate }, core: {key}},
14
+ settings: { log, core: { key } },
14
15
  splitApi: { postUniqueKeysBulkCs, postUniqueKeysBulkSs },
15
16
  storage: { uniqueKeys }
16
17
  } = params;
17
-
18
+
18
19
  const isClientSide = key !== undefined;
19
20
  const postUniqueKeysBulk = isClientSide ? postUniqueKeysBulkCs : postUniqueKeysBulkSs;
20
21
 
21
- const syncTask = submitterFactory(log, postUniqueKeysBulk, uniqueKeys!, uniqueKeysRefreshRate, 'unique keys');
22
+ const syncTask = submitterFactory(log, postUniqueKeysBulk, uniqueKeys!, UNIQUE_KEYS_RATE, DATA_NAME);
22
23
 
23
24
  // register unique keys submitter to be executed when uniqueKeys cache is full
24
25
  uniqueKeys!.setOnFullQueueCb(() => {
@@ -29,7 +30,7 @@ export function uniqueKeysSubmitterFactory(params: ISdkFactoryContextSync) {
29
30
  // If submitter is stopped (e.g., user consent declined or unknown, or app state offline), we don't send the data.
30
31
  // Data will be sent when submitter is resumed.
31
32
  });
32
-
33
+
33
34
  return syncTask;
34
35
  }
35
36
 
@@ -1,21 +1,6 @@
1
- import { CONSUMER_MODE, CONSUMER_PARTIAL_MODE, OPTIMIZED, PRODUCER_MODE, STANDALONE_MODE } from '../../utils/constants';
1
+ import { CONSUMER_MODE, CONSUMER_PARTIAL_MODE } from '../../utils/constants';
2
2
  import { ISettings } from '../../types';
3
3
 
4
- /**
5
- * Checks if impressions previous time should be added or not.
6
- */
7
- export function shouldAddPt(settings: ISettings) {
8
- return [PRODUCER_MODE, STANDALONE_MODE, CONSUMER_PARTIAL_MODE].indexOf(settings.mode) > -1 ? true : false;
9
- }
10
-
11
- /**
12
- * Checks if it should dedupe impressions or not.
13
- */
14
- export function shouldBeOptimized(settings: ISettings) {
15
- if (!shouldAddPt(settings)) return false;
16
- return settings.sync.impressionsMode === OPTIMIZED ? true : false;
17
- }
18
-
19
4
  /**
20
5
  * Storage is async if mode is consumer or partial consumer
21
6
  */
@@ -31,9 +31,9 @@ export function impressionsTrackerFactory(
31
31
 
32
32
  const impressionsCount = impressions.length;
33
33
  const { impressionsToStore, impressionsToListener, deduped } = strategy.process(impressions);
34
-
34
+
35
35
  const impressionsToListenerCount = impressionsToListener.length;
36
-
36
+
37
37
  if ( impressionsToStore.length>0 ){
38
38
  const res = impressionsCache.track(impressionsToStore);
39
39
 
@@ -4,14 +4,14 @@ import { IStrategy } from '../types';
4
4
 
5
5
  /**
6
6
  * Debug strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
7
- *
7
+ *
8
8
  * @param impressionsObserver impression observer. Previous time (pt property) is included in impression instances
9
9
  * @returns IStrategyResult
10
10
  */
11
11
  export function strategyDebugFactory(
12
12
  impressionsObserver: IImpressionObserver
13
13
  ): IStrategy {
14
-
14
+
15
15
  return {
16
16
  process(impressions: ImpressionDTO[]) {
17
17
  impressions.forEach((impression) => {
@@ -19,8 +19,8 @@ export function strategyDebugFactory(
19
19
  impression.pt = impressionsObserver.testAndSet(impression);
20
20
  });
21
21
  return {
22
- impressionsToStore: impressions,
23
- impressionsToListener: impressions,
22
+ impressionsToStore: impressions,
23
+ impressionsToListener: impressions,
24
24
  deduped: 0
25
25
  };
26
26
  }
@@ -1,32 +1,32 @@
1
- import { IImpressionCountsCacheSync } from '../../storages/types';
1
+ import { IImpressionCountsCacheBase } from '../../storages/types';
2
2
  import { ImpressionDTO } from '../../types';
3
3
  import { IStrategy, IUniqueKeysTracker } from '../types';
4
4
 
5
5
  /**
6
6
  * None strategy for impressions tracker.
7
- *
7
+ *
8
8
  * @param impressionsCounter cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
9
- * @param uniqueKeysTracker unique keys tracker in charge of tracking the unique keys per split.
9
+ * @param uniqueKeysTracker unique keys tracker in charge of tracking the unique keys per split.
10
10
  * @returns IStrategyResult
11
11
  */
12
12
  export function strategyNoneFactory(
13
- impressionsCounter: IImpressionCountsCacheSync,
13
+ impressionsCounter: IImpressionCountsCacheBase,
14
14
  uniqueKeysTracker: IUniqueKeysTracker
15
15
  ): IStrategy {
16
-
16
+
17
17
  return {
18
18
  process(impressions: ImpressionDTO[]) {
19
- impressions.forEach((impression) => {
19
+ impressions.forEach((impression) => {
20
20
  const now = Date.now();
21
21
  // Increments impression counter per featureName
22
22
  impressionsCounter.track(impression.feature, now, 1);
23
23
  // Keep track by unique key
24
24
  uniqueKeysTracker.track(impression.keyName, impression.feature);
25
25
  });
26
-
26
+
27
27
  return {
28
- impressionsToStore: [],
29
- impressionsToListener: impressions,
28
+ impressionsToStore: [],
29
+ impressionsToListener: impressions,
30
30
  deduped: 0
31
31
  };
32
32
  }
@@ -1,4 +1,4 @@
1
- import { IImpressionCountsCacheSync } from '../../storages/types';
1
+ import { IImpressionCountsCacheBase } from '../../storages/types';
2
2
  import { ImpressionDTO } from '../../types';
3
3
  import { truncateTimeFrame } from '../../utils/time';
4
4
  import { IImpressionObserver } from '../impressionObserver/types';
@@ -6,35 +6,35 @@ import { IStrategy } from '../types';
6
6
 
7
7
  /**
8
8
  * Optimized strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
9
- *
9
+ *
10
10
  * @param impressionsObserver impression observer. previous time (pt property) is included in impression instances
11
11
  * @param impressionsCounter cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
12
12
  * @returns IStrategyResult
13
13
  */
14
14
  export function strategyOptimizedFactory(
15
15
  impressionsObserver: IImpressionObserver,
16
- impressionsCounter: IImpressionCountsCacheSync,
16
+ impressionsCounter: IImpressionCountsCacheBase,
17
17
  ): IStrategy {
18
-
18
+
19
19
  return {
20
20
  process(impressions: ImpressionDTO[]) {
21
21
  const impressionsToStore: ImpressionDTO[] = [];
22
22
  impressions.forEach((impression) => {
23
23
  impression.pt = impressionsObserver.testAndSet(impression);
24
-
24
+
25
25
  const now = Date.now();
26
-
26
+
27
27
  // Increments impression counter per featureName
28
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)) {
32
32
  impressionsToStore.push(impression);
33
33
  }
34
34
  });
35
35
  return {
36
- impressionsToStore: impressionsToStore,
37
- impressionsToListener: impressions,
36
+ impressionsToStore: impressionsToStore,
37
+ impressionsToListener: impressions,
38
38
  deduped: impressions.length - impressionsToStore.length
39
39
  };
40
40
  }
@@ -4,16 +4,16 @@ import { IUniqueKeysCacheBase } from '../storages/types';
4
4
  import { IFilterAdapter, IUniqueKeysTracker } from './types';
5
5
 
6
6
  const noopFilterAdapter = {
7
- add() {return true;},
8
- contains() {return true;},
9
- clear() {}
7
+ add() { return true; },
8
+ contains() { return true; },
9
+ clear() { }
10
10
  };
11
11
 
12
12
  /**
13
13
  * Trackes uniques keys
14
14
  * Unique Keys Tracker will be in charge of checking if the MTK was already sent to the BE in the last period
15
- * or schedule to be sent; if not it will be added in an internal cache and sent in the next post.
16
- *
15
+ * or schedule to be sent; if not it will be added in an internal cache and sent in the next post.
16
+ *
17
17
  * @param log Logger instance
18
18
  * @param uniqueKeysCache cache to save unique keys
19
19
  * @param filterAdapter filter adapter
@@ -42,7 +42,7 @@ export function uniqueKeysTrackerFactory(
42
42
  stop(): void {
43
43
  clearInterval(intervalId);
44
44
  }
45
-
45
+
46
46
  };
47
47
 
48
48
  }
package/src/types.ts CHANGED
@@ -80,8 +80,6 @@ export interface ISettings {
80
80
  featuresRefreshRate: number,
81
81
  impressionsRefreshRate: number,
82
82
  impressionsQueueSize: number,
83
- uniqueKeysRefreshRate: number,
84
- uniqueKeysCacheSize: number,
85
83
  /**
86
84
  * @deprecated
87
85
  */
@@ -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,11 @@ 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
-
142
138
 
143
139
  // Log deprecation for old telemetry param
144
140
  if (scheduler.metricsRefreshRate) log.warn('`metricsRefreshRate` will be deprecated soon. For configuring telemetry rates, update `telemetryRefreshRate` value in configs');
@@ -157,8 +153,8 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
157
153
  if (storage) withDefaults.storage = storage(withDefaults);
158
154
 
159
155
  // Validate key and TT (for client-side)
156
+ const maybeKey = withDefaults.core.key;
160
157
  if (validationParams.acceptKey) {
161
- const maybeKey = withDefaults.core.key;
162
158
  // Although `key` is required in client-side, it can be omitted in LOCALHOST mode. In that case, the value `localhost_key` is used.
163
159
  if (withDefaults.mode === LOCALHOST_MODE && maybeKey === undefined) {
164
160
  withDefaults.core.key = 'localhost_key';
@@ -175,6 +171,10 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
175
171
  withDefaults.core.trafficType = validateTrafficType(log, maybeTT, 'Client instantiation');
176
172
  }
177
173
  }
174
+ } else {
175
+ // On server-side, key is undefined and used to distinguish from client-side
176
+ if (maybeKey !== undefined) log.warn('Provided `key` is ignored in server-side SDK.'); // @ts-ignore
177
+ withDefaults.core.key = undefined;
178
178
  }
179
179
 
180
180
  // Current ip/hostname information
@@ -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;
@@ -29,7 +29,7 @@ export declare abstract class AbstractSplitsCacheAsync implements ISplitsCacheAs
29
29
  * @param {string} name
30
30
  * @param {string} defaultTreatment
31
31
  * @param {number} changeNumber
32
- * @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,
33
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.
34
34
  * The promise will never be rejected.
35
35
  */
@@ -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;
@@ -1,8 +1,12 @@
1
1
  import { KeyBuilder } from './KeyBuilder';
2
2
  import { IMetadata } from '../dtos/types';
3
3
  import { Method } from '../sync/submitters/types';
4
+ export declare const METHOD_NAMES: Record<Method, string>;
4
5
  export declare class KeyBuilderSS extends KeyBuilder {
5
- protected readonly metadata: IMetadata;
6
+ latencyPrefix: string;
7
+ exceptionPrefix: string;
8
+ initPrefix: string;
9
+ private versionablePrefix;
6
10
  constructor(prefix: string, metadata: IMetadata);
7
11
  buildRegisteredSegmentsKey(): string;
8
12
  buildImpressionsKey(): string;
@@ -13,5 +17,4 @@ export declare class KeyBuilderSS extends KeyBuilder {
13
17
  buildLatencyKey(method: Method, bucket: number): string;
14
18
  buildExceptionKey(method: Method): string;
15
19
  buildInitKey(): string;
16
- private buildVersionablePrefix;
17
20
  }
@@ -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,10 +1,21 @@
1
- import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies } from '../../sync/submitters/types';
2
- import { ITelemetryCacheSync } from '../types';
1
+ import { ImpressionDataType, EventDataType, StreamingEvent, Method, OperationType, TelemetryUsageStatsPayload } from '../../sync/submitters/types';
2
+ import { ISegmentsCacheSync, ISplitsCacheSync, 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({ settings }: IStorageFactoryParams): boolean;
7
10
  export declare class TelemetryCacheInMemory implements ITelemetryCacheSync {
11
+ private splits?;
12
+ private segments?;
13
+ constructor(splits?: ISplitsCacheSync | undefined, segments?: ISegmentsCacheSync | undefined);
14
+ private e;
15
+ isEmpty(): boolean;
16
+ clear(): void;
17
+ pop(): TelemetryUsageStatsPayload;
18
+ /** Config stats */
8
19
  private timeUntilReady?;
9
20
  getTimeUntilReady(): number | undefined;
10
21
  recordTimeUntilReady(ms: number): void;
@@ -14,6 +25,7 @@ export declare class TelemetryCacheInMemory implements ITelemetryCacheSync {
14
25
  private notReadyUsage;
15
26
  getNonReadyUsage(): number;
16
27
  recordNonReadyUsage(): void;
28
+ /** Usage stats */
17
29
  private impressionStats;
18
30
  getImpressionStats(type: ImpressionDataType): number;
19
31
  recordImpressionStats(type: ImpressionDataType, count: number): void;
@@ -21,13 +33,15 @@ export declare class TelemetryCacheInMemory implements ITelemetryCacheSync {
21
33
  getEventStats(type: EventDataType): number;
22
34
  recordEventStats(type: EventDataType, count: number): void;
23
35
  private lastSync;
24
- getLastSynchronization(): LastSync;
36
+ getLastSynchronization(): Partial<Record<OperationType, number | undefined>>;
25
37
  recordSuccessfulSync(resource: OperationType, timeMs: number): void;
26
38
  private httpErrors;
27
- popHttpErrors(): HttpErrors;
39
+ popHttpErrors(): Partial<Record<OperationType, {
40
+ [statusCode: string]: number;
41
+ }>>;
28
42
  recordHttpError(resource: OperationType, status: number): void;
29
43
  private httpLatencies;
30
- popHttpLatencies(): HttpLatencies;
44
+ popHttpLatencies(): Partial<Record<OperationType, number[]>>;
31
45
  recordHttpLatency(resource: OperationType, latencyMs: number): void;
32
46
  private authRejections;
33
47
  popAuthRejections(): number;
@@ -45,9 +59,9 @@ export declare class TelemetryCacheInMemory implements ITelemetryCacheSync {
45
59
  getSessionLength(): number | undefined;
46
60
  recordSessionLength(ms: number): void;
47
61
  private exceptions;
48
- popExceptions(): MethodExceptions;
62
+ popExceptions(): Partial<Record<Method, number>>;
49
63
  recordException(method: Method): void;
50
64
  private latencies;
51
- popLatencies(): MethodLatencies;
65
+ popLatencies(): Partial<Record<Method, number[]>>;
52
66
  recordLatency(method: Method, latencyMs: number): void;
53
67
  }
@@ -1,21 +1,25 @@
1
1
  import { IUniqueKeysCacheBase } from '../types';
2
2
  import { ISet } from '../../utils/lang/sets';
3
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;
4
10
  export declare class UniqueKeysCacheInMemory implements IUniqueKeysCacheBase {
5
11
  protected onFullQueue?: () => void;
6
12
  private readonly maxStorage;
7
13
  private uniqueTrackerSize;
8
14
  protected uniqueKeysTracker: {
9
- [keys: string]: ISet<string>;
15
+ [featureName: string]: ISet<string>;
10
16
  };
11
17
  constructor(uniqueKeysQueueSize?: number);
12
18
  setOnFullQueueCb(cb: () => void): void;
13
19
  /**
14
- * Store unique keys in sequential order
15
- * key: string = feature name.
16
- * value: Set<string> = set of unique keys.
20
+ * Store unique keys per feature.
17
21
  */
18
- track(key: string, featureName: string): void;
22
+ track(userKey: string, featureName: string): void;
19
23
  /**
20
24
  * Clear the data stored on the cache.
21
25
  */
@@ -28,8 +32,4 @@ export declare class UniqueKeysCacheInMemory implements IUniqueKeysCacheBase {
28
32
  * Check if the cache is empty.
29
33
  */
30
34
  isEmpty(): boolean;
31
- /**
32
- * Converts `uniqueKeys` data from cache into request payload for SS.
33
- */
34
- private fromUniqueKeysCollector;
35
35
  }
@@ -13,11 +13,9 @@ export declare class UniqueKeysCacheInMemoryCS implements IUniqueKeysCacheBase {
13
13
  constructor(uniqueKeysQueueSize?: number);
14
14
  setOnFullQueueCb(cb: () => void): void;
15
15
  /**
16
- * Store unique keys in sequential order
17
- * key: string = key.
18
- * value: HashSet<string> = set of split names.
16
+ * Store unique keys per feature.
19
17
  */
20
- track(key: string, featureName: string): void;
18
+ track(userKey: string, featureName: string): void;
21
19
  /**
22
20
  * Clear the data stored on the cache.
23
21
  */