@splitsoftware/splitio-commons 3.1.1-rc.0 → 3.1.1-rc.1
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 +1 -1
- package/cjs/evaluator/condition/index.js +1 -1
- package/cjs/evaluator/index.js +18 -25
- package/cjs/sdkClient/client.js +18 -17
- package/esm/evaluator/condition/index.js +1 -1
- package/esm/evaluator/index.js +18 -25
- package/esm/sdkClient/client.js +18 -17
- package/package.json +1 -1
- package/src/evaluator/Engine.ts +3 -3
- package/src/evaluator/condition/index.ts +2 -2
- package/src/evaluator/index.ts +23 -37
- package/src/evaluator/types.ts +2 -7
- package/src/sdkClient/client.ts +24 -25
package/CHANGES.txt
CHANGED
|
@@ -23,7 +23,7 @@ function conditionContext(log, matcherEvaluator, treatments, label, conditionTyp
|
|
|
23
23
|
// Whitelisting has more priority than traffic allocation, so we don't apply this filtering to those conditions.
|
|
24
24
|
if (conditionType === 'ROLLOUT' && !(0, engineUtils_1.shouldApplyRollout)(trafficAllocation, key.bucketingKey, trafficAllocationSeed)) {
|
|
25
25
|
return {
|
|
26
|
-
treatment
|
|
26
|
+
// treatment value is assigned later, at Engine's evaluationResult
|
|
27
27
|
label: labels_1.NOT_IN_SPLIT
|
|
28
28
|
};
|
|
29
29
|
}
|
package/cjs/evaluator/index.js
CHANGED
|
@@ -7,6 +7,7 @@ var labels_1 = require("../utils/labels");
|
|
|
7
7
|
var constants_1 = require("../utils/constants");
|
|
8
8
|
var sets_1 = require("../utils/lang/sets");
|
|
9
9
|
var constants_2 = require("../logger/constants");
|
|
10
|
+
var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
10
11
|
var EVALUATION_EXCEPTION = {
|
|
11
12
|
treatment: constants_1.CONTROL,
|
|
12
13
|
label: labels_1.EXCEPTION,
|
|
@@ -24,7 +25,7 @@ function treatmentsException(definitionNames) {
|
|
|
24
25
|
});
|
|
25
26
|
return evaluations;
|
|
26
27
|
}
|
|
27
|
-
function evaluateFeature(log, key, definitionName, attributes, storage
|
|
28
|
+
function evaluateFeature(log, key, definitionName, attributes, storage) {
|
|
28
29
|
var definition;
|
|
29
30
|
try {
|
|
30
31
|
definition = storage.definitions.get(definitionName);
|
|
@@ -34,15 +35,15 @@ function evaluateFeature(log, key, definitionName, attributes, storage, options)
|
|
|
34
35
|
return EVALUATION_EXCEPTION;
|
|
35
36
|
}
|
|
36
37
|
return (0, thenable_1.thenable)(definition) ?
|
|
37
|
-
definition.then(function (definition) { return getEvaluation(log, key, definition, attributes, storage
|
|
38
|
+
definition.then(function (definition) { return getEvaluation(log, key, definition, attributes, storage); })
|
|
38
39
|
.catch(
|
|
39
40
|
// Exception on async storage. For example, when the storage is redis or
|
|
40
41
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
41
42
|
function () { return EVALUATION_EXCEPTION; }) :
|
|
42
|
-
getEvaluation(log, key, definition, attributes, storage
|
|
43
|
+
getEvaluation(log, key, definition, attributes, storage);
|
|
43
44
|
}
|
|
44
45
|
exports.evaluateFeature = evaluateFeature;
|
|
45
|
-
function evaluateFeatures(log, key, definitionNames, attributes, storage
|
|
46
|
+
function evaluateFeatures(log, key, definitionNames, attributes, storage) {
|
|
46
47
|
var definitions;
|
|
47
48
|
try {
|
|
48
49
|
definitions = storage.definitions.getMany(definitionNames);
|
|
@@ -52,15 +53,15 @@ function evaluateFeatures(log, key, definitionNames, attributes, storage, option
|
|
|
52
53
|
return treatmentsException(definitionNames);
|
|
53
54
|
}
|
|
54
55
|
return (0, thenable_1.thenable)(definitions) ?
|
|
55
|
-
definitions.then(function (definitions) { return getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
56
|
+
definitions.then(function (definitions) { return getEvaluations(log, key, definitionNames, definitions, attributes, storage); })
|
|
56
57
|
.catch(
|
|
57
58
|
// Exception on async storage. For example, when the storage is redis or
|
|
58
59
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
59
60
|
function () { return treatmentsException(definitionNames); }) :
|
|
60
|
-
getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
61
|
+
getEvaluations(log, key, definitionNames, definitions, attributes, storage);
|
|
61
62
|
}
|
|
62
63
|
exports.evaluateFeatures = evaluateFeatures;
|
|
63
|
-
function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method
|
|
64
|
+
function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method) {
|
|
64
65
|
var storedFlagNames;
|
|
65
66
|
function evaluate(featureFlagsByFlagSets) {
|
|
66
67
|
var featureFlags = new Set();
|
|
@@ -74,7 +75,7 @@ function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, met
|
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
return featureFlags.size ?
|
|
77
|
-
evaluateFeatures(log, key, (0, sets_1.setToArray)(featureFlags), attributes, storage
|
|
78
|
+
evaluateFeatures(log, key, (0, sets_1.setToArray)(featureFlags), attributes, storage) :
|
|
78
79
|
{};
|
|
79
80
|
}
|
|
80
81
|
// get features by flag sets
|
|
@@ -92,30 +93,21 @@ function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, met
|
|
|
92
93
|
evaluate(storedFlagNames);
|
|
93
94
|
}
|
|
94
95
|
exports.evaluateFeaturesByFlagSets = evaluateFeaturesByFlagSets;
|
|
95
|
-
function
|
|
96
|
-
evaluation.changeNumber = definition.changeNumber;
|
|
97
|
-
evaluation.config = definition.configurations && definition.configurations[evaluation.treatment] || null;
|
|
98
|
-
evaluation.type = definition.type;
|
|
99
|
-
evaluation.subtype = definition.subtype;
|
|
100
|
-
// @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
|
|
101
|
-
evaluation.impressionsDisabled = (options === null || options === void 0 ? void 0 : options.impressionsDisabled) || definition.impressionsDisabled;
|
|
102
|
-
return evaluation;
|
|
103
|
-
}
|
|
104
|
-
function getEvaluation(log, key, definition, attributes, storage, options) {
|
|
96
|
+
function getEvaluation(log, key, definition, attributes, storage) {
|
|
105
97
|
if (definition) {
|
|
106
98
|
var split = (0, Engine_1.engineParser)(log, definition, storage);
|
|
107
99
|
var evaluation = split.getTreatment(key, attributes, evaluateFeature);
|
|
108
100
|
return (0, thenable_1.thenable)(evaluation) ?
|
|
109
|
-
evaluation.then(function (result) { return
|
|
110
|
-
|
|
101
|
+
evaluation.then(function (result) { return (0, objectAssign_1.objectAssign)(result, { definition: definition }); }) :
|
|
102
|
+
(0, objectAssign_1.objectAssign)(evaluation, { definition: definition });
|
|
111
103
|
}
|
|
112
104
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
113
105
|
}
|
|
114
|
-
function getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
106
|
+
function getEvaluations(log, key, definitionNames, definitions, attributes, storage) {
|
|
115
107
|
var result = {};
|
|
116
108
|
var thenables = [];
|
|
117
109
|
definitionNames.forEach(function (definitionName) {
|
|
118
|
-
var evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage
|
|
110
|
+
var evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage);
|
|
119
111
|
(0, thenable_1.thenable)(evaluation) ?
|
|
120
112
|
thenables.push(evaluation.then(function (res) {
|
|
121
113
|
result[definitionName] = res;
|
|
@@ -139,10 +131,11 @@ function evaluateDefaultTreatment(definitionName, storage) {
|
|
|
139
131
|
exports.evaluateDefaultTreatment = evaluateDefaultTreatment;
|
|
140
132
|
function getDefaultTreatment(definition) {
|
|
141
133
|
if (definition) {
|
|
142
|
-
return
|
|
134
|
+
return {
|
|
143
135
|
treatment: definition.defaultTreatment,
|
|
144
|
-
label: labels_1.NO_CONDITION_MATCH
|
|
145
|
-
|
|
136
|
+
label: labels_1.NO_CONDITION_MATCH,
|
|
137
|
+
definition: definition,
|
|
138
|
+
};
|
|
146
139
|
}
|
|
147
140
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
148
141
|
}
|
package/cjs/sdkClient/client.js
CHANGED
|
@@ -18,10 +18,10 @@ function treatmentsNotReady(featureFlagNames) {
|
|
|
18
18
|
});
|
|
19
19
|
return evaluations;
|
|
20
20
|
}
|
|
21
|
-
function stringify(
|
|
22
|
-
if (
|
|
21
|
+
function stringify(properties) {
|
|
22
|
+
if (properties) {
|
|
23
23
|
try {
|
|
24
|
-
return JSON.stringify(
|
|
24
|
+
return JSON.stringify(properties);
|
|
25
25
|
}
|
|
26
26
|
catch ( /* JSON.stringify should never throw with validated options, but handling just in case */_a) { /* JSON.stringify should never throw with validated options, but handling just in case */ }
|
|
27
27
|
}
|
|
@@ -40,13 +40,13 @@ function clientFactory(params) {
|
|
|
40
40
|
var stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? constants_1.TREATMENT_WITH_CONFIG : constants_1.TREATMENT);
|
|
41
41
|
var wrapUp = function (evaluationResult) {
|
|
42
42
|
var queue = [];
|
|
43
|
-
var treatment = processEvaluation(evaluationResult, featureFlagName, key,
|
|
43
|
+
var treatment = processEvaluation(evaluationResult, featureFlagName, key, withConfig, methodName, queue, options);
|
|
44
44
|
impressionsTracker.track(queue, attributes);
|
|
45
45
|
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
46
46
|
return treatment;
|
|
47
47
|
};
|
|
48
48
|
var evaluation = readinessManager.isReadyFromCache() ?
|
|
49
|
-
(0, evaluator_1.evaluateFeature)(log, key, featureFlagName, attributes, storage
|
|
49
|
+
(0, evaluator_1.evaluateFeature)(log, key, featureFlagName, attributes, storage) :
|
|
50
50
|
isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
|
|
51
51
|
Promise.resolve(treatmentNotReady) :
|
|
52
52
|
treatmentNotReady;
|
|
@@ -62,16 +62,15 @@ function clientFactory(params) {
|
|
|
62
62
|
var wrapUp = function (evaluationResults) {
|
|
63
63
|
var queue = [];
|
|
64
64
|
var treatments = {};
|
|
65
|
-
var properties = stringify(options);
|
|
66
65
|
Object.keys(evaluationResults).forEach(function (featureFlagName) {
|
|
67
|
-
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key,
|
|
66
|
+
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, withConfig, methodName, queue, options);
|
|
68
67
|
});
|
|
69
68
|
impressionsTracker.track(queue, attributes);
|
|
70
69
|
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
71
70
|
return treatments;
|
|
72
71
|
};
|
|
73
72
|
var evaluations = readinessManager.isReadyFromCache() ?
|
|
74
|
-
(0, evaluator_1.evaluateFeatures)(log, key, featureFlagNames, attributes, storage
|
|
73
|
+
(0, evaluator_1.evaluateFeatures)(log, key, featureFlagNames, attributes, storage) :
|
|
75
74
|
isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
|
|
76
75
|
Promise.resolve(treatmentsNotReady(featureFlagNames)) :
|
|
77
76
|
treatmentsNotReady(featureFlagNames);
|
|
@@ -88,16 +87,15 @@ function clientFactory(params) {
|
|
|
88
87
|
var wrapUp = function (evaluationResults) {
|
|
89
88
|
var queue = [];
|
|
90
89
|
var treatments = {};
|
|
91
|
-
var properties = stringify(options);
|
|
92
90
|
Object.keys(evaluationResults).forEach(function (featureFlagName) {
|
|
93
|
-
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key,
|
|
91
|
+
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, withConfig, methodName, queue, options);
|
|
94
92
|
});
|
|
95
93
|
impressionsTracker.track(queue, attributes);
|
|
96
94
|
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
97
95
|
return treatments;
|
|
98
96
|
};
|
|
99
97
|
var evaluations = readinessManager.isReadyFromCache() ?
|
|
100
|
-
(0, evaluator_1.evaluateFeaturesByFlagSets)(log, key, flagSetNames, attributes, storage, methodName
|
|
98
|
+
(0, evaluator_1.evaluateFeaturesByFlagSets)(log, key, flagSetNames, attributes, storage, methodName) :
|
|
101
99
|
isAsync ?
|
|
102
100
|
Promise.resolve({}) :
|
|
103
101
|
{};
|
|
@@ -113,11 +111,14 @@ function clientFactory(params) {
|
|
|
113
111
|
return getTreatmentsByFlagSets(key, [flagSetName], attributes, options, true, constants_1.TREATMENTS_WITH_CONFIG_BY_FLAGSET, constants_1.GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
|
|
114
112
|
}
|
|
115
113
|
// Internal function
|
|
116
|
-
function processEvaluation(evaluation, featureFlagName, key,
|
|
114
|
+
function processEvaluation(evaluation, featureFlagName, key, withConfig, invokingMethodName, queue, options) {
|
|
115
|
+
var _a;
|
|
116
|
+
if (options === void 0) { options = {}; }
|
|
117
117
|
var matchingKey = (0, key_1.getMatching)(key);
|
|
118
118
|
var bucketingKey = (0, key_1.getBucketing)(key);
|
|
119
|
-
var
|
|
120
|
-
var treatment = evaluation.treatment, label = evaluation.label
|
|
119
|
+
var definition = evaluation.definition;
|
|
120
|
+
var treatment = evaluation.treatment, label = evaluation.label;
|
|
121
|
+
var config = ((_a = definition === null || definition === void 0 ? void 0 : definition.configurations) === null || _a === void 0 ? void 0 : _a[treatment]) || null;
|
|
121
122
|
if (treatment === constants_1.CONTROL) {
|
|
122
123
|
var fallbackTreatment = fallbackCalculator(featureFlagName, label);
|
|
123
124
|
treatment = fallbackTreatment.treatment;
|
|
@@ -134,10 +135,10 @@ function clientFactory(params) {
|
|
|
134
135
|
time: Date.now(),
|
|
135
136
|
bucketingKey: bucketingKey,
|
|
136
137
|
label: label,
|
|
137
|
-
changeNumber: changeNumber,
|
|
138
|
-
properties: properties
|
|
138
|
+
changeNumber: definition.changeNumber,
|
|
139
|
+
properties: stringify(options.properties)
|
|
139
140
|
},
|
|
140
|
-
disabled: impressionsDisabled
|
|
141
|
+
disabled: options.impressionsDisabled || definition.impressionsDisabled
|
|
141
142
|
});
|
|
142
143
|
}
|
|
143
144
|
if (withConfig) {
|
|
@@ -20,7 +20,7 @@ export function conditionContext(log, matcherEvaluator, treatments, label, condi
|
|
|
20
20
|
// Whitelisting has more priority than traffic allocation, so we don't apply this filtering to those conditions.
|
|
21
21
|
if (conditionType === 'ROLLOUT' && !shouldApplyRollout(trafficAllocation, key.bucketingKey, trafficAllocationSeed)) {
|
|
22
22
|
return {
|
|
23
|
-
treatment
|
|
23
|
+
// treatment value is assigned later, at Engine's evaluationResult
|
|
24
24
|
label: NOT_IN_SPLIT
|
|
25
25
|
};
|
|
26
26
|
}
|
package/esm/evaluator/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { EXCEPTION, NO_CONDITION_MATCH, DEFINITION_NOT_FOUND } from '../utils/la
|
|
|
4
4
|
import { CONTROL } from '../utils/constants';
|
|
5
5
|
import { returnSetsUnion, setToArray } from '../utils/lang/sets';
|
|
6
6
|
import { WARN_FLAGSET_WITHOUT_FLAGS } from '../logger/constants';
|
|
7
|
+
import { objectAssign } from '../utils/lang/objectAssign';
|
|
7
8
|
var EVALUATION_EXCEPTION = {
|
|
8
9
|
treatment: CONTROL,
|
|
9
10
|
label: EXCEPTION,
|
|
@@ -21,7 +22,7 @@ function treatmentsException(definitionNames) {
|
|
|
21
22
|
});
|
|
22
23
|
return evaluations;
|
|
23
24
|
}
|
|
24
|
-
export function evaluateFeature(log, key, definitionName, attributes, storage
|
|
25
|
+
export function evaluateFeature(log, key, definitionName, attributes, storage) {
|
|
25
26
|
var definition;
|
|
26
27
|
try {
|
|
27
28
|
definition = storage.definitions.get(definitionName);
|
|
@@ -31,14 +32,14 @@ export function evaluateFeature(log, key, definitionName, attributes, storage, o
|
|
|
31
32
|
return EVALUATION_EXCEPTION;
|
|
32
33
|
}
|
|
33
34
|
return thenable(definition) ?
|
|
34
|
-
definition.then(function (definition) { return getEvaluation(log, key, definition, attributes, storage
|
|
35
|
+
definition.then(function (definition) { return getEvaluation(log, key, definition, attributes, storage); })
|
|
35
36
|
.catch(
|
|
36
37
|
// Exception on async storage. For example, when the storage is redis or
|
|
37
38
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
38
39
|
function () { return EVALUATION_EXCEPTION; }) :
|
|
39
|
-
getEvaluation(log, key, definition, attributes, storage
|
|
40
|
+
getEvaluation(log, key, definition, attributes, storage);
|
|
40
41
|
}
|
|
41
|
-
export function evaluateFeatures(log, key, definitionNames, attributes, storage
|
|
42
|
+
export function evaluateFeatures(log, key, definitionNames, attributes, storage) {
|
|
42
43
|
var definitions;
|
|
43
44
|
try {
|
|
44
45
|
definitions = storage.definitions.getMany(definitionNames);
|
|
@@ -48,14 +49,14 @@ export function evaluateFeatures(log, key, definitionNames, attributes, storage,
|
|
|
48
49
|
return treatmentsException(definitionNames);
|
|
49
50
|
}
|
|
50
51
|
return thenable(definitions) ?
|
|
51
|
-
definitions.then(function (definitions) { return getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
52
|
+
definitions.then(function (definitions) { return getEvaluations(log, key, definitionNames, definitions, attributes, storage); })
|
|
52
53
|
.catch(
|
|
53
54
|
// Exception on async storage. For example, when the storage is redis or
|
|
54
55
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
55
56
|
function () { return treatmentsException(definitionNames); }) :
|
|
56
|
-
getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
57
|
+
getEvaluations(log, key, definitionNames, definitions, attributes, storage);
|
|
57
58
|
}
|
|
58
|
-
export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method
|
|
59
|
+
export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method) {
|
|
59
60
|
var storedFlagNames;
|
|
60
61
|
function evaluate(featureFlagsByFlagSets) {
|
|
61
62
|
var featureFlags = new Set();
|
|
@@ -69,7 +70,7 @@ export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, stora
|
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
return featureFlags.size ?
|
|
72
|
-
evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage
|
|
73
|
+
evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage) :
|
|
73
74
|
{};
|
|
74
75
|
}
|
|
75
76
|
// get features by flag sets
|
|
@@ -86,30 +87,21 @@ export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, stora
|
|
|
86
87
|
.catch(function () { return ({}); }) :
|
|
87
88
|
evaluate(storedFlagNames);
|
|
88
89
|
}
|
|
89
|
-
function
|
|
90
|
-
evaluation.changeNumber = definition.changeNumber;
|
|
91
|
-
evaluation.config = definition.configurations && definition.configurations[evaluation.treatment] || null;
|
|
92
|
-
evaluation.type = definition.type;
|
|
93
|
-
evaluation.subtype = definition.subtype;
|
|
94
|
-
// @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
|
|
95
|
-
evaluation.impressionsDisabled = (options === null || options === void 0 ? void 0 : options.impressionsDisabled) || definition.impressionsDisabled;
|
|
96
|
-
return evaluation;
|
|
97
|
-
}
|
|
98
|
-
function getEvaluation(log, key, definition, attributes, storage, options) {
|
|
90
|
+
function getEvaluation(log, key, definition, attributes, storage) {
|
|
99
91
|
if (definition) {
|
|
100
92
|
var split = engineParser(log, definition, storage);
|
|
101
93
|
var evaluation = split.getTreatment(key, attributes, evaluateFeature);
|
|
102
94
|
return thenable(evaluation) ?
|
|
103
|
-
evaluation.then(function (result) { return
|
|
104
|
-
|
|
95
|
+
evaluation.then(function (result) { return objectAssign(result, { definition: definition }); }) :
|
|
96
|
+
objectAssign(evaluation, { definition: definition });
|
|
105
97
|
}
|
|
106
98
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
107
99
|
}
|
|
108
|
-
function getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
100
|
+
function getEvaluations(log, key, definitionNames, definitions, attributes, storage) {
|
|
109
101
|
var result = {};
|
|
110
102
|
var thenables = [];
|
|
111
103
|
definitionNames.forEach(function (definitionName) {
|
|
112
|
-
var evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage
|
|
104
|
+
var evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage);
|
|
113
105
|
thenable(evaluation) ?
|
|
114
106
|
thenables.push(evaluation.then(function (res) {
|
|
115
107
|
result[definitionName] = res;
|
|
@@ -132,10 +124,11 @@ export function evaluateDefaultTreatment(definitionName, storage) {
|
|
|
132
124
|
}
|
|
133
125
|
function getDefaultTreatment(definition) {
|
|
134
126
|
if (definition) {
|
|
135
|
-
return
|
|
127
|
+
return {
|
|
136
128
|
treatment: definition.defaultTreatment,
|
|
137
|
-
label: NO_CONDITION_MATCH
|
|
138
|
-
|
|
129
|
+
label: NO_CONDITION_MATCH,
|
|
130
|
+
definition: definition,
|
|
131
|
+
};
|
|
139
132
|
}
|
|
140
133
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
141
134
|
}
|
package/esm/sdkClient/client.js
CHANGED
|
@@ -15,10 +15,10 @@ function treatmentsNotReady(featureFlagNames) {
|
|
|
15
15
|
});
|
|
16
16
|
return evaluations;
|
|
17
17
|
}
|
|
18
|
-
export function stringify(
|
|
19
|
-
if (
|
|
18
|
+
export function stringify(properties) {
|
|
19
|
+
if (properties) {
|
|
20
20
|
try {
|
|
21
|
-
return JSON.stringify(
|
|
21
|
+
return JSON.stringify(properties);
|
|
22
22
|
}
|
|
23
23
|
catch ( /* JSON.stringify should never throw with validated options, but handling just in case */_a) { /* JSON.stringify should never throw with validated options, but handling just in case */ }
|
|
24
24
|
}
|
|
@@ -36,13 +36,13 @@ export function clientFactory(params) {
|
|
|
36
36
|
var stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENT_WITH_CONFIG : TREATMENT);
|
|
37
37
|
var wrapUp = function (evaluationResult) {
|
|
38
38
|
var queue = [];
|
|
39
|
-
var treatment = processEvaluation(evaluationResult, featureFlagName, key,
|
|
39
|
+
var treatment = processEvaluation(evaluationResult, featureFlagName, key, withConfig, methodName, queue, options);
|
|
40
40
|
impressionsTracker.track(queue, attributes);
|
|
41
41
|
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
42
42
|
return treatment;
|
|
43
43
|
};
|
|
44
44
|
var evaluation = readinessManager.isReadyFromCache() ?
|
|
45
|
-
evaluateFeature(log, key, featureFlagName, attributes, storage
|
|
45
|
+
evaluateFeature(log, key, featureFlagName, attributes, storage) :
|
|
46
46
|
isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
|
|
47
47
|
Promise.resolve(treatmentNotReady) :
|
|
48
48
|
treatmentNotReady;
|
|
@@ -58,16 +58,15 @@ export function clientFactory(params) {
|
|
|
58
58
|
var wrapUp = function (evaluationResults) {
|
|
59
59
|
var queue = [];
|
|
60
60
|
var treatments = {};
|
|
61
|
-
var properties = stringify(options);
|
|
62
61
|
Object.keys(evaluationResults).forEach(function (featureFlagName) {
|
|
63
|
-
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key,
|
|
62
|
+
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, withConfig, methodName, queue, options);
|
|
64
63
|
});
|
|
65
64
|
impressionsTracker.track(queue, attributes);
|
|
66
65
|
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
67
66
|
return treatments;
|
|
68
67
|
};
|
|
69
68
|
var evaluations = readinessManager.isReadyFromCache() ?
|
|
70
|
-
evaluateFeatures(log, key, featureFlagNames, attributes, storage
|
|
69
|
+
evaluateFeatures(log, key, featureFlagNames, attributes, storage) :
|
|
71
70
|
isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
|
|
72
71
|
Promise.resolve(treatmentsNotReady(featureFlagNames)) :
|
|
73
72
|
treatmentsNotReady(featureFlagNames);
|
|
@@ -84,16 +83,15 @@ export function clientFactory(params) {
|
|
|
84
83
|
var wrapUp = function (evaluationResults) {
|
|
85
84
|
var queue = [];
|
|
86
85
|
var treatments = {};
|
|
87
|
-
var properties = stringify(options);
|
|
88
86
|
Object.keys(evaluationResults).forEach(function (featureFlagName) {
|
|
89
|
-
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key,
|
|
87
|
+
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, withConfig, methodName, queue, options);
|
|
90
88
|
});
|
|
91
89
|
impressionsTracker.track(queue, attributes);
|
|
92
90
|
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
93
91
|
return treatments;
|
|
94
92
|
};
|
|
95
93
|
var evaluations = readinessManager.isReadyFromCache() ?
|
|
96
|
-
evaluateFeaturesByFlagSets(log, key, flagSetNames, attributes, storage, methodName
|
|
94
|
+
evaluateFeaturesByFlagSets(log, key, flagSetNames, attributes, storage, methodName) :
|
|
97
95
|
isAsync ?
|
|
98
96
|
Promise.resolve({}) :
|
|
99
97
|
{};
|
|
@@ -109,11 +107,14 @@ export function clientFactory(params) {
|
|
|
109
107
|
return getTreatmentsByFlagSets(key, [flagSetName], attributes, options, true, TREATMENTS_WITH_CONFIG_BY_FLAGSET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
|
|
110
108
|
}
|
|
111
109
|
// Internal function
|
|
112
|
-
function processEvaluation(evaluation, featureFlagName, key,
|
|
110
|
+
function processEvaluation(evaluation, featureFlagName, key, withConfig, invokingMethodName, queue, options) {
|
|
111
|
+
var _a;
|
|
112
|
+
if (options === void 0) { options = {}; }
|
|
113
113
|
var matchingKey = getMatching(key);
|
|
114
114
|
var bucketingKey = getBucketing(key);
|
|
115
|
-
var
|
|
116
|
-
var treatment = evaluation.treatment, label = evaluation.label
|
|
115
|
+
var definition = evaluation.definition;
|
|
116
|
+
var treatment = evaluation.treatment, label = evaluation.label;
|
|
117
|
+
var config = ((_a = definition === null || definition === void 0 ? void 0 : definition.configurations) === null || _a === void 0 ? void 0 : _a[treatment]) || null;
|
|
117
118
|
if (treatment === CONTROL) {
|
|
118
119
|
var fallbackTreatment = fallbackCalculator(featureFlagName, label);
|
|
119
120
|
treatment = fallbackTreatment.treatment;
|
|
@@ -130,10 +131,10 @@ export function clientFactory(params) {
|
|
|
130
131
|
time: Date.now(),
|
|
131
132
|
bucketingKey: bucketingKey,
|
|
132
133
|
label: label,
|
|
133
|
-
changeNumber: changeNumber,
|
|
134
|
-
properties: properties
|
|
134
|
+
changeNumber: definition.changeNumber,
|
|
135
|
+
properties: stringify(options.properties)
|
|
135
136
|
},
|
|
136
|
-
disabled: impressionsDisabled
|
|
137
|
+
disabled: options.impressionsDisabled || definition.impressionsDisabled
|
|
137
138
|
});
|
|
138
139
|
}
|
|
139
140
|
if (withConfig) {
|
package/package.json
CHANGED
package/src/evaluator/Engine.ts
CHANGED
|
@@ -7,12 +7,12 @@ import { CONTROL } from '../utils/constants';
|
|
|
7
7
|
import { IDefinition, MaybeThenable } from '../dtos/types';
|
|
8
8
|
import SplitIO from '../../types/splitio';
|
|
9
9
|
import { IStorageAsync, IStorageSync } from '../storages/types';
|
|
10
|
-
import { IEvaluation,
|
|
10
|
+
import { IEvaluation, IDefinitionEvaluator } from './types';
|
|
11
11
|
import { ILogger } from '../logger/types';
|
|
12
12
|
import { ENGINE_DEFAULT } from '../logger/constants';
|
|
13
13
|
import { prerequisitesMatcherContext } from './matchers/prerequisites';
|
|
14
14
|
|
|
15
|
-
function evaluationResult(result: IEvaluation | undefined, defaultTreatment: string):
|
|
15
|
+
function evaluationResult(result: IEvaluation | undefined, defaultTreatment: string): IEvaluation {
|
|
16
16
|
return {
|
|
17
17
|
treatment: get(result, 'treatment', defaultTreatment),
|
|
18
18
|
label: get(result, 'label', NO_CONDITION_MATCH)
|
|
@@ -29,7 +29,7 @@ export function engineParser(log: ILogger, split: IDefinition, storage: IStorage
|
|
|
29
29
|
|
|
30
30
|
return {
|
|
31
31
|
|
|
32
|
-
getTreatment(key: SplitIO.SplitKey, attributes: SplitIO.Attributes | undefined, splitEvaluator: IDefinitionEvaluator): MaybeThenable<
|
|
32
|
+
getTreatment(key: SplitIO.SplitKey, attributes: SplitIO.Attributes | undefined, splitEvaluator: IDefinitionEvaluator): MaybeThenable<IEvaluation> {
|
|
33
33
|
|
|
34
34
|
const parsedKey = keyParser(key);
|
|
35
35
|
|
|
@@ -29,9 +29,9 @@ export function conditionContext(log: ILogger, matcherEvaluator: (key: SplitIO.S
|
|
|
29
29
|
// Whitelisting has more priority than traffic allocation, so we don't apply this filtering to those conditions.
|
|
30
30
|
if (conditionType === 'ROLLOUT' && !shouldApplyRollout(trafficAllocation!, key.bucketingKey, trafficAllocationSeed!)) {
|
|
31
31
|
return {
|
|
32
|
-
|
|
32
|
+
// treatment value is assigned later, at Engine's evaluationResult
|
|
33
33
|
label: NOT_IN_SPLIT
|
|
34
|
-
};
|
|
34
|
+
} as IEvaluation;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// matcherEvaluator could be Async, this relays on matchers return value, so we need
|
package/src/evaluator/index.ts
CHANGED
|
@@ -4,11 +4,12 @@ import { EXCEPTION, NO_CONDITION_MATCH, DEFINITION_NOT_FOUND } from '../utils/la
|
|
|
4
4
|
import { CONTROL } from '../utils/constants';
|
|
5
5
|
import { IDefinition, MaybeThenable } from '../dtos/types';
|
|
6
6
|
import { IStorageAsync, IStorageSync } from '../storages/types';
|
|
7
|
-
import {
|
|
7
|
+
import { IEvaluation } from './types';
|
|
8
8
|
import SplitIO from '../../types/splitio';
|
|
9
9
|
import { ILogger } from '../logger/types';
|
|
10
10
|
import { returnSetsUnion, setToArray } from '../utils/lang/sets';
|
|
11
11
|
import { WARN_FLAGSET_WITHOUT_FLAGS } from '../logger/constants';
|
|
12
|
+
import { objectAssign } from '../utils/lang/objectAssign';
|
|
12
13
|
|
|
13
14
|
const EVALUATION_EXCEPTION = {
|
|
14
15
|
treatment: CONTROL,
|
|
@@ -23,7 +24,7 @@ const EVALUATION_DEFINITION_NOT_FOUND = {
|
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
function treatmentsException(definitionNames: string[]) {
|
|
26
|
-
const evaluations: Record<string,
|
|
27
|
+
const evaluations: Record<string, IEvaluation> = {};
|
|
27
28
|
definitionNames.forEach(definitionName => {
|
|
28
29
|
evaluations[definitionName] = EVALUATION_EXCEPTION;
|
|
29
30
|
});
|
|
@@ -36,8 +37,7 @@ export function evaluateFeature(
|
|
|
36
37
|
definitionName: string,
|
|
37
38
|
attributes: SplitIO.Attributes | undefined,
|
|
38
39
|
storage: IStorageSync | IStorageAsync,
|
|
39
|
-
|
|
40
|
-
): MaybeThenable<IEvaluationResult> {
|
|
40
|
+
): MaybeThenable<IEvaluation> {
|
|
41
41
|
let definition;
|
|
42
42
|
|
|
43
43
|
try {
|
|
@@ -48,13 +48,13 @@ export function evaluateFeature(
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
return thenable(definition) ?
|
|
51
|
-
definition.then((definition) => getEvaluation(log, key, definition, attributes, storage
|
|
51
|
+
definition.then((definition) => getEvaluation(log, key, definition, attributes, storage))
|
|
52
52
|
.catch(
|
|
53
53
|
// Exception on async storage. For example, when the storage is redis or
|
|
54
54
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
55
55
|
() => EVALUATION_EXCEPTION
|
|
56
56
|
) :
|
|
57
|
-
getEvaluation(log, key, definition, attributes, storage
|
|
57
|
+
getEvaluation(log, key, definition, attributes, storage);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export function evaluateFeatures(
|
|
@@ -63,8 +63,7 @@ export function evaluateFeatures(
|
|
|
63
63
|
definitionNames: string[],
|
|
64
64
|
attributes: SplitIO.Attributes | undefined,
|
|
65
65
|
storage: IStorageSync | IStorageAsync,
|
|
66
|
-
|
|
67
|
-
): MaybeThenable<Record<string, IEvaluationResult>> {
|
|
66
|
+
): MaybeThenable<Record<string, IEvaluation>> {
|
|
68
67
|
let definitions;
|
|
69
68
|
|
|
70
69
|
try {
|
|
@@ -75,13 +74,13 @@ export function evaluateFeatures(
|
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
return thenable(definitions) ?
|
|
78
|
-
definitions.then(definitions => getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
77
|
+
definitions.then(definitions => getEvaluations(log, key, definitionNames, definitions, attributes, storage))
|
|
79
78
|
.catch(
|
|
80
79
|
// Exception on async storage. For example, when the storage is redis or
|
|
81
80
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
82
81
|
() => treatmentsException(definitionNames)
|
|
83
82
|
) :
|
|
84
|
-
getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
83
|
+
getEvaluations(log, key, definitionNames, definitions, attributes, storage);
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
export function evaluateFeaturesByFlagSets(
|
|
@@ -91,8 +90,7 @@ export function evaluateFeaturesByFlagSets(
|
|
|
91
90
|
attributes: SplitIO.Attributes | undefined,
|
|
92
91
|
storage: IStorageSync | IStorageAsync,
|
|
93
92
|
method: string,
|
|
94
|
-
|
|
95
|
-
): MaybeThenable<Record<string, IEvaluationResult>> {
|
|
93
|
+
): MaybeThenable<Record<string, IEvaluation>> {
|
|
96
94
|
let storedFlagNames: MaybeThenable<Set<string>[]>;
|
|
97
95
|
|
|
98
96
|
function evaluate(featureFlagsByFlagSets: Set<string>[]) {
|
|
@@ -107,7 +105,7 @@ export function evaluateFeaturesByFlagSets(
|
|
|
107
105
|
}
|
|
108
106
|
|
|
109
107
|
return featureFlags.size ?
|
|
110
|
-
evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage
|
|
108
|
+
evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage) :
|
|
111
109
|
{};
|
|
112
110
|
}
|
|
113
111
|
|
|
@@ -126,33 +124,21 @@ export function evaluateFeaturesByFlagSets(
|
|
|
126
124
|
evaluate(storedFlagNames);
|
|
127
125
|
}
|
|
128
126
|
|
|
129
|
-
function setEvaluationDataFromDefinition(evaluation: IEvaluationResult, definition: IDefinition, options?: SplitIO.EvaluationOptions): IEvaluationResult {
|
|
130
|
-
evaluation.changeNumber = definition.changeNumber;
|
|
131
|
-
evaluation.config = definition.configurations && definition.configurations[evaluation.treatment] || null;
|
|
132
|
-
evaluation.type = definition.type;
|
|
133
|
-
evaluation.subtype = definition.subtype;
|
|
134
|
-
// @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
|
|
135
|
-
evaluation.impressionsDisabled = options?.impressionsDisabled || definition.impressionsDisabled;
|
|
136
|
-
|
|
137
|
-
return evaluation;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
127
|
function getEvaluation(
|
|
141
128
|
log: ILogger,
|
|
142
129
|
key: SplitIO.SplitKey,
|
|
143
130
|
definition: IDefinition | null,
|
|
144
131
|
attributes: SplitIO.Attributes | undefined,
|
|
145
132
|
storage: IStorageSync | IStorageAsync,
|
|
146
|
-
|
|
147
|
-
): MaybeThenable<IEvaluationResult> {
|
|
133
|
+
): MaybeThenable<IEvaluation> {
|
|
148
134
|
|
|
149
135
|
if (definition) {
|
|
150
136
|
const split = engineParser(log, definition, storage);
|
|
151
137
|
const evaluation = split.getTreatment(key, attributes, evaluateFeature);
|
|
152
138
|
|
|
153
139
|
return thenable(evaluation) ?
|
|
154
|
-
evaluation.then(result =>
|
|
155
|
-
|
|
140
|
+
evaluation.then(result => objectAssign(result, { definition })) :
|
|
141
|
+
objectAssign(evaluation, { definition });
|
|
156
142
|
}
|
|
157
143
|
|
|
158
144
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
@@ -165,12 +151,11 @@ function getEvaluations(
|
|
|
165
151
|
definitions: Record<string, IDefinition | null>,
|
|
166
152
|
attributes: SplitIO.Attributes | undefined,
|
|
167
153
|
storage: IStorageSync | IStorageAsync,
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const result: Record<string, IEvaluationResult> = {};
|
|
154
|
+
): MaybeThenable<Record<string, IEvaluation>> {
|
|
155
|
+
const result: Record<string, IEvaluation> = {};
|
|
171
156
|
const thenables: Promise<void>[] = [];
|
|
172
157
|
definitionNames.forEach(definitionName => {
|
|
173
|
-
const evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage
|
|
158
|
+
const evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage);
|
|
174
159
|
thenable(evaluation) ?
|
|
175
160
|
thenables.push(evaluation.then(res => {
|
|
176
161
|
result[definitionName] = res;
|
|
@@ -184,7 +169,7 @@ function getEvaluations(
|
|
|
184
169
|
export function evaluateDefaultTreatment(
|
|
185
170
|
definitionName: string,
|
|
186
171
|
storage: IStorageSync | IStorageAsync,
|
|
187
|
-
): MaybeThenable<
|
|
172
|
+
): MaybeThenable<IEvaluation> {
|
|
188
173
|
let definition;
|
|
189
174
|
|
|
190
175
|
try {
|
|
@@ -200,12 +185,13 @@ export function evaluateDefaultTreatment(
|
|
|
200
185
|
|
|
201
186
|
function getDefaultTreatment(
|
|
202
187
|
definition: IDefinition | null,
|
|
203
|
-
): MaybeThenable<
|
|
188
|
+
): MaybeThenable<IEvaluation> {
|
|
204
189
|
if (definition) {
|
|
205
|
-
return
|
|
190
|
+
return {
|
|
206
191
|
treatment: definition.defaultTreatment,
|
|
207
|
-
label: NO_CONDITION_MATCH // "default rule"
|
|
208
|
-
|
|
192
|
+
label: NO_CONDITION_MATCH, // "default rule"
|
|
193
|
+
definition,
|
|
194
|
+
};
|
|
209
195
|
}
|
|
210
196
|
|
|
211
197
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
package/src/evaluator/types.ts
CHANGED
|
@@ -19,16 +19,11 @@ export interface IMatcherDto {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export interface IEvaluation {
|
|
22
|
-
treatment
|
|
22
|
+
treatment: string,
|
|
23
23
|
label: string,
|
|
24
|
-
|
|
25
|
-
config?: string | null | SplitIO.JsonObject
|
|
26
|
-
type?: IDefinition['type']
|
|
27
|
-
subtype?: IDefinition['subtype']
|
|
24
|
+
definition?: IDefinition
|
|
28
25
|
}
|
|
29
26
|
|
|
30
|
-
export type IEvaluationResult = IEvaluation & { treatment: string; impressionsDisabled?: boolean }
|
|
31
|
-
|
|
32
27
|
export type IDefinitionEvaluator = (log: ILogger, key: SplitIO.SplitKey, definitionName: string, attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync) => MaybeThenable<IEvaluation>
|
|
33
28
|
|
|
34
29
|
export type IEvaluator = (key: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: IDefinitionEvaluator) => MaybeThenable<IEvaluation | boolean | undefined>
|
package/src/sdkClient/client.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { getMatching, getBucketing } from '../utils/key';
|
|
|
4
4
|
import { validateDefinitionExistence } from '../utils/inputValidation/definitionExistence';
|
|
5
5
|
import { SDK_NOT_READY } from '../utils/labels';
|
|
6
6
|
import { CONTROL, TREATMENT, TREATMENTS, TREATMENT_WITH_CONFIG, TREATMENTS_WITH_CONFIG, TREATMENTS_WITH_CONFIG_BY_FLAGSETS, TREATMENTS_BY_FLAGSETS, TREATMENTS_BY_FLAGSET, TREATMENTS_WITH_CONFIG_BY_FLAGSET, GET_TREATMENTS_WITH_CONFIG, GET_TREATMENTS_BY_FLAG_SETS, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, GET_TREATMENTS_BY_FLAG_SET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, GET_TREATMENT_WITH_CONFIG, GET_TREATMENT, GET_TREATMENTS } from '../utils/constants';
|
|
7
|
-
import {
|
|
7
|
+
import { IEvaluation } from '../evaluator/types';
|
|
8
8
|
import SplitIO from '../../types/splitio';
|
|
9
9
|
import { IMPRESSION_QUEUEING } from '../logger/constants';
|
|
10
10
|
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
@@ -16,17 +16,17 @@ import { trackMethodFactory } from './trackMethod';
|
|
|
16
16
|
const treatmentNotReady = { treatment: CONTROL, label: SDK_NOT_READY };
|
|
17
17
|
|
|
18
18
|
function treatmentsNotReady(featureFlagNames: string[]) {
|
|
19
|
-
const evaluations: Record<string,
|
|
19
|
+
const evaluations: Record<string, IEvaluation> = {};
|
|
20
20
|
featureFlagNames.forEach(featureFlagName => {
|
|
21
21
|
evaluations[featureFlagName] = treatmentNotReady;
|
|
22
22
|
});
|
|
23
23
|
return evaluations;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export function stringify(
|
|
27
|
-
if (
|
|
26
|
+
export function stringify(properties?: SplitIO.Properties) {
|
|
27
|
+
if (properties) {
|
|
28
28
|
try {
|
|
29
|
-
return JSON.stringify(
|
|
29
|
+
return JSON.stringify(properties);
|
|
30
30
|
} catch { /* JSON.stringify should never throw with validated options, but handling just in case */ }
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -42,9 +42,9 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
42
42
|
function getTreatment(key: SplitIO.SplitKey, featureFlagName: string, attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions, withConfig = false, methodName = GET_TREATMENT) {
|
|
43
43
|
const stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENT_WITH_CONFIG : TREATMENT);
|
|
44
44
|
|
|
45
|
-
const wrapUp = (evaluationResult:
|
|
45
|
+
const wrapUp = (evaluationResult: IEvaluation) => {
|
|
46
46
|
const queue: ImpressionDecorated[] = [];
|
|
47
|
-
const treatment = processEvaluation(evaluationResult, featureFlagName, key,
|
|
47
|
+
const treatment = processEvaluation(evaluationResult, featureFlagName, key, withConfig, methodName, queue, options);
|
|
48
48
|
impressionsTracker.track(queue, attributes);
|
|
49
49
|
|
|
50
50
|
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
@@ -52,7 +52,7 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
const evaluation = readinessManager.isReadyFromCache() ?
|
|
55
|
-
evaluateFeature(log, key, featureFlagName, attributes, storage
|
|
55
|
+
evaluateFeature(log, key, featureFlagName, attributes, storage) :
|
|
56
56
|
isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
|
|
57
57
|
Promise.resolve(treatmentNotReady) :
|
|
58
58
|
treatmentNotReady;
|
|
@@ -67,12 +67,11 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
67
67
|
function getTreatments(key: SplitIO.SplitKey, featureFlagNames: string[], attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions, withConfig = false, methodName = GET_TREATMENTS) {
|
|
68
68
|
const stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENTS_WITH_CONFIG : TREATMENTS);
|
|
69
69
|
|
|
70
|
-
const wrapUp = (evaluationResults: Record<string,
|
|
70
|
+
const wrapUp = (evaluationResults: Record<string, IEvaluation>) => {
|
|
71
71
|
const queue: ImpressionDecorated[] = [];
|
|
72
72
|
const treatments: SplitIO.Treatments | SplitIO.TreatmentsWithConfig = {};
|
|
73
|
-
const properties = stringify(options);
|
|
74
73
|
Object.keys(evaluationResults).forEach(featureFlagName => {
|
|
75
|
-
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key,
|
|
74
|
+
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, withConfig, methodName, queue, options);
|
|
76
75
|
});
|
|
77
76
|
impressionsTracker.track(queue, attributes);
|
|
78
77
|
|
|
@@ -81,7 +80,7 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
81
80
|
};
|
|
82
81
|
|
|
83
82
|
const evaluations = readinessManager.isReadyFromCache() ?
|
|
84
|
-
evaluateFeatures(log, key, featureFlagNames, attributes, storage
|
|
83
|
+
evaluateFeatures(log, key, featureFlagNames, attributes, storage) :
|
|
85
84
|
isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
|
|
86
85
|
Promise.resolve(treatmentsNotReady(featureFlagNames)) :
|
|
87
86
|
treatmentsNotReady(featureFlagNames);
|
|
@@ -96,12 +95,11 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
96
95
|
function getTreatmentsByFlagSets(key: SplitIO.SplitKey, flagSetNames: string[], attributes?: SplitIO.Attributes, options?: SplitIO.EvaluationOptions, withConfig = false, method: Method = TREATMENTS_BY_FLAGSETS, methodName = GET_TREATMENTS_BY_FLAG_SETS) {
|
|
97
96
|
const stopTelemetryTracker = telemetryTracker.trackEval(method);
|
|
98
97
|
|
|
99
|
-
const wrapUp = (evaluationResults: Record<string,
|
|
98
|
+
const wrapUp = (evaluationResults: Record<string, IEvaluation>) => {
|
|
100
99
|
const queue: ImpressionDecorated[] = [];
|
|
101
100
|
const treatments: SplitIO.Treatments | SplitIO.TreatmentsWithConfig = {};
|
|
102
|
-
const properties = stringify(options);
|
|
103
101
|
Object.keys(evaluationResults).forEach(featureFlagName => {
|
|
104
|
-
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key,
|
|
102
|
+
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, withConfig, methodName, queue, options);
|
|
105
103
|
});
|
|
106
104
|
impressionsTracker.track(queue, attributes);
|
|
107
105
|
|
|
@@ -110,7 +108,7 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
110
108
|
};
|
|
111
109
|
|
|
112
110
|
const evaluations = readinessManager.isReadyFromCache() ?
|
|
113
|
-
evaluateFeaturesByFlagSets(log, key, flagSetNames, attributes, storage, methodName
|
|
111
|
+
evaluateFeaturesByFlagSets(log, key, flagSetNames, attributes, storage, methodName) :
|
|
114
112
|
isAsync ?
|
|
115
113
|
Promise.resolve({}) :
|
|
116
114
|
{};
|
|
@@ -132,19 +130,20 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
132
130
|
|
|
133
131
|
// Internal function
|
|
134
132
|
function processEvaluation(
|
|
135
|
-
evaluation:
|
|
133
|
+
evaluation: IEvaluation,
|
|
136
134
|
featureFlagName: string,
|
|
137
135
|
key: SplitIO.SplitKey,
|
|
138
|
-
properties: string | undefined,
|
|
139
136
|
withConfig: boolean,
|
|
140
137
|
invokingMethodName: string,
|
|
141
|
-
queue: ImpressionDecorated[]
|
|
138
|
+
queue: ImpressionDecorated[],
|
|
139
|
+
options: SplitIO.EvaluationOptions = {}
|
|
142
140
|
): SplitIO.Treatment | SplitIO.TreatmentWithConfig {
|
|
143
141
|
const matchingKey = getMatching(key);
|
|
144
142
|
const bucketingKey = getBucketing(key);
|
|
145
143
|
|
|
146
|
-
const {
|
|
147
|
-
let { treatment, label
|
|
144
|
+
const { definition } = evaluation;
|
|
145
|
+
let { treatment, label } = evaluation;
|
|
146
|
+
let config = definition?.configurations?.[treatment] || null;
|
|
148
147
|
|
|
149
148
|
if (treatment === CONTROL) {
|
|
150
149
|
const fallbackTreatment = fallbackCalculator(featureFlagName, label);
|
|
@@ -163,10 +162,10 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
163
162
|
time: Date.now(),
|
|
164
163
|
bucketingKey,
|
|
165
164
|
label,
|
|
166
|
-
changeNumber: changeNumber
|
|
167
|
-
properties
|
|
168
|
-
},
|
|
169
|
-
disabled: impressionsDisabled
|
|
165
|
+
changeNumber: definition!.changeNumber,
|
|
166
|
+
properties: stringify(options.properties)
|
|
167
|
+
}, // @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
|
|
168
|
+
disabled: options.impressionsDisabled || definition!.impressionsDisabled
|
|
170
169
|
});
|
|
171
170
|
}
|
|
172
171
|
|