@splitsoftware/splitio-commons 3.1.1-rc.0 → 3.1.1-rc.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 +1 -1
- package/cjs/evaluator/condition/index.js +1 -1
- package/cjs/evaluator/index.js +21 -23
- package/cjs/sdkClient/client.js +15 -16
- package/esm/evaluator/condition/index.js +1 -1
- package/esm/evaluator/index.js +21 -23
- package/esm/sdkClient/client.js +15 -16
- 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 +27 -35
- package/src/evaluator/types.ts +2 -6
- package/src/sdkClient/client.ts +22 -24
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,13 @@ function treatmentsException(definitionNames) {
|
|
|
24
25
|
});
|
|
25
26
|
return evaluations;
|
|
26
27
|
}
|
|
27
|
-
function
|
|
28
|
+
function setEvaluationDataFromDefinition(evaluation, definition) {
|
|
29
|
+
return (0, objectAssign_1.objectAssign)(evaluation, {
|
|
30
|
+
definition: definition,
|
|
31
|
+
config: definition.configurations && definition.configurations[evaluation.treatment] || null
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function evaluateFeature(log, key, definitionName, attributes, storage) {
|
|
28
35
|
var definition;
|
|
29
36
|
try {
|
|
30
37
|
definition = storage.definitions.get(definitionName);
|
|
@@ -34,15 +41,15 @@ function evaluateFeature(log, key, definitionName, attributes, storage, options)
|
|
|
34
41
|
return EVALUATION_EXCEPTION;
|
|
35
42
|
}
|
|
36
43
|
return (0, thenable_1.thenable)(definition) ?
|
|
37
|
-
definition.then(function (definition) { return getEvaluation(log, key, definition, attributes, storage
|
|
44
|
+
definition.then(function (definition) { return getEvaluation(log, key, definition, attributes, storage); })
|
|
38
45
|
.catch(
|
|
39
46
|
// Exception on async storage. For example, when the storage is redis or
|
|
40
47
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
41
48
|
function () { return EVALUATION_EXCEPTION; }) :
|
|
42
|
-
getEvaluation(log, key, definition, attributes, storage
|
|
49
|
+
getEvaluation(log, key, definition, attributes, storage);
|
|
43
50
|
}
|
|
44
51
|
exports.evaluateFeature = evaluateFeature;
|
|
45
|
-
function evaluateFeatures(log, key, definitionNames, attributes, storage
|
|
52
|
+
function evaluateFeatures(log, key, definitionNames, attributes, storage) {
|
|
46
53
|
var definitions;
|
|
47
54
|
try {
|
|
48
55
|
definitions = storage.definitions.getMany(definitionNames);
|
|
@@ -52,15 +59,15 @@ function evaluateFeatures(log, key, definitionNames, attributes, storage, option
|
|
|
52
59
|
return treatmentsException(definitionNames);
|
|
53
60
|
}
|
|
54
61
|
return (0, thenable_1.thenable)(definitions) ?
|
|
55
|
-
definitions.then(function (definitions) { return getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
62
|
+
definitions.then(function (definitions) { return getEvaluations(log, key, definitionNames, definitions, attributes, storage); })
|
|
56
63
|
.catch(
|
|
57
64
|
// Exception on async storage. For example, when the storage is redis or
|
|
58
65
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
59
66
|
function () { return treatmentsException(definitionNames); }) :
|
|
60
|
-
getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
67
|
+
getEvaluations(log, key, definitionNames, definitions, attributes, storage);
|
|
61
68
|
}
|
|
62
69
|
exports.evaluateFeatures = evaluateFeatures;
|
|
63
|
-
function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method
|
|
70
|
+
function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method) {
|
|
64
71
|
var storedFlagNames;
|
|
65
72
|
function evaluate(featureFlagsByFlagSets) {
|
|
66
73
|
var featureFlags = new Set();
|
|
@@ -74,7 +81,7 @@ function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, met
|
|
|
74
81
|
}
|
|
75
82
|
}
|
|
76
83
|
return featureFlags.size ?
|
|
77
|
-
evaluateFeatures(log, key, (0, sets_1.setToArray)(featureFlags), attributes, storage
|
|
84
|
+
evaluateFeatures(log, key, (0, sets_1.setToArray)(featureFlags), attributes, storage) :
|
|
78
85
|
{};
|
|
79
86
|
}
|
|
80
87
|
// get features by flag sets
|
|
@@ -92,30 +99,21 @@ function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, met
|
|
|
92
99
|
evaluate(storedFlagNames);
|
|
93
100
|
}
|
|
94
101
|
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) {
|
|
102
|
+
function getEvaluation(log, key, definition, attributes, storage) {
|
|
105
103
|
if (definition) {
|
|
106
104
|
var split = (0, Engine_1.engineParser)(log, definition, storage);
|
|
107
105
|
var evaluation = split.getTreatment(key, attributes, evaluateFeature);
|
|
108
106
|
return (0, thenable_1.thenable)(evaluation) ?
|
|
109
|
-
evaluation.then(function (result) { return setEvaluationDataFromDefinition(result, definition
|
|
110
|
-
setEvaluationDataFromDefinition(evaluation, definition
|
|
107
|
+
evaluation.then(function (result) { return setEvaluationDataFromDefinition(result, definition); }) :
|
|
108
|
+
setEvaluationDataFromDefinition(evaluation, definition);
|
|
111
109
|
}
|
|
112
110
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
113
111
|
}
|
|
114
|
-
function getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
112
|
+
function getEvaluations(log, key, definitionNames, definitions, attributes, storage) {
|
|
115
113
|
var result = {};
|
|
116
114
|
var thenables = [];
|
|
117
115
|
definitionNames.forEach(function (definitionName) {
|
|
118
|
-
var evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage
|
|
116
|
+
var evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage);
|
|
119
117
|
(0, thenable_1.thenable)(evaluation) ?
|
|
120
118
|
thenables.push(evaluation.then(function (res) {
|
|
121
119
|
result[definitionName] = res;
|
|
@@ -141,7 +139,7 @@ function getDefaultTreatment(definition) {
|
|
|
141
139
|
if (definition) {
|
|
142
140
|
return setEvaluationDataFromDefinition({
|
|
143
141
|
treatment: definition.defaultTreatment,
|
|
144
|
-
label: labels_1.NO_CONDITION_MATCH // "default rule"
|
|
142
|
+
label: labels_1.NO_CONDITION_MATCH, // "default rule"
|
|
145
143
|
}, definition);
|
|
146
144
|
}
|
|
147
145
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
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,10 +111,11 @@ 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
|
+
if (options === void 0) { options = {}; }
|
|
117
116
|
var matchingKey = (0, key_1.getMatching)(key);
|
|
118
117
|
var bucketingKey = (0, key_1.getBucketing)(key);
|
|
119
|
-
var
|
|
118
|
+
var definition = evaluation.definition;
|
|
120
119
|
var treatment = evaluation.treatment, label = evaluation.label, _a = evaluation.config, config = _a === void 0 ? null : _a;
|
|
121
120
|
if (treatment === constants_1.CONTROL) {
|
|
122
121
|
var fallbackTreatment = fallbackCalculator(featureFlagName, label);
|
|
@@ -134,10 +133,10 @@ function clientFactory(params) {
|
|
|
134
133
|
time: Date.now(),
|
|
135
134
|
bucketingKey: bucketingKey,
|
|
136
135
|
label: label,
|
|
137
|
-
changeNumber: changeNumber,
|
|
138
|
-
properties: properties
|
|
136
|
+
changeNumber: definition.changeNumber,
|
|
137
|
+
properties: stringify(options.properties)
|
|
139
138
|
},
|
|
140
|
-
disabled: impressionsDisabled
|
|
139
|
+
disabled: options.impressionsDisabled || definition.impressionsDisabled
|
|
141
140
|
});
|
|
142
141
|
}
|
|
143
142
|
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,13 @@ function treatmentsException(definitionNames) {
|
|
|
21
22
|
});
|
|
22
23
|
return evaluations;
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
+
function setEvaluationDataFromDefinition(evaluation, definition) {
|
|
26
|
+
return objectAssign(evaluation, {
|
|
27
|
+
definition: definition,
|
|
28
|
+
config: definition.configurations && definition.configurations[evaluation.treatment] || null
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
export function evaluateFeature(log, key, definitionName, attributes, storage) {
|
|
25
32
|
var definition;
|
|
26
33
|
try {
|
|
27
34
|
definition = storage.definitions.get(definitionName);
|
|
@@ -31,14 +38,14 @@ export function evaluateFeature(log, key, definitionName, attributes, storage, o
|
|
|
31
38
|
return EVALUATION_EXCEPTION;
|
|
32
39
|
}
|
|
33
40
|
return thenable(definition) ?
|
|
34
|
-
definition.then(function (definition) { return getEvaluation(log, key, definition, attributes, storage
|
|
41
|
+
definition.then(function (definition) { return getEvaluation(log, key, definition, attributes, storage); })
|
|
35
42
|
.catch(
|
|
36
43
|
// Exception on async storage. For example, when the storage is redis or
|
|
37
44
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
38
45
|
function () { return EVALUATION_EXCEPTION; }) :
|
|
39
|
-
getEvaluation(log, key, definition, attributes, storage
|
|
46
|
+
getEvaluation(log, key, definition, attributes, storage);
|
|
40
47
|
}
|
|
41
|
-
export function evaluateFeatures(log, key, definitionNames, attributes, storage
|
|
48
|
+
export function evaluateFeatures(log, key, definitionNames, attributes, storage) {
|
|
42
49
|
var definitions;
|
|
43
50
|
try {
|
|
44
51
|
definitions = storage.definitions.getMany(definitionNames);
|
|
@@ -48,14 +55,14 @@ export function evaluateFeatures(log, key, definitionNames, attributes, storage,
|
|
|
48
55
|
return treatmentsException(definitionNames);
|
|
49
56
|
}
|
|
50
57
|
return thenable(definitions) ?
|
|
51
|
-
definitions.then(function (definitions) { return getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
58
|
+
definitions.then(function (definitions) { return getEvaluations(log, key, definitionNames, definitions, attributes, storage); })
|
|
52
59
|
.catch(
|
|
53
60
|
// Exception on async storage. For example, when the storage is redis or
|
|
54
61
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
55
62
|
function () { return treatmentsException(definitionNames); }) :
|
|
56
|
-
getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
63
|
+
getEvaluations(log, key, definitionNames, definitions, attributes, storage);
|
|
57
64
|
}
|
|
58
|
-
export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method
|
|
65
|
+
export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method) {
|
|
59
66
|
var storedFlagNames;
|
|
60
67
|
function evaluate(featureFlagsByFlagSets) {
|
|
61
68
|
var featureFlags = new Set();
|
|
@@ -69,7 +76,7 @@ export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, stora
|
|
|
69
76
|
}
|
|
70
77
|
}
|
|
71
78
|
return featureFlags.size ?
|
|
72
|
-
evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage
|
|
79
|
+
evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage) :
|
|
73
80
|
{};
|
|
74
81
|
}
|
|
75
82
|
// get features by flag sets
|
|
@@ -86,30 +93,21 @@ export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, stora
|
|
|
86
93
|
.catch(function () { return ({}); }) :
|
|
87
94
|
evaluate(storedFlagNames);
|
|
88
95
|
}
|
|
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) {
|
|
96
|
+
function getEvaluation(log, key, definition, attributes, storage) {
|
|
99
97
|
if (definition) {
|
|
100
98
|
var split = engineParser(log, definition, storage);
|
|
101
99
|
var evaluation = split.getTreatment(key, attributes, evaluateFeature);
|
|
102
100
|
return thenable(evaluation) ?
|
|
103
|
-
evaluation.then(function (result) { return setEvaluationDataFromDefinition(result, definition
|
|
104
|
-
setEvaluationDataFromDefinition(evaluation, definition
|
|
101
|
+
evaluation.then(function (result) { return setEvaluationDataFromDefinition(result, definition); }) :
|
|
102
|
+
setEvaluationDataFromDefinition(evaluation, definition);
|
|
105
103
|
}
|
|
106
104
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
107
105
|
}
|
|
108
|
-
function getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
106
|
+
function getEvaluations(log, key, definitionNames, definitions, attributes, storage) {
|
|
109
107
|
var result = {};
|
|
110
108
|
var thenables = [];
|
|
111
109
|
definitionNames.forEach(function (definitionName) {
|
|
112
|
-
var evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage
|
|
110
|
+
var evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage);
|
|
113
111
|
thenable(evaluation) ?
|
|
114
112
|
thenables.push(evaluation.then(function (res) {
|
|
115
113
|
result[definitionName] = res;
|
|
@@ -134,7 +132,7 @@ function getDefaultTreatment(definition) {
|
|
|
134
132
|
if (definition) {
|
|
135
133
|
return setEvaluationDataFromDefinition({
|
|
136
134
|
treatment: definition.defaultTreatment,
|
|
137
|
-
label: NO_CONDITION_MATCH // "default rule"
|
|
135
|
+
label: NO_CONDITION_MATCH, // "default rule"
|
|
138
136
|
}, definition);
|
|
139
137
|
}
|
|
140
138
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
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,10 +107,11 @@ 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
|
+
if (options === void 0) { options = {}; }
|
|
113
112
|
var matchingKey = getMatching(key);
|
|
114
113
|
var bucketingKey = getBucketing(key);
|
|
115
|
-
var
|
|
114
|
+
var definition = evaluation.definition;
|
|
116
115
|
var treatment = evaluation.treatment, label = evaluation.label, _a = evaluation.config, config = _a === void 0 ? null : _a;
|
|
117
116
|
if (treatment === CONTROL) {
|
|
118
117
|
var fallbackTreatment = fallbackCalculator(featureFlagName, label);
|
|
@@ -130,10 +129,10 @@ export function clientFactory(params) {
|
|
|
130
129
|
time: Date.now(),
|
|
131
130
|
bucketingKey: bucketingKey,
|
|
132
131
|
label: label,
|
|
133
|
-
changeNumber: changeNumber,
|
|
134
|
-
properties: properties
|
|
132
|
+
changeNumber: definition.changeNumber,
|
|
133
|
+
properties: stringify(options.properties)
|
|
135
134
|
},
|
|
136
|
-
disabled: impressionsDisabled
|
|
135
|
+
disabled: options.impressionsDisabled || definition.impressionsDisabled
|
|
137
136
|
});
|
|
138
137
|
}
|
|
139
138
|
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,21 +24,27 @@ 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
|
});
|
|
30
31
|
return evaluations;
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
function setEvaluationDataFromDefinition(evaluation: IEvaluation, definition: IDefinition): IEvaluation {
|
|
35
|
+
return objectAssign(evaluation, {
|
|
36
|
+
definition,
|
|
37
|
+
config: definition.configurations && definition.configurations[evaluation.treatment] || null
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
export function evaluateFeature(
|
|
34
42
|
log: ILogger,
|
|
35
43
|
key: SplitIO.SplitKey,
|
|
36
44
|
definitionName: string,
|
|
37
45
|
attributes: SplitIO.Attributes | undefined,
|
|
38
46
|
storage: IStorageSync | IStorageAsync,
|
|
39
|
-
|
|
40
|
-
): MaybeThenable<IEvaluationResult> {
|
|
47
|
+
): MaybeThenable<IEvaluation> {
|
|
41
48
|
let definition;
|
|
42
49
|
|
|
43
50
|
try {
|
|
@@ -48,13 +55,13 @@ export function evaluateFeature(
|
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
return thenable(definition) ?
|
|
51
|
-
definition.then((definition) => getEvaluation(log, key, definition, attributes, storage
|
|
58
|
+
definition.then((definition) => getEvaluation(log, key, definition, attributes, storage))
|
|
52
59
|
.catch(
|
|
53
60
|
// Exception on async storage. For example, when the storage is redis or
|
|
54
61
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
55
62
|
() => EVALUATION_EXCEPTION
|
|
56
63
|
) :
|
|
57
|
-
getEvaluation(log, key, definition, attributes, storage
|
|
64
|
+
getEvaluation(log, key, definition, attributes, storage);
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
export function evaluateFeatures(
|
|
@@ -63,8 +70,7 @@ export function evaluateFeatures(
|
|
|
63
70
|
definitionNames: string[],
|
|
64
71
|
attributes: SplitIO.Attributes | undefined,
|
|
65
72
|
storage: IStorageSync | IStorageAsync,
|
|
66
|
-
|
|
67
|
-
): MaybeThenable<Record<string, IEvaluationResult>> {
|
|
73
|
+
): MaybeThenable<Record<string, IEvaluation>> {
|
|
68
74
|
let definitions;
|
|
69
75
|
|
|
70
76
|
try {
|
|
@@ -75,13 +81,13 @@ export function evaluateFeatures(
|
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
return thenable(definitions) ?
|
|
78
|
-
definitions.then(definitions => getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
84
|
+
definitions.then(definitions => getEvaluations(log, key, definitionNames, definitions, attributes, storage))
|
|
79
85
|
.catch(
|
|
80
86
|
// Exception on async storage. For example, when the storage is redis or
|
|
81
87
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
82
88
|
() => treatmentsException(definitionNames)
|
|
83
89
|
) :
|
|
84
|
-
getEvaluations(log, key, definitionNames, definitions, attributes, storage
|
|
90
|
+
getEvaluations(log, key, definitionNames, definitions, attributes, storage);
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
export function evaluateFeaturesByFlagSets(
|
|
@@ -91,8 +97,7 @@ export function evaluateFeaturesByFlagSets(
|
|
|
91
97
|
attributes: SplitIO.Attributes | undefined,
|
|
92
98
|
storage: IStorageSync | IStorageAsync,
|
|
93
99
|
method: string,
|
|
94
|
-
|
|
95
|
-
): MaybeThenable<Record<string, IEvaluationResult>> {
|
|
100
|
+
): MaybeThenable<Record<string, IEvaluation>> {
|
|
96
101
|
let storedFlagNames: MaybeThenable<Set<string>[]>;
|
|
97
102
|
|
|
98
103
|
function evaluate(featureFlagsByFlagSets: Set<string>[]) {
|
|
@@ -107,7 +112,7 @@ export function evaluateFeaturesByFlagSets(
|
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
return featureFlags.size ?
|
|
110
|
-
evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage
|
|
115
|
+
evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage) :
|
|
111
116
|
{};
|
|
112
117
|
}
|
|
113
118
|
|
|
@@ -126,33 +131,21 @@ export function evaluateFeaturesByFlagSets(
|
|
|
126
131
|
evaluate(storedFlagNames);
|
|
127
132
|
}
|
|
128
133
|
|
|
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
134
|
function getEvaluation(
|
|
141
135
|
log: ILogger,
|
|
142
136
|
key: SplitIO.SplitKey,
|
|
143
137
|
definition: IDefinition | null,
|
|
144
138
|
attributes: SplitIO.Attributes | undefined,
|
|
145
139
|
storage: IStorageSync | IStorageAsync,
|
|
146
|
-
|
|
147
|
-
): MaybeThenable<IEvaluationResult> {
|
|
140
|
+
): MaybeThenable<IEvaluation> {
|
|
148
141
|
|
|
149
142
|
if (definition) {
|
|
150
143
|
const split = engineParser(log, definition, storage);
|
|
151
144
|
const evaluation = split.getTreatment(key, attributes, evaluateFeature);
|
|
152
145
|
|
|
153
146
|
return thenable(evaluation) ?
|
|
154
|
-
evaluation.then(result => setEvaluationDataFromDefinition(result, definition
|
|
155
|
-
setEvaluationDataFromDefinition(evaluation, definition
|
|
147
|
+
evaluation.then(result => setEvaluationDataFromDefinition(result, definition)) :
|
|
148
|
+
setEvaluationDataFromDefinition(evaluation, definition);
|
|
156
149
|
}
|
|
157
150
|
|
|
158
151
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
@@ -165,12 +158,11 @@ function getEvaluations(
|
|
|
165
158
|
definitions: Record<string, IDefinition | null>,
|
|
166
159
|
attributes: SplitIO.Attributes | undefined,
|
|
167
160
|
storage: IStorageSync | IStorageAsync,
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const result: Record<string, IEvaluationResult> = {};
|
|
161
|
+
): MaybeThenable<Record<string, IEvaluation>> {
|
|
162
|
+
const result: Record<string, IEvaluation> = {};
|
|
171
163
|
const thenables: Promise<void>[] = [];
|
|
172
164
|
definitionNames.forEach(definitionName => {
|
|
173
|
-
const evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage
|
|
165
|
+
const evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage);
|
|
174
166
|
thenable(evaluation) ?
|
|
175
167
|
thenables.push(evaluation.then(res => {
|
|
176
168
|
result[definitionName] = res;
|
|
@@ -184,7 +176,7 @@ function getEvaluations(
|
|
|
184
176
|
export function evaluateDefaultTreatment(
|
|
185
177
|
definitionName: string,
|
|
186
178
|
storage: IStorageSync | IStorageAsync,
|
|
187
|
-
): MaybeThenable<
|
|
179
|
+
): MaybeThenable<IEvaluation> {
|
|
188
180
|
let definition;
|
|
189
181
|
|
|
190
182
|
try {
|
|
@@ -200,11 +192,11 @@ export function evaluateDefaultTreatment(
|
|
|
200
192
|
|
|
201
193
|
function getDefaultTreatment(
|
|
202
194
|
definition: IDefinition | null,
|
|
203
|
-
): MaybeThenable<
|
|
195
|
+
): MaybeThenable<IEvaluation> {
|
|
204
196
|
if (definition) {
|
|
205
197
|
return setEvaluationDataFromDefinition({
|
|
206
198
|
treatment: definition.defaultTreatment,
|
|
207
|
-
label: NO_CONDITION_MATCH // "default rule"
|
|
199
|
+
label: NO_CONDITION_MATCH, // "default rule"
|
|
208
200
|
}, definition);
|
|
209
201
|
}
|
|
210
202
|
|
package/src/evaluator/types.ts
CHANGED
|
@@ -19,16 +19,12 @@ export interface IMatcherDto {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export interface IEvaluation {
|
|
22
|
-
treatment
|
|
22
|
+
treatment: string,
|
|
23
23
|
label: string,
|
|
24
|
-
|
|
24
|
+
definition?: IDefinition
|
|
25
25
|
config?: string | null | SplitIO.JsonObject
|
|
26
|
-
type?: IDefinition['type']
|
|
27
|
-
subtype?: IDefinition['subtype']
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
export type IEvaluationResult = IEvaluation & { treatment: string; impressionsDisabled?: boolean }
|
|
31
|
-
|
|
32
28
|
export type IDefinitionEvaluator = (log: ILogger, key: SplitIO.SplitKey, definitionName: string, attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync) => MaybeThenable<IEvaluation>
|
|
33
29
|
|
|
34
30
|
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,18 +130,18 @@ 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 {
|
|
144
|
+
const { definition } = evaluation;
|
|
147
145
|
let { treatment, label, config = null } = evaluation;
|
|
148
146
|
|
|
149
147
|
if (treatment === CONTROL) {
|
|
@@ -163,10 +161,10 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
163
161
|
time: Date.now(),
|
|
164
162
|
bucketingKey,
|
|
165
163
|
label,
|
|
166
|
-
changeNumber: changeNumber
|
|
167
|
-
properties
|
|
168
|
-
},
|
|
169
|
-
disabled: impressionsDisabled
|
|
164
|
+
changeNumber: definition!.changeNumber,
|
|
165
|
+
properties: stringify(options.properties)
|
|
166
|
+
}, // @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
|
|
167
|
+
disabled: options.impressionsDisabled || definition!.impressionsDisabled
|
|
170
168
|
});
|
|
171
169
|
}
|
|
172
170
|
|