@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.
- package/CHANGES.txt +8 -1
- package/cjs/evaluator/condition/engineUtils.js +2 -2
- package/cjs/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +3 -3
- package/cjs/evaluator/fallbackTreatmentsCalculator/index.js +21 -32
- package/cjs/evaluator/matchers/whitelist.js +1 -1
- package/cjs/integrations/pluggable.js +1 -1
- package/cjs/listeners/node.js +2 -2
- package/cjs/logger/constants.js +3 -4
- package/cjs/logger/index.js +1 -1
- package/cjs/logger/messages/debug.js +1 -1
- package/cjs/logger/messages/error.js +1 -1
- package/cjs/logger/messages/info.js +2 -3
- package/cjs/logger/messages/warn.js +4 -4
- package/cjs/sdkClient/client.js +2 -3
- package/cjs/sdkClient/clientAttributesDecoration.js +3 -3
- package/cjs/sdkClient/clientInputValidation.js +36 -68
- package/cjs/sdkClient/identity.js +1 -1
- package/cjs/sdkClient/sdkClient.js +19 -7
- package/cjs/sdkFactory/index.js +8 -41
- package/cjs/services/splitApi.js +13 -13
- package/cjs/services/splitHttpClient.js +1 -1
- package/cjs/storages/KeyBuilder.js +12 -12
- package/cjs/storages/KeyBuilderCS.js +13 -13
- package/cjs/storages/KeyBuilderSS.js +15 -15
- package/cjs/storages/getRolloutPlan.js +1 -1
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -1
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +1 -1
- package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +1 -1
- package/cjs/storages/inRedis/EventsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +5 -5
- package/cjs/storages/inRedis/ImpressionsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/RedisAdapter.js +8 -8
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +6 -6
- package/cjs/storages/inRedis/TelemetryCacheInRedis.js +7 -7
- package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +3 -3
- package/cjs/storages/pluggable/EventsCachePluggable.js +1 -1
- package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +6 -6
- package/cjs/storages/pluggable/SplitsCachePluggable.js +4 -4
- package/cjs/storages/pluggable/TelemetryCachePluggable.js +7 -7
- package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +2 -2
- package/cjs/storages/pluggable/index.js +3 -3
- package/cjs/storages/pluggable/wrapperAdapter.js +1 -1
- package/cjs/storages/setRolloutPlan.js +3 -3
- package/cjs/storages/utils.js +6 -6
- package/cjs/sync/offline/splitsParser/parseCondition.js +1 -1
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/cjs/sync/polling/pollingManagerSS.js +2 -2
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +6 -6
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +12 -10
- package/cjs/sync/streaming/SSEClient/index.js +2 -2
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
- package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +2 -2
- package/cjs/sync/streaming/parseUtils.js +1 -1
- package/cjs/sync/submitters/submitter.js +1 -1
- package/cjs/trackers/eventTracker.js +10 -12
- package/cjs/trackers/impressionObserver/buildKey.js +1 -1
- package/cjs/trackers/impressionsTracker.js +37 -20
- package/cjs/trackers/uniqueKeysTracker.js +1 -1
- package/cjs/utils/inputValidation/apiKey.js +1 -1
- package/cjs/utils/inputValidation/attribute.js +2 -2
- package/cjs/utils/inputValidation/eventProperties.js +1 -1
- package/cjs/utils/inputValidation/isOperational.js +1 -1
- package/cjs/utils/lang/index.js +1 -1
- package/cjs/utils/lang/sets.js +4 -4
- package/cjs/utils/promise/timeout.js +1 -1
- package/cjs/utils/settingsValidation/splitFilters.js +2 -2
- package/cjs/utils/settingsValidation/url.js +5 -5
- package/esm/evaluator/condition/engineUtils.js +2 -2
- package/esm/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +3 -3
- package/esm/evaluator/fallbackTreatmentsCalculator/index.js +21 -33
- package/esm/evaluator/matchers/whitelist.js +1 -1
- package/esm/integrations/pluggable.js +1 -1
- package/esm/listeners/node.js +2 -2
- package/esm/logger/constants.js +0 -1
- package/esm/logger/index.js +1 -1
- package/esm/logger/messages/info.js +1 -2
- package/esm/logger/messages/warn.js +3 -3
- package/esm/sdkClient/client.js +3 -4
- package/esm/sdkClient/clientAttributesDecoration.js +3 -3
- package/esm/sdkClient/clientInputValidation.js +36 -68
- package/esm/sdkClient/identity.js +1 -1
- package/esm/sdkClient/sdkClient.js +20 -8
- package/esm/sdkFactory/index.js +8 -41
- package/esm/services/splitApi.js +13 -13
- package/esm/services/splitHttpClient.js +1 -1
- package/esm/storages/KeyBuilder.js +12 -12
- package/esm/storages/KeyBuilderCS.js +12 -12
- package/esm/storages/KeyBuilderSS.js +14 -14
- package/esm/storages/getRolloutPlan.js +1 -1
- package/esm/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
- package/esm/storages/inRedis/EventsCacheInRedis.js +1 -1
- package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +4 -4
- package/esm/storages/inRedis/RedisAdapter.js +7 -7
- package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -4
- package/esm/storages/inRedis/TelemetryCacheInRedis.js +7 -7
- package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +1 -1
- package/esm/storages/pluggable/EventsCachePluggable.js +1 -1
- package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +5 -5
- package/esm/storages/pluggable/SplitsCachePluggable.js +2 -2
- package/esm/storages/pluggable/TelemetryCachePluggable.js +7 -7
- package/esm/storages/pluggable/UniqueKeysCachePluggable.js +1 -1
- package/esm/storages/pluggable/index.js +2 -2
- package/esm/storages/pluggable/wrapperAdapter.js +1 -1
- package/esm/storages/setRolloutPlan.js +3 -3
- package/esm/storages/utils.js +6 -6
- package/esm/sync/offline/splitsParser/parseCondition.js +1 -1
- package/esm/sync/polling/pollingManagerSS.js +2 -2
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +6 -6
- package/esm/sync/polling/updaters/splitChangesUpdater.js +12 -10
- package/esm/sync/streaming/SSEClient/index.js +2 -2
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
- package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +2 -2
- package/esm/sync/streaming/parseUtils.js +1 -1
- package/esm/sync/submitters/submitter.js +1 -1
- package/esm/trackers/eventTracker.js +10 -12
- package/esm/trackers/impressionObserver/buildKey.js +1 -1
- package/esm/trackers/impressionsTracker.js +38 -21
- package/esm/trackers/uniqueKeysTracker.js +1 -1
- package/esm/utils/inputValidation/apiKey.js +1 -1
- package/esm/utils/inputValidation/attribute.js +2 -2
- package/esm/utils/inputValidation/isOperational.js +1 -1
- package/esm/utils/lang/sets.js +4 -4
- package/esm/utils/promise/timeout.js +1 -1
- package/esm/utils/settingsValidation/splitFilters.js +2 -2
- package/esm/utils/settingsValidation/url.js +5 -5
- package/package.json +6 -6
- package/src/dtos/types.ts +15 -15
- package/src/evaluator/condition/engineUtils.ts +2 -2
- package/src/evaluator/fallbackTreatmentsCalculator/index.ts +23 -41
- package/src/evaluator/matchers/whitelist.ts +2 -2
- package/src/evaluator/types.ts +2 -2
- package/src/evaluator/value/index.ts +1 -1
- package/src/integrations/pluggable.ts +1 -1
- package/src/logger/constants.ts +0 -1
- package/src/logger/messages/info.ts +1 -2
- package/src/logger/messages/warn.ts +3 -3
- package/src/sdkClient/client.ts +3 -5
- package/src/sdkClient/clientInputValidation.ts +38 -61
- package/src/sdkClient/sdkClient.ts +20 -5
- package/src/sdkFactory/index.ts +10 -47
- package/src/sdkFactory/types.ts +6 -3
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +1 -1
- package/src/storages/inMemory/SplitsCacheInMemory.ts +1 -1
- package/src/storages/inRedis/SplitsCacheInRedis.ts +1 -1
- package/src/storages/pluggable/SplitsCachePluggable.ts +1 -1
- package/src/storages/setRolloutPlan.ts +2 -2
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
- package/src/sync/polling/updaters/splitChangesUpdater.ts +11 -9
- package/src/trackers/eventTracker.ts +7 -10
- package/src/trackers/impressionsTracker.ts +42 -26
- package/src/trackers/types.ts +3 -1
- package/src/utils/lang/sets.ts +4 -2
- 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)
|
|
63
|
-
|
|
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
|
-
|
|
66
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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,
|
|
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
|
-
|
|
80
|
+
impressionsTracker.stop();
|
|
66
81
|
}
|
|
67
82
|
|
|
68
83
|
// Stop background jobs
|
package/src/sdkFactory/index.ts
CHANGED
|
@@ -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,
|
|
29
|
-
integrationsManagerFactory, sdkManagerFactory, sdkClientMethodFactory,
|
|
30
|
-
|
|
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 =
|
|
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
|
|
76
|
-
const
|
|
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,
|
|
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
|
-
|
|
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());
|
package/src/sdkFactory/types.ts
CHANGED
|
@@ -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
|
|
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) => (
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
46
|
-
|
|
45
|
+
if (conditions) {
|
|
46
|
+
for (let i = 0; i < conditions.length; i++) {
|
|
47
|
+
const matchers = conditions[i].matcherGroup.matchers;
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
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
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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 {
|
|
4
|
-
import { IImpressionsHandler, IImpressionsTracker, ImpressionDecorated
|
|
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
|
-
|
|
15
|
-
|
|
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 {
|
|
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 =
|
|
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 (
|
|
52
|
-
(
|
|
53
|
-
(
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
}
|
package/src/trackers/types.ts
CHANGED
|
@@ -29,7 +29,9 @@ export type ImpressionDecorated = {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
export interface IImpressionsTracker {
|
|
32
|
-
|
|
32
|
+
start(): void;
|
|
33
|
+
stop(): void;
|
|
34
|
+
track(impressions: ImpressionDecorated[], attributes?: SplitIO.Attributes): void;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
/** Telemetry tracker */
|