@splitsoftware/splitio-commons 1.10.0 → 1.10.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 +9 -0
- package/cjs/evaluator/index.js +18 -1
- package/cjs/logger/constants.js +7 -3
- package/cjs/logger/messages/error.js +2 -0
- package/cjs/logger/messages/warn.js +4 -2
- package/cjs/sdkClient/client.js +33 -0
- package/cjs/sdkClient/clientAttributesDecoration.js +20 -0
- package/cjs/sdkClient/clientCS.js +4 -0
- package/cjs/sdkClient/clientInputValidation.js +52 -3
- package/cjs/sdkManager/index.js +1 -0
- package/cjs/services/splitApi.js +7 -1
- package/cjs/storages/KeyBuilder.js +3 -0
- package/cjs/storages/KeyBuilderSS.js +4 -0
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +63 -27
- package/cjs/storages/inLocalStorage/index.js +2 -2
- package/cjs/storages/inMemory/InMemoryStorage.js +2 -2
- package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -3
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +47 -2
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +11 -0
- package/cjs/storages/pluggable/SplitsCachePluggable.js +11 -0
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +39 -5
- package/cjs/sync/submitters/telemetrySubmitter.js +15 -1
- package/cjs/utils/constants/index.js +6 -2
- package/cjs/utils/lang/sets.js +9 -1
- package/cjs/utils/settingsValidation/index.js +1 -1
- package/cjs/utils/settingsValidation/splitFilters.js +78 -15
- package/esm/evaluator/index.js +16 -0
- package/esm/logger/constants.js +5 -1
- package/esm/logger/messages/error.js +2 -0
- package/esm/logger/messages/warn.js +4 -2
- package/esm/sdkClient/client.js +35 -2
- package/esm/sdkClient/clientAttributesDecoration.js +20 -0
- package/esm/sdkClient/clientCS.js +4 -0
- package/esm/sdkClient/clientInputValidation.js +52 -3
- package/esm/sdkManager/index.js +1 -0
- package/esm/services/splitApi.js +7 -1
- package/esm/storages/KeyBuilder.js +3 -0
- package/esm/storages/KeyBuilderSS.js +4 -0
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +63 -27
- package/esm/storages/inLocalStorage/index.js +2 -2
- package/esm/storages/inMemory/InMemoryStorage.js +2 -2
- package/esm/storages/inMemory/InMemoryStorageCS.js +3 -3
- package/esm/storages/inMemory/SplitsCacheInMemory.js +47 -2
- package/esm/storages/inRedis/SplitsCacheInRedis.js +11 -0
- package/esm/storages/pluggable/SplitsCachePluggable.js +11 -0
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/esm/sync/polling/updaters/splitChangesUpdater.js +39 -5
- package/esm/sync/submitters/telemetrySubmitter.js +15 -1
- package/esm/utils/constants/index.js +4 -0
- package/esm/utils/lang/sets.js +7 -0
- package/esm/utils/settingsValidation/index.js +1 -1
- package/esm/utils/settingsValidation/splitFilters.js +72 -10
- package/package.json +2 -2
- package/src/dtos/types.ts +3 -2
- package/src/evaluator/index.ts +24 -0
- package/src/logger/constants.ts +5 -1
- package/src/logger/messages/error.ts +2 -0
- package/src/logger/messages/warn.ts +4 -2
- package/src/sdkClient/client.ts +42 -2
- package/src/sdkClient/clientAttributesDecoration.ts +24 -0
- package/src/sdkClient/clientCS.ts +4 -0
- package/src/sdkClient/clientInputValidation.ts +56 -3
- package/src/sdkManager/index.ts +1 -0
- package/src/services/splitApi.ts +6 -1
- package/src/storages/AbstractSplitsCacheAsync.ts +2 -0
- package/src/storages/AbstractSplitsCacheSync.ts +3 -0
- package/src/storages/KeyBuilder.ts +4 -0
- package/src/storages/KeyBuilderSS.ts +4 -0
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +74 -28
- package/src/storages/inLocalStorage/index.ts +2 -2
- package/src/storages/inMemory/InMemoryStorage.ts +2 -2
- package/src/storages/inMemory/InMemoryStorageCS.ts +3 -3
- package/src/storages/inMemory/SplitsCacheInMemory.ts +50 -1
- package/src/storages/inRedis/SplitsCacheInRedis.ts +12 -0
- package/src/storages/pluggable/SplitsCachePluggable.ts +12 -0
- package/src/storages/types.ts +7 -3
- package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -0
- package/src/sync/polling/updaters/splitChangesUpdater.ts +40 -6
- package/src/sync/submitters/telemetrySubmitter.ts +19 -2
- package/src/sync/submitters/types.ts +7 -1
- package/src/types.ts +115 -2
- package/src/utils/constants/index.ts +4 -0
- package/src/utils/lang/sets.ts +8 -0
- package/src/utils/settingsValidation/index.ts +1 -1
- package/src/utils/settingsValidation/splitFilters.ts +78 -10
- package/types/dtos/types.d.ts +1 -0
- package/types/evaluator/index.d.ts +1 -0
- package/types/logger/constants.d.ts +5 -1
- package/types/myLogger.d.ts +5 -0
- package/types/sdkClient/clientAttributesDecoration.d.ts +4 -0
- package/types/sdkClient/types.d.ts +18 -0
- package/types/storages/AbstractSplitsCacheAsync.d.ts +2 -0
- package/types/storages/AbstractSplitsCacheSync.d.ts +2 -0
- package/types/storages/KeyBuilder.d.ts +1 -0
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +6 -1
- package/types/storages/inMemory/CountsCacheInMemory.d.ts +20 -0
- package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +20 -0
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +9 -1
- package/types/storages/inRedis/CountsCacheInRedis.d.ts +9 -0
- package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +9 -0
- package/types/storages/inRedis/SplitsCacheInRedis.d.ts +8 -0
- package/types/storages/metadataBuilder.d.ts +3 -0
- package/types/storages/pluggable/SplitsCachePluggable.d.ts +8 -0
- package/types/storages/types.d.ts +4 -0
- package/types/sync/offline/LocalhostFromFile.d.ts +2 -0
- package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +2 -0
- package/types/sync/offline/updaters/splitChangesUpdater.d.ts +0 -0
- package/types/sync/polling/updaters/splitChangesUpdater.d.ts +3 -3
- package/types/sync/submitters/eventsSyncTask.d.ts +8 -0
- package/types/sync/submitters/impressionCountsSubmitterInRedis.d.ts +5 -0
- package/types/sync/submitters/impressionCountsSyncTask.d.ts +13 -0
- package/types/sync/submitters/impressionsSyncTask.d.ts +14 -0
- package/types/sync/submitters/metricsSyncTask.d.ts +12 -0
- package/types/sync/submitters/submitterSyncTask.d.ts +10 -0
- package/types/sync/submitters/types.d.ts +7 -1
- package/types/sync/submitters/uniqueKeysSubmitterInRedis.d.ts +5 -0
- package/types/sync/syncTaskComposite.d.ts +5 -0
- package/types/trackers/filter/bloomFilter.d.ts +10 -0
- package/types/trackers/filter/dictionaryFilter.d.ts +8 -0
- package/types/trackers/filter/types.d.ts +5 -0
- package/types/types.d.ts +114 -1
- package/types/utils/constants/index.d.ts +4 -0
- package/types/utils/lang/sets.d.ts +1 -0
- package/types/utils/settingsValidation/splitFilters.d.ts +2 -2
- package/types/utils/timeTracker/index.d.ts +70 -0
- package/types/sdkClient/identity.d.ts +0 -6
- package/types/utils/inputValidation/sdkKey.d.ts +0 -7
- /package/types/storages/inMemory/{UniqueKeysCacheInMemory.d.ts → uniqueKeysCacheInMemory.d.ts} +0 -0
- /package/types/storages/inMemory/{UniqueKeysCacheInMemoryCS.d.ts → uniqueKeysCacheInMemoryCS.d.ts} +0 -0
- /package/types/storages/inRedis/{UniqueKeysCacheInRedis.d.ts → uniqueKeysCacheInRedis.d.ts} +0 -0
|
@@ -11,6 +11,10 @@ export function clientAttributesDecoration(log, client) {
|
|
|
11
11
|
var clientGetTreatmentWithConfig = client.getTreatmentWithConfig;
|
|
12
12
|
var clientGetTreatments = client.getTreatments;
|
|
13
13
|
var clientGetTreatmentsWithConfig = client.getTreatmentsWithConfig;
|
|
14
|
+
var clientGetTreatmentsByFlagSets = client.getTreatmentsByFlagSets;
|
|
15
|
+
var clientGetTreatmentsWithConfigByFlagSets = client.getTreatmentsWithConfigByFlagSets;
|
|
16
|
+
var clientGetTreatmentsByFlagSet = client.getTreatmentsByFlagSet;
|
|
17
|
+
var clientGetTreatmentsWithConfigByFlagSet = client.getTreatmentsWithConfigByFlagSet;
|
|
14
18
|
var clientTrack = client.track;
|
|
15
19
|
function getTreatment(maybeKey, maybeFeatureFlagName, maybeAttributes) {
|
|
16
20
|
return clientGetTreatment(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes));
|
|
@@ -24,6 +28,18 @@ export function clientAttributesDecoration(log, client) {
|
|
|
24
28
|
function getTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, maybeAttributes) {
|
|
25
29
|
return clientGetTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes));
|
|
26
30
|
}
|
|
31
|
+
function getTreatmentsByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
|
|
32
|
+
return clientGetTreatmentsByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes));
|
|
33
|
+
}
|
|
34
|
+
function getTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
|
|
35
|
+
return clientGetTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes));
|
|
36
|
+
}
|
|
37
|
+
function getTreatmentsByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
|
|
38
|
+
return clientGetTreatmentsByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes));
|
|
39
|
+
}
|
|
40
|
+
function getTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
|
|
41
|
+
return clientGetTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes));
|
|
42
|
+
}
|
|
27
43
|
function track(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties) {
|
|
28
44
|
return clientTrack(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties);
|
|
29
45
|
}
|
|
@@ -39,6 +55,10 @@ export function clientAttributesDecoration(log, client) {
|
|
|
39
55
|
getTreatmentWithConfig: getTreatmentWithConfig,
|
|
40
56
|
getTreatments: getTreatments,
|
|
41
57
|
getTreatmentsWithConfig: getTreatmentsWithConfig,
|
|
58
|
+
getTreatmentsByFlagSets: getTreatmentsByFlagSets,
|
|
59
|
+
getTreatmentsWithConfigByFlagSets: getTreatmentsWithConfigByFlagSets,
|
|
60
|
+
getTreatmentsByFlagSet: getTreatmentsByFlagSet,
|
|
61
|
+
getTreatmentsWithConfigByFlagSet: getTreatmentsWithConfigByFlagSet,
|
|
42
62
|
track: track,
|
|
43
63
|
/**
|
|
44
64
|
* Add an attribute to client's in memory attributes storage
|
|
@@ -15,6 +15,10 @@ export function clientCSDecorator(log, client, key, trafficType) {
|
|
|
15
15
|
getTreatmentWithConfig: clientCS.getTreatmentWithConfig.bind(clientCS, key),
|
|
16
16
|
getTreatments: clientCS.getTreatments.bind(clientCS, key),
|
|
17
17
|
getTreatmentsWithConfig: clientCS.getTreatmentsWithConfig.bind(clientCS, key),
|
|
18
|
+
getTreatmentsByFlagSets: clientCS.getTreatmentsByFlagSets.bind(clientCS, key),
|
|
19
|
+
getTreatmentsWithConfigByFlagSets: clientCS.getTreatmentsWithConfigByFlagSets.bind(clientCS, key),
|
|
20
|
+
getTreatmentsByFlagSet: clientCS.getTreatmentsByFlagSet.bind(clientCS, key),
|
|
21
|
+
getTreatmentsWithConfigByFlagSet: clientCS.getTreatmentsWithConfigByFlagSet.bind(clientCS, key),
|
|
18
22
|
// Key is bound to the `track` method. Same thing happens with trafficType but only if provided
|
|
19
23
|
track: trafficType ? clientCS.track.bind(clientCS, key, trafficType) : clientCS.track.bind(clientCS, key),
|
|
20
24
|
// Not part of the public API. These properties are used to support other modules (e.g., Split Suite)
|
|
@@ -3,6 +3,7 @@ import { validateAttributes, validateEvent, validateEventValue, validateEventPro
|
|
|
3
3
|
import { startsWith } from '../utils/lang';
|
|
4
4
|
import { CONTROL, CONTROL_WITH_CONFIG } from '../utils/constants';
|
|
5
5
|
import { isStorageSync } from '../trackers/impressionObserver/utils';
|
|
6
|
+
import { flagSetsAreValid } from '../utils/settingsValidation/splitFilters';
|
|
6
7
|
/**
|
|
7
8
|
* Decorator that validates the input before actually executing the client methods.
|
|
8
9
|
* We should "guard" the client here, while not polluting the "real" implementation of those methods.
|
|
@@ -13,18 +14,26 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
13
14
|
/**
|
|
14
15
|
* Avoid repeating this validations code
|
|
15
16
|
*/
|
|
16
|
-
function validateEvaluationParams(maybeKey, maybeFeatureFlagNameOrNames, maybeAttributes, methodName) {
|
|
17
|
+
function validateEvaluationParams(maybeKey, maybeFeatureFlagNameOrNames, maybeAttributes, methodName, maybeFlagSetNameOrNames) {
|
|
17
18
|
var multi = startsWith(methodName, 'getTreatments');
|
|
18
19
|
var key = validateKey(log, maybeKey, methodName);
|
|
19
|
-
var splitOrSplits =
|
|
20
|
+
var splitOrSplits = false;
|
|
21
|
+
var flagSetOrFlagSets = [];
|
|
22
|
+
if (maybeFeatureFlagNameOrNames) {
|
|
23
|
+
splitOrSplits = multi ? validateSplits(log, maybeFeatureFlagNameOrNames, methodName) : validateSplit(log, maybeFeatureFlagNameOrNames, methodName);
|
|
24
|
+
}
|
|
20
25
|
var attributes = validateAttributes(log, maybeAttributes, methodName);
|
|
21
26
|
var isNotDestroyed = validateIfNotDestroyed(log, readinessManager, methodName);
|
|
27
|
+
if (maybeFlagSetNameOrNames) {
|
|
28
|
+
flagSetOrFlagSets = flagSetsAreValid(log, methodName, maybeFlagSetNameOrNames, settings.sync.__splitFiltersValidation.groupedFilters.bySet);
|
|
29
|
+
}
|
|
22
30
|
validateIfOperational(log, readinessManager, methodName, splitOrSplits);
|
|
23
|
-
var valid = isNotDestroyed && key && splitOrSplits && attributes !== false;
|
|
31
|
+
var valid = isNotDestroyed && key && (splitOrSplits || flagSetOrFlagSets.length > 0) && attributes !== false;
|
|
24
32
|
return {
|
|
25
33
|
valid: valid,
|
|
26
34
|
key: key,
|
|
27
35
|
splitOrSplits: splitOrSplits,
|
|
36
|
+
flagSetOrFlagSets: flagSetOrFlagSets,
|
|
28
37
|
attributes: attributes
|
|
29
38
|
};
|
|
30
39
|
}
|
|
@@ -73,6 +82,42 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
73
82
|
return wrapResult(res_2);
|
|
74
83
|
}
|
|
75
84
|
}
|
|
85
|
+
function getTreatmentsByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
|
|
86
|
+
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, 'getTreatmentsByFlagSets', maybeFlagSets);
|
|
87
|
+
if (params.valid) {
|
|
88
|
+
return client.getTreatmentsByFlagSets(params.key, params.flagSetOrFlagSets, params.attributes);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
return wrapResult({});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function getTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
|
|
95
|
+
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, 'getTreatmentsWithConfigByFlagSets', maybeFlagSets);
|
|
96
|
+
if (params.valid) {
|
|
97
|
+
return client.getTreatmentsWithConfigByFlagSets(params.key, params.flagSetOrFlagSets, params.attributes);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
return wrapResult({});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function getTreatmentsByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
|
|
104
|
+
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, 'getTreatmentsByFlagSet', [maybeFlagSet]);
|
|
105
|
+
if (params.valid) {
|
|
106
|
+
return client.getTreatmentsByFlagSet(params.key, params.flagSetOrFlagSets[0], params.attributes);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
return wrapResult({});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function getTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
|
|
113
|
+
var params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, 'getTreatmentsWithConfigByFlagSet', [maybeFlagSet]);
|
|
114
|
+
if (params.valid) {
|
|
115
|
+
return client.getTreatmentsWithConfigByFlagSet(params.key, params.flagSetOrFlagSets[0], params.attributes);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
return wrapResult({});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
76
121
|
function track(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties) {
|
|
77
122
|
var key = validateKey(log, maybeKey, 'track');
|
|
78
123
|
var tt = validateTrafficType(log, maybeTT, 'track');
|
|
@@ -92,6 +137,10 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
92
137
|
getTreatmentWithConfig: getTreatmentWithConfig,
|
|
93
138
|
getTreatments: getTreatments,
|
|
94
139
|
getTreatmentsWithConfig: getTreatmentsWithConfig,
|
|
140
|
+
getTreatmentsByFlagSets: getTreatmentsByFlagSets,
|
|
141
|
+
getTreatmentsWithConfigByFlagSets: getTreatmentsWithConfigByFlagSets,
|
|
142
|
+
getTreatmentsByFlagSet: getTreatmentsByFlagSet,
|
|
143
|
+
getTreatmentsWithConfigByFlagSet: getTreatmentsWithConfigByFlagSet,
|
|
95
144
|
track: track
|
|
96
145
|
};
|
|
97
146
|
}
|
package/esm/sdkManager/index.js
CHANGED
|
@@ -25,6 +25,7 @@ function objectToView(splitObject) {
|
|
|
25
25
|
changeNumber: splitObject.changeNumber || 0,
|
|
26
26
|
treatments: collectTreatments(splitObject),
|
|
27
27
|
configs: splitObject.configurations || {},
|
|
28
|
+
sets: splitObject.sets || [],
|
|
28
29
|
defaultTreatment: splitObject.defaultTreatment
|
|
29
30
|
};
|
|
30
31
|
}
|
package/esm/services/splitApi.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { splitHttpClientFactory } from './splitHttpClient';
|
|
2
2
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
3
3
|
import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT } from '../utils/constants';
|
|
4
|
+
import { ERROR_TOO_MANY_SETS } from '../logger/constants';
|
|
4
5
|
var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
|
|
5
6
|
function userKeyToQueryParam(userKey) {
|
|
6
7
|
return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
|
|
@@ -37,7 +38,12 @@ export function splitApiFactory(settings, platform, telemetryTracker) {
|
|
|
37
38
|
},
|
|
38
39
|
fetchSplitChanges: function (since, noCache, till) {
|
|
39
40
|
var url = urls.sdk + "/splitChanges?since=" + since + (till ? '&till=' + till : '') + (filterQueryString || '');
|
|
40
|
-
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SPLITS))
|
|
41
|
+
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SPLITS))
|
|
42
|
+
.catch(function (err) {
|
|
43
|
+
if (err.statusCode === 414)
|
|
44
|
+
settings.log.error(ERROR_TOO_MANY_SETS);
|
|
45
|
+
throw err;
|
|
46
|
+
});
|
|
41
47
|
},
|
|
42
48
|
fetchSegmentChanges: function (since, segmentName, noCache, till) {
|
|
43
49
|
var url = urls.sdk + "/segmentChanges/" + segmentName + "?since=" + since + (till ? '&till=' + till : '');
|
|
@@ -12,6 +12,9 @@ var KeyBuilder = /** @class */ (function () {
|
|
|
12
12
|
KeyBuilder.prototype.buildTrafficTypeKey = function (trafficType) {
|
|
13
13
|
return this.prefix + ".trafficType." + trafficType;
|
|
14
14
|
};
|
|
15
|
+
KeyBuilder.prototype.buildFlagSetKey = function (flagSet) {
|
|
16
|
+
return this.prefix + ".flagset." + flagSet;
|
|
17
|
+
};
|
|
15
18
|
KeyBuilder.prototype.buildSplitKey = function (splitName) {
|
|
16
19
|
return this.prefix + ".split." + splitName;
|
|
17
20
|
};
|
|
@@ -5,6 +5,10 @@ export var METHOD_NAMES = {
|
|
|
5
5
|
ts: 'treatments',
|
|
6
6
|
tc: 'treatmentWithConfig',
|
|
7
7
|
tcs: 'treatmentsWithConfig',
|
|
8
|
+
tf: 'treatmentsByFlagSet',
|
|
9
|
+
tfs: 'treatmentsByFlagSets',
|
|
10
|
+
tcf: 'treatmentsWithConfigByFlagSet',
|
|
11
|
+
tcfs: 'treatmentsWithConfigByFlagSets',
|
|
8
12
|
tr: 'track'
|
|
9
13
|
};
|
|
10
14
|
var KeyBuilderSS = /** @class */ (function (_super) {
|
|
@@ -2,6 +2,7 @@ import { __extends } from "tslib";
|
|
|
2
2
|
import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
|
|
3
3
|
import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
|
|
4
4
|
import { LOG_PREFIX } from './constants';
|
|
5
|
+
import { _Set, returnSetsUnion, setToArray } from '../../utils/lang/sets';
|
|
5
6
|
/**
|
|
6
7
|
* ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
|
|
7
8
|
*/
|
|
@@ -13,12 +14,12 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
13
14
|
* @param {ISplitFiltersValidation} splitFiltersValidation
|
|
14
15
|
*/
|
|
15
16
|
function SplitsCacheInLocal(log, keys, expirationTimestamp, splitFiltersValidation) {
|
|
16
|
-
if (splitFiltersValidation === void 0) { splitFiltersValidation = { queryString: null, groupedFilters: { byName: [], byPrefix: [] }, validFilters: [] }; }
|
|
17
|
+
if (splitFiltersValidation === void 0) { splitFiltersValidation = { queryString: null, groupedFilters: { bySet: [], byName: [], byPrefix: [] }, validFilters: [] }; }
|
|
17
18
|
var _this = _super.call(this) || this;
|
|
18
19
|
_this.log = log;
|
|
19
|
-
_this.cacheReadyButNeedsToFlush = false;
|
|
20
20
|
_this.keys = keys;
|
|
21
21
|
_this.splitFiltersValidation = splitFiltersValidation;
|
|
22
|
+
_this.flagSetsFilter = _this.splitFiltersValidation.groupedFilters.bySet;
|
|
22
23
|
_this._checkExpiration(expirationTimestamp);
|
|
23
24
|
_this._checkFilterQuery();
|
|
24
25
|
return _this;
|
|
@@ -91,6 +92,9 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
91
92
|
localStorage.setItem(splitKey, JSON.stringify(split));
|
|
92
93
|
this._incrementCounts(split);
|
|
93
94
|
this._decrementCounts(previousSplit);
|
|
95
|
+
if (previousSplit)
|
|
96
|
+
this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
97
|
+
this.addToFlagSets(split);
|
|
94
98
|
return true;
|
|
95
99
|
}
|
|
96
100
|
catch (e) {
|
|
@@ -103,6 +107,8 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
103
107
|
var split = this.getSplit(name);
|
|
104
108
|
localStorage.removeItem(this.keys.buildSplitKey(name));
|
|
105
109
|
this._decrementCounts(split);
|
|
110
|
+
if (split)
|
|
111
|
+
this.removeFromFlagSets(split.name, split.sets);
|
|
106
112
|
return true;
|
|
107
113
|
}
|
|
108
114
|
catch (e) {
|
|
@@ -115,11 +121,6 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
115
121
|
return item && JSON.parse(item);
|
|
116
122
|
};
|
|
117
123
|
SplitsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
118
|
-
// when cache is ready but using a new split query, we must clear all split data
|
|
119
|
-
if (this.cacheReadyButNeedsToFlush) {
|
|
120
|
-
this.clear();
|
|
121
|
-
this.cacheReadyButNeedsToFlush = false;
|
|
122
|
-
}
|
|
123
124
|
// when using a new split query, we must update it at the store
|
|
124
125
|
if (this.updateNewFilter) {
|
|
125
126
|
this.log.info(LOG_PREFIX + 'Split filter query was modified. Updating cache.');
|
|
@@ -192,7 +193,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
192
193
|
* @override
|
|
193
194
|
*/
|
|
194
195
|
SplitsCacheInLocal.prototype.checkCache = function () {
|
|
195
|
-
return this.getChangeNumber() > -1
|
|
196
|
+
return this.getChangeNumber() > -1;
|
|
196
197
|
};
|
|
197
198
|
/**
|
|
198
199
|
* Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
|
|
@@ -208,31 +209,16 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
208
209
|
}
|
|
209
210
|
};
|
|
210
211
|
SplitsCacheInLocal.prototype._checkFilterQuery = function () {
|
|
211
|
-
var
|
|
212
|
-
var _a = this.splitFiltersValidation, queryString = _a.queryString, groupedFilters = _a.groupedFilters;
|
|
212
|
+
var queryString = this.splitFiltersValidation.queryString;
|
|
213
213
|
var queryKey = this.keys.buildSplitsFilterQueryKey();
|
|
214
214
|
var currentQueryString = localStorage.getItem(queryKey);
|
|
215
215
|
if (currentQueryString !== queryString) {
|
|
216
216
|
try {
|
|
217
217
|
// mark cache to update the new query filter on first successful splits fetch
|
|
218
218
|
this.updateNewFilter = true;
|
|
219
|
-
// if
|
|
220
|
-
if (this.checkCache())
|
|
221
|
-
|
|
222
|
-
localStorage.setItem(this.keys.buildSplitsTillKey(), '-1');
|
|
223
|
-
// * remove from cache splits that doesn't match with the new filters
|
|
224
|
-
this.getSplitNames().forEach(function (splitName) {
|
|
225
|
-
if (queryString && (
|
|
226
|
-
// @TODO consider redefining `groupedFilters` to expose a method like `groupedFilters::filter(splitName): boolean`
|
|
227
|
-
groupedFilters.byName.indexOf(splitName) > -1 ||
|
|
228
|
-
groupedFilters.byPrefix.some(function (prefix) { return splitName.startsWith(prefix + '__'); }))) {
|
|
229
|
-
// * set `cacheReadyButNeedsToFlush` so that `checkCache` returns true (the storage is ready to be used) and the data is cleared before updating on first successful splits fetch
|
|
230
|
-
_this.cacheReadyButNeedsToFlush = true;
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
_this.removeSplit(splitName);
|
|
234
|
-
});
|
|
235
|
-
}
|
|
219
|
+
// if there is cache, clear it
|
|
220
|
+
if (this.checkCache())
|
|
221
|
+
this.clear();
|
|
236
222
|
}
|
|
237
223
|
catch (e) {
|
|
238
224
|
this.log.error(LOG_PREFIX + e);
|
|
@@ -240,6 +226,56 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
240
226
|
}
|
|
241
227
|
// if the filter didn't change, nothing is done
|
|
242
228
|
};
|
|
229
|
+
SplitsCacheInLocal.prototype.getNamesByFlagSets = function (flagSets) {
|
|
230
|
+
var _this = this;
|
|
231
|
+
var toReturn = new _Set([]);
|
|
232
|
+
flagSets.forEach(function (flagSet) {
|
|
233
|
+
var flagSetKey = _this.keys.buildFlagSetKey(flagSet);
|
|
234
|
+
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
235
|
+
if (flagSetFromLocalStorage) {
|
|
236
|
+
var flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
|
|
237
|
+
toReturn = returnSetsUnion(toReturn, flagSetCache);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
return toReturn;
|
|
241
|
+
};
|
|
242
|
+
SplitsCacheInLocal.prototype.addToFlagSets = function (featureFlag) {
|
|
243
|
+
var _this = this;
|
|
244
|
+
if (!featureFlag.sets)
|
|
245
|
+
return;
|
|
246
|
+
featureFlag.sets.forEach(function (featureFlagSet) {
|
|
247
|
+
if (_this.flagSetsFilter.length > 0 && !_this.flagSetsFilter.some(function (filterFlagSet) { return filterFlagSet === featureFlagSet; }))
|
|
248
|
+
return;
|
|
249
|
+
var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
|
|
250
|
+
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
251
|
+
if (!flagSetFromLocalStorage)
|
|
252
|
+
flagSetFromLocalStorage = '[]';
|
|
253
|
+
var flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
|
|
254
|
+
flagSetCache.add(featureFlag.name);
|
|
255
|
+
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
|
|
256
|
+
});
|
|
257
|
+
};
|
|
258
|
+
SplitsCacheInLocal.prototype.removeFromFlagSets = function (featureFlagName, flagSets) {
|
|
259
|
+
var _this = this;
|
|
260
|
+
if (!flagSets)
|
|
261
|
+
return;
|
|
262
|
+
flagSets.forEach(function (flagSet) {
|
|
263
|
+
_this.removeNames(flagSet, featureFlagName);
|
|
264
|
+
});
|
|
265
|
+
};
|
|
266
|
+
SplitsCacheInLocal.prototype.removeNames = function (flagSetName, featureFlagName) {
|
|
267
|
+
var flagSetKey = this.keys.buildFlagSetKey(flagSetName);
|
|
268
|
+
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
269
|
+
if (!flagSetFromLocalStorage)
|
|
270
|
+
return;
|
|
271
|
+
var flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
|
|
272
|
+
flagSetCache.delete(featureFlagName);
|
|
273
|
+
if (flagSetCache.size === 0) {
|
|
274
|
+
localStorage.removeItem(flagSetKey);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
|
|
278
|
+
};
|
|
243
279
|
return SplitsCacheInLocal;
|
|
244
280
|
}(AbstractSplitsCacheSync));
|
|
245
281
|
export { SplitsCacheInLocal };
|
|
@@ -43,7 +43,7 @@ export function InLocalStorage(options) {
|
|
|
43
43
|
uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
|
|
44
44
|
destroy: function () {
|
|
45
45
|
var _a;
|
|
46
|
-
this.splits = new SplitsCacheInMemory();
|
|
46
|
+
this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
47
47
|
this.segments = new MySegmentsCacheInMemory();
|
|
48
48
|
this.impressions.clear();
|
|
49
49
|
this.impressionCounts && this.impressionCounts.clear();
|
|
@@ -61,7 +61,7 @@ export function InLocalStorage(options) {
|
|
|
61
61
|
events: this.events,
|
|
62
62
|
telemetry: this.telemetry,
|
|
63
63
|
destroy: function () {
|
|
64
|
-
this.splits = new SplitsCacheInMemory();
|
|
64
|
+
this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
65
65
|
this.segments = new MySegmentsCacheInMemory();
|
|
66
66
|
}
|
|
67
67
|
};
|
|
@@ -12,8 +12,8 @@ import { UniqueKeysCacheInMemory } from './UniqueKeysCacheInMemory';
|
|
|
12
12
|
* @param params parameters required by EventsCacheSync
|
|
13
13
|
*/
|
|
14
14
|
export function InMemoryStorageFactory(params) {
|
|
15
|
-
var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize,
|
|
16
|
-
var splits = new SplitsCacheInMemory();
|
|
15
|
+
var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, _c = _a.sync, impressionsMode = _c.impressionsMode, __splitFiltersValidation = _c.__splitFiltersValidation;
|
|
16
|
+
var splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
17
17
|
var segments = new SegmentsCacheInMemory();
|
|
18
18
|
var storage = {
|
|
19
19
|
splits: splits,
|
|
@@ -12,8 +12,8 @@ import { UniqueKeysCacheInMemoryCS } from './UniqueKeysCacheInMemoryCS';
|
|
|
12
12
|
* @param params parameters required by EventsCacheSync
|
|
13
13
|
*/
|
|
14
14
|
export function InMemoryStorageCSFactory(params) {
|
|
15
|
-
var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize,
|
|
16
|
-
var splits = new SplitsCacheInMemory();
|
|
15
|
+
var _a = params.settings, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize, _c = _a.sync, impressionsMode = _c.impressionsMode, __splitFiltersValidation = _c.__splitFiltersValidation;
|
|
16
|
+
var splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
17
17
|
var segments = new MySegmentsCacheInMemory();
|
|
18
18
|
var storage = {
|
|
19
19
|
splits: splits,
|
|
@@ -43,7 +43,7 @@ export function InMemoryStorageCSFactory(params) {
|
|
|
43
43
|
telemetry: this.telemetry,
|
|
44
44
|
// Set a new splits cache to clean it for the client without affecting other clients
|
|
45
45
|
destroy: function () {
|
|
46
|
-
this.splits = new SplitsCacheInMemory();
|
|
46
|
+
this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
47
47
|
this.segments.clear();
|
|
48
48
|
}
|
|
49
49
|
};
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { __extends } from "tslib";
|
|
2
2
|
import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
|
|
3
3
|
import { isFiniteNumber } from '../../utils/lang';
|
|
4
|
+
import { _Set, returnSetsUnion } from '../../utils/lang/sets';
|
|
4
5
|
/**
|
|
5
6
|
* Default ISplitsCacheSync implementation that stores split definitions in memory.
|
|
6
7
|
* Supported by all JS runtimes.
|
|
7
8
|
*/
|
|
8
9
|
var SplitsCacheInMemory = /** @class */ (function (_super) {
|
|
9
10
|
__extends(SplitsCacheInMemory, _super);
|
|
10
|
-
function SplitsCacheInMemory() {
|
|
11
|
-
|
|
11
|
+
function SplitsCacheInMemory(splitFiltersValidation) {
|
|
12
|
+
if (splitFiltersValidation === void 0) { splitFiltersValidation = { queryString: null, groupedFilters: { bySet: [], byName: [], byPrefix: [] }, validFilters: [] }; }
|
|
13
|
+
var _this = _super.call(this) || this;
|
|
12
14
|
_this.splitsCache = {};
|
|
13
15
|
_this.ttCache = {};
|
|
14
16
|
_this.changeNumber = -1;
|
|
15
17
|
_this.splitsWithSegmentsCount = 0;
|
|
18
|
+
_this.flagSetsCache = {};
|
|
19
|
+
_this.flagSetsFilter = splitFiltersValidation.groupedFilters.bySet;
|
|
16
20
|
return _this;
|
|
17
21
|
}
|
|
18
22
|
SplitsCacheInMemory.prototype.clear = function () {
|
|
@@ -28,6 +32,7 @@ var SplitsCacheInMemory = /** @class */ (function (_super) {
|
|
|
28
32
|
this.ttCache[previousTtName]--;
|
|
29
33
|
if (!this.ttCache[previousTtName])
|
|
30
34
|
delete this.ttCache[previousTtName];
|
|
35
|
+
this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
31
36
|
if (usesSegments(previousSplit)) { // Substract from segments count for the previous version of this Split.
|
|
32
37
|
this.splitsWithSegmentsCount--;
|
|
33
38
|
}
|
|
@@ -38,6 +43,7 @@ var SplitsCacheInMemory = /** @class */ (function (_super) {
|
|
|
38
43
|
// Update TT cache
|
|
39
44
|
var ttName = split.trafficTypeName;
|
|
40
45
|
this.ttCache[ttName] = (this.ttCache[ttName] || 0) + 1;
|
|
46
|
+
this.addToFlagSets(split);
|
|
41
47
|
// Add to segments count for the new version of the Split
|
|
42
48
|
if (usesSegments(split))
|
|
43
49
|
this.splitsWithSegmentsCount++;
|
|
@@ -56,6 +62,7 @@ var SplitsCacheInMemory = /** @class */ (function (_super) {
|
|
|
56
62
|
this.ttCache[ttName]--; // Update tt cache
|
|
57
63
|
if (!this.ttCache[ttName])
|
|
58
64
|
delete this.ttCache[ttName];
|
|
65
|
+
this.removeFromFlagSets(split.name, split.sets);
|
|
59
66
|
// Update the segments count.
|
|
60
67
|
if (usesSegments(split))
|
|
61
68
|
this.splitsWithSegmentsCount--;
|
|
@@ -84,6 +91,44 @@ var SplitsCacheInMemory = /** @class */ (function (_super) {
|
|
|
84
91
|
SplitsCacheInMemory.prototype.usesSegments = function () {
|
|
85
92
|
return this.getChangeNumber() === -1 || this.splitsWithSegmentsCount > 0;
|
|
86
93
|
};
|
|
94
|
+
SplitsCacheInMemory.prototype.getNamesByFlagSets = function (flagSets) {
|
|
95
|
+
var _this = this;
|
|
96
|
+
var toReturn = new _Set([]);
|
|
97
|
+
flagSets.forEach(function (flagSet) {
|
|
98
|
+
var featureFlagNames = _this.flagSetsCache[flagSet];
|
|
99
|
+
if (featureFlagNames) {
|
|
100
|
+
toReturn = returnSetsUnion(toReturn, featureFlagNames);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
return toReturn;
|
|
104
|
+
};
|
|
105
|
+
SplitsCacheInMemory.prototype.addToFlagSets = function (featureFlag) {
|
|
106
|
+
var _this = this;
|
|
107
|
+
if (!featureFlag.sets)
|
|
108
|
+
return;
|
|
109
|
+
featureFlag.sets.forEach(function (featureFlagSet) {
|
|
110
|
+
if (_this.flagSetsFilter.length > 0 && !_this.flagSetsFilter.some(function (filterFlagSet) { return filterFlagSet === featureFlagSet; }))
|
|
111
|
+
return;
|
|
112
|
+
if (!_this.flagSetsCache[featureFlagSet])
|
|
113
|
+
_this.flagSetsCache[featureFlagSet] = new _Set([]);
|
|
114
|
+
_this.flagSetsCache[featureFlagSet].add(featureFlag.name);
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
SplitsCacheInMemory.prototype.removeFromFlagSets = function (featureFlagName, flagSets) {
|
|
118
|
+
var _this = this;
|
|
119
|
+
if (!flagSets)
|
|
120
|
+
return;
|
|
121
|
+
flagSets.forEach(function (flagSet) {
|
|
122
|
+
_this.removeNames(flagSet, featureFlagName);
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
SplitsCacheInMemory.prototype.removeNames = function (flagSetName, featureFlagName) {
|
|
126
|
+
if (!this.flagSetsCache[flagSetName])
|
|
127
|
+
return;
|
|
128
|
+
this.flagSetsCache[flagSetName].delete(featureFlagName);
|
|
129
|
+
if (this.flagSetsCache[flagSetName].size === 0)
|
|
130
|
+
delete this.flagSetsCache[flagSetName];
|
|
131
|
+
};
|
|
87
132
|
return SplitsCacheInMemory;
|
|
88
133
|
}(AbstractSplitsCacheSync));
|
|
89
134
|
export { SplitsCacheInMemory };
|
|
@@ -2,6 +2,7 @@ import { __extends } from "tslib";
|
|
|
2
2
|
import { isFiniteNumber, isNaNNumber } from '../../utils/lang';
|
|
3
3
|
import { LOG_PREFIX } from './constants';
|
|
4
4
|
import { AbstractSplitsCacheAsync } from '../AbstractSplitsCacheAsync';
|
|
5
|
+
import { _Set } from '../../utils/lang/sets';
|
|
5
6
|
/**
|
|
6
7
|
* Discard errors for an answer of multiple operations.
|
|
7
8
|
*/
|
|
@@ -168,6 +169,16 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
|
|
|
168
169
|
var _this = this;
|
|
169
170
|
return this.redis.keys(this.keys.searchPatternForSplitKeys()).then(function (listOfKeys) { return listOfKeys.map(_this.keys.extractKey); });
|
|
170
171
|
};
|
|
172
|
+
/**
|
|
173
|
+
* Get list of split names related to a given flag set names list.
|
|
174
|
+
* The returned promise is resolved with the list of split names,
|
|
175
|
+
* or rejected if wrapper operation fails.
|
|
176
|
+
* @todo this is a no-op method to be implemented
|
|
177
|
+
*/
|
|
178
|
+
SplitsCacheInRedis.prototype.getNamesByFlagSets = function () {
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
180
|
+
return new Promise(function (flagSets) { return new _Set([]); });
|
|
181
|
+
};
|
|
171
182
|
/**
|
|
172
183
|
* Check traffic type existence.
|
|
173
184
|
* The returned promise is resolved with a boolean indicating whether the TT exist or not.
|
|
@@ -2,6 +2,7 @@ import { __extends } from "tslib";
|
|
|
2
2
|
import { isFiniteNumber, isNaNNumber } from '../../utils/lang';
|
|
3
3
|
import { LOG_PREFIX } from './constants';
|
|
4
4
|
import { AbstractSplitsCacheAsync } from '../AbstractSplitsCacheAsync';
|
|
5
|
+
import { _Set } from '../../utils/lang/sets';
|
|
5
6
|
/**
|
|
6
7
|
* ISplitsCacheAsync implementation for pluggable storages.
|
|
7
8
|
*/
|
|
@@ -142,6 +143,16 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
|
|
|
142
143
|
var _this = this;
|
|
143
144
|
return this.wrapper.getKeysByPrefix(this.keys.buildSplitKeyPrefix()).then(function (listOfKeys) { return listOfKeys.map(_this.keys.extractKey); });
|
|
144
145
|
};
|
|
146
|
+
/**
|
|
147
|
+
* Get list of split names related to a given flag set names list.
|
|
148
|
+
* The returned promise is resolved with the list of split names,
|
|
149
|
+
* or rejected if wrapper operation fails.
|
|
150
|
+
* @todo this is a no-op method to be implemented
|
|
151
|
+
*/
|
|
152
|
+
SplitsCachePluggable.prototype.getNamesByFlagSets = function () {
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
154
|
+
return new Promise(function (flagSets) { return new _Set([]); });
|
|
155
|
+
};
|
|
145
156
|
/**
|
|
146
157
|
* Check traffic type existence.
|
|
147
158
|
* The returned promise is resolved with a boolean indicating whether the TT exist or not.
|
|
@@ -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.splits, storage.segments, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
|
|
8
|
+
return syncTaskFactory(settings.log, splitChangesUpdaterFactory(settings.log, splitChangesFetcherFactory(fetchSplitChanges), storage.splits, storage.segments, settings.sync.__splitFiltersValidation, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
|
|
9
9
|
}
|
|
@@ -2,6 +2,7 @@ import { _Set, setToArray } from '../../../utils/lang/sets';
|
|
|
2
2
|
import { timeout } from '../../../utils/promise/timeout';
|
|
3
3
|
import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
|
|
4
4
|
import { SYNC_SPLITS_FETCH, SYNC_SPLITS_NEW, SYNC_SPLITS_REMOVED, SYNC_SPLITS_SEGMENTS, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
|
|
5
|
+
import { startsWith } from '../../../utils/lang';
|
|
5
6
|
// Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
|
|
6
7
|
// Returns a promise that could be rejected.
|
|
7
8
|
// @TODO review together with Segments and MySegments storage APIs
|
|
@@ -28,15 +29,34 @@ export function parseSegments(_a) {
|
|
|
28
29
|
}
|
|
29
30
|
return segments;
|
|
30
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* If there are defined filters and one feature flag doesn't match with them, its status is changed to 'ARCHIVE' to avoid storing it
|
|
34
|
+
* If there are set filter defined, names filter is ignored
|
|
35
|
+
*
|
|
36
|
+
* @param featureFlag feature flag to be evaluated
|
|
37
|
+
* @param filters splitFiltersValidation bySet | byName
|
|
38
|
+
*/
|
|
39
|
+
function matchFilters(featureFlag, filters) {
|
|
40
|
+
var _a = filters.groupedFilters, setsFilter = _a.bySet, namesFilter = _a.byName, prefixFilter = _a.byPrefix;
|
|
41
|
+
if (setsFilter.length > 0)
|
|
42
|
+
return featureFlag.sets && featureFlag.sets.some(function (featureFlagSet) { return setsFilter.indexOf(featureFlagSet) > -1; });
|
|
43
|
+
var namesFilterConfigured = namesFilter.length > 0;
|
|
44
|
+
var prefixFilterConfigured = prefixFilter.length > 0;
|
|
45
|
+
if (!namesFilterConfigured && !prefixFilterConfigured)
|
|
46
|
+
return true;
|
|
47
|
+
var matchNames = namesFilterConfigured && namesFilter.indexOf(featureFlag.name) > -1;
|
|
48
|
+
var matchPrefix = prefixFilterConfigured && prefixFilter.some(function (prefix) { return startsWith(featureFlag.name, prefix); });
|
|
49
|
+
return matchNames || matchPrefix;
|
|
50
|
+
}
|
|
31
51
|
/**
|
|
32
52
|
* Given the list of splits from /splitChanges endpoint, it returns the mutations,
|
|
33
53
|
* i.e., an object with added splits, removed splits and used segments.
|
|
34
54
|
* Exported for testing purposes.
|
|
35
55
|
*/
|
|
36
|
-
export function computeSplitsMutation(entries) {
|
|
56
|
+
export function computeSplitsMutation(entries, filters) {
|
|
37
57
|
var segments = new _Set();
|
|
38
58
|
var computed = entries.reduce(function (accum, split) {
|
|
39
|
-
if (split.status === 'ACTIVE') {
|
|
59
|
+
if (split.status === 'ACTIVE' && matchFilters(split, filters)) {
|
|
40
60
|
accum.added.push([split.name, split]);
|
|
41
61
|
parseSegments(split).forEach(function (segmentName) {
|
|
42
62
|
segments.add(segmentName);
|
|
@@ -64,7 +84,7 @@ export function computeSplitsMutation(entries) {
|
|
|
64
84
|
* @param requestTimeoutBeforeReady How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
|
|
65
85
|
* @param retriesOnFailureBeforeReady How many retries on `/splitChanges` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
|
|
66
86
|
*/
|
|
67
|
-
export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
|
|
87
|
+
export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments, splitFiltersValidation, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
|
|
68
88
|
if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
|
|
69
89
|
if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
|
|
70
90
|
var startingUp = true;
|
|
@@ -74,6 +94,17 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
|
|
|
74
94
|
promise = timeout(requestTimeoutBeforeReady, promise);
|
|
75
95
|
return promise;
|
|
76
96
|
}
|
|
97
|
+
/** Returns true if at least one split was updated */
|
|
98
|
+
function update(flagsChange) {
|
|
99
|
+
var added = flagsChange[1], removed = flagsChange[2];
|
|
100
|
+
// There is at least one added or modified feature flag
|
|
101
|
+
if (added && added.some(function (update) { return update; }))
|
|
102
|
+
return true;
|
|
103
|
+
// There is at least one removed feature flag
|
|
104
|
+
if (removed && removed.some(function (update) { return update; }))
|
|
105
|
+
return true;
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
77
108
|
/**
|
|
78
109
|
* SplitChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch splits or synchronize them with the storage.
|
|
79
110
|
* Returned promise will not be rejected.
|
|
@@ -94,7 +125,7 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
|
|
|
94
125
|
splitChangesFetcher(since, noCache, till, _promiseDecorator))
|
|
95
126
|
.then(function (splitChanges) {
|
|
96
127
|
startingUp = false;
|
|
97
|
-
var mutation = computeSplitsMutation(splitChanges.splits);
|
|
128
|
+
var mutation = computeSplitsMutation(splitChanges.splits, splitFiltersValidation);
|
|
98
129
|
log.debug(SYNC_SPLITS_NEW, [mutation.added.length]);
|
|
99
130
|
log.debug(SYNC_SPLITS_REMOVED, [mutation.removed.length]);
|
|
100
131
|
log.debug(SYNC_SPLITS_SEGMENTS, [mutation.segments.length]);
|
|
@@ -106,7 +137,10 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
|
|
|
106
137
|
splits.addSplits(mutation.added),
|
|
107
138
|
splits.removeSplits(mutation.removed),
|
|
108
139
|
segments.registerSegments(mutation.segments)
|
|
109
|
-
]).then(function () {
|
|
140
|
+
]).then(function (flagsChange) {
|
|
141
|
+
var triggerSdkUpdate = update(flagsChange);
|
|
142
|
+
if (!triggerSdkUpdate)
|
|
143
|
+
return true;
|
|
110
144
|
if (splitsEventEmitter) {
|
|
111
145
|
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
112
146
|
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && (isClientSide || checkAllSegmentsExist(segments))))
|