@splitsoftware/splitio-commons 3.0.1-rc.3 → 3.1.1-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +6 -1
- package/cjs/evaluator/index.js +27 -40
- package/cjs/listeners/browser.js +2 -2
- package/cjs/services/authProvider.js +1 -1
- package/cjs/storages/utils.js +1 -0
- package/cjs/sync/submitters/impressionsSubmitter.js +5 -4
- package/esm/evaluator/index.js +27 -40
- package/esm/listeners/browser.js +2 -2
- package/esm/services/authProvider.js +1 -1
- package/esm/storages/utils.js +1 -0
- package/esm/sync/submitters/impressionsSubmitter.js +5 -4
- package/package.json +1 -1
- package/src/dtos/types.ts +7 -0
- package/src/evaluator/index.ts +32 -64
- package/src/evaluator/types.ts +3 -1
- package/src/listeners/browser.ts +2 -2
- package/src/sdkFactory/types.ts +0 -4
- package/src/services/authProvider.ts +1 -1
- package/src/storages/utils.ts +1 -0
- package/src/sync/submitters/impressionsSubmitter.ts +6 -6
- package/src/sync/submitters/types.ts +2 -1
- package/types/splitio.d.ts +1 -171
- package/cjs/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.js +0 -70
- package/cjs/evaluator/fallbackConfigsCalculator/index.js +0 -25
- package/esm/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.js +0 -64
- package/esm/evaluator/fallbackConfigsCalculator/index.js +0 -21
- package/src/evaluator/fallbackConfigsCalculator/fallbackSanitizer/index.ts +0 -76
- package/src/evaluator/fallbackConfigsCalculator/index.ts +0 -24
package/CHANGES.txt
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.2.0 (July 31, 2026)
|
|
2
|
+
- Added support for AI configs.
|
|
3
|
+
- Removed Configs SDK-related types and modules and moved them to the Configs SDK repository.
|
|
4
|
+
|
|
5
|
+
3.1.0 (July 23, 2026)
|
|
2
6
|
- Added support for rule-based segments in /api/v1/configs endpoint.
|
|
7
|
+
- Updated polling flow to fetch new referenced segments immediately.
|
|
3
8
|
|
|
4
9
|
3.0.0 (June 26, 2026)
|
|
5
10
|
- Extracted SDK lifecycle methods (`init`, `flush`, and `destroy`) into a reusable `sdkLifecycle` module.
|
package/cjs/evaluator/index.js
CHANGED
|
@@ -33,13 +33,13 @@ function evaluateFeature(log, key, definitionName, attributes, storage, options)
|
|
|
33
33
|
// Exception on sync storage. Not possible ATM with InMemory and InLocal storages.
|
|
34
34
|
return EVALUATION_EXCEPTION;
|
|
35
35
|
}
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
return (0, thenable_1.thenable)(definition) ?
|
|
37
|
+
definition.then(function (definition) { return getEvaluation(log, key, definition, attributes, storage, options); })
|
|
38
|
+
.catch(
|
|
38
39
|
// Exception on async storage. For example, when the storage is redis or
|
|
39
40
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
40
|
-
function () { return EVALUATION_EXCEPTION; })
|
|
41
|
-
|
|
42
|
-
return getEvaluation(log, key, definition, attributes, storage, options);
|
|
41
|
+
function () { return EVALUATION_EXCEPTION; }) :
|
|
42
|
+
getEvaluation(log, key, definition, attributes, storage, options);
|
|
43
43
|
}
|
|
44
44
|
exports.evaluateFeature = evaluateFeature;
|
|
45
45
|
function evaluateFeatures(log, key, definitionNames, attributes, storage, options) {
|
|
@@ -53,11 +53,10 @@ function evaluateFeatures(log, key, definitionNames, attributes, storage, option
|
|
|
53
53
|
}
|
|
54
54
|
return (0, thenable_1.thenable)(definitions) ?
|
|
55
55
|
definitions.then(function (definitions) { return getEvaluations(log, key, definitionNames, definitions, attributes, storage, options); })
|
|
56
|
-
.catch(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}) :
|
|
56
|
+
.catch(
|
|
57
|
+
// Exception on async storage. For example, when the storage is redis or
|
|
58
|
+
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
59
|
+
function () { return treatmentsException(definitionNames); }) :
|
|
61
60
|
getEvaluations(log, key, definitionNames, definitions, attributes, storage, options);
|
|
62
61
|
}
|
|
63
62
|
exports.evaluateFeatures = evaluateFeatures;
|
|
@@ -89,33 +88,26 @@ function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, met
|
|
|
89
88
|
// evaluate related features
|
|
90
89
|
return (0, thenable_1.thenable)(storedFlagNames) ?
|
|
91
90
|
storedFlagNames.then(function (storedFlagNames) { return evaluate(storedFlagNames); })
|
|
92
|
-
.catch(function () {
|
|
93
|
-
return {};
|
|
94
|
-
}) :
|
|
91
|
+
.catch(function () { return ({}); }) :
|
|
95
92
|
evaluate(storedFlagNames);
|
|
96
93
|
}
|
|
97
94
|
exports.evaluateFeaturesByFlagSets = evaluateFeaturesByFlagSets;
|
|
95
|
+
function setEvaluationDataFromDefinition(evaluation, definition, options) {
|
|
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
|
+
}
|
|
98
104
|
function getEvaluation(log, key, definition, attributes, storage, options) {
|
|
99
105
|
if (definition) {
|
|
100
106
|
var split = (0, Engine_1.engineParser)(log, definition, storage);
|
|
101
107
|
var evaluation = split.getTreatment(key, attributes, evaluateFeature);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
result.changeNumber = definition.changeNumber;
|
|
106
|
-
result.config = definition.configurations && definition.configurations[result.treatment] || null;
|
|
107
|
-
// @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
|
|
108
|
-
result.impressionsDisabled = (options === null || options === void 0 ? void 0 : options.impressionsDisabled) || definition.impressionsDisabled;
|
|
109
|
-
return result;
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
evaluation.changeNumber = definition.changeNumber;
|
|
114
|
-
evaluation.config = definition.configurations && definition.configurations[evaluation.treatment] || null;
|
|
115
|
-
// @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
|
|
116
|
-
evaluation.impressionsDisabled = (options === null || options === void 0 ? void 0 : options.impressionsDisabled) || definition.impressionsDisabled;
|
|
117
|
-
}
|
|
118
|
-
return evaluation;
|
|
108
|
+
return (0, thenable_1.thenable)(evaluation) ?
|
|
109
|
+
evaluation.then(function (result) { return setEvaluationDataFromDefinition(result, definition, options); }) :
|
|
110
|
+
setEvaluationDataFromDefinition(evaluation, definition, options);
|
|
119
111
|
}
|
|
120
112
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
121
113
|
}
|
|
@@ -124,14 +116,11 @@ function getEvaluations(log, key, definitionNames, definitions, attributes, stor
|
|
|
124
116
|
var thenables = [];
|
|
125
117
|
definitionNames.forEach(function (definitionName) {
|
|
126
118
|
var evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage, options);
|
|
127
|
-
|
|
119
|
+
(0, thenable_1.thenable)(evaluation) ?
|
|
128
120
|
thenables.push(evaluation.then(function (res) {
|
|
129
121
|
result[definitionName] = res;
|
|
130
|
-
}))
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
122
|
+
})) :
|
|
133
123
|
result[definitionName] = evaluation;
|
|
134
|
-
}
|
|
135
124
|
});
|
|
136
125
|
return thenables.length > 0 ? Promise.all(thenables).then(function () { return result; }) : result;
|
|
137
126
|
}
|
|
@@ -150,12 +139,10 @@ function evaluateDefaultTreatment(definitionName, storage) {
|
|
|
150
139
|
exports.evaluateDefaultTreatment = evaluateDefaultTreatment;
|
|
151
140
|
function getDefaultTreatment(definition) {
|
|
152
141
|
if (definition) {
|
|
153
|
-
return {
|
|
142
|
+
return setEvaluationDataFromDefinition({
|
|
154
143
|
treatment: definition.defaultTreatment,
|
|
155
|
-
label: labels_1.NO_CONDITION_MATCH
|
|
156
|
-
|
|
157
|
-
changeNumber: definition.changeNumber
|
|
158
|
-
};
|
|
144
|
+
label: labels_1.NO_CONDITION_MATCH // "default rule"
|
|
145
|
+
}, definition);
|
|
159
146
|
}
|
|
160
147
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
161
148
|
}
|
package/cjs/listeners/browser.js
CHANGED
|
@@ -14,14 +14,14 @@ var EVENT_NAME = 'for visibilitychange and pagehide events.';
|
|
|
14
14
|
*/
|
|
15
15
|
var BrowserSignalListener = /** @class */ (function () {
|
|
16
16
|
function BrowserSignalListener(_a) {
|
|
17
|
-
var syncManager = _a.syncManager, settings = _a.settings, storage = _a.storage, serviceApi = _a.serviceApi
|
|
17
|
+
var syncManager = _a.syncManager, settings = _a.settings, storage = _a.storage, serviceApi = _a.serviceApi;
|
|
18
18
|
this.syncManager = syncManager;
|
|
19
19
|
this.settings = settings;
|
|
20
20
|
this.storage = storage;
|
|
21
21
|
this.serviceApi = serviceApi;
|
|
22
22
|
this.flushData = this.flushData.bind(this);
|
|
23
23
|
this.flushDataIfHidden = this.flushDataIfHidden.bind(this);
|
|
24
|
-
this.fromImpressionsCollector = impressionsSubmitter_1.fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled
|
|
24
|
+
this.fromImpressionsCollector = impressionsSubmitter_1.fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled);
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* start method.
|
|
@@ -16,7 +16,7 @@ function isExpired(credential) {
|
|
|
16
16
|
function authProviderFactory(settings, splitHttpClient, telemetryTracker) {
|
|
17
17
|
var urls = settings.urls, log = settings.log;
|
|
18
18
|
function fetchAuth() {
|
|
19
|
-
var url = "".concat(urls.auth, "/api/v3/auth?capabilities=config");
|
|
19
|
+
var url = "".concat(urls.auth, "/api/v3/auth?capabilities=config,aiconfig");
|
|
20
20
|
return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_2.TOKEN), false, true);
|
|
21
21
|
}
|
|
22
22
|
var authenticate = (0, AuthClient_1.authenticateFactory)(fetchAuth);
|
package/cjs/storages/utils.js
CHANGED
|
@@ -7,7 +7,7 @@ var constants_1 = require("../../logger/constants");
|
|
|
7
7
|
/**
|
|
8
8
|
* Converts `impressions` data from cache into request payload.
|
|
9
9
|
*/
|
|
10
|
-
function fromImpressionsCollector(sendLabels,
|
|
10
|
+
function fromImpressionsCollector(sendLabels, data) {
|
|
11
11
|
var groupedByFeature = (0, lang_1.groupBy)(data, 'feature');
|
|
12
12
|
var dto = [];
|
|
13
13
|
(0, lang_1.forOwn)(groupedByFeature, function (value, name) {
|
|
@@ -23,7 +23,8 @@ function fromImpressionsCollector(sendLabels, entityType, data) {
|
|
|
23
23
|
b: entry.bucketingKey,
|
|
24
24
|
pt: entry.pt,
|
|
25
25
|
properties: entry.properties,
|
|
26
|
-
|
|
26
|
+
// @ts-expect-error - entityType is not yet public. @TODO: add to SplitIO.ImpressionDTO type
|
|
27
|
+
et: entry.entityType, // Definition type
|
|
27
28
|
};
|
|
28
29
|
})
|
|
29
30
|
});
|
|
@@ -35,9 +36,9 @@ exports.fromImpressionsCollector = fromImpressionsCollector;
|
|
|
35
36
|
* Submitter that periodically posts impressions data
|
|
36
37
|
*/
|
|
37
38
|
function impressionsSubmitterFactory(params) {
|
|
38
|
-
var _a = params.settings, log = _a.log, impressionsRefreshRate = _a.scheduler.impressionsRefreshRate, labelsEnabled = _a.core.labelsEnabled, postTestImpressionsBulk = params.serviceApi.postTestImpressionsBulk, impressions = params.storage.impressions
|
|
39
|
+
var _a = params.settings, log = _a.log, impressionsRefreshRate = _a.scheduler.impressionsRefreshRate, labelsEnabled = _a.core.labelsEnabled, postTestImpressionsBulk = params.serviceApi.postTestImpressionsBulk, impressions = params.storage.impressions;
|
|
39
40
|
// retry impressions only once.
|
|
40
|
-
var syncTask = (0, submitter_1.submitterFactory)(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled
|
|
41
|
+
var syncTask = (0, submitter_1.submitterFactory)(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled), 1);
|
|
41
42
|
// register impressions submitter to be executed when impressions cache is full
|
|
42
43
|
impressions.setOnFullQueueCb(function () {
|
|
43
44
|
if (syncTask.isRunning()) {
|
package/esm/evaluator/index.js
CHANGED
|
@@ -30,13 +30,13 @@ export function evaluateFeature(log, key, definitionName, attributes, storage, o
|
|
|
30
30
|
// Exception on sync storage. Not possible ATM with InMemory and InLocal storages.
|
|
31
31
|
return EVALUATION_EXCEPTION;
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
return thenable(definition) ?
|
|
34
|
+
definition.then(function (definition) { return getEvaluation(log, key, definition, attributes, storage, options); })
|
|
35
|
+
.catch(
|
|
35
36
|
// Exception on async storage. For example, when the storage is redis or
|
|
36
37
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
37
|
-
function () { return EVALUATION_EXCEPTION; })
|
|
38
|
-
|
|
39
|
-
return getEvaluation(log, key, definition, attributes, storage, options);
|
|
38
|
+
function () { return EVALUATION_EXCEPTION; }) :
|
|
39
|
+
getEvaluation(log, key, definition, attributes, storage, options);
|
|
40
40
|
}
|
|
41
41
|
export function evaluateFeatures(log, key, definitionNames, attributes, storage, options) {
|
|
42
42
|
var definitions;
|
|
@@ -49,11 +49,10 @@ export function evaluateFeatures(log, key, definitionNames, attributes, storage,
|
|
|
49
49
|
}
|
|
50
50
|
return thenable(definitions) ?
|
|
51
51
|
definitions.then(function (definitions) { return getEvaluations(log, key, definitionNames, definitions, attributes, storage, options); })
|
|
52
|
-
.catch(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}) :
|
|
52
|
+
.catch(
|
|
53
|
+
// Exception on async storage. For example, when the storage is redis or
|
|
54
|
+
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
55
|
+
function () { return treatmentsException(definitionNames); }) :
|
|
57
56
|
getEvaluations(log, key, definitionNames, definitions, attributes, storage, options);
|
|
58
57
|
}
|
|
59
58
|
export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method, options) {
|
|
@@ -84,32 +83,25 @@ export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, stora
|
|
|
84
83
|
// evaluate related features
|
|
85
84
|
return thenable(storedFlagNames) ?
|
|
86
85
|
storedFlagNames.then(function (storedFlagNames) { return evaluate(storedFlagNames); })
|
|
87
|
-
.catch(function () {
|
|
88
|
-
return {};
|
|
89
|
-
}) :
|
|
86
|
+
.catch(function () { return ({}); }) :
|
|
90
87
|
evaluate(storedFlagNames);
|
|
91
88
|
}
|
|
89
|
+
function setEvaluationDataFromDefinition(evaluation, definition, options) {
|
|
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
|
+
}
|
|
92
98
|
function getEvaluation(log, key, definition, attributes, storage, options) {
|
|
93
99
|
if (definition) {
|
|
94
100
|
var split = engineParser(log, definition, storage);
|
|
95
101
|
var evaluation = split.getTreatment(key, attributes, evaluateFeature);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
result.changeNumber = definition.changeNumber;
|
|
100
|
-
result.config = definition.configurations && definition.configurations[result.treatment] || null;
|
|
101
|
-
// @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
|
|
102
|
-
result.impressionsDisabled = (options === null || options === void 0 ? void 0 : options.impressionsDisabled) || definition.impressionsDisabled;
|
|
103
|
-
return result;
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
evaluation.changeNumber = definition.changeNumber;
|
|
108
|
-
evaluation.config = definition.configurations && definition.configurations[evaluation.treatment] || null;
|
|
109
|
-
// @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
|
|
110
|
-
evaluation.impressionsDisabled = (options === null || options === void 0 ? void 0 : options.impressionsDisabled) || definition.impressionsDisabled;
|
|
111
|
-
}
|
|
112
|
-
return evaluation;
|
|
102
|
+
return thenable(evaluation) ?
|
|
103
|
+
evaluation.then(function (result) { return setEvaluationDataFromDefinition(result, definition, options); }) :
|
|
104
|
+
setEvaluationDataFromDefinition(evaluation, definition, options);
|
|
113
105
|
}
|
|
114
106
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
115
107
|
}
|
|
@@ -118,14 +110,11 @@ function getEvaluations(log, key, definitionNames, definitions, attributes, stor
|
|
|
118
110
|
var thenables = [];
|
|
119
111
|
definitionNames.forEach(function (definitionName) {
|
|
120
112
|
var evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage, options);
|
|
121
|
-
|
|
113
|
+
thenable(evaluation) ?
|
|
122
114
|
thenables.push(evaluation.then(function (res) {
|
|
123
115
|
result[definitionName] = res;
|
|
124
|
-
}))
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
116
|
+
})) :
|
|
127
117
|
result[definitionName] = evaluation;
|
|
128
|
-
}
|
|
129
118
|
});
|
|
130
119
|
return thenables.length > 0 ? Promise.all(thenables).then(function () { return result; }) : result;
|
|
131
120
|
}
|
|
@@ -143,12 +132,10 @@ export function evaluateDefaultTreatment(definitionName, storage) {
|
|
|
143
132
|
}
|
|
144
133
|
function getDefaultTreatment(definition) {
|
|
145
134
|
if (definition) {
|
|
146
|
-
return {
|
|
135
|
+
return setEvaluationDataFromDefinition({
|
|
147
136
|
treatment: definition.defaultTreatment,
|
|
148
|
-
label: NO_CONDITION_MATCH
|
|
149
|
-
|
|
150
|
-
changeNumber: definition.changeNumber
|
|
151
|
-
};
|
|
137
|
+
label: NO_CONDITION_MATCH // "default rule"
|
|
138
|
+
}, definition);
|
|
152
139
|
}
|
|
153
140
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
154
141
|
}
|
package/esm/listeners/browser.js
CHANGED
|
@@ -11,14 +11,14 @@ var EVENT_NAME = 'for visibilitychange and pagehide events.';
|
|
|
11
11
|
*/
|
|
12
12
|
var BrowserSignalListener = /** @class */ (function () {
|
|
13
13
|
function BrowserSignalListener(_a) {
|
|
14
|
-
var syncManager = _a.syncManager, settings = _a.settings, storage = _a.storage, serviceApi = _a.serviceApi
|
|
14
|
+
var syncManager = _a.syncManager, settings = _a.settings, storage = _a.storage, serviceApi = _a.serviceApi;
|
|
15
15
|
this.syncManager = syncManager;
|
|
16
16
|
this.settings = settings;
|
|
17
17
|
this.storage = storage;
|
|
18
18
|
this.serviceApi = serviceApi;
|
|
19
19
|
this.flushData = this.flushData.bind(this);
|
|
20
20
|
this.flushDataIfHidden = this.flushDataIfHidden.bind(this);
|
|
21
|
-
this.fromImpressionsCollector = fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled
|
|
21
|
+
this.fromImpressionsCollector = fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled);
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* start method.
|
|
@@ -13,7 +13,7 @@ function isExpired(credential) {
|
|
|
13
13
|
export function authProviderFactory(settings, splitHttpClient, telemetryTracker) {
|
|
14
14
|
var urls = settings.urls, log = settings.log;
|
|
15
15
|
function fetchAuth() {
|
|
16
|
-
var url = "".concat(urls.auth, "/api/v3/auth?capabilities=config");
|
|
16
|
+
var url = "".concat(urls.auth, "/api/v3/auth?capabilities=config,aiconfig");
|
|
17
17
|
return splitHttpClient(url, undefined, telemetryTracker.trackHttp(TOKEN), false, true);
|
|
18
18
|
}
|
|
19
19
|
var authenticate = authenticateFactory(fetchAuth);
|
package/esm/storages/utils.js
CHANGED
|
@@ -4,7 +4,7 @@ import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
|
|
|
4
4
|
/**
|
|
5
5
|
* Converts `impressions` data from cache into request payload.
|
|
6
6
|
*/
|
|
7
|
-
export function fromImpressionsCollector(sendLabels,
|
|
7
|
+
export function fromImpressionsCollector(sendLabels, data) {
|
|
8
8
|
var groupedByFeature = groupBy(data, 'feature');
|
|
9
9
|
var dto = [];
|
|
10
10
|
forOwn(groupedByFeature, function (value, name) {
|
|
@@ -20,7 +20,8 @@ export function fromImpressionsCollector(sendLabels, entityType, data) {
|
|
|
20
20
|
b: entry.bucketingKey,
|
|
21
21
|
pt: entry.pt,
|
|
22
22
|
properties: entry.properties,
|
|
23
|
-
|
|
23
|
+
// @ts-expect-error - entityType is not yet public. @TODO: add to SplitIO.ImpressionDTO type
|
|
24
|
+
et: entry.entityType, // Definition type
|
|
24
25
|
};
|
|
25
26
|
})
|
|
26
27
|
});
|
|
@@ -31,9 +32,9 @@ export function fromImpressionsCollector(sendLabels, entityType, data) {
|
|
|
31
32
|
* Submitter that periodically posts impressions data
|
|
32
33
|
*/
|
|
33
34
|
export function impressionsSubmitterFactory(params) {
|
|
34
|
-
var _a = params.settings, log = _a.log, impressionsRefreshRate = _a.scheduler.impressionsRefreshRate, labelsEnabled = _a.core.labelsEnabled, postTestImpressionsBulk = params.serviceApi.postTestImpressionsBulk, impressions = params.storage.impressions
|
|
35
|
+
var _a = params.settings, log = _a.log, impressionsRefreshRate = _a.scheduler.impressionsRefreshRate, labelsEnabled = _a.core.labelsEnabled, postTestImpressionsBulk = params.serviceApi.postTestImpressionsBulk, impressions = params.storage.impressions;
|
|
35
36
|
// retry impressions only once.
|
|
36
|
-
var syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled
|
|
37
|
+
var syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled), 1);
|
|
37
38
|
// register impressions submitter to be executed when impressions cache is full
|
|
38
39
|
impressions.setOnFullQueueCb(function () {
|
|
39
40
|
if (syncTask.isRunning()) {
|
package/package.json
CHANGED
package/src/dtos/types.ts
CHANGED
|
@@ -215,6 +215,9 @@ export interface IRBSegment extends TargetingEntity {
|
|
|
215
215
|
} | null
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
export type ConfigType = 'standard' | 'ai';
|
|
219
|
+
export type ConfigSubtype = 'llm_call';
|
|
220
|
+
|
|
218
221
|
export interface IDefinition extends TargetingEntity {
|
|
219
222
|
trafficTypeName: string;
|
|
220
223
|
sets?: string[] | null;
|
|
@@ -231,6 +234,10 @@ export interface IDefinition extends TargetingEntity {
|
|
|
231
234
|
configurations?: {
|
|
232
235
|
[treatmentName: string]: string | SplitIO.JsonObject
|
|
233
236
|
} | null;
|
|
237
|
+
/** Definition classification. Absent means a feature flag. */
|
|
238
|
+
type?: ConfigType;
|
|
239
|
+
/** Only meaningful when `type === 'AI'`. */
|
|
240
|
+
subtype?: ConfigSubtype;
|
|
234
241
|
}
|
|
235
242
|
|
|
236
243
|
/** Interface of the parsed JSON response of `/splitChanges` */
|
package/src/evaluator/index.ts
CHANGED
|
@@ -47,29 +47,14 @@ export function evaluateFeature(
|
|
|
47
47
|
return EVALUATION_EXCEPTION;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
)).catch(
|
|
59
|
-
// Exception on async storage. For example, when the storage is redis or
|
|
60
|
-
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
61
|
-
() => EVALUATION_EXCEPTION
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return getEvaluation(
|
|
66
|
-
log,
|
|
67
|
-
key,
|
|
68
|
-
definition,
|
|
69
|
-
attributes,
|
|
70
|
-
storage,
|
|
71
|
-
options,
|
|
72
|
-
);
|
|
50
|
+
return thenable(definition) ?
|
|
51
|
+
definition.then((definition) => getEvaluation(log, key, definition, attributes, storage, options))
|
|
52
|
+
.catch(
|
|
53
|
+
// Exception on async storage. For example, when the storage is redis or
|
|
54
|
+
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
55
|
+
() => EVALUATION_EXCEPTION
|
|
56
|
+
) :
|
|
57
|
+
getEvaluation(log, key, definition, attributes, storage, options);
|
|
73
58
|
}
|
|
74
59
|
|
|
75
60
|
export function evaluateFeatures(
|
|
@@ -91,11 +76,11 @@ export function evaluateFeatures(
|
|
|
91
76
|
|
|
92
77
|
return thenable(definitions) ?
|
|
93
78
|
definitions.then(definitions => getEvaluations(log, key, definitionNames, definitions, attributes, storage, options))
|
|
94
|
-
.catch(
|
|
79
|
+
.catch(
|
|
95
80
|
// Exception on async storage. For example, when the storage is redis or
|
|
96
81
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
97
|
-
|
|
98
|
-
|
|
82
|
+
() => treatmentsException(definitionNames)
|
|
83
|
+
) :
|
|
99
84
|
getEvaluations(log, key, definitionNames, definitions, attributes, storage, options);
|
|
100
85
|
}
|
|
101
86
|
|
|
@@ -137,12 +122,21 @@ export function evaluateFeaturesByFlagSets(
|
|
|
137
122
|
// evaluate related features
|
|
138
123
|
return thenable(storedFlagNames) ?
|
|
139
124
|
storedFlagNames.then((storedFlagNames) => evaluate(storedFlagNames))
|
|
140
|
-
.catch(() => {
|
|
141
|
-
return {};
|
|
142
|
-
}) :
|
|
125
|
+
.catch(() => ({})) :
|
|
143
126
|
evaluate(storedFlagNames);
|
|
144
127
|
}
|
|
145
128
|
|
|
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
|
+
|
|
146
140
|
function getEvaluation(
|
|
147
141
|
log: ILogger,
|
|
148
142
|
key: SplitIO.SplitKey,
|
|
@@ -156,24 +150,9 @@ function getEvaluation(
|
|
|
156
150
|
const split = engineParser(log, definition, storage);
|
|
157
151
|
const evaluation = split.getTreatment(key, attributes, evaluateFeature);
|
|
158
152
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
result.changeNumber = definition.changeNumber;
|
|
163
|
-
result.config = definition.configurations && definition.configurations[result.treatment] || null;
|
|
164
|
-
// @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
|
|
165
|
-
result.impressionsDisabled = options?.impressionsDisabled || definition.impressionsDisabled;
|
|
166
|
-
|
|
167
|
-
return result;
|
|
168
|
-
});
|
|
169
|
-
} else {
|
|
170
|
-
evaluation.changeNumber = definition.changeNumber;
|
|
171
|
-
evaluation.config = definition.configurations && definition.configurations[evaluation.treatment] || null;
|
|
172
|
-
// @ts-expect-error impressionsDisabled is not exposed in the public typings yet.
|
|
173
|
-
evaluation.impressionsDisabled = options?.impressionsDisabled || definition.impressionsDisabled;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return evaluation;
|
|
153
|
+
return thenable(evaluation) ?
|
|
154
|
+
evaluation.then(result => setEvaluationDataFromDefinition(result, definition, options)) :
|
|
155
|
+
setEvaluationDataFromDefinition(evaluation, definition, options);
|
|
177
156
|
}
|
|
178
157
|
|
|
179
158
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
|
@@ -191,21 +170,12 @@ function getEvaluations(
|
|
|
191
170
|
const result: Record<string, IEvaluationResult> = {};
|
|
192
171
|
const thenables: Promise<void>[] = [];
|
|
193
172
|
definitionNames.forEach(definitionName => {
|
|
194
|
-
const evaluation = getEvaluation(
|
|
195
|
-
|
|
196
|
-
key,
|
|
197
|
-
definitions[definitionName],
|
|
198
|
-
attributes,
|
|
199
|
-
storage,
|
|
200
|
-
options
|
|
201
|
-
);
|
|
202
|
-
if (thenable(evaluation)) {
|
|
173
|
+
const evaluation = getEvaluation(log, key, definitions[definitionName], attributes, storage, options);
|
|
174
|
+
thenable(evaluation) ?
|
|
203
175
|
thenables.push(evaluation.then(res => {
|
|
204
176
|
result[definitionName] = res;
|
|
205
|
-
}))
|
|
206
|
-
} else {
|
|
177
|
+
})) :
|
|
207
178
|
result[definitionName] = evaluation;
|
|
208
|
-
}
|
|
209
179
|
});
|
|
210
180
|
|
|
211
181
|
return thenables.length > 0 ? Promise.all(thenables).then(() => result) : result;
|
|
@@ -232,12 +202,10 @@ function getDefaultTreatment(
|
|
|
232
202
|
definition: IDefinition | null,
|
|
233
203
|
): MaybeThenable<IEvaluationResult> {
|
|
234
204
|
if (definition) {
|
|
235
|
-
return {
|
|
205
|
+
return setEvaluationDataFromDefinition({
|
|
236
206
|
treatment: definition.defaultTreatment,
|
|
237
|
-
label: NO_CONDITION_MATCH
|
|
238
|
-
|
|
239
|
-
changeNumber: definition.changeNumber
|
|
240
|
-
};
|
|
207
|
+
label: NO_CONDITION_MATCH // "default rule"
|
|
208
|
+
}, definition);
|
|
241
209
|
}
|
|
242
210
|
|
|
243
211
|
return EVALUATION_DEFINITION_NOT_FOUND;
|
package/src/evaluator/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IBetweenMatcherData, IBetweenStringMatcherData, IDependencyMatcherData, MaybeThenable } from '../dtos/types';
|
|
1
|
+
import { IBetweenMatcherData, IBetweenStringMatcherData, IDefinition, IDependencyMatcherData, MaybeThenable } from '../dtos/types';
|
|
2
2
|
import { IStorageAsync, IStorageSync } from '../storages/types';
|
|
3
3
|
import SplitIO from '../../types/splitio';
|
|
4
4
|
import { ILogger } from '../logger/types';
|
|
@@ -23,6 +23,8 @@ export interface IEvaluation {
|
|
|
23
23
|
label: string,
|
|
24
24
|
changeNumber?: number,
|
|
25
25
|
config?: string | null | SplitIO.JsonObject
|
|
26
|
+
type?: IDefinition['type']
|
|
27
|
+
subtype?: IDefinition['subtype']
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
export type IEvaluationResult = IEvaluation & { treatment: string; impressionsDisabled?: boolean }
|
package/src/listeners/browser.ts
CHANGED
|
@@ -28,14 +28,14 @@ export class BrowserSignalListener implements ISignalListener {
|
|
|
28
28
|
private serviceApi: IServiceApi;
|
|
29
29
|
private fromImpressionsCollector: (data: SplitIO.ImpressionDTO[]) => ImpressionsPayload;
|
|
30
30
|
|
|
31
|
-
constructor({ syncManager, settings, storage, serviceApi
|
|
31
|
+
constructor({ syncManager, settings, storage, serviceApi }: ISdkFactoryContextSync) {
|
|
32
32
|
this.syncManager = syncManager;
|
|
33
33
|
this.settings = settings;
|
|
34
34
|
this.storage = storage;
|
|
35
35
|
this.serviceApi = serviceApi;
|
|
36
36
|
this.flushData = this.flushData.bind(this);
|
|
37
37
|
this.flushDataIfHidden = this.flushDataIfHidden.bind(this);
|
|
38
|
-
this.fromImpressionsCollector = fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled
|
|
38
|
+
this.fromImpressionsCollector = fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
package/src/sdkFactory/types.ts
CHANGED
|
@@ -43,9 +43,6 @@ export interface IPlatform {
|
|
|
43
43
|
SignalListener?: new (params: ISdkFactoryContext) => ISignalListener, // Used by BrowserSignalListener
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
// Definition type
|
|
47
|
-
export type EntityType = 'config' | 'flag';
|
|
48
|
-
|
|
49
46
|
export interface ISdkFactoryContext {
|
|
50
47
|
platform: IPlatform,
|
|
51
48
|
sdkReadinessManager: ISdkReadinessManager,
|
|
@@ -59,7 +56,6 @@ export interface ISdkFactoryContext {
|
|
|
59
56
|
syncManager?: ISyncManager,
|
|
60
57
|
clients: Record<string, SplitIO.IBasicClient>,
|
|
61
58
|
fallbackCalculator: IFallbackCalculator,
|
|
62
|
-
entityType?: EntityType
|
|
63
59
|
}
|
|
64
60
|
|
|
65
61
|
export interface ISdkFactoryContextSync extends ISdkFactoryContext {
|
|
@@ -28,7 +28,7 @@ export function authProviderFactory(settings: ISettings, splitHttpClient: ISplit
|
|
|
28
28
|
const { urls, log } = settings;
|
|
29
29
|
|
|
30
30
|
function fetchAuth() {
|
|
31
|
-
let url = `${urls.auth}/api/v3/auth?capabilities=config`;
|
|
31
|
+
let url = `${urls.auth}/api/v3/auth?capabilities=config,aiconfig`;
|
|
32
32
|
return splitHttpClient(url, undefined, telemetryTracker.trackHttp(TOKEN), false, true);
|
|
33
33
|
}
|
|
34
34
|
|
package/src/storages/utils.ts
CHANGED
|
@@ -3,12 +3,12 @@ import SplitIO from '../../../types/splitio';
|
|
|
3
3
|
import { submitterFactory } from './submitter';
|
|
4
4
|
import { ImpressionsPayload } from './types';
|
|
5
5
|
import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
|
|
6
|
-
import {
|
|
6
|
+
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Converts `impressions` data from cache into request payload.
|
|
10
10
|
*/
|
|
11
|
-
export function fromImpressionsCollector(sendLabels: boolean,
|
|
11
|
+
export function fromImpressionsCollector(sendLabels: boolean, data: SplitIO.ImpressionDTO[]): ImpressionsPayload {
|
|
12
12
|
let groupedByFeature = groupBy(data, 'feature');
|
|
13
13
|
let dto: ImpressionsPayload = [];
|
|
14
14
|
|
|
@@ -25,7 +25,8 @@ export function fromImpressionsCollector(sendLabels: boolean, entityType: Entity
|
|
|
25
25
|
b: entry.bucketingKey, // Bucketing Key
|
|
26
26
|
pt: entry.pt, // Previous time
|
|
27
27
|
properties: entry.properties, // Properties
|
|
28
|
-
|
|
28
|
+
// @ts-expect-error - entityType is not yet public. @TODO: add to SplitIO.ImpressionDTO type
|
|
29
|
+
et: entry.entityType, // Definition type
|
|
29
30
|
};
|
|
30
31
|
})
|
|
31
32
|
});
|
|
@@ -42,12 +43,11 @@ export function impressionsSubmitterFactory(params: ISdkFactoryContextSync) {
|
|
|
42
43
|
const {
|
|
43
44
|
settings: { log, scheduler: { impressionsRefreshRate }, core: { labelsEnabled } },
|
|
44
45
|
serviceApi: { postTestImpressionsBulk },
|
|
45
|
-
storage: { impressions }
|
|
46
|
-
entityType
|
|
46
|
+
storage: { impressions }
|
|
47
47
|
} = params;
|
|
48
48
|
|
|
49
49
|
// retry impressions only once.
|
|
50
|
-
const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled
|
|
50
|
+
const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled), 1);
|
|
51
51
|
|
|
52
52
|
// register impressions submitter to be executed when impressions cache is full
|
|
53
53
|
impressions.setOnFullQueueCb(() => {
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { IMetadata } from '../../dtos/types';
|
|
3
3
|
import SplitIO from '../../../types/splitio';
|
|
4
4
|
import { ISyncTask } from '../types';
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
type EntityType = 'config' | 'flag' | 'ai-config';
|
|
6
7
|
|
|
7
8
|
type ImpressionPayload = {
|
|
8
9
|
/** Matching Key */
|
package/types/splitio.d.ts
CHANGED
|
@@ -2290,133 +2290,9 @@ declare namespace SplitIO {
|
|
|
2290
2290
|
split(featureFlagName: string): SplitViewAsync;
|
|
2291
2291
|
}
|
|
2292
2292
|
|
|
2293
|
-
/**
|
|
2294
|
-
* Fallback configuration objects returned by the `client.getConfig` method when the SDK is not ready or the provided config name is not found.
|
|
2295
|
-
*/
|
|
2296
|
-
type FallbackConfigs = {
|
|
2297
|
-
/**
|
|
2298
|
-
* Fallback config for all config names.
|
|
2299
|
-
*/
|
|
2300
|
-
global?: Config;
|
|
2301
|
-
/**
|
|
2302
|
-
* Fallback configs for specific config names. It takes precedence over the global fallback config.
|
|
2303
|
-
*/
|
|
2304
|
-
byName?: {
|
|
2305
|
-
[configName: string]: Config;
|
|
2306
|
-
};
|
|
2307
|
-
}
|
|
2308
|
-
|
|
2309
|
-
/**
|
|
2310
|
-
* Configs SDK settings.
|
|
2311
|
-
*/
|
|
2312
|
-
interface ConfigsClientSettings {
|
|
2313
|
-
/**
|
|
2314
|
-
* SDK key used to authenticate with Harness services.
|
|
2315
|
-
*
|
|
2316
|
-
* @see {@link https://developer.harness.io/docs/feature-management-experimentation/management-and-administration/account-settings/api-keys/}
|
|
2317
|
-
*/
|
|
2318
|
-
sdkKey: string;
|
|
2319
|
-
/**
|
|
2320
|
-
* Log level for SDK logging.
|
|
2321
|
-
* - `'none'`: No logging
|
|
2322
|
-
* - `'error'`: Log errors only
|
|
2323
|
-
* - `'warn'`: Log warnings and errors
|
|
2324
|
-
* - `'info'`: Log info, warnings, and errors
|
|
2325
|
-
* - `'debug'`: Log debug info and above
|
|
2326
|
-
* @defaultValue `'none'`
|
|
2327
|
-
*/
|
|
2328
|
-
logLevel?: 'none' | 'error' | 'warn' | 'info' | 'debug';
|
|
2329
|
-
/**
|
|
2330
|
-
* Synchronization configuration.
|
|
2331
|
-
*/
|
|
2332
|
-
sync?: {
|
|
2333
|
-
/**
|
|
2334
|
-
* Polling rate for configs and segments refresh, in seconds. Minimum value: 5.
|
|
2335
|
-
*
|
|
2336
|
-
* @defaultValue `60`
|
|
2337
|
-
*/
|
|
2338
|
-
pollingRate?: number;
|
|
2339
|
-
/**
|
|
2340
|
-
* Push rate for events and impressions, in seconds. Minimum value: 60.
|
|
2341
|
-
*
|
|
2342
|
-
* @defaultValue `60`
|
|
2343
|
-
*/
|
|
2344
|
-
pushRate?: number;
|
|
2345
|
-
/**
|
|
2346
|
-
* Maximum queue size for events and impressions. When the queue reaches this size, a flush is triggered. Minimum value: 1000.
|
|
2347
|
-
*
|
|
2348
|
-
* @defaultValue `10000`
|
|
2349
|
-
*/
|
|
2350
|
-
queueSize?: number;
|
|
2351
|
-
/**
|
|
2352
|
-
* Time in seconds before emitting the `SDK_READY_TIMED_OUT` event.
|
|
2353
|
-
* A value of `-1` disables the timeout and thus the event is never emitted.
|
|
2354
|
-
*
|
|
2355
|
-
* @defaultValue `10`
|
|
2356
|
-
*/
|
|
2357
|
-
readyTimeout?: number;
|
|
2358
|
-
/**
|
|
2359
|
-
* Base URLs used by the SDK for different services.
|
|
2360
|
-
*/
|
|
2361
|
-
serviceEndpoints?: {
|
|
2362
|
-
/**
|
|
2363
|
-
* String property to override the base URL where the SDK will get JWT authentication credentials.
|
|
2364
|
-
*
|
|
2365
|
-
* @defaultValue `'https://auth.split.io'`
|
|
2366
|
-
*/
|
|
2367
|
-
auth?: string;
|
|
2368
|
-
/**
|
|
2369
|
-
* String property to override the base URL where the SDK will get rollout plan related data, like configs and segments definitions.
|
|
2370
|
-
*
|
|
2371
|
-
* @defaultValue `'https://configs.split.io'`
|
|
2372
|
-
*/
|
|
2373
|
-
configs?: string;
|
|
2374
|
-
/**
|
|
2375
|
-
* String property to override the base URL where the SDK will post event-related information like impressions.
|
|
2376
|
-
*
|
|
2377
|
-
* @defaultValue `'https://events.split.io'`
|
|
2378
|
-
*/
|
|
2379
|
-
events?: string;
|
|
2380
|
-
};
|
|
2381
|
-
};
|
|
2382
|
-
/**
|
|
2383
|
-
* Fallback configuration objects returned by the `client.getConfig` method when the SDK is not ready or the provided config name is not found.
|
|
2384
|
-
*/
|
|
2385
|
-
fallbackConfigs?: FallbackConfigs;
|
|
2386
|
-
/**
|
|
2387
|
-
* Custom options object for HTTP(S) requests.
|
|
2388
|
-
* If provided, this object is merged with the options object passed by the SDK for EventSource and Fetch calls.
|
|
2389
|
-
*/
|
|
2390
|
-
requestOptions?: {
|
|
2391
|
-
/**
|
|
2392
|
-
* Custom Node.js HTTP(S) Agent used by the SDK for HTTP(S) requests.
|
|
2393
|
-
*
|
|
2394
|
-
* You can use it, for example, for certificate pinning or setting a network proxy:
|
|
2395
|
-
*
|
|
2396
|
-
* ```
|
|
2397
|
-
* const { ConfigsClient } = require('@splitsoftware/configs');
|
|
2398
|
-
* const { HttpsProxyAgent } = require('https-proxy-agent');
|
|
2399
|
-
*
|
|
2400
|
-
* const proxyAgent = new HttpsProxyAgent(process.env.HTTPS_PROXY || 'http://10.10.1.10:1080');
|
|
2401
|
-
*
|
|
2402
|
-
* const client = ConfigsClient({
|
|
2403
|
-
* ...
|
|
2404
|
-
* requestOptions: {
|
|
2405
|
-
* agent: proxyAgent
|
|
2406
|
-
* }
|
|
2407
|
-
* })
|
|
2408
|
-
* ```
|
|
2409
|
-
*
|
|
2410
|
-
* @see {@link https://nodejs.org/api/https.html#class-httpsagent}
|
|
2411
|
-
*
|
|
2412
|
-
* @defaultValue `undefined`
|
|
2413
|
-
*/
|
|
2414
|
-
agent?: RequestOptions['agent'];
|
|
2415
|
-
};
|
|
2416
|
-
}
|
|
2417
2293
|
|
|
2418
2294
|
/**
|
|
2419
|
-
* Target for
|
|
2295
|
+
* Target for an evaluation.
|
|
2420
2296
|
*/
|
|
2421
2297
|
interface Target {
|
|
2422
2298
|
/**
|
|
@@ -2434,50 +2310,4 @@ declare namespace SplitIO {
|
|
|
2434
2310
|
type JsonValue = string | number | boolean | null | JsonObject | JsonArray;
|
|
2435
2311
|
type JsonArray = JsonValue[];
|
|
2436
2312
|
type JsonObject = { [key: string]: JsonValue; };
|
|
2437
|
-
|
|
2438
|
-
/**
|
|
2439
|
-
* Config object returned by getConfig.
|
|
2440
|
-
*/
|
|
2441
|
-
type Config = {
|
|
2442
|
-
/**
|
|
2443
|
-
* The name of the variant.
|
|
2444
|
-
*/
|
|
2445
|
-
variant: string;
|
|
2446
|
-
/**
|
|
2447
|
-
* The config value, a raw JSON object.
|
|
2448
|
-
*/
|
|
2449
|
-
value: JsonObject;
|
|
2450
|
-
}
|
|
2451
|
-
|
|
2452
|
-
/**
|
|
2453
|
-
* Configs SDK client interface.
|
|
2454
|
-
*/
|
|
2455
|
-
interface ConfigsClient extends Omit<IStatusInterface, 'ready' | 'whenReadyFromCache'> {
|
|
2456
|
-
/**
|
|
2457
|
-
* Destroys the client.
|
|
2458
|
-
*
|
|
2459
|
-
* @returns A promise that resolves once all clients are destroyed.
|
|
2460
|
-
*/
|
|
2461
|
-
destroy(): Promise<void>;
|
|
2462
|
-
/**
|
|
2463
|
-
* Gets the config object for a given config name and optional target. If no target is provided, the default variant of the config is returned.
|
|
2464
|
-
*
|
|
2465
|
-
* @param configName - The name of the config we want to get.
|
|
2466
|
-
* @param target - The target of the config evaluation.
|
|
2467
|
-
* @param options - An object of type EvaluationOptions for advanced evaluation options.
|
|
2468
|
-
* @returns The config object.
|
|
2469
|
-
*/
|
|
2470
|
-
getConfig(configName: string, target?: Target, options?: EvaluationOptions): Config;
|
|
2471
|
-
/**
|
|
2472
|
-
* Tracks an event to be fed to the results product on Harness FME user interface.
|
|
2473
|
-
*
|
|
2474
|
-
* @param trafficKey - The key that identifies the entity related to this event.
|
|
2475
|
-
* @param trafficType - The traffic type of the entity related to this event. See {@link https://developer.harness.io/docs/feature-management-experimentation/management-and-administration/fme-settings/traffic-types/}
|
|
2476
|
-
* @param eventType - The event type corresponding to this event.
|
|
2477
|
-
* @param value - The value of this event.
|
|
2478
|
-
* @param properties - The properties of this event. Values can be string, number, boolean or null.
|
|
2479
|
-
* @returns Whether the event was added to the queue successfully or not.
|
|
2480
|
-
*/
|
|
2481
|
-
track(trafficKey: SplitKey, trafficType: string, eventType: string, value?: number, properties?: Properties): boolean;
|
|
2482
|
-
}
|
|
2483
2313
|
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.sanitizeFallbacks = exports.isValidConfig = exports.isValidConfigName = void 0;
|
|
4
|
-
var lang_1 = require("../../../utils/lang");
|
|
5
|
-
var CONFIG_NAME_DISCARD_REASON = 'Invalid config name (max 100 chars, no spaces)';
|
|
6
|
-
var VARIANT_DISCARD_REASON = 'Invalid variant (max 100 chars and must match pattern)';
|
|
7
|
-
var VALUE_DISCARD_REASON = 'Invalid value (must be an object)';
|
|
8
|
-
var VARIANT_PATTERN = /^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$/;
|
|
9
|
-
function isValidConfigName(name) {
|
|
10
|
-
return name.length <= 100 && !name.includes(' ');
|
|
11
|
-
}
|
|
12
|
-
exports.isValidConfigName = isValidConfigName;
|
|
13
|
-
function isValidConfig(config) {
|
|
14
|
-
if (!(0, lang_1.isObject)(config))
|
|
15
|
-
return false;
|
|
16
|
-
if (!(0, lang_1.isString)(config.variant) || config.variant.length > 100 || !VARIANT_PATTERN.test(config.variant))
|
|
17
|
-
return false;
|
|
18
|
-
if (!(0, lang_1.isObject)(config.value))
|
|
19
|
-
return false;
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
exports.isValidConfig = isValidConfig;
|
|
23
|
-
function sanitizeGlobal(logger, config) {
|
|
24
|
-
if (config === undefined)
|
|
25
|
-
return undefined;
|
|
26
|
-
if (!isValidConfig(config)) {
|
|
27
|
-
if (!(0, lang_1.isObject)(config) || !(0, lang_1.isString)(config.variant) || config.variant.length > 100 || !VARIANT_PATTERN.test(config.variant)) {
|
|
28
|
-
logger.error("Fallback configs - Discarded fallback: ".concat(VARIANT_DISCARD_REASON));
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
logger.error("Fallback configs - Discarded fallback: ".concat(VALUE_DISCARD_REASON));
|
|
32
|
-
}
|
|
33
|
-
return undefined;
|
|
34
|
-
}
|
|
35
|
-
return config;
|
|
36
|
-
}
|
|
37
|
-
function sanitizeByName(logger, byNameFallbacks) {
|
|
38
|
-
var sanitizedByName = {};
|
|
39
|
-
if (!(0, lang_1.isObject)(byNameFallbacks))
|
|
40
|
-
return sanitizedByName;
|
|
41
|
-
Object.keys(byNameFallbacks).forEach(function (configName) {
|
|
42
|
-
var config = byNameFallbacks[configName];
|
|
43
|
-
if (!isValidConfigName(configName)) {
|
|
44
|
-
logger.error("Fallback configs - Discarded config '".concat(configName, "': ").concat(CONFIG_NAME_DISCARD_REASON));
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
if (!isValidConfig(config)) {
|
|
48
|
-
if (!(0, lang_1.isObject)(config) || !(0, lang_1.isString)(config.variant) || config.variant.length > 100 || !VARIANT_PATTERN.test(config.variant)) {
|
|
49
|
-
logger.error("Fallback configs - Discarded config '".concat(configName, "': ").concat(VARIANT_DISCARD_REASON));
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
logger.error("Fallback configs - Discarded config '".concat(configName, "': ").concat(VALUE_DISCARD_REASON));
|
|
53
|
-
}
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
sanitizedByName[configName] = config;
|
|
57
|
-
});
|
|
58
|
-
return sanitizedByName;
|
|
59
|
-
}
|
|
60
|
-
function sanitizeFallbacks(logger, fallbacks) {
|
|
61
|
-
if (!(0, lang_1.isObject)(fallbacks)) {
|
|
62
|
-
logger.error('Fallback configs - Discarded configuration: it must be an object with optional `global` and `byName` properties');
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
global: sanitizeGlobal(logger, fallbacks.global),
|
|
67
|
-
byName: sanitizeByName(logger, fallbacks.byName)
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
exports.sanitizeFallbacks = sanitizeFallbacks;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FallbackConfigsCalculator = exports.FALLBACK_PREFIX = void 0;
|
|
4
|
-
var constants_1 = require("../../utils/constants");
|
|
5
|
-
exports.FALLBACK_PREFIX = 'fallback - ';
|
|
6
|
-
function FallbackConfigsCalculator(fallbacks) {
|
|
7
|
-
if (fallbacks === void 0) { fallbacks = {}; }
|
|
8
|
-
return function (configName, label) {
|
|
9
|
-
var _a;
|
|
10
|
-
if (label === void 0) { label = ''; }
|
|
11
|
-
var fallback = ((_a = fallbacks.byName) === null || _a === void 0 ? void 0 : _a[configName]) || fallbacks.global;
|
|
12
|
-
return fallback ?
|
|
13
|
-
{
|
|
14
|
-
treatment: fallback.variant,
|
|
15
|
-
config: fallback.value,
|
|
16
|
-
label: "".concat(exports.FALLBACK_PREFIX).concat(label),
|
|
17
|
-
} :
|
|
18
|
-
{
|
|
19
|
-
treatment: constants_1.CONTROL,
|
|
20
|
-
config: null,
|
|
21
|
-
label: label,
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
exports.FallbackConfigsCalculator = FallbackConfigsCalculator;
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { isObject, isString } from '../../../utils/lang';
|
|
2
|
-
var CONFIG_NAME_DISCARD_REASON = 'Invalid config name (max 100 chars, no spaces)';
|
|
3
|
-
var VARIANT_DISCARD_REASON = 'Invalid variant (max 100 chars and must match pattern)';
|
|
4
|
-
var VALUE_DISCARD_REASON = 'Invalid value (must be an object)';
|
|
5
|
-
var VARIANT_PATTERN = /^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$/;
|
|
6
|
-
export function isValidConfigName(name) {
|
|
7
|
-
return name.length <= 100 && !name.includes(' ');
|
|
8
|
-
}
|
|
9
|
-
export function isValidConfig(config) {
|
|
10
|
-
if (!isObject(config))
|
|
11
|
-
return false;
|
|
12
|
-
if (!isString(config.variant) || config.variant.length > 100 || !VARIANT_PATTERN.test(config.variant))
|
|
13
|
-
return false;
|
|
14
|
-
if (!isObject(config.value))
|
|
15
|
-
return false;
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
function sanitizeGlobal(logger, config) {
|
|
19
|
-
if (config === undefined)
|
|
20
|
-
return undefined;
|
|
21
|
-
if (!isValidConfig(config)) {
|
|
22
|
-
if (!isObject(config) || !isString(config.variant) || config.variant.length > 100 || !VARIANT_PATTERN.test(config.variant)) {
|
|
23
|
-
logger.error("Fallback configs - Discarded fallback: ".concat(VARIANT_DISCARD_REASON));
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
logger.error("Fallback configs - Discarded fallback: ".concat(VALUE_DISCARD_REASON));
|
|
27
|
-
}
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
return config;
|
|
31
|
-
}
|
|
32
|
-
function sanitizeByName(logger, byNameFallbacks) {
|
|
33
|
-
var sanitizedByName = {};
|
|
34
|
-
if (!isObject(byNameFallbacks))
|
|
35
|
-
return sanitizedByName;
|
|
36
|
-
Object.keys(byNameFallbacks).forEach(function (configName) {
|
|
37
|
-
var config = byNameFallbacks[configName];
|
|
38
|
-
if (!isValidConfigName(configName)) {
|
|
39
|
-
logger.error("Fallback configs - Discarded config '".concat(configName, "': ").concat(CONFIG_NAME_DISCARD_REASON));
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
if (!isValidConfig(config)) {
|
|
43
|
-
if (!isObject(config) || !isString(config.variant) || config.variant.length > 100 || !VARIANT_PATTERN.test(config.variant)) {
|
|
44
|
-
logger.error("Fallback configs - Discarded config '".concat(configName, "': ").concat(VARIANT_DISCARD_REASON));
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
logger.error("Fallback configs - Discarded config '".concat(configName, "': ").concat(VALUE_DISCARD_REASON));
|
|
48
|
-
}
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
sanitizedByName[configName] = config;
|
|
52
|
-
});
|
|
53
|
-
return sanitizedByName;
|
|
54
|
-
}
|
|
55
|
-
export function sanitizeFallbacks(logger, fallbacks) {
|
|
56
|
-
if (!isObject(fallbacks)) {
|
|
57
|
-
logger.error('Fallback configs - Discarded configuration: it must be an object with optional `global` and `byName` properties');
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
return {
|
|
61
|
-
global: sanitizeGlobal(logger, fallbacks.global),
|
|
62
|
-
byName: sanitizeByName(logger, fallbacks.byName)
|
|
63
|
-
};
|
|
64
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { CONTROL } from '../../utils/constants';
|
|
2
|
-
export var FALLBACK_PREFIX = 'fallback - ';
|
|
3
|
-
export function FallbackConfigsCalculator(fallbacks) {
|
|
4
|
-
if (fallbacks === void 0) { fallbacks = {}; }
|
|
5
|
-
return function (configName, label) {
|
|
6
|
-
var _a;
|
|
7
|
-
if (label === void 0) { label = ''; }
|
|
8
|
-
var fallback = ((_a = fallbacks.byName) === null || _a === void 0 ? void 0 : _a[configName]) || fallbacks.global;
|
|
9
|
-
return fallback ?
|
|
10
|
-
{
|
|
11
|
-
treatment: fallback.variant,
|
|
12
|
-
config: fallback.value,
|
|
13
|
-
label: "".concat(FALLBACK_PREFIX).concat(label),
|
|
14
|
-
} :
|
|
15
|
-
{
|
|
16
|
-
treatment: CONTROL,
|
|
17
|
-
config: null,
|
|
18
|
-
label: label,
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import SplitIO from '../../../../types/splitio';
|
|
2
|
-
import { ILogger } from '../../../logger/types';
|
|
3
|
-
import { isObject, isString } from '../../../utils/lang';
|
|
4
|
-
|
|
5
|
-
const CONFIG_NAME_DISCARD_REASON = 'Invalid config name (max 100 chars, no spaces)';
|
|
6
|
-
const VARIANT_DISCARD_REASON = 'Invalid variant (max 100 chars and must match pattern)';
|
|
7
|
-
const VALUE_DISCARD_REASON = 'Invalid value (must be an object)';
|
|
8
|
-
|
|
9
|
-
const VARIANT_PATTERN = /^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$/;
|
|
10
|
-
|
|
11
|
-
export function isValidConfigName(name: string): boolean {
|
|
12
|
-
return name.length <= 100 && !name.includes(' ');
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function isValidConfig(config?: SplitIO.Config): boolean {
|
|
16
|
-
if (!isObject(config)) return false;
|
|
17
|
-
if (!isString(config!.variant) || config!.variant.length > 100 || !VARIANT_PATTERN.test(config!.variant)) return false;
|
|
18
|
-
if (!isObject(config!.value)) return false;
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function sanitizeGlobal(logger: ILogger, config?: SplitIO.Config): SplitIO.Config | undefined {
|
|
23
|
-
if (config === undefined) return undefined;
|
|
24
|
-
if (!isValidConfig(config)) {
|
|
25
|
-
if (!isObject(config) || !isString(config!.variant) || config!.variant.length > 100 || !VARIANT_PATTERN.test(config!.variant)) {
|
|
26
|
-
logger.error(`Fallback configs - Discarded fallback: ${VARIANT_DISCARD_REASON}`);
|
|
27
|
-
} else {
|
|
28
|
-
logger.error(`Fallback configs - Discarded fallback: ${VALUE_DISCARD_REASON}`);
|
|
29
|
-
}
|
|
30
|
-
return undefined;
|
|
31
|
-
}
|
|
32
|
-
return config;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function sanitizeByName(
|
|
36
|
-
logger: ILogger,
|
|
37
|
-
byNameFallbacks?: Record<string, SplitIO.Config>
|
|
38
|
-
): Record<string, SplitIO.Config> {
|
|
39
|
-
const sanitizedByName: Record<string, SplitIO.Config> = {};
|
|
40
|
-
|
|
41
|
-
if (!isObject(byNameFallbacks)) return sanitizedByName;
|
|
42
|
-
|
|
43
|
-
Object.keys(byNameFallbacks!).forEach((configName) => {
|
|
44
|
-
const config = byNameFallbacks![configName];
|
|
45
|
-
|
|
46
|
-
if (!isValidConfigName(configName)) {
|
|
47
|
-
logger.error(`Fallback configs - Discarded config '${configName}': ${CONFIG_NAME_DISCARD_REASON}`);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (!isValidConfig(config)) {
|
|
52
|
-
if (!isObject(config) || !isString(config.variant) || config.variant.length > 100 || !VARIANT_PATTERN.test(config.variant)) {
|
|
53
|
-
logger.error(`Fallback configs - Discarded config '${configName}': ${VARIANT_DISCARD_REASON}`);
|
|
54
|
-
} else {
|
|
55
|
-
logger.error(`Fallback configs - Discarded config '${configName}': ${VALUE_DISCARD_REASON}`);
|
|
56
|
-
}
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
sanitizedByName[configName] = config;
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
return sanitizedByName;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function sanitizeFallbacks(logger: ILogger, fallbacks: SplitIO.FallbackConfigs): SplitIO.FallbackConfigs | undefined {
|
|
67
|
-
if (!isObject(fallbacks)) {
|
|
68
|
-
logger.error('Fallback configs - Discarded configuration: it must be an object with optional `global` and `byName` properties');
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return {
|
|
73
|
-
global: sanitizeGlobal(logger, fallbacks.global),
|
|
74
|
-
byName: sanitizeByName(logger, fallbacks.byName)
|
|
75
|
-
};
|
|
76
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { IFallbackCalculator } from '../fallbackTreatmentsCalculator/index';
|
|
2
|
-
import { CONTROL } from '../../utils/constants';
|
|
3
|
-
import SplitIO from '../../../types/splitio';
|
|
4
|
-
|
|
5
|
-
export const FALLBACK_PREFIX = 'fallback - ';
|
|
6
|
-
|
|
7
|
-
export function FallbackConfigsCalculator(fallbacks: SplitIO.FallbackConfigs = {}): IFallbackCalculator {
|
|
8
|
-
|
|
9
|
-
return (configName: string, label = '') => {
|
|
10
|
-
const fallback = fallbacks.byName?.[configName] || fallbacks.global;
|
|
11
|
-
|
|
12
|
-
return fallback ?
|
|
13
|
-
{
|
|
14
|
-
treatment: fallback.variant,
|
|
15
|
-
config: fallback.value,
|
|
16
|
-
label: `${FALLBACK_PREFIX}${label}`,
|
|
17
|
-
} :
|
|
18
|
-
{
|
|
19
|
-
treatment: CONTROL,
|
|
20
|
-
config: null,
|
|
21
|
-
label,
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
}
|