@splitsoftware/splitio-commons 2.1.0 → 2.1.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +3 -0
- package/cjs/logger/constants.js +4 -6
- package/cjs/logger/messages/debug.js +1 -3
- package/cjs/logger/messages/error.js +1 -1
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/sdkClient/client.js +29 -19
- package/cjs/sdkClient/clientAttributesDecoration.js +19 -25
- package/cjs/sdkClient/clientInputValidation.js +28 -26
- package/cjs/storages/AbstractSplitsCacheAsync.js +12 -1
- package/cjs/storages/AbstractSplitsCacheSync.js +5 -7
- package/cjs/storages/KeyBuilder.js +0 -16
- package/cjs/storages/KeyBuilderCS.js +8 -2
- package/cjs/storages/dataLoader.js +1 -2
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +5 -2
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +24 -31
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +4 -21
- package/cjs/storages/pluggable/SplitsCachePluggable.js +2 -19
- package/cjs/storages/utils.js +1 -0
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +12 -13
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +9 -23
- package/cjs/sync/submitters/impressionsSubmitter.js +3 -2
- package/cjs/trackers/strategy/strategyOptimized.js +3 -0
- package/cjs/utils/inputValidation/eventProperties.js +12 -1
- package/cjs/utils/inputValidation/index.js +3 -1
- package/esm/logger/constants.js +1 -3
- package/esm/logger/messages/debug.js +1 -3
- package/esm/logger/messages/error.js +1 -1
- package/esm/logger/messages/warn.js +1 -1
- package/esm/sdkClient/client.js +29 -19
- package/esm/sdkClient/clientAttributesDecoration.js +19 -25
- package/esm/sdkClient/clientInputValidation.js +29 -27
- package/esm/storages/AbstractSplitsCacheAsync.js +12 -1
- package/esm/storages/AbstractSplitsCacheSync.js +5 -7
- package/esm/storages/KeyBuilder.js +0 -16
- package/esm/storages/KeyBuilderCS.js +8 -2
- package/esm/storages/dataLoader.js +1 -2
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +5 -2
- package/esm/storages/inMemory/SplitsCacheInMemory.js +24 -31
- package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -21
- package/esm/storages/pluggable/SplitsCachePluggable.js +2 -19
- package/esm/storages/utils.js +1 -0
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +12 -13
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/esm/sync/polling/updaters/splitChangesUpdater.js +10 -24
- package/esm/sync/submitters/impressionsSubmitter.js +3 -2
- package/esm/trackers/strategy/strategyOptimized.js +3 -0
- package/esm/utils/inputValidation/eventProperties.js +10 -0
- package/esm/utils/inputValidation/index.js +1 -0
- package/package.json +1 -1
- package/src/logger/constants.ts +1 -3
- package/src/logger/messages/debug.ts +1 -3
- package/src/logger/messages/error.ts +1 -1
- package/src/logger/messages/warn.ts +1 -1
- package/src/sdkClient/client.ts +31 -21
- package/src/sdkClient/clientAttributesDecoration.ts +20 -27
- package/src/sdkClient/clientInputValidation.ts +30 -27
- package/src/storages/AbstractSplitsCacheAsync.ts +15 -5
- package/src/storages/AbstractSplitsCacheSync.ts +9 -13
- package/src/storages/KeyBuilder.ts +0 -20
- package/src/storages/KeyBuilderCS.ts +10 -3
- package/src/storages/dataLoader.ts +1 -2
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +5 -2
- package/src/storages/inMemory/SplitsCacheInMemory.ts +22 -27
- package/src/storages/inRedis/SplitsCacheInRedis.ts +4 -21
- package/src/storages/pluggable/SplitsCachePluggable.ts +2 -19
- package/src/storages/types.ts +10 -16
- package/src/storages/utils.ts +1 -0
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +14 -15
- package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -2
- package/src/sync/polling/updaters/splitChangesUpdater.ts +12 -27
- package/src/sync/submitters/impressionsSubmitter.ts +3 -2
- package/src/sync/submitters/types.ts +23 -33
- package/src/trackers/strategy/strategyOptimized.ts +3 -0
- package/src/utils/inputValidation/eventProperties.ts +10 -0
- package/src/utils/inputValidation/index.ts +1 -0
- package/types/splitio.d.ts +100 -35
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
2
|
-
import { validateAttributes, validateEvent, validateEventValue, validateEventProperties, validateKey, validateSplit, validateSplits, validateTrafficType, validateIfNotDestroyed, validateIfOperational } from '../utils/inputValidation';
|
|
2
|
+
import { validateAttributes, validateEvent, validateEventValue, validateEventProperties, validateKey, validateSplit, validateSplits, validateTrafficType, validateIfNotDestroyed, validateIfOperational, validateEvaluationOptions } from '../utils/inputValidation';
|
|
3
3
|
import { startsWith } from '../utils/lang';
|
|
4
4
|
import { CONTROL, CONTROL_WITH_CONFIG, GET_TREATMENT, GET_TREATMENTS, GET_TREATMENTS_BY_FLAG_SET, GET_TREATMENTS_BY_FLAG_SETS, GET_TREATMENTS_WITH_CONFIG, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, GET_TREATMENT_WITH_CONFIG, TRACK_FN_LABEL } from '../utils/constants';
|
|
5
5
|
import { isConsumerMode } from '../utils/settingsValidation/mode';
|
|
@@ -14,7 +14,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
14
14
|
/**
|
|
15
15
|
* Avoid repeating this validations code
|
|
16
16
|
*/
|
|
17
|
-
function validateEvaluationParams(maybeKey, maybeNameOrNames, maybeAttributes,
|
|
17
|
+
function validateEvaluationParams(methodName, maybeKey, maybeNameOrNames, maybeAttributes, maybeOptions) {
|
|
18
18
|
var key = validateKey(log, maybeKey, methodName);
|
|
19
19
|
var nameOrNames = methodName.indexOf('ByFlagSet') > -1 ?
|
|
20
20
|
validateFlagSets(log, methodName, maybeNameOrNames, settings.sync.__splitFiltersValidation.groupedFilters.bySet) :
|
|
@@ -23,40 +23,42 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
23
23
|
validateSplit(log, maybeNameOrNames, methodName);
|
|
24
24
|
var attributes = validateAttributes(log, maybeAttributes, methodName);
|
|
25
25
|
var isNotDestroyed = validateIfNotDestroyed(log, readinessManager, methodName);
|
|
26
|
+
var options = validateEvaluationOptions(log, maybeOptions, methodName);
|
|
26
27
|
validateIfOperational(log, readinessManager, methodName, nameOrNames);
|
|
27
28
|
var valid = isNotDestroyed && key && nameOrNames && attributes !== false;
|
|
28
29
|
return {
|
|
29
30
|
valid: valid,
|
|
30
31
|
key: key,
|
|
31
32
|
nameOrNames: nameOrNames,
|
|
32
|
-
attributes: attributes
|
|
33
|
+
attributes: attributes,
|
|
34
|
+
options: options
|
|
33
35
|
};
|
|
34
36
|
}
|
|
35
37
|
function wrapResult(value) {
|
|
36
38
|
return isAsync ? Promise.resolve(value) : value;
|
|
37
39
|
}
|
|
38
|
-
function getTreatment(maybeKey, maybeFeatureFlagName, maybeAttributes) {
|
|
39
|
-
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes,
|
|
40
|
+
function getTreatment(maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions) {
|
|
41
|
+
var params = validateEvaluationParams(GET_TREATMENT, maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions);
|
|
40
42
|
if (params.valid) {
|
|
41
|
-
return client.getTreatment(params.key, params.nameOrNames, params.attributes);
|
|
43
|
+
return client.getTreatment(params.key, params.nameOrNames, params.attributes, params.options);
|
|
42
44
|
}
|
|
43
45
|
else {
|
|
44
46
|
return wrapResult(CONTROL);
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
|
-
function getTreatmentWithConfig(maybeKey, maybeFeatureFlagName, maybeAttributes) {
|
|
48
|
-
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes,
|
|
49
|
+
function getTreatmentWithConfig(maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions) {
|
|
50
|
+
var params = validateEvaluationParams(GET_TREATMENT_WITH_CONFIG, maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions);
|
|
49
51
|
if (params.valid) {
|
|
50
|
-
return client.getTreatmentWithConfig(params.key, params.nameOrNames, params.attributes);
|
|
52
|
+
return client.getTreatmentWithConfig(params.key, params.nameOrNames, params.attributes, params.options);
|
|
51
53
|
}
|
|
52
54
|
else {
|
|
53
55
|
return wrapResult(objectAssign({}, CONTROL_WITH_CONFIG));
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
|
-
function getTreatments(maybeKey, maybeFeatureFlagNames, maybeAttributes) {
|
|
57
|
-
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes,
|
|
58
|
+
function getTreatments(maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions) {
|
|
59
|
+
var params = validateEvaluationParams(GET_TREATMENTS, maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions);
|
|
58
60
|
if (params.valid) {
|
|
59
|
-
return client.getTreatments(params.key, params.nameOrNames, params.attributes);
|
|
61
|
+
return client.getTreatments(params.key, params.nameOrNames, params.attributes, params.options);
|
|
60
62
|
}
|
|
61
63
|
else {
|
|
62
64
|
var res_1 = {};
|
|
@@ -65,10 +67,10 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
65
67
|
return wrapResult(res_1);
|
|
66
68
|
}
|
|
67
69
|
}
|
|
68
|
-
function getTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, maybeAttributes) {
|
|
69
|
-
var params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes,
|
|
70
|
+
function getTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions) {
|
|
71
|
+
var params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG, maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions);
|
|
70
72
|
if (params.valid) {
|
|
71
|
-
return client.getTreatmentsWithConfig(params.key, params.nameOrNames, params.attributes);
|
|
73
|
+
return client.getTreatmentsWithConfig(params.key, params.nameOrNames, params.attributes, params.options);
|
|
72
74
|
}
|
|
73
75
|
else {
|
|
74
76
|
var res_2 = {};
|
|
@@ -77,37 +79,37 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
77
79
|
return wrapResult(res_2);
|
|
78
80
|
}
|
|
79
81
|
}
|
|
80
|
-
function getTreatmentsByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
|
|
81
|
-
var params = validateEvaluationParams(maybeKey, maybeFlagSets, maybeAttributes,
|
|
82
|
+
function getTreatmentsByFlagSets(maybeKey, maybeFlagSets, maybeAttributes, maybeOptions) {
|
|
83
|
+
var params = validateEvaluationParams(GET_TREATMENTS_BY_FLAG_SETS, maybeKey, maybeFlagSets, maybeAttributes, maybeOptions);
|
|
82
84
|
if (params.valid) {
|
|
83
|
-
return client.getTreatmentsByFlagSets(params.key, params.nameOrNames, params.attributes);
|
|
85
|
+
return client.getTreatmentsByFlagSets(params.key, params.nameOrNames, params.attributes, params.options);
|
|
84
86
|
}
|
|
85
87
|
else {
|
|
86
88
|
return wrapResult({});
|
|
87
89
|
}
|
|
88
90
|
}
|
|
89
|
-
function getTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
|
|
90
|
-
var params = validateEvaluationParams(maybeKey, maybeFlagSets, maybeAttributes,
|
|
91
|
+
function getTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, maybeAttributes, maybeOptions) {
|
|
92
|
+
var params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, maybeKey, maybeFlagSets, maybeAttributes, maybeOptions);
|
|
91
93
|
if (params.valid) {
|
|
92
|
-
return client.getTreatmentsWithConfigByFlagSets(params.key, params.nameOrNames, params.attributes);
|
|
94
|
+
return client.getTreatmentsWithConfigByFlagSets(params.key, params.nameOrNames, params.attributes, params.options);
|
|
93
95
|
}
|
|
94
96
|
else {
|
|
95
97
|
return wrapResult({});
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
|
-
function getTreatmentsByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
|
|
99
|
-
var params = validateEvaluationParams(maybeKey, [maybeFlagSet], maybeAttributes,
|
|
100
|
+
function getTreatmentsByFlagSet(maybeKey, maybeFlagSet, maybeAttributes, maybeOptions) {
|
|
101
|
+
var params = validateEvaluationParams(GET_TREATMENTS_BY_FLAG_SET, maybeKey, [maybeFlagSet], maybeAttributes, maybeOptions);
|
|
100
102
|
if (params.valid) {
|
|
101
|
-
return client.getTreatmentsByFlagSet(params.key, params.nameOrNames[0], params.attributes);
|
|
103
|
+
return client.getTreatmentsByFlagSet(params.key, params.nameOrNames[0], params.attributes, params.options);
|
|
102
104
|
}
|
|
103
105
|
else {
|
|
104
106
|
return wrapResult({});
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
|
-
function getTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
|
|
108
|
-
var params = validateEvaluationParams(maybeKey, [maybeFlagSet], maybeAttributes,
|
|
109
|
+
function getTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, maybeAttributes, maybeOptions) {
|
|
110
|
+
var params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, maybeKey, [maybeFlagSet], maybeAttributes, maybeOptions);
|
|
109
111
|
if (params.valid) {
|
|
110
|
-
return client.getTreatmentsWithConfigByFlagSet(params.key, params.nameOrNames[0], params.attributes);
|
|
112
|
+
return client.getTreatmentsWithConfigByFlagSet(params.key, params.nameOrNames[0], params.attributes, params.options);
|
|
111
113
|
}
|
|
112
114
|
else {
|
|
113
115
|
return wrapResult({});
|
|
@@ -6,6 +6,17 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
6
6
|
var AbstractSplitsCacheAsync = /** @class */ (function () {
|
|
7
7
|
function AbstractSplitsCacheAsync() {
|
|
8
8
|
}
|
|
9
|
+
AbstractSplitsCacheAsync.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
10
|
+
var _this = this;
|
|
11
|
+
return Promise.all([
|
|
12
|
+
this.setChangeNumber(changeNumber),
|
|
13
|
+
Promise.all(toAdd.map(function (addedFF) { return _this.addSplit(addedFF); })),
|
|
14
|
+
Promise.all(toRemove.map(function (removedFF) { return _this.removeSplit(removedFF.name); }))
|
|
15
|
+
]).then(function (_a) {
|
|
16
|
+
var added = _a[1], removed = _a[2];
|
|
17
|
+
return added.some(function (result) { return result; }) || removed.some(function (result) { return result; });
|
|
18
|
+
});
|
|
19
|
+
};
|
|
9
20
|
// @TODO revisit segment-related methods ('usesSegments', 'getRegisteredSegments', 'registerSegments')
|
|
10
21
|
// noop, just keeping the interface. This is used by standalone client-side API only, and so only implemented by InMemory and InLocalStorage.
|
|
11
22
|
AbstractSplitsCacheAsync.prototype.usesSegments = function () {
|
|
@@ -34,7 +45,7 @@ var AbstractSplitsCacheAsync = /** @class */ (function () {
|
|
|
34
45
|
newSplit.killed = true;
|
|
35
46
|
newSplit.defaultTreatment = defaultTreatment;
|
|
36
47
|
newSplit.changeNumber = changeNumber;
|
|
37
|
-
return _this.addSplit(
|
|
48
|
+
return _this.addSplit(newSplit);
|
|
38
49
|
}
|
|
39
50
|
return false;
|
|
40
51
|
}).catch(function () { return false; });
|
|
@@ -7,13 +7,11 @@ import { IN_SEGMENT, IN_LARGE_SEGMENT } from '../utils/constants';
|
|
|
7
7
|
var AbstractSplitsCacheSync = /** @class */ (function () {
|
|
8
8
|
function AbstractSplitsCacheSync() {
|
|
9
9
|
}
|
|
10
|
-
AbstractSplitsCacheSync.prototype.
|
|
10
|
+
AbstractSplitsCacheSync.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
11
11
|
var _this = this;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
var _this = this;
|
|
16
|
-
return names.map(function (name) { return _this.removeSplit(name); });
|
|
12
|
+
this.setChangeNumber(changeNumber);
|
|
13
|
+
var updated = toAdd.map(function (addedFF) { return _this.addSplit(addedFF); }).some(function (result) { return result; });
|
|
14
|
+
return toRemove.map(function (removedFF) { return _this.removeSplit(removedFF.name); }).some(function (result) { return result; }) || updated;
|
|
17
15
|
};
|
|
18
16
|
AbstractSplitsCacheSync.prototype.getSplits = function (names) {
|
|
19
17
|
var _this = this;
|
|
@@ -48,7 +46,7 @@ var AbstractSplitsCacheSync = /** @class */ (function () {
|
|
|
48
46
|
newSplit.killed = true;
|
|
49
47
|
newSplit.defaultTreatment = defaultTreatment;
|
|
50
48
|
newSplit.changeNumber = changeNumber;
|
|
51
|
-
return this.addSplit(
|
|
49
|
+
return this.addSplit(newSplit);
|
|
52
50
|
}
|
|
53
51
|
return false;
|
|
54
52
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { startsWith } from '../utils/lang';
|
|
2
1
|
import { hash } from '../utils/murmur3/murmur3';
|
|
3
2
|
var everythingAtTheEnd = /[^.]+$/;
|
|
4
3
|
var DEFAULT_PREFIX = 'SPLITIO';
|
|
@@ -22,30 +21,15 @@ var KeyBuilder = /** @class */ (function () {
|
|
|
22
21
|
KeyBuilder.prototype.buildSplitsTillKey = function () {
|
|
23
22
|
return this.prefix + ".splits.till";
|
|
24
23
|
};
|
|
25
|
-
// NOT USED
|
|
26
|
-
// buildSplitsReady() {
|
|
27
|
-
// return `${this.prefix}.splits.ready`;
|
|
28
|
-
// }
|
|
29
|
-
KeyBuilder.prototype.isSplitKey = function (key) {
|
|
30
|
-
return startsWith(key, this.prefix + ".split.");
|
|
31
|
-
};
|
|
32
24
|
KeyBuilder.prototype.buildSplitKeyPrefix = function () {
|
|
33
25
|
return this.prefix + ".split.";
|
|
34
26
|
};
|
|
35
|
-
// Only used by InLocalStorage.
|
|
36
|
-
KeyBuilder.prototype.buildSplitsWithSegmentCountKey = function () {
|
|
37
|
-
return this.prefix + ".splits.usingSegments";
|
|
38
|
-
};
|
|
39
27
|
KeyBuilder.prototype.buildSegmentNameKey = function (segmentName) {
|
|
40
28
|
return this.prefix + ".segment." + segmentName;
|
|
41
29
|
};
|
|
42
30
|
KeyBuilder.prototype.buildSegmentTillKey = function (segmentName) {
|
|
43
31
|
return this.prefix + ".segment." + segmentName + ".till";
|
|
44
32
|
};
|
|
45
|
-
// NOT USED
|
|
46
|
-
// buildSegmentsReady() {
|
|
47
|
-
// return `${this.prefix}.segments.ready`;
|
|
48
|
-
// }
|
|
49
33
|
KeyBuilder.prototype.extractKey = function (builtKey) {
|
|
50
34
|
var s = builtKey.match(everythingAtTheEnd);
|
|
51
35
|
if (s && s.length) {
|
|
@@ -18,7 +18,7 @@ var KeyBuilderCS = /** @class */ (function (_super) {
|
|
|
18
18
|
KeyBuilderCS.prototype.extractSegmentName = function (builtSegmentKeyName) {
|
|
19
19
|
var prefix = this.prefix + "." + this.matchingKey + ".segment.";
|
|
20
20
|
if (startsWith(builtSegmentKeyName, prefix))
|
|
21
|
-
return builtSegmentKeyName.
|
|
21
|
+
return builtSegmentKeyName.slice(prefix.length);
|
|
22
22
|
};
|
|
23
23
|
KeyBuilderCS.prototype.buildLastUpdatedKey = function () {
|
|
24
24
|
return this.prefix + ".splits.lastUpdated";
|
|
@@ -29,6 +29,12 @@ var KeyBuilderCS = /** @class */ (function (_super) {
|
|
|
29
29
|
KeyBuilderCS.prototype.buildTillKey = function () {
|
|
30
30
|
return this.prefix + "." + this.matchingKey + ".segments.till";
|
|
31
31
|
};
|
|
32
|
+
KeyBuilderCS.prototype.isSplitKey = function (key) {
|
|
33
|
+
return startsWith(key, this.prefix + ".split.");
|
|
34
|
+
};
|
|
35
|
+
KeyBuilderCS.prototype.buildSplitsWithSegmentCountKey = function () {
|
|
36
|
+
return this.prefix + ".splits.usingSegments";
|
|
37
|
+
};
|
|
32
38
|
return KeyBuilderCS;
|
|
33
39
|
}(KeyBuilder));
|
|
34
40
|
export { KeyBuilderCS };
|
|
@@ -40,7 +46,7 @@ export function myLargeSegmentsKeyBuilder(prefix, matchingKey) {
|
|
|
40
46
|
extractSegmentName: function (builtSegmentKeyName) {
|
|
41
47
|
var p = prefix + "." + matchingKey + ".largeSegment.";
|
|
42
48
|
if (startsWith(builtSegmentKeyName, p))
|
|
43
|
-
return builtSegmentKeyName.
|
|
49
|
+
return builtSegmentKeyName.slice(p.length);
|
|
44
50
|
},
|
|
45
51
|
buildTillKey: function () {
|
|
46
52
|
return prefix + "." + matchingKey + ".largeSegments.till";
|
|
@@ -29,9 +29,8 @@ export function dataLoaderFactory(preloadedData) {
|
|
|
29
29
|
return;
|
|
30
30
|
// cleaning up the localStorage data, since some cached splits might need be part of the preloaded data
|
|
31
31
|
storage.splits.clear();
|
|
32
|
-
storage.splits.setChangeNumber(since);
|
|
33
32
|
// splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
|
|
34
|
-
storage.splits.
|
|
33
|
+
storage.splits.update(Object.keys(splitsData).map(function (splitName) { return JSON.parse(splitsData[splitName]); }), [], since);
|
|
35
34
|
// add mySegments data
|
|
36
35
|
var mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userId];
|
|
37
36
|
if (!mySegmentsData) {
|
|
@@ -79,9 +79,10 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
79
79
|
});
|
|
80
80
|
this.hasSync = false;
|
|
81
81
|
};
|
|
82
|
-
SplitsCacheInLocal.prototype.addSplit = function (
|
|
82
|
+
SplitsCacheInLocal.prototype.addSplit = function (split) {
|
|
83
83
|
try {
|
|
84
|
-
var
|
|
84
|
+
var name_1 = split.name;
|
|
85
|
+
var splitKey = this.keys.buildSplitKey(name_1);
|
|
85
86
|
var splitFromLocalStorage = localStorage.getItem(splitKey);
|
|
86
87
|
var previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
|
|
87
88
|
localStorage.setItem(splitKey, JSON.stringify(split));
|
|
@@ -100,6 +101,8 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
100
101
|
SplitsCacheInLocal.prototype.removeSplit = function (name) {
|
|
101
102
|
try {
|
|
102
103
|
var split = this.getSplit(name);
|
|
104
|
+
if (!split)
|
|
105
|
+
return false;
|
|
103
106
|
localStorage.removeItem(this.keys.buildSplitKey(name));
|
|
104
107
|
this._decrementCounts(split);
|
|
105
108
|
if (split)
|
|
@@ -22,7 +22,8 @@ var SplitsCacheInMemory = /** @class */ (function (_super) {
|
|
|
22
22
|
this.changeNumber = -1;
|
|
23
23
|
this.segmentsCount = 0;
|
|
24
24
|
};
|
|
25
|
-
SplitsCacheInMemory.prototype.addSplit = function (
|
|
25
|
+
SplitsCacheInMemory.prototype.addSplit = function (split) {
|
|
26
|
+
var name = split.name;
|
|
26
27
|
var previousSplit = this.getSplit(name);
|
|
27
28
|
if (previousSplit) { // We had this Split already
|
|
28
29
|
var previousTtName = previousSplit.trafficTypeName;
|
|
@@ -34,40 +35,32 @@ var SplitsCacheInMemory = /** @class */ (function (_super) {
|
|
|
34
35
|
if (usesSegments(previousSplit))
|
|
35
36
|
this.segmentsCount--;
|
|
36
37
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
38
|
+
// Store the Split.
|
|
39
|
+
this.splitsCache[name] = split;
|
|
40
|
+
// Update TT cache
|
|
41
|
+
var ttName = split.trafficTypeName;
|
|
42
|
+
this.ttCache[ttName] = (this.ttCache[ttName] || 0) + 1;
|
|
43
|
+
this.addToFlagSets(split);
|
|
44
|
+
// Add to segments count for the new version of the Split
|
|
45
|
+
if (usesSegments(split))
|
|
46
|
+
this.segmentsCount++;
|
|
47
|
+
return true;
|
|
52
48
|
};
|
|
53
49
|
SplitsCacheInMemory.prototype.removeSplit = function (name) {
|
|
54
50
|
var split = this.getSplit(name);
|
|
55
|
-
if (split)
|
|
56
|
-
// Delete the Split
|
|
57
|
-
delete this.splitsCache[name];
|
|
58
|
-
var ttName = split.trafficTypeName;
|
|
59
|
-
this.ttCache[ttName]--; // Update tt cache
|
|
60
|
-
if (!this.ttCache[ttName])
|
|
61
|
-
delete this.ttCache[ttName];
|
|
62
|
-
this.removeFromFlagSets(split.name, split.sets);
|
|
63
|
-
// Update the segments count.
|
|
64
|
-
if (usesSegments(split))
|
|
65
|
-
this.segmentsCount--;
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
51
|
+
if (!split)
|
|
69
52
|
return false;
|
|
70
|
-
|
|
53
|
+
// Delete the Split
|
|
54
|
+
delete this.splitsCache[name];
|
|
55
|
+
var ttName = split.trafficTypeName;
|
|
56
|
+
this.ttCache[ttName]--; // Update tt cache
|
|
57
|
+
if (!this.ttCache[ttName])
|
|
58
|
+
delete this.ttCache[ttName];
|
|
59
|
+
this.removeFromFlagSets(split.name, split.sets);
|
|
60
|
+
// Update the segments count.
|
|
61
|
+
if (usesSegments(split))
|
|
62
|
+
this.segmentsCount--;
|
|
63
|
+
return true;
|
|
71
64
|
};
|
|
72
65
|
SplitsCacheInMemory.prototype.getSplit = function (name) {
|
|
73
66
|
return this.splitsCache[name] || null;
|
|
@@ -64,8 +64,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
|
|
|
64
64
|
* The returned promise is resolved when the operation success
|
|
65
65
|
* or rejected if it fails (e.g., redis operation fails)
|
|
66
66
|
*/
|
|
67
|
-
SplitsCacheInRedis.prototype.addSplit = function (
|
|
67
|
+
SplitsCacheInRedis.prototype.addSplit = function (split) {
|
|
68
68
|
var _this = this;
|
|
69
|
+
var name = split.name;
|
|
69
70
|
var splitKey = this.keys.buildSplitKey(name);
|
|
70
71
|
return this.redis.get(splitKey).then(function (splitFromStorage) {
|
|
71
72
|
// handling parsing error
|
|
@@ -89,18 +90,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
|
|
|
89
90
|
}).then(function () { return _this._updateFlagSets(name, parsedPreviousSplit && parsedPreviousSplit.sets, split.sets); });
|
|
90
91
|
}).then(function () { return true; });
|
|
91
92
|
};
|
|
92
|
-
/**
|
|
93
|
-
* Add a list of splits.
|
|
94
|
-
* The returned promise is resolved when the operation success
|
|
95
|
-
* or rejected if it fails (e.g., redis operation fails)
|
|
96
|
-
*/
|
|
97
|
-
SplitsCacheInRedis.prototype.addSplits = function (entries) {
|
|
98
|
-
var _this = this;
|
|
99
|
-
return Promise.all(entries.map(function (keyValuePair) { return _this.addSplit(keyValuePair[0], keyValuePair[1]); }));
|
|
100
|
-
};
|
|
101
93
|
/**
|
|
102
94
|
* Remove a given split.
|
|
103
|
-
* The returned promise is resolved when the operation success, with
|
|
95
|
+
* The returned promise is resolved when the operation success, with true or false indicating if the split existed (and was removed) or not.
|
|
104
96
|
* or rejected if it fails (e.g., redis operation fails).
|
|
105
97
|
*/
|
|
106
98
|
SplitsCacheInRedis.prototype.removeSplit = function (name) {
|
|
@@ -110,18 +102,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
|
|
|
110
102
|
return _this._decrementCounts(split).then(function () { return _this._updateFlagSets(name, split.sets); });
|
|
111
103
|
}
|
|
112
104
|
}).then(function () {
|
|
113
|
-
return _this.redis.del(_this.keys.buildSplitKey(name));
|
|
105
|
+
return _this.redis.del(_this.keys.buildSplitKey(name)).then(function (status) { return status === 1; });
|
|
114
106
|
});
|
|
115
107
|
};
|
|
116
|
-
/**
|
|
117
|
-
* Remove a list of splits.
|
|
118
|
-
* The returned promise is resolved when the operation success,
|
|
119
|
-
* or rejected if it fails (e.g., redis operation fails).
|
|
120
|
-
*/
|
|
121
|
-
SplitsCacheInRedis.prototype.removeSplits = function (names) {
|
|
122
|
-
var _this = this;
|
|
123
|
-
return Promise.all(names.map(function (name) { return _this.removeSplit(name); }));
|
|
124
|
-
};
|
|
125
108
|
/**
|
|
126
109
|
* Get split definition or null if it's not defined.
|
|
127
110
|
* Returned promise is rejected if redis operation fails.
|
|
@@ -51,8 +51,9 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
|
|
|
51
51
|
* The returned promise is resolved when the operation success
|
|
52
52
|
* or rejected if it fails (e.g., wrapper operation fails)
|
|
53
53
|
*/
|
|
54
|
-
SplitsCachePluggable.prototype.addSplit = function (
|
|
54
|
+
SplitsCachePluggable.prototype.addSplit = function (split) {
|
|
55
55
|
var _this = this;
|
|
56
|
+
var name = split.name;
|
|
56
57
|
var splitKey = this.keys.buildSplitKey(name);
|
|
57
58
|
return this.wrapper.get(splitKey).then(function (splitFromStorage) {
|
|
58
59
|
// handling parsing error
|
|
@@ -76,15 +77,6 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
|
|
|
76
77
|
}).then(function () { return _this._updateFlagSets(name, parsedPreviousSplit && parsedPreviousSplit.sets, split.sets); });
|
|
77
78
|
}).then(function () { return true; });
|
|
78
79
|
};
|
|
79
|
-
/**
|
|
80
|
-
* Add a list of splits.
|
|
81
|
-
* The returned promise is resolved when the operation success
|
|
82
|
-
* or rejected if it fails (e.g., wrapper operation fails)
|
|
83
|
-
*/
|
|
84
|
-
SplitsCachePluggable.prototype.addSplits = function (entries) {
|
|
85
|
-
var _this = this;
|
|
86
|
-
return Promise.all(entries.map(function (keyValuePair) { return _this.addSplit(keyValuePair[0], keyValuePair[1]); }));
|
|
87
|
-
};
|
|
88
80
|
/**
|
|
89
81
|
* Remove a given split.
|
|
90
82
|
* The returned promise is resolved when the operation success, with a boolean indicating if the split existed or not.
|
|
@@ -100,15 +92,6 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
|
|
|
100
92
|
return _this.wrapper.del(_this.keys.buildSplitKey(name));
|
|
101
93
|
});
|
|
102
94
|
};
|
|
103
|
-
/**
|
|
104
|
-
* Remove a list of splits.
|
|
105
|
-
* The returned promise is resolved when the operation success, with a boolean array indicating if the splits existed or not.
|
|
106
|
-
* or rejected if it fails (e.g., wrapper operation fails).
|
|
107
|
-
*/
|
|
108
|
-
SplitsCachePluggable.prototype.removeSplits = function (names) {
|
|
109
|
-
var _this = this;
|
|
110
|
-
return Promise.all(names.map(function (name) { return _this.removeSplit(name); }));
|
|
111
|
-
};
|
|
112
95
|
/**
|
|
113
96
|
* Get split.
|
|
114
97
|
* The returned promise is resolved with the split definition or null if it's not defined,
|
package/esm/storages/utils.js
CHANGED
|
@@ -23,22 +23,21 @@ export function fromObjectUpdaterFactory(splitsParser, storage, readiness, setti
|
|
|
23
23
|
if (!loadError && splitsMock) {
|
|
24
24
|
log.debug(SYNC_OFFLINE_DATA, [JSON.stringify(splitsMock)]);
|
|
25
25
|
forOwn(splitsMock, function (val, name) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
]);
|
|
26
|
+
// @ts-ignore Split changeNumber and seed is undefined in localhost mode
|
|
27
|
+
splits.push({
|
|
28
|
+
name: name,
|
|
29
|
+
status: 'ACTIVE',
|
|
30
|
+
killed: false,
|
|
31
|
+
trafficAllocation: 100,
|
|
32
|
+
defaultTreatment: CONTROL,
|
|
33
|
+
conditions: val.conditions || [],
|
|
34
|
+
configurations: val.configurations,
|
|
35
|
+
trafficTypeName: val.trafficTypeName
|
|
36
|
+
});
|
|
38
37
|
});
|
|
39
38
|
return Promise.all([
|
|
40
39
|
splitsCache.clear(),
|
|
41
|
-
splitsCache.
|
|
40
|
+
splitsCache.update(splits, [], Date.now())
|
|
42
41
|
]).then(function () {
|
|
43
42
|
readiness.splits.emit(SDK_SPLITS_ARRIVED);
|
|
44
43
|
if (startingUp) {
|
|
@@ -5,5 +5,5 @@ import { splitChangesUpdaterFactory } from '../updaters/splitChangesUpdater';
|
|
|
5
5
|
* Creates a sync task that periodically executes a `splitChangesUpdater` task
|
|
6
6
|
*/
|
|
7
7
|
export function splitsSyncTaskFactory(fetchSplitChanges, storage, readiness, settings, isClientSide) {
|
|
8
|
-
return syncTaskFactory(settings.log, splitChangesUpdaterFactory(settings.log, splitChangesFetcherFactory(fetchSplitChanges), storage
|
|
8
|
+
return syncTaskFactory(settings.log, splitChangesUpdaterFactory(settings.log, splitChangesFetcherFactory(fetchSplitChanges), storage, settings.sync.__splitFiltersValidation, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
|
|
9
9
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { timeout } from '../../../utils/promise/timeout';
|
|
2
2
|
import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
|
|
3
|
-
import { SYNC_SPLITS_FETCH,
|
|
3
|
+
import { SYNC_SPLITS_FETCH, SYNC_SPLITS_UPDATE, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
|
|
4
4
|
import { startsWith } from '../../../utils/lang';
|
|
5
5
|
import { IN_SEGMENT } from '../../../utils/constants';
|
|
6
6
|
import { setToArray } from '../../../utils/lang/sets';
|
|
@@ -58,13 +58,13 @@ export function computeSplitsMutation(entries, filters) {
|
|
|
58
58
|
var segments = new Set();
|
|
59
59
|
var computed = entries.reduce(function (accum, split) {
|
|
60
60
|
if (split.status === 'ACTIVE' && matchFilters(split, filters)) {
|
|
61
|
-
accum.added.push(
|
|
61
|
+
accum.added.push(split);
|
|
62
62
|
parseSegments(split).forEach(function (segmentName) {
|
|
63
63
|
segments.add(segmentName);
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
66
|
else {
|
|
67
|
-
accum.removed.push(split
|
|
67
|
+
accum.removed.push(split);
|
|
68
68
|
}
|
|
69
69
|
return accum;
|
|
70
70
|
}, { added: [], removed: [], segments: [] });
|
|
@@ -85,9 +85,10 @@ export function computeSplitsMutation(entries, filters) {
|
|
|
85
85
|
* @param requestTimeoutBeforeReady - How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
|
|
86
86
|
* @param retriesOnFailureBeforeReady - How many retries on `/splitChanges` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
|
|
87
87
|
*/
|
|
88
|
-
export function splitChangesUpdaterFactory(log, splitChangesFetcher,
|
|
88
|
+
export function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFiltersValidation, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
|
|
89
89
|
if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
|
|
90
90
|
if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
|
|
91
|
+
var splits = storage.splits, segments = storage.segments;
|
|
91
92
|
var startingUp = true;
|
|
92
93
|
/** timeout decorator for `splitChangesFetcher` promise */
|
|
93
94
|
function _promiseDecorator(promise) {
|
|
@@ -95,17 +96,6 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
|
|
|
95
96
|
promise = timeout(requestTimeoutBeforeReady, promise);
|
|
96
97
|
return promise;
|
|
97
98
|
}
|
|
98
|
-
/** Returns true if at least one split was updated */
|
|
99
|
-
function isThereUpdate(flagsChange) {
|
|
100
|
-
var added = flagsChange[1], removed = flagsChange[2];
|
|
101
|
-
// There is at least one added or modified feature flag
|
|
102
|
-
if (added && added.some(function (update) { return update; }))
|
|
103
|
-
return true;
|
|
104
|
-
// There is at least one removed feature flag
|
|
105
|
-
if (removed && removed.some(function (update) { return update; }))
|
|
106
|
-
return true;
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
99
|
/**
|
|
110
100
|
* SplitChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch splits or synchronize them with the storage.
|
|
111
101
|
* Returned promise will not be rejected.
|
|
@@ -127,21 +117,17 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
|
|
|
127
117
|
.then(function (splitChanges) {
|
|
128
118
|
startingUp = false;
|
|
129
119
|
var mutation = computeSplitsMutation(splitChanges.splits, splitFiltersValidation);
|
|
130
|
-
log.debug(
|
|
131
|
-
log.debug(SYNC_SPLITS_REMOVED, [mutation.removed.length]);
|
|
132
|
-
log.debug(SYNC_SPLITS_SEGMENTS, [mutation.segments.length]);
|
|
120
|
+
log.debug(SYNC_SPLITS_UPDATE, [mutation.added.length, mutation.removed.length, mutation.segments.length]);
|
|
133
121
|
// Write into storage
|
|
134
122
|
// @TODO call `setChangeNumber` only if the other storage operations have succeeded, in order to keep storage consistency
|
|
135
123
|
return Promise.all([
|
|
136
|
-
|
|
137
|
-
splits.setChangeNumber(splitChanges.till),
|
|
138
|
-
splits.addSplits(mutation.added),
|
|
139
|
-
splits.removeSplits(mutation.removed),
|
|
124
|
+
splits.update(mutation.added, mutation.removed, splitChanges.till),
|
|
140
125
|
segments.registerSegments(mutation.segments)
|
|
141
|
-
]).then(function (
|
|
126
|
+
]).then(function (_a) {
|
|
127
|
+
var isThereUpdate = _a[0];
|
|
142
128
|
if (splitsEventEmitter) {
|
|
143
129
|
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
144
|
-
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate
|
|
130
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate && (isClientSide || checkAllSegmentsExist(segments))))
|
|
145
131
|
.catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
146
132
|
.then(function (emitSplitsArrivedEvent) {
|
|
147
133
|
// emit SDK events
|
|
@@ -19,8 +19,9 @@ export function fromImpressionsCollector(sendLabels, data) {
|
|
|
19
19
|
m: entry.time,
|
|
20
20
|
c: entry.changeNumber,
|
|
21
21
|
r: sendLabels ? entry.label : undefined,
|
|
22
|
-
b: entry.bucketingKey
|
|
23
|
-
pt: entry.pt
|
|
22
|
+
b: entry.bucketingKey,
|
|
23
|
+
pt: entry.pt,
|
|
24
|
+
properties: entry.properties // Properties
|
|
24
25
|
};
|
|
25
26
|
return keyImpression;
|
|
26
27
|
})
|
|
@@ -9,6 +9,9 @@ import { truncateTimeFrame } from '../../utils/time';
|
|
|
9
9
|
export function strategyOptimizedFactory(impressionsObserver, impressionCounts) {
|
|
10
10
|
return {
|
|
11
11
|
process: function (impression) {
|
|
12
|
+
// DEBUG mode without previous time, for impressions with properties
|
|
13
|
+
if (impression.properties)
|
|
14
|
+
return true;
|
|
12
15
|
impression.pt = impressionsObserver.testAndSet(impression);
|
|
13
16
|
var now = Date.now();
|
|
14
17
|
// Increments impression counter per featureName
|
|
@@ -57,3 +57,13 @@ export function validateEventProperties(log, maybeProperties, method) {
|
|
|
57
57
|
}
|
|
58
58
|
return output;
|
|
59
59
|
}
|
|
60
|
+
export function validateEvaluationOptions(log, maybeOptions, method) {
|
|
61
|
+
if (isObject(maybeOptions)) {
|
|
62
|
+
var properties = validateEventProperties(log, maybeOptions.properties, method).properties;
|
|
63
|
+
return properties && Object.keys(properties).length > 0 ? { properties: properties } : undefined;
|
|
64
|
+
}
|
|
65
|
+
else if (maybeOptions) {
|
|
66
|
+
log.error(ERROR_NOT_PLAIN_OBJECT, [method, 'evaluation options']);
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
@@ -11,3 +11,4 @@ export { validateIfNotDestroyed, validateIfOperational } from './isOperational';
|
|
|
11
11
|
export { validateSplitExistence } from './splitExistence';
|
|
12
12
|
export { validateTrafficTypeExistence } from './trafficTypeExistence';
|
|
13
13
|
export { validatePreloadedData } from './preloadedData';
|
|
14
|
+
export { validateEvaluationOptions } from './eventProperties';
|