@splitsoftware/splitio-commons 2.12.0 → 2.12.2

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 (157) hide show
  1. package/CHANGES.txt +8 -1
  2. package/cjs/evaluator/condition/engineUtils.js +2 -2
  3. package/cjs/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +3 -3
  4. package/cjs/evaluator/fallbackTreatmentsCalculator/index.js +21 -32
  5. package/cjs/evaluator/matchers/whitelist.js +1 -1
  6. package/cjs/integrations/pluggable.js +1 -1
  7. package/cjs/listeners/node.js +2 -2
  8. package/cjs/logger/constants.js +3 -4
  9. package/cjs/logger/index.js +1 -1
  10. package/cjs/logger/messages/debug.js +1 -1
  11. package/cjs/logger/messages/error.js +1 -1
  12. package/cjs/logger/messages/info.js +2 -3
  13. package/cjs/logger/messages/warn.js +4 -4
  14. package/cjs/sdkClient/client.js +2 -3
  15. package/cjs/sdkClient/clientAttributesDecoration.js +3 -3
  16. package/cjs/sdkClient/clientInputValidation.js +36 -68
  17. package/cjs/sdkClient/identity.js +1 -1
  18. package/cjs/sdkClient/sdkClient.js +19 -7
  19. package/cjs/sdkFactory/index.js +8 -41
  20. package/cjs/services/splitApi.js +13 -13
  21. package/cjs/services/splitHttpClient.js +1 -1
  22. package/cjs/storages/KeyBuilder.js +12 -12
  23. package/cjs/storages/KeyBuilderCS.js +13 -13
  24. package/cjs/storages/KeyBuilderSS.js +15 -15
  25. package/cjs/storages/getRolloutPlan.js +1 -1
  26. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -1
  27. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +1 -1
  28. package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
  29. package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +1 -1
  30. package/cjs/storages/inMemory/SplitsCacheInMemory.js +1 -1
  31. package/cjs/storages/inRedis/EventsCacheInRedis.js +1 -1
  32. package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +5 -5
  33. package/cjs/storages/inRedis/ImpressionsCacheInRedis.js +1 -1
  34. package/cjs/storages/inRedis/RedisAdapter.js +8 -8
  35. package/cjs/storages/inRedis/SplitsCacheInRedis.js +6 -6
  36. package/cjs/storages/inRedis/TelemetryCacheInRedis.js +7 -7
  37. package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +3 -3
  38. package/cjs/storages/pluggable/EventsCachePluggable.js +1 -1
  39. package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +6 -6
  40. package/cjs/storages/pluggable/SplitsCachePluggable.js +4 -4
  41. package/cjs/storages/pluggable/TelemetryCachePluggable.js +7 -7
  42. package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +2 -2
  43. package/cjs/storages/pluggable/index.js +3 -3
  44. package/cjs/storages/pluggable/wrapperAdapter.js +1 -1
  45. package/cjs/storages/setRolloutPlan.js +3 -3
  46. package/cjs/storages/utils.js +6 -6
  47. package/cjs/sync/offline/splitsParser/parseCondition.js +1 -1
  48. package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
  49. package/cjs/sync/polling/pollingManagerSS.js +2 -2
  50. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +6 -6
  51. package/cjs/sync/polling/updaters/splitChangesUpdater.js +12 -10
  52. package/cjs/sync/streaming/SSEClient/index.js +2 -2
  53. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
  54. package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
  55. package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +2 -2
  56. package/cjs/sync/streaming/parseUtils.js +1 -1
  57. package/cjs/sync/submitters/submitter.js +1 -1
  58. package/cjs/trackers/eventTracker.js +10 -12
  59. package/cjs/trackers/impressionObserver/buildKey.js +1 -1
  60. package/cjs/trackers/impressionsTracker.js +37 -20
  61. package/cjs/trackers/uniqueKeysTracker.js +1 -1
  62. package/cjs/utils/inputValidation/apiKey.js +1 -1
  63. package/cjs/utils/inputValidation/attribute.js +2 -2
  64. package/cjs/utils/inputValidation/eventProperties.js +1 -1
  65. package/cjs/utils/inputValidation/isOperational.js +1 -1
  66. package/cjs/utils/lang/index.js +1 -1
  67. package/cjs/utils/lang/sets.js +4 -4
  68. package/cjs/utils/promise/timeout.js +1 -1
  69. package/cjs/utils/settingsValidation/splitFilters.js +2 -2
  70. package/cjs/utils/settingsValidation/url.js +5 -5
  71. package/esm/evaluator/condition/engineUtils.js +2 -2
  72. package/esm/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +3 -3
  73. package/esm/evaluator/fallbackTreatmentsCalculator/index.js +21 -33
  74. package/esm/evaluator/matchers/whitelist.js +1 -1
  75. package/esm/integrations/pluggable.js +1 -1
  76. package/esm/listeners/node.js +2 -2
  77. package/esm/logger/constants.js +0 -1
  78. package/esm/logger/index.js +1 -1
  79. package/esm/logger/messages/info.js +1 -2
  80. package/esm/logger/messages/warn.js +3 -3
  81. package/esm/sdkClient/client.js +3 -4
  82. package/esm/sdkClient/clientAttributesDecoration.js +3 -3
  83. package/esm/sdkClient/clientInputValidation.js +36 -68
  84. package/esm/sdkClient/identity.js +1 -1
  85. package/esm/sdkClient/sdkClient.js +20 -8
  86. package/esm/sdkFactory/index.js +8 -41
  87. package/esm/services/splitApi.js +13 -13
  88. package/esm/services/splitHttpClient.js +1 -1
  89. package/esm/storages/KeyBuilder.js +12 -12
  90. package/esm/storages/KeyBuilderCS.js +12 -12
  91. package/esm/storages/KeyBuilderSS.js +14 -14
  92. package/esm/storages/getRolloutPlan.js +1 -1
  93. package/esm/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
  94. package/esm/storages/inRedis/EventsCacheInRedis.js +1 -1
  95. package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +4 -4
  96. package/esm/storages/inRedis/RedisAdapter.js +7 -7
  97. package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -4
  98. package/esm/storages/inRedis/TelemetryCacheInRedis.js +7 -7
  99. package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +1 -1
  100. package/esm/storages/pluggable/EventsCachePluggable.js +1 -1
  101. package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +5 -5
  102. package/esm/storages/pluggable/SplitsCachePluggable.js +2 -2
  103. package/esm/storages/pluggable/TelemetryCachePluggable.js +7 -7
  104. package/esm/storages/pluggable/UniqueKeysCachePluggable.js +1 -1
  105. package/esm/storages/pluggable/index.js +2 -2
  106. package/esm/storages/pluggable/wrapperAdapter.js +1 -1
  107. package/esm/storages/setRolloutPlan.js +3 -3
  108. package/esm/storages/utils.js +6 -6
  109. package/esm/sync/offline/splitsParser/parseCondition.js +1 -1
  110. package/esm/sync/polling/pollingManagerSS.js +2 -2
  111. package/esm/sync/polling/updaters/segmentChangesUpdater.js +6 -6
  112. package/esm/sync/polling/updaters/splitChangesUpdater.js +12 -10
  113. package/esm/sync/streaming/SSEClient/index.js +2 -2
  114. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
  115. package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
  116. package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +2 -2
  117. package/esm/sync/streaming/parseUtils.js +1 -1
  118. package/esm/sync/submitters/submitter.js +1 -1
  119. package/esm/trackers/eventTracker.js +10 -12
  120. package/esm/trackers/impressionObserver/buildKey.js +1 -1
  121. package/esm/trackers/impressionsTracker.js +38 -21
  122. package/esm/trackers/uniqueKeysTracker.js +1 -1
  123. package/esm/utils/inputValidation/apiKey.js +1 -1
  124. package/esm/utils/inputValidation/attribute.js +2 -2
  125. package/esm/utils/inputValidation/isOperational.js +1 -1
  126. package/esm/utils/lang/sets.js +4 -4
  127. package/esm/utils/promise/timeout.js +1 -1
  128. package/esm/utils/settingsValidation/splitFilters.js +2 -2
  129. package/esm/utils/settingsValidation/url.js +5 -5
  130. package/package.json +6 -6
  131. package/src/dtos/types.ts +15 -15
  132. package/src/evaluator/condition/engineUtils.ts +2 -2
  133. package/src/evaluator/fallbackTreatmentsCalculator/index.ts +23 -41
  134. package/src/evaluator/matchers/whitelist.ts +2 -2
  135. package/src/evaluator/types.ts +2 -2
  136. package/src/evaluator/value/index.ts +1 -1
  137. package/src/integrations/pluggable.ts +1 -1
  138. package/src/logger/constants.ts +0 -1
  139. package/src/logger/messages/info.ts +1 -2
  140. package/src/logger/messages/warn.ts +3 -3
  141. package/src/sdkClient/client.ts +3 -5
  142. package/src/sdkClient/clientInputValidation.ts +38 -61
  143. package/src/sdkClient/sdkClient.ts +20 -5
  144. package/src/sdkFactory/index.ts +10 -47
  145. package/src/sdkFactory/types.ts +6 -3
  146. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +1 -1
  147. package/src/storages/inMemory/SplitsCacheInMemory.ts +1 -1
  148. package/src/storages/inRedis/SplitsCacheInRedis.ts +1 -1
  149. package/src/storages/pluggable/SplitsCachePluggable.ts +1 -1
  150. package/src/storages/setRolloutPlan.ts +2 -2
  151. package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
  152. package/src/sync/polling/updaters/splitChangesUpdater.ts +11 -9
  153. package/src/trackers/eventTracker.ts +7 -10
  154. package/src/trackers/impressionsTracker.ts +42 -26
  155. package/src/trackers/types.ts +3 -1
  156. package/src/utils/lang/sets.ts +4 -2
  157. package/types/splitio.d.ts +22 -18
@@ -59,17 +59,20 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
59
59
  };
60
60
  }
61
61
 
62
- function evaluateFallBackTreatment(featureFlagName: string, withConfig: boolean): SplitIO.Treatment | SplitIO.TreatmentWithConfig {
63
- const { treatment, config } = fallbackTreatmentsCalculator.resolve(featureFlagName, '');
62
+ function evaluateFallBackTreatment(featureFlagName: string | false | string[], withConfig: boolean) {
63
+ if (Array.isArray(featureFlagName)) {
64
+ const res: SplitIO.Treatments = {};
65
+ featureFlagName.forEach((split: string) => res[split] = evaluateFallBackTreatment(split, withConfig) as SplitIO.Treatment);
66
+ return res;
67
+ }
68
+
69
+ const { treatment, config } = fallbackTreatmentsCalculator(featureFlagName as string);
64
70
 
65
- if (withConfig) {
66
- return {
71
+ return withConfig ?
72
+ {
67
73
  treatment,
68
74
  config
69
- };
70
- }
71
-
72
- return treatment;
75
+ } : treatment;
73
76
  }
74
77
 
75
78
  function wrapResult<T>(value: T): MaybeThenable<T> {
@@ -79,89 +82,65 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
79
82
  function getTreatment(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
80
83
  const params = validateEvaluationParams(GET_TREATMENT, maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions);
81
84
 
82
- if (params.valid) {
83
- return client.getTreatment(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined, params.options);
84
- } else {
85
- const result = evaluateFallBackTreatment(params.nameOrNames as string, false);
86
- return wrapResult(result);
87
- }
85
+ return params.valid ?
86
+ client.getTreatment(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined, params.options) :
87
+ wrapResult(evaluateFallBackTreatment(params.nameOrNames, false));
88
88
  }
89
89
 
90
90
  function getTreatmentWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
91
91
  const params = validateEvaluationParams(GET_TREATMENT_WITH_CONFIG, maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions);
92
92
 
93
- if (params.valid) {
94
- return client.getTreatmentWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined, params.options);
95
- } else {
96
- const result = evaluateFallBackTreatment(params.nameOrNames as string, true);
97
- return wrapResult(result);
98
- }
93
+ return params.valid ?
94
+ client.getTreatmentWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string, params.attributes as SplitIO.Attributes | undefined, params.options) :
95
+ wrapResult(evaluateFallBackTreatment(params.nameOrNames, true));
99
96
  }
100
97
 
101
98
  function getTreatments(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
102
99
  const params = validateEvaluationParams(GET_TREATMENTS, maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions);
103
100
 
104
- if (params.valid) {
105
- return client.getTreatments(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
106
- } else {
107
- const res: SplitIO.Treatments = {};
108
- if (params.nameOrNames) (params.nameOrNames as string[]).forEach((split: string) => res[split] = evaluateFallBackTreatment(split, false) as SplitIO.Treatment);
109
-
110
- return wrapResult(res);
111
- }
101
+ return params.valid ?
102
+ client.getTreatments(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options) :
103
+ wrapResult(evaluateFallBackTreatment(params.nameOrNames || [], false));
112
104
  }
113
105
 
114
106
  function getTreatmentsWithConfig(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
115
107
  const params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG, maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions);
116
108
 
117
- if (params.valid) {
118
- return client.getTreatmentsWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
119
- } else {
120
- const res: SplitIO.TreatmentsWithConfig = {};
121
- if (params.nameOrNames) (params.nameOrNames as string[]).forEach(split => res[split] = evaluateFallBackTreatment(split, true) as SplitIO.TreatmentWithConfig);
122
-
123
- return wrapResult(res);
124
- }
109
+ return params.valid ?
110
+ client.getTreatmentsWithConfig(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options) :
111
+ wrapResult(evaluateFallBackTreatment(params.nameOrNames || [], true));
125
112
  }
126
113
 
127
114
  function getTreatmentsByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
128
115
  const params = validateEvaluationParams(GET_TREATMENTS_BY_FLAG_SETS, maybeKey, maybeFlagSets, maybeAttributes, maybeOptions);
129
116
 
130
- if (params.valid) {
131
- return client.getTreatmentsByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
132
- } else {
133
- return wrapResult({});
134
- }
117
+ return params.valid ?
118
+ client.getTreatmentsByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options) :
119
+ wrapResult({});
135
120
  }
136
121
 
137
122
  function getTreatmentsWithConfigByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
138
123
  const params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, maybeKey, maybeFlagSets, maybeAttributes, maybeOptions);
139
124
 
140
- if (params.valid) {
141
- return client.getTreatmentsWithConfigByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options);
142
- } else {
143
- return wrapResult({});
144
- }
125
+ return params.valid ?
126
+ client.getTreatmentsWithConfigByFlagSets(params.key as SplitIO.SplitKey, params.nameOrNames as string[], params.attributes as SplitIO.Attributes | undefined, params.options) :
127
+ wrapResult({});
145
128
  }
146
129
 
147
130
  function getTreatmentsByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
148
131
  const params = validateEvaluationParams(GET_TREATMENTS_BY_FLAG_SET, maybeKey, [maybeFlagSet], maybeAttributes, maybeOptions);
149
132
 
150
- if (params.valid) {
151
- return client.getTreatmentsByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined, params.options);
152
- } else {
153
- return wrapResult({});
154
- }
133
+ return params.valid ?
134
+ client.getTreatmentsByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined, params.options) :
135
+ wrapResult({});
155
136
  }
156
137
 
157
138
  function getTreatmentsWithConfigByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes, maybeOptions?: SplitIO.EvaluationOptions) {
158
139
  const params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, maybeKey, [maybeFlagSet], maybeAttributes, maybeOptions);
159
140
 
160
- if (params.valid) {
161
- return client.getTreatmentsWithConfigByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined, params.options);
162
- } else {
163
- return wrapResult({});
164
- }
141
+ return params.valid ?
142
+ client.getTreatmentsWithConfigByFlagSet(params.key as SplitIO.SplitKey, (params.nameOrNames as string[])[0], params.attributes as SplitIO.Attributes | undefined, params.options) :
143
+ wrapResult({});
165
144
  }
166
145
 
167
146
  function track(maybeKey: SplitIO.SplitKey, maybeTT: string, maybeEvent: string, maybeEventValue?: number, maybeProperties?: SplitIO.Properties) {
@@ -172,11 +151,9 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
172
151
  const { properties, size } = validateEventProperties(log, maybeProperties, TRACK_FN_LABEL);
173
152
  const isNotDestroyed = validateIfNotDestroyed(log, readinessManager, TRACK_FN_LABEL);
174
153
 
175
- if (isNotDestroyed && key && tt && event && eventValue !== false && properties !== false) { // @ts-expect-error
176
- return client.track(key, tt, event, eventValue, properties, size);
177
- } else {
178
- return isAsync ? Promise.resolve(false) : false;
179
- }
154
+ return isNotDestroyed && key && tt && event && eventValue !== false && properties !== false ? // @ts-expect-error
155
+ client.track(key, tt, event, eventValue, properties, size) :
156
+ wrapResult(false);
180
157
  }
181
158
 
182
159
  return {
@@ -1,6 +1,6 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
2
  import SplitIO from '../../types/splitio';
3
- import { releaseApiKey } from '../utils/inputValidation/apiKey';
3
+ import { releaseApiKey, validateAndTrackApiKey } from '../utils/inputValidation/apiKey';
4
4
  import { clientFactory } from './client';
5
5
  import { clientInputValidationDecorator } from './clientInputValidation';
6
6
  import { ISdkFactoryContext } from '../sdkFactory/types';
@@ -8,11 +8,12 @@ import { ISdkFactoryContext } from '../sdkFactory/types';
8
8
  const COOLDOWN_TIME_IN_MILLIS = 1000;
9
9
 
10
10
  /**
11
- * Creates an Sdk client, i.e., a base client with status and destroy interface
11
+ * Creates an Sdk client, i.e., a base client with status, init, flush and destroy interface
12
12
  */
13
13
  export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: boolean): SplitIO.IClient | SplitIO.IAsyncClient {
14
- const { sdkReadinessManager, syncManager, storage, signalListener, settings, telemetryTracker, uniqueKeysTracker } = params;
14
+ const { sdkReadinessManager, syncManager, storage, signalListener, settings, telemetryTracker, impressionsTracker } = params;
15
15
 
16
+ let hasInit = false;
16
17
  let lastActionTime = 0;
17
18
 
18
19
  function __cooldown(func: Function, time: number) {
@@ -47,13 +48,27 @@ export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: bo
47
48
  params.fallbackTreatmentsCalculator
48
49
  ),
49
50
 
50
- // Sdk destroy
51
51
  {
52
+ init() {
53
+ if (hasInit) return;
54
+ hasInit = true;
55
+
56
+ if (!isSharedClient) {
57
+ validateAndTrackApiKey(settings.log, settings.core.authorizationKey);
58
+ sdkReadinessManager.readinessManager.init();
59
+ impressionsTracker.start();
60
+ syncManager && syncManager.start();
61
+ signalListener && signalListener.start();
62
+ }
63
+ },
64
+
52
65
  flush() {
53
66
  // @TODO define cooldown time
54
67
  return __cooldown(__flush, COOLDOWN_TIME_IN_MILLIS);
55
68
  },
69
+
56
70
  destroy() {
71
+ hasInit = false;
57
72
  // Mark the SDK as destroyed immediately
58
73
  sdkReadinessManager.readinessManager.destroy();
59
74
 
@@ -62,7 +77,7 @@ export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: bo
62
77
  releaseApiKey(settings.core.authorizationKey);
63
78
  telemetryTracker.sessionLength();
64
79
  signalListener && signalListener.stop();
65
- uniqueKeysTracker.stop();
80
+ impressionsTracker.stop();
66
81
  }
67
82
 
68
83
  // Stop background jobs
@@ -4,16 +4,10 @@ import { impressionsTrackerFactory } from '../trackers/impressionsTracker';
4
4
  import { eventTrackerFactory } from '../trackers/eventTracker';
5
5
  import { telemetryTrackerFactory } from '../trackers/telemetryTracker';
6
6
  import SplitIO from '../../types/splitio';
7
- import { validateAndTrackApiKey } from '../utils/inputValidation/apiKey';
8
7
  import { createLoggerAPI } from '../logger/sdkLogger';
9
8
  import { NEW_FACTORY, RETRIEVE_MANAGER } from '../logger/constants';
10
9
  import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../readiness/constants';
11
10
  import { objectAssign } from '../utils/lang/objectAssign';
12
- import { strategyDebugFactory } from '../trackers/strategy/strategyDebug';
13
- import { strategyOptimizedFactory } from '../trackers/strategy/strategyOptimized';
14
- import { strategyNoneFactory } from '../trackers/strategy/strategyNone';
15
- import { uniqueKeysTrackerFactory } from '../trackers/uniqueKeysTracker';
16
- import { DEBUG, OPTIMIZED } from '../utils/constants';
17
11
  import { setRolloutPlan } from '../storages/setRolloutPlan';
18
12
  import { IStorageSync } from '../storages/types';
19
13
  import { getMatching } from '../utils/key';
@@ -25,23 +19,13 @@ import { FallbackTreatmentsCalculator } from '../evaluator/fallbackTreatmentsCal
25
19
  export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IAsyncSDK | SplitIO.IBrowserSDK | SplitIO.IBrowserAsyncSDK {
26
20
 
27
21
  const { settings, platform, storageFactory, splitApiFactory, extraProps,
28
- syncManagerFactory, SignalListener, impressionsObserverFactory,
29
- integrationsManagerFactory, sdkManagerFactory, sdkClientMethodFactory,
30
- filterAdapterFactory, lazyInit } = params;
31
- const { log, sync: { impressionsMode }, initialRolloutPlan, core: { key } } = settings;
22
+ syncManagerFactory, SignalListener,
23
+ integrationsManagerFactory, sdkManagerFactory, sdkClientMethodFactory, lazyInit } = params;
24
+ const { log, initialRolloutPlan, core: { key } } = settings;
32
25
 
33
26
  // @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid SDK Key, etc.
34
27
  // On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
35
28
 
36
- // initialization
37
- let hasInit = false;
38
- const initCallbacks: (() => void)[] = [];
39
-
40
- function whenInit(cb: () => void) {
41
- if (hasInit) cb();
42
- else initCallbacks.push(cb);
43
- }
44
-
45
29
  const sdkReadinessManager = sdkReadinessManagerFactory(platform.EventEmitter, settings);
46
30
  const readiness = sdkReadinessManager.readinessManager;
47
31
 
@@ -61,38 +45,29 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IA
61
45
  }
62
46
  });
63
47
 
64
- const fallbackTreatmentsCalculator = new FallbackTreatmentsCalculator(settings.fallbackTreatments);
48
+ const fallbackTreatmentsCalculator = FallbackTreatmentsCalculator(settings.fallbackTreatments);
65
49
 
66
50
  if (initialRolloutPlan) {
67
51
  setRolloutPlan(log, initialRolloutPlan, storage as IStorageSync, key && getMatching(key));
68
52
  if ((storage as IStorageSync).splits.getChangeNumber() > -1) readiness.splits.emit(SDK_SPLITS_CACHE_LOADED, { initialCacheLoad: false /* Not an initial load, cache exists */ });
69
53
  }
70
54
 
71
- const clients: Record<string, SplitIO.IBasicClient> = {};
55
+ const clients: Record<string, SplitIO.IBasicClient & { init: () => void }> = {};
72
56
  const telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
73
57
  const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage, telemetryTracker });
74
58
 
75
- const observer = impressionsObserverFactory();
76
- const uniqueKeysTracker = uniqueKeysTrackerFactory(log, storage.uniqueKeys, filterAdapterFactory && filterAdapterFactory());
77
-
78
- const noneStrategy = strategyNoneFactory(storage.impressionCounts, uniqueKeysTracker);
79
- const strategy = impressionsMode === OPTIMIZED ?
80
- strategyOptimizedFactory(observer, storage.impressionCounts) :
81
- impressionsMode === DEBUG ?
82
- strategyDebugFactory(observer) :
83
- noneStrategy;
84
-
85
- const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, noneStrategy, strategy, whenInit, integrationsManager, storage.telemetry);
86
- const eventTracker = eventTrackerFactory(settings, storage.events, whenInit, integrationsManager, storage.telemetry);
59
+ const impressionsTracker = impressionsTrackerFactory(params, storage, integrationsManager);
60
+ const eventTracker = eventTrackerFactory(settings, storage.events, integrationsManager, storage.telemetry);
87
61
 
88
62
  // splitApi is used by SyncManager and Browser signal listener
89
63
  const splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
90
64
 
91
- const ctx: ISdkFactoryContext = { clients, splitApi, eventTracker, impressionsTracker, telemetryTracker, uniqueKeysTracker, sdkReadinessManager, readiness, settings, storage, platform, fallbackTreatmentsCalculator };
65
+ const ctx: ISdkFactoryContext = { clients, splitApi, eventTracker, impressionsTracker, telemetryTracker, sdkReadinessManager, readiness, settings, storage, platform, fallbackTreatmentsCalculator };
92
66
 
93
67
  const syncManager = syncManagerFactory && syncManagerFactory(ctx as ISdkFactoryContextSync);
94
68
  ctx.syncManager = syncManager;
95
69
 
70
+ // @TODO: move into platform, and call inside sdkClientFactory (if it's used only there)
96
71
  const signalListener = SignalListener && new SignalListener(syncManager, settings, storage, splitApi);
97
72
  ctx.signalListener = signalListener;
98
73
 
@@ -102,18 +77,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IA
102
77
 
103
78
 
104
79
  function init() {
105
- if (hasInit) return;
106
- hasInit = true;
107
-
108
- // We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle.
109
- validateAndTrackApiKey(log, settings.core.authorizationKey);
110
- readiness.init();
111
- uniqueKeysTracker.start();
112
- syncManager && syncManager.start();
113
- signalListener && signalListener.start();
114
-
115
- initCallbacks.forEach((cb) => cb());
116
- initCallbacks.length = 0;
80
+ Object.keys(clients).map(key => clients[key].init());
117
81
  }
118
82
 
119
83
  log.info(NEW_FACTORY, [settings.version]);
@@ -135,7 +99,6 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IA
135
99
  settings,
136
100
 
137
101
  destroy() {
138
- hasInit = false;
139
102
  return Promise.all(Object.keys(clients).map(key => clients[key].destroy())).then(() => { });
140
103
  }
141
104
  }, extraProps && extraProps(ctx), lazyInit ? { init } : init());
@@ -8,7 +8,7 @@ import { IFetch, ISplitApi, IEventSourceConstructor } from '../services/types';
8
8
  import { IStorageAsync, IStorageSync, IStorageFactoryParams } from '../storages/types';
9
9
  import { ISyncManager } from '../sync/types';
10
10
  import { IImpressionObserver } from '../trackers/impressionObserver/types';
11
- import { IImpressionsTracker, IEventTracker, ITelemetryTracker, IFilterAdapter, IUniqueKeysTracker } from '../trackers/types';
11
+ import { IImpressionsTracker, IEventTracker, ITelemetryTracker, IFilterAdapter } from '../trackers/types';
12
12
  import { ISettings } from '../types';
13
13
  import SplitIO from '../../types/splitio';
14
14
 
@@ -47,7 +47,6 @@ export interface ISdkFactoryContext {
47
47
  eventTracker: IEventTracker,
48
48
  telemetryTracker: ITelemetryTracker,
49
49
  storage: IStorageSync | IStorageAsync,
50
- uniqueKeysTracker: IUniqueKeysTracker,
51
50
  signalListener?: ISignalListener
52
51
  splitApi?: ISplitApi
53
52
  syncManager?: ISyncManager,
@@ -98,7 +97,11 @@ export interface ISdkFactoryParams {
98
97
 
99
98
  // Sdk client method factory.
100
99
  // It Allows to distinguish SDK clients with the client-side API (`IBrowserSDK` and `IBrowserAsyncSDK`) or server-side API (`ISDK` and `IAsyncSDK`).
101
- sdkClientMethodFactory: (params: ISdkFactoryContext) => ({ (): SplitIO.IBrowserClient; (key: SplitIO.SplitKey): SplitIO.IBrowserClient; } | (() => SplitIO.IClient) | (() => SplitIO.IAsyncClient))
100
+ sdkClientMethodFactory: (params: ISdkFactoryContext) => (
101
+ { (): SplitIO.IBrowserClient & { init(): void }; (key: SplitIO.SplitKey): SplitIO.IBrowserClient & { init(): void }; } |
102
+ (() => SplitIO.IClient & { init(): void }) |
103
+ (() => SplitIO.IAsyncClient & { init(): void })
104
+ )
102
105
 
103
106
  // Impression observer factory.
104
107
  impressionsObserverFactory: () => IImpressionObserver
@@ -205,7 +205,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
205
205
  });
206
206
  }
207
207
 
208
- private removeFromFlagSets(featureFlagName: string, flagSets?: string[]) {
208
+ private removeFromFlagSets(featureFlagName: string, flagSets?: string[] | null) {
209
209
  if (!flagSets) return;
210
210
 
211
211
  flagSets.forEach(flagSet => {
@@ -114,7 +114,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
114
114
  });
115
115
  }
116
116
 
117
- private removeFromFlagSets(featureFlagName: string, flagSets: string[] | undefined) {
117
+ private removeFromFlagSets(featureFlagName: string, flagSets?: string[] | null) {
118
118
  if (!flagSets) return;
119
119
  flagSets.forEach(flagSet => {
120
120
  this.removeNames(flagSet, featureFlagName);
@@ -59,7 +59,7 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
59
59
  return this.redis.incr(ttKey);
60
60
  }
61
61
 
62
- private _updateFlagSets(featureFlagName: string, flagSetsOfRemovedFlag?: string[], flagSetsOfAddedFlag?: string[]) {
62
+ private _updateFlagSets(featureFlagName: string, flagSetsOfRemovedFlag?: string[] | null, flagSetsOfAddedFlag?: string[] | null) {
63
63
  const removeFromFlagSets = returnDifference(flagSetsOfRemovedFlag, flagSetsOfAddedFlag);
64
64
 
65
65
  let addToFlagSets = returnDifference(flagSetsOfAddedFlag, flagSetsOfRemovedFlag);
@@ -43,7 +43,7 @@ export class SplitsCachePluggable extends AbstractSplitsCacheAsync {
43
43
  return this.wrapper.incr(ttKey);
44
44
  }
45
45
 
46
- private _updateFlagSets(featureFlagName: string, flagSetsOfRemovedFlag?: string[], flagSetsOfAddedFlag?: string[]) {
46
+ private _updateFlagSets(featureFlagName: string, flagSetsOfRemovedFlag?: string[] | null, flagSetsOfAddedFlag?: string[] | null) {
47
47
  const removeFromFlagSets = returnDifference(flagSetsOfRemovedFlag, flagSetsOfAddedFlag);
48
48
 
49
49
  let addToFlagSets = returnDifference(flagSetsOfAddedFlag, flagSetsOfRemovedFlag);
@@ -35,12 +35,12 @@ export function setRolloutPlan(log: ILogger, rolloutPlan: RolloutPlan, storage:
35
35
 
36
36
  if (splits && ff) {
37
37
  splits.clear();
38
- splits.update(ff.d, [], ff.t);
38
+ splits.update(ff.d || [], [], ff.t);
39
39
  }
40
40
 
41
41
  if (rbSegments && rbs) {
42
42
  rbSegments.clear();
43
- rbSegments.update(rbs.d, [], rbs.t);
43
+ rbSegments.update(rbs.d || [], [], rbs.t);
44
44
  }
45
45
 
46
46
  const segmentChanges = rolloutPlan.segmentChanges;
@@ -102,7 +102,7 @@ export function segmentChangesUpdaterFactory(
102
102
  // If the operation is forbidden, it may be due to permissions. Destroy the SDK instance.
103
103
  // @TODO although factory status is destroyed, synchronization is not stopped
104
104
  if (readiness) readiness.setDestroyed();
105
- log.error(`${LOG_PREFIX_INSTANTIATION}: you passed a client-side type authorizationKey, please grab an SDK Key from the Split user interface that is of type server-side.`);
105
+ log.error(`${LOG_PREFIX_INSTANTIATION}: you passed a client-side type authorizationKey, please grab an SDK Key from Harness FME UI that is of type server-side.`);
106
106
  } else {
107
107
  log.warn(`${LOG_PREFIX_SYNC_SEGMENTS}Error while doing fetch of segments. ${error}`);
108
108
  }
@@ -31,7 +31,7 @@ function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
31
31
  * Exported for testing purposes.
32
32
  */
33
33
  export function parseSegments(ruleEntity: ISplit | IRBSegment, matcherType: typeof IN_SEGMENT | typeof IN_RULE_BASED_SEGMENT = IN_SEGMENT): Set<string> {
34
- const { conditions = [], excluded } = ruleEntity as IRBSegment;
34
+ const { conditions, excluded } = ruleEntity as IRBSegment;
35
35
 
36
36
  const segments = new Set<string>();
37
37
  if (excluded && excluded.segments) {
@@ -42,12 +42,14 @@ export function parseSegments(ruleEntity: ISplit | IRBSegment, matcherType: type
42
42
  });
43
43
  }
44
44
 
45
- for (let i = 0; i < conditions.length; i++) {
46
- const matchers = conditions[i].matcherGroup.matchers;
45
+ if (conditions) {
46
+ for (let i = 0; i < conditions.length; i++) {
47
+ const matchers = conditions[i].matcherGroup.matchers;
47
48
 
48
- matchers.forEach(matcher => {
49
- if (matcher.matcherType === matcherType) segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
50
- });
49
+ matchers.forEach(matcher => {
50
+ if (matcher.matcherType === matcherType) segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
51
+ });
52
+ }
51
53
  }
52
54
 
53
55
  return segments;
@@ -88,7 +90,7 @@ function matchFilters(featureFlag: ISplit, filters: ISplitFiltersValidation) {
88
90
  export function computeMutation<T extends ISplit | IRBSegment>(rules: Array<T>, segments: Set<string>, filters?: ISplitFiltersValidation): ISplitMutations<T> {
89
91
 
90
92
  return rules.reduce((accum, ruleEntity) => {
91
- if (ruleEntity.status === 'ACTIVE' && (!filters || matchFilters(ruleEntity as ISplit, filters))) {
93
+ if (ruleEntity.status !== 'ARCHIVED' && (!filters || matchFilters(ruleEntity as ISplit, filters))) {
92
94
  accum.added.push(ruleEntity);
93
95
 
94
96
  parseSegments(ruleEntity).forEach((segmentName: string) => {
@@ -171,7 +173,7 @@ export function splitChangesUpdaterFactory(
171
173
  let updatedFlags: string[] = [];
172
174
  let ffUpdate: MaybeThenable<boolean> = false;
173
175
  if (splitChanges.ff) {
174
- const { added, removed, names } = computeMutation(splitChanges.ff.d, usedSegments, splitFiltersValidation);
176
+ const { added, removed, names } = computeMutation(splitChanges.ff.d || [], usedSegments, splitFiltersValidation);
175
177
  updatedFlags = names;
176
178
  log.debug(SYNC_SPLITS_UPDATE, [added.length, removed.length]);
177
179
  ffUpdate = splits.update(added, removed, splitChanges.ff.t);
@@ -179,7 +181,7 @@ export function splitChangesUpdaterFactory(
179
181
 
180
182
  let rbsUpdate: MaybeThenable<boolean> = false;
181
183
  if (splitChanges.rbs) {
182
- const { added, removed } = computeMutation(splitChanges.rbs.d, usedSegments);
184
+ const { added, removed } = computeMutation(splitChanges.rbs.d || [], usedSegments);
183
185
  log.debug(SYNC_RBS_UPDATE, [added.length, removed.length]);
184
186
  rbsUpdate = rbSegments.update(added, removed, splitChanges.rbs.t);
185
187
  }
@@ -17,7 +17,6 @@ import { isConsumerMode } from '../utils/settingsValidation/mode';
17
17
  export function eventTrackerFactory(
18
18
  settings: ISettings,
19
19
  eventsCache: IEventsCacheBase,
20
- whenInit: (cb: () => void) => void,
21
20
  integrationsManager?: IEventsHandler,
22
21
  telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync
23
22
  ): IEventTracker {
@@ -33,15 +32,13 @@ export function eventTrackerFactory(
33
32
  if (tracked) {
34
33
  log.info(EVENTS_TRACKER_SUCCESS, [msg]);
35
34
  if (integrationsManager) {
36
- whenInit(() => {
37
- // Wrap in a timeout because we don't want it to be blocking.
38
- setTimeout(() => {
39
- // copy of event, to avoid unexpected behavior if modified by integrations
40
- const eventDataCopy = objectAssign({}, eventData);
41
- if (properties) eventDataCopy.properties = objectAssign({}, properties);
42
- // integrationsManager does not throw errors (they are internally handled by each integration module)
43
- integrationsManager.handleEvent(eventDataCopy);
44
- });
35
+ // Wrap in a timeout because we don't want it to be blocking.
36
+ setTimeout(() => {
37
+ // copy of event, to avoid unexpected behavior if modified by integrations
38
+ const eventDataCopy = objectAssign({}, eventData);
39
+ if (properties) eventDataCopy.properties = objectAssign({}, properties);
40
+ // integrationsManager does not throw errors (they are internally handled by each integration module)
41
+ integrationsManager.handleEvent(eventDataCopy);
45
42
  });
46
43
  }
47
44
  } else {
@@ -1,28 +1,46 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
2
  import { thenable } from '../utils/promise/thenable';
3
- import { IImpressionsCacheBase, ITelemetryCacheSync, ITelemetryCacheAsync } from '../storages/types';
4
- import { IImpressionsHandler, IImpressionsTracker, ImpressionDecorated, IStrategy } from './types';
5
- import { ISettings } from '../types';
3
+ import { ITelemetryCacheSync, IStorageBase } from '../storages/types';
4
+ import { IImpressionsHandler, IImpressionsTracker, ImpressionDecorated } from './types';
6
5
  import { IMPRESSIONS_TRACKER_SUCCESS, ERROR_IMPRESSIONS_TRACKER, ERROR_IMPRESSIONS_LISTENER } from '../logger/constants';
7
- import { CONSENT_DECLINED, DEDUPED, QUEUED } from '../utils/constants';
6
+ import { CONSENT_DECLINED, DEBUG, DEDUPED, OPTIMIZED, QUEUED } from '../utils/constants';
8
7
  import SplitIO from '../../types/splitio';
8
+ import { ISdkFactoryParams } from '../sdkFactory/types';
9
+ import { strategyDebugFactory } from './strategy/strategyDebug';
10
+ import { strategyNoneFactory } from './strategy/strategyNone';
11
+ import { strategyOptimizedFactory } from './strategy/strategyOptimized';
12
+ import { uniqueKeysTrackerFactory } from './uniqueKeysTracker';
9
13
 
10
14
  /**
11
15
  * Impressions tracker stores impressions in cache and pass them to the listener and integrations manager if provided.
12
16
  */
13
17
  export function impressionsTrackerFactory(
14
- settings: ISettings,
15
- impressionsCache: IImpressionsCacheBase,
16
- noneStrategy: IStrategy,
17
- strategy: IStrategy,
18
- whenInit: (cb: () => void) => void,
18
+ params: Pick<ISdkFactoryParams, 'settings' | 'impressionsObserverFactory' | 'filterAdapterFactory'>,
19
+ storage: Pick<IStorageBase, 'impressions' | 'impressionCounts' | 'uniqueKeys' | 'telemetry'>,
19
20
  integrationsManager?: IImpressionsHandler,
20
- telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync,
21
21
  ): IImpressionsTracker {
22
22
 
23
- const { log, impressionListener, runtime: { ip, hostname }, version } = settings;
23
+ const { settings, impressionsObserverFactory, filterAdapterFactory } = params;
24
+ const { log, impressionListener, runtime: { ip, hostname }, version, sync: { impressionsMode } } = settings;
25
+ const observer = impressionsObserverFactory();
26
+ const uniqueKeysTracker = uniqueKeysTrackerFactory(log, storage.uniqueKeys, filterAdapterFactory && filterAdapterFactory());
27
+
28
+ const noneStrategy = strategyNoneFactory(storage.impressionCounts, uniqueKeysTracker);
29
+ const strategy = impressionsMode === OPTIMIZED ?
30
+ strategyOptimizedFactory(observer, storage.impressionCounts) :
31
+ impressionsMode === DEBUG ?
32
+ strategyDebugFactory(observer) :
33
+ noneStrategy;
24
34
 
25
35
  return {
36
+ start() {
37
+ uniqueKeysTracker.start();
38
+ },
39
+
40
+ stop() {
41
+ uniqueKeysTracker.stop();
42
+ },
43
+
26
44
  track(impressions: ImpressionDecorated[], attributes?: SplitIO.Attributes) {
27
45
  if (settings.userConsent === CONSENT_DECLINED) return;
28
46
 
@@ -36,7 +54,7 @@ export function impressionsTrackerFactory(
36
54
  const impressionsToStoreLength = impressionsToStore.length;
37
55
 
38
56
  if (impressionsToStoreLength) {
39
- const res = impressionsCache.track(impressionsToStore.map((item) => item.imp));
57
+ const res = storage.impressions.track(impressionsToStore.map((item) => item.imp));
40
58
 
41
59
  // If we're on an async storage, handle error and log it.
42
60
  if (thenable(res)) {
@@ -48,9 +66,9 @@ export function impressionsTrackerFactory(
48
66
  } else {
49
67
  // Record when impressionsCache is sync only (standalone mode)
50
68
  // @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
51
- if (telemetryCache) {
52
- (telemetryCache as ITelemetryCacheSync).recordImpressionStats(QUEUED, impressionsToStoreLength);
53
- (telemetryCache as ITelemetryCacheSync).recordImpressionStats(DEDUPED, impressionsLength - impressionsToStoreLength);
69
+ if (storage.telemetry) {
70
+ (storage.telemetry as ITelemetryCacheSync).recordImpressionStats(QUEUED, impressionsToStoreLength);
71
+ (storage.telemetry as ITelemetryCacheSync).recordImpressionStats(DEDUPED, impressionsLength - impressionsToStoreLength);
54
72
  }
55
73
  }
56
74
  }
@@ -67,18 +85,16 @@ export function impressionsTrackerFactory(
67
85
  sdkLanguageVersion: version
68
86
  };
69
87
 
70
- whenInit(() => {
71
- // Wrap in a timeout because we don't want it to be blocking.
72
- setTimeout(() => {
73
- // integrationsManager.handleImpression does not throw errors
74
- if (integrationsManager) integrationsManager.handleImpression(impressionData);
88
+ // Wrap in a timeout because we don't want it to be blocking.
89
+ setTimeout(() => {
90
+ // integrationsManager.handleImpression does not throw errors
91
+ if (integrationsManager) integrationsManager.handleImpression(impressionData);
75
92
 
76
- try { // @ts-ignore. An exception on the listeners should not break the SDK.
77
- if (impressionListener) impressionListener.logImpression(impressionData);
78
- } catch (err) {
79
- log.error(ERROR_IMPRESSIONS_LISTENER, [err]);
80
- }
81
- });
93
+ try { // @ts-ignore. An exception on the listeners should not break the SDK.
94
+ if (impressionListener) impressionListener.logImpression(impressionData);
95
+ } catch (err) {
96
+ log.error(ERROR_IMPRESSIONS_LISTENER, [err]);
97
+ }
82
98
  });
83
99
  }
84
100
  }
@@ -29,7 +29,9 @@ export type ImpressionDecorated = {
29
29
  };
30
30
 
31
31
  export interface IImpressionsTracker {
32
- track(impressions: ImpressionDecorated[], attributes?: SplitIO.Attributes): void
32
+ start(): void;
33
+ stop(): void;
34
+ track(impressions: ImpressionDecorated[], attributes?: SplitIO.Attributes): void;
33
35
  }
34
36
 
35
37
  /** Telemetry tracker */