@splitsoftware/splitio-commons 2.2.1-rc.3 → 2.2.1-rc.5
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 +5 -2
- package/README.md +1 -0
- package/cjs/consent/sdkUserConsent.js +5 -3
- package/cjs/evaluator/combiners/and.js +2 -6
- package/cjs/evaluator/combiners/ifelseif.js +6 -6
- package/cjs/evaluator/condition/index.js +6 -5
- package/cjs/evaluator/index.js +7 -7
- package/cjs/evaluator/matchers/index.js +3 -1
- package/cjs/evaluator/matchers/matcherTypes.js +1 -0
- package/cjs/evaluator/matchers/rbsegment.js +56 -0
- package/cjs/evaluator/matchersTransform/index.js +4 -0
- package/cjs/evaluator/parser/index.js +2 -2
- package/cjs/evaluator/value/sanitize.js +1 -0
- package/cjs/listeners/browser.js +2 -5
- package/cjs/logger/constants.js +4 -3
- package/cjs/logger/messages/debug.js +3 -2
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/services/splitApi.js +3 -4
- package/cjs/services/splitHttpClient.js +3 -1
- package/cjs/storages/AbstractSplitsCacheSync.js +5 -2
- package/cjs/storages/KeyBuilder.js +9 -0
- package/cjs/storages/KeyBuilderCS.js +3 -0
- package/cjs/storages/KeyBuilderSS.js +3 -0
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +117 -0
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +9 -14
- package/cjs/storages/inLocalStorage/index.js +5 -1
- package/cjs/storages/inLocalStorage/validateCache.js +2 -1
- package/cjs/storages/inMemory/InMemoryStorage.js +3 -0
- package/cjs/storages/inMemory/InMemoryStorageCS.js +4 -0
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +61 -0
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +1 -0
- package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +64 -0
- package/cjs/storages/inRedis/index.js +5 -3
- package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +64 -0
- package/cjs/storages/pluggable/index.js +2 -0
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +54 -4
- package/cjs/sync/polling/pollingManagerCS.js +7 -7
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +59 -33
- package/cjs/sync/streaming/SSEHandler/index.js +1 -0
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +106 -77
- package/cjs/sync/streaming/constants.js +2 -1
- package/cjs/sync/streaming/pushManager.js +3 -16
- package/cjs/sync/syncManagerOnline.js +2 -2
- package/cjs/utils/constants/index.js +6 -2
- package/esm/consent/sdkUserConsent.js +5 -3
- package/esm/evaluator/combiners/and.js +2 -6
- package/esm/evaluator/combiners/ifelseif.js +7 -7
- package/esm/evaluator/condition/index.js +6 -5
- package/esm/evaluator/index.js +7 -7
- package/esm/evaluator/matchers/index.js +3 -1
- package/esm/evaluator/matchers/matcherTypes.js +1 -0
- package/esm/evaluator/matchers/rbsegment.js +52 -0
- package/esm/evaluator/matchersTransform/index.js +4 -0
- package/esm/evaluator/parser/index.js +2 -2
- package/esm/evaluator/value/sanitize.js +1 -0
- package/esm/listeners/browser.js +2 -5
- package/esm/logger/constants.js +1 -0
- package/esm/logger/messages/debug.js +3 -2
- package/esm/logger/messages/warn.js +1 -1
- package/esm/services/splitApi.js +3 -4
- package/esm/services/splitHttpClient.js +3 -1
- package/esm/storages/AbstractSplitsCacheSync.js +5 -2
- package/esm/storages/KeyBuilder.js +9 -0
- package/esm/storages/KeyBuilderCS.js +3 -0
- package/esm/storages/KeyBuilderSS.js +3 -0
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +114 -0
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +9 -14
- package/esm/storages/inLocalStorage/index.js +5 -1
- package/esm/storages/inLocalStorage/validateCache.js +2 -1
- package/esm/storages/inMemory/InMemoryStorage.js +3 -0
- package/esm/storages/inMemory/InMemoryStorageCS.js +4 -0
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +58 -0
- package/esm/storages/inMemory/SplitsCacheInMemory.js +1 -0
- package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +61 -0
- package/esm/storages/inRedis/index.js +5 -3
- package/esm/storages/pluggable/RBSegmentsCachePluggable.js +61 -0
- package/esm/storages/pluggable/index.js +2 -0
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +54 -4
- package/esm/sync/polling/pollingManagerCS.js +7 -7
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/esm/sync/polling/updaters/splitChangesUpdater.js +59 -33
- package/esm/sync/streaming/SSEHandler/index.js +2 -1
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +102 -73
- package/esm/sync/streaming/constants.js +1 -0
- package/esm/sync/streaming/pushManager.js +6 -19
- package/esm/sync/syncManagerOnline.js +2 -2
- package/esm/utils/constants/index.js +5 -1
- package/package.json +1 -1
- package/src/consent/sdkUserConsent.ts +3 -2
- package/src/dtos/types.ts +37 -8
- package/src/evaluator/Engine.ts +1 -1
- package/src/evaluator/combiners/and.ts +5 -4
- package/src/evaluator/combiners/ifelseif.ts +7 -9
- package/src/evaluator/condition/engineUtils.ts +1 -1
- package/src/evaluator/condition/index.ts +12 -12
- package/src/evaluator/index.ts +7 -7
- package/src/evaluator/matchers/index.ts +3 -1
- package/src/evaluator/matchers/matcherTypes.ts +1 -0
- package/src/evaluator/matchers/rbsegment.ts +74 -0
- package/src/evaluator/matchersTransform/index.ts +3 -0
- package/src/evaluator/parser/index.ts +3 -3
- package/src/evaluator/types.ts +2 -2
- package/src/evaluator/value/index.ts +2 -2
- package/src/evaluator/value/sanitize.ts +5 -4
- package/src/listeners/browser.ts +2 -3
- package/src/logger/constants.ts +1 -0
- package/src/logger/messages/debug.ts +3 -2
- package/src/logger/messages/warn.ts +1 -1
- package/src/sdkManager/index.ts +1 -1
- package/src/services/splitApi.ts +3 -4
- package/src/services/splitHttpClient.ts +3 -1
- package/src/services/types.ts +1 -1
- package/src/storages/AbstractSplitsCacheSync.ts +6 -3
- package/src/storages/KeyBuilder.ts +12 -0
- package/src/storages/KeyBuilderCS.ts +4 -0
- package/src/storages/KeyBuilderSS.ts +4 -0
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +136 -0
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +10 -14
- package/src/storages/inLocalStorage/index.ts +5 -1
- package/src/storages/inLocalStorage/validateCache.ts +3 -1
- package/src/storages/inMemory/InMemoryStorage.ts +3 -0
- package/src/storages/inMemory/InMemoryStorageCS.ts +4 -0
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +68 -0
- package/src/storages/inMemory/SplitsCacheInMemory.ts +1 -0
- package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +79 -0
- package/src/storages/inRedis/index.ts +5 -3
- package/src/storages/pluggable/RBSegmentsCachePluggable.ts +76 -0
- package/src/storages/pluggable/index.ts +2 -0
- package/src/storages/types.ts +33 -1
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +65 -4
- package/src/sync/polling/fetchers/types.ts +1 -0
- package/src/sync/polling/pollingManagerCS.ts +7 -7
- package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -1
- package/src/sync/polling/types.ts +2 -2
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -2
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
- package/src/sync/polling/updaters/splitChangesUpdater.ts +70 -43
- package/src/sync/streaming/SSEHandler/index.ts +2 -1
- package/src/sync/streaming/SSEHandler/types.ts +2 -2
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +98 -68
- package/src/sync/streaming/constants.ts +1 -0
- package/src/sync/streaming/parseUtils.ts +2 -2
- package/src/sync/streaming/pushManager.ts +6 -18
- package/src/sync/streaming/types.ts +3 -2
- package/src/sync/syncManagerOnline.ts +2 -2
- package/src/utils/constants/index.ts +6 -1
- package/src/utils/lang/index.ts +1 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.splitChangesUpdaterFactory = exports.
|
|
3
|
+
exports.splitChangesUpdaterFactory = exports.computeMutation = exports.parseSegments = void 0;
|
|
4
4
|
var timeout_1 = require("../../../utils/promise/timeout");
|
|
5
5
|
var constants_1 = require("../../../readiness/constants");
|
|
6
6
|
var constants_2 = require("../../../logger/constants");
|
|
7
7
|
var lang_1 = require("../../../utils/lang");
|
|
8
8
|
var constants_3 = require("../../../utils/constants");
|
|
9
9
|
var sets_1 = require("../../../utils/lang/sets");
|
|
10
|
+
var constants_4 = require("../../streaming/constants");
|
|
10
11
|
// Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
|
|
11
12
|
// Returns a promise that could be rejected.
|
|
12
13
|
// @TODO review together with Segments and MySegments storage APIs
|
|
@@ -18,16 +19,25 @@ function checkAllSegmentsExist(segments) {
|
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
|
-
* Collect segments from a raw
|
|
22
|
+
* Collect segments from a raw FF or RBS definition.
|
|
22
23
|
* Exported for testing purposes.
|
|
23
24
|
*/
|
|
24
|
-
function parseSegments(
|
|
25
|
-
|
|
25
|
+
function parseSegments(ruleEntity, matcherType) {
|
|
26
|
+
if (matcherType === void 0) { matcherType = constants_3.IN_SEGMENT; }
|
|
27
|
+
var _a = ruleEntity, _b = _a.conditions, conditions = _b === void 0 ? [] : _b, excluded = _a.excluded;
|
|
26
28
|
var segments = new Set();
|
|
29
|
+
if (excluded && excluded.segments) {
|
|
30
|
+
excluded.segments.forEach(function (_a) {
|
|
31
|
+
var type = _a.type, name = _a.name;
|
|
32
|
+
if ((type === constants_3.STANDARD_SEGMENT && matcherType === constants_3.IN_SEGMENT) || (type === constants_3.RULE_BASED_SEGMENT && matcherType === constants_3.IN_RULE_BASED_SEGMENT)) {
|
|
33
|
+
segments.add(name);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
27
37
|
for (var i = 0; i < conditions.length; i++) {
|
|
28
38
|
var matchers = conditions[i].matcherGroup.matchers;
|
|
29
39
|
matchers.forEach(function (matcher) {
|
|
30
|
-
if (matcher.matcherType ===
|
|
40
|
+
if (matcher.matcherType === matcherType)
|
|
31
41
|
segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
|
|
32
42
|
});
|
|
33
43
|
}
|
|
@@ -58,24 +68,21 @@ function matchFilters(featureFlag, filters) {
|
|
|
58
68
|
* i.e., an object with added splits, removed splits and used segments.
|
|
59
69
|
* Exported for testing purposes.
|
|
60
70
|
*/
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
parseSegments(split).forEach(function (segmentName) {
|
|
71
|
+
function computeMutation(rules, segments, filters) {
|
|
72
|
+
return rules.reduce(function (accum, ruleEntity) {
|
|
73
|
+
if (ruleEntity.status === 'ACTIVE' && (!filters || matchFilters(ruleEntity, filters))) {
|
|
74
|
+
accum.added.push(ruleEntity);
|
|
75
|
+
parseSegments(ruleEntity).forEach(function (segmentName) {
|
|
67
76
|
segments.add(segmentName);
|
|
68
77
|
});
|
|
69
78
|
}
|
|
70
79
|
else {
|
|
71
|
-
accum.removed.push(
|
|
80
|
+
accum.removed.push(ruleEntity);
|
|
72
81
|
}
|
|
73
82
|
return accum;
|
|
74
|
-
}, { added: [], removed: []
|
|
75
|
-
computed.segments = (0, sets_1.setToArray)(segments);
|
|
76
|
-
return computed;
|
|
83
|
+
}, { added: [], removed: [] });
|
|
77
84
|
}
|
|
78
|
-
exports.
|
|
85
|
+
exports.computeMutation = computeMutation;
|
|
79
86
|
/**
|
|
80
87
|
* factory of SplitChanges updater, a task that:
|
|
81
88
|
* - fetches split changes using `splitChangesFetcher`
|
|
@@ -93,7 +100,7 @@ exports.computeSplitsMutation = computeSplitsMutation;
|
|
|
93
100
|
function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFiltersValidation, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
|
|
94
101
|
if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
|
|
95
102
|
if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
|
|
96
|
-
var splits = storage.splits, segments = storage.segments;
|
|
103
|
+
var splits = storage.splits, rbSegments = storage.rbSegments, segments = storage.segments;
|
|
97
104
|
var startingUp = true;
|
|
98
105
|
/** timeout decorator for `splitChangesFetcher` promise */
|
|
99
106
|
function _promiseDecorator(promise) {
|
|
@@ -108,29 +115,48 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFilt
|
|
|
108
115
|
* @param noCache - true to revalidate data to fetch
|
|
109
116
|
* @param till - query param to bypass CDN requests
|
|
110
117
|
*/
|
|
111
|
-
return function splitChangesUpdater(noCache, till,
|
|
118
|
+
return function splitChangesUpdater(noCache, till, instantUpdate) {
|
|
112
119
|
/**
|
|
113
120
|
* @param since - current changeNumber at splitsCache
|
|
114
121
|
* @param retry - current number of retry attempts
|
|
115
122
|
*/
|
|
116
|
-
function _splitChangesUpdater(
|
|
123
|
+
function _splitChangesUpdater(sinces, retry) {
|
|
117
124
|
if (retry === void 0) { retry = 0; }
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
var since = sinces[0], rbSince = sinces[1];
|
|
126
|
+
log.debug(constants_2.SYNC_SPLITS_FETCH, sinces);
|
|
127
|
+
return Promise.resolve(instantUpdate ?
|
|
128
|
+
instantUpdate.type === constants_4.SPLIT_UPDATE ?
|
|
129
|
+
// IFFU edge case: a change to a flag that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
|
|
130
|
+
Promise.resolve(rbSegments.contains(parseSegments(instantUpdate.payload, constants_3.IN_RULE_BASED_SEGMENT))).then(function (contains) {
|
|
131
|
+
return contains ?
|
|
132
|
+
{ ff: { d: [instantUpdate.payload], t: instantUpdate.changeNumber } } :
|
|
133
|
+
splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
|
|
134
|
+
}) :
|
|
135
|
+
{ rbs: { d: [instantUpdate.payload], t: instantUpdate.changeNumber } } :
|
|
136
|
+
splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator))
|
|
122
137
|
.then(function (splitChanges) {
|
|
123
138
|
startingUp = false;
|
|
124
|
-
var
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
139
|
+
var usedSegments = new Set();
|
|
140
|
+
var ffUpdate = false;
|
|
141
|
+
if (splitChanges.ff) {
|
|
142
|
+
var _a = computeMutation(splitChanges.ff.d, usedSegments, splitFiltersValidation), added = _a.added, removed = _a.removed;
|
|
143
|
+
log.debug(constants_2.SYNC_SPLITS_UPDATE, [added.length, removed.length]);
|
|
144
|
+
ffUpdate = splits.update(added, removed, splitChanges.ff.t);
|
|
145
|
+
}
|
|
146
|
+
var rbsUpdate = false;
|
|
147
|
+
if (splitChanges.rbs) {
|
|
148
|
+
var _b = computeMutation(splitChanges.rbs.d, usedSegments), added = _b.added, removed = _b.removed;
|
|
149
|
+
log.debug(constants_2.SYNC_RBS_UPDATE, [added.length, removed.length]);
|
|
150
|
+
rbsUpdate = rbSegments.update(added, removed, splitChanges.rbs.t);
|
|
151
|
+
}
|
|
152
|
+
return Promise.all([ffUpdate, rbsUpdate,
|
|
153
|
+
// @TODO if at least 1 segment fetch fails due to 404 and other segments are updated in the storage, SDK_UPDATE is not emitted
|
|
154
|
+
segments.registerSegments((0, sets_1.setToArray)(usedSegments))
|
|
129
155
|
]).then(function (_a) {
|
|
130
|
-
var
|
|
156
|
+
var ffChanged = _a[0], rbsChanged = _a[1];
|
|
131
157
|
if (splitsEventEmitter) {
|
|
132
158
|
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
133
|
-
return Promise.resolve(!splitsEventEmitter.splitsArrived || (
|
|
159
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
|
|
134
160
|
.catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
135
161
|
.then(function (emitSplitsArrivedEvent) {
|
|
136
162
|
// emit SDK events
|
|
@@ -147,7 +173,7 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFilt
|
|
|
147
173
|
if (startingUp && retriesOnFailureBeforeReady > retry) {
|
|
148
174
|
retry += 1;
|
|
149
175
|
log.info(constants_2.SYNC_SPLITS_FETCH_RETRY, [retry, error]);
|
|
150
|
-
return _splitChangesUpdater(
|
|
176
|
+
return _splitChangesUpdater(sinces, retry);
|
|
151
177
|
}
|
|
152
178
|
else {
|
|
153
179
|
startingUp = false;
|
|
@@ -155,8 +181,8 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFilt
|
|
|
155
181
|
return false;
|
|
156
182
|
});
|
|
157
183
|
}
|
|
158
|
-
|
|
159
|
-
return
|
|
184
|
+
// `getChangeNumber` never rejects or throws error
|
|
185
|
+
return Promise.all([splits.getChangeNumber(), rbSegments.getChangeNumber()]).then(_splitChangesUpdater);
|
|
160
186
|
};
|
|
161
187
|
}
|
|
162
188
|
exports.splitChangesUpdaterFactory = splitChangesUpdaterFactory;
|
|
@@ -78,6 +78,7 @@ function SSEHandlerFactory(log, pushEmitter, telemetryTracker) {
|
|
|
78
78
|
case constants_1.MEMBERSHIPS_MS_UPDATE:
|
|
79
79
|
case constants_1.MEMBERSHIPS_LS_UPDATE:
|
|
80
80
|
case constants_1.SPLIT_KILL:
|
|
81
|
+
case constants_1.RB_SEGMENT_UPDATE:
|
|
81
82
|
pushEmitter.emit(parsedData.type, parsedData);
|
|
82
83
|
break;
|
|
83
84
|
/* occupancy & control events, handled by NotificationManagerKeeper */
|
|
@@ -1,106 +1,135 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SplitsUpdateWorker = void 0;
|
|
4
|
-
var constants_1 = require("../../../
|
|
4
|
+
var constants_1 = require("../../../logger/constants");
|
|
5
|
+
var constants_2 = require("../../../readiness/constants");
|
|
5
6
|
var Backoff_1 = require("../../../utils/Backoff");
|
|
6
|
-
var
|
|
7
|
-
var
|
|
7
|
+
var constants_3 = require("../../../utils/constants");
|
|
8
|
+
var constants_4 = require("../constants");
|
|
9
|
+
var parseUtils_1 = require("../parseUtils");
|
|
10
|
+
var constants_5 = require("./constants");
|
|
8
11
|
/**
|
|
9
12
|
* SplitsUpdateWorker factory
|
|
10
13
|
*/
|
|
11
|
-
function SplitsUpdateWorker(log,
|
|
12
|
-
var
|
|
13
|
-
var
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (splitUpdateNotification_1)
|
|
32
|
-
telemetryTracker.trackUpdatesFromSSE(constants_2.SPLITS);
|
|
33
|
-
// fetch new registered segments for server-side API. Not retrying on error
|
|
34
|
-
if (segmentsSyncTask)
|
|
35
|
-
segmentsSyncTask.execute(true);
|
|
36
|
-
var attempts = backoff.attempts + 1;
|
|
37
|
-
if (maxChangeNumber <= splitsCache.getChangeNumber()) {
|
|
38
|
-
log.debug("Refresh completed" + (cdnBypass ? ' bypassing the CDN' : '') + " in " + attempts + " attempts.");
|
|
39
|
-
isHandlingEvent = false;
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
if (attempts < constants_3.FETCH_BACKOFF_MAX_RETRIES) {
|
|
43
|
-
backoff.scheduleCall();
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
if (cdnBypass) {
|
|
47
|
-
log.debug("No changes fetched after " + attempts + " attempts with CDN bypassed.");
|
|
48
|
-
isHandlingEvent = false;
|
|
14
|
+
function SplitsUpdateWorker(log, storage, splitsSyncTask, splitsEventEmitter, telemetryTracker, segmentsSyncTask) {
|
|
15
|
+
var ff = SplitsUpdateWorker(storage.splits);
|
|
16
|
+
var rbs = SplitsUpdateWorker(storage.rbSegments);
|
|
17
|
+
function SplitsUpdateWorker(cache) {
|
|
18
|
+
var maxChangeNumber = -1;
|
|
19
|
+
var handleNewEvent = false;
|
|
20
|
+
var isHandlingEvent;
|
|
21
|
+
var cdnBypass;
|
|
22
|
+
var instantUpdate;
|
|
23
|
+
var backoff = new Backoff_1.Backoff(__handleSplitUpdateCall, constants_5.FETCH_BACKOFF_BASE, constants_5.FETCH_BACKOFF_MAX_WAIT);
|
|
24
|
+
function __handleSplitUpdateCall() {
|
|
25
|
+
isHandlingEvent = true;
|
|
26
|
+
if (maxChangeNumber > cache.getChangeNumber()) {
|
|
27
|
+
handleNewEvent = false;
|
|
28
|
+
// fetch splits revalidating data if cached
|
|
29
|
+
splitsSyncTask.execute(true, cdnBypass ? maxChangeNumber : undefined, instantUpdate).then(function () {
|
|
30
|
+
if (!isHandlingEvent)
|
|
31
|
+
return; // halt if `stop` has been called
|
|
32
|
+
if (handleNewEvent) {
|
|
33
|
+
__handleSplitUpdateCall();
|
|
49
34
|
}
|
|
50
35
|
else {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
36
|
+
if (instantUpdate)
|
|
37
|
+
telemetryTracker.trackUpdatesFromSSE(constants_3.SPLITS);
|
|
38
|
+
// fetch new registered segments for server-side API. Not retrying on error
|
|
39
|
+
if (segmentsSyncTask)
|
|
40
|
+
segmentsSyncTask.execute(true);
|
|
41
|
+
var attempts = backoff.attempts + 1;
|
|
42
|
+
if (ff.isSync() && rbs.isSync()) {
|
|
43
|
+
log.debug("Refresh completed" + (cdnBypass ? ' bypassing the CDN' : '') + " in " + attempts + " attempts.");
|
|
44
|
+
isHandlingEvent = false;
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (attempts < constants_5.FETCH_BACKOFF_MAX_RETRIES) {
|
|
48
|
+
backoff.scheduleCall();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (cdnBypass) {
|
|
52
|
+
log.debug("No changes fetched after " + attempts + " attempts with CDN bypassed.");
|
|
53
|
+
isHandlingEvent = false;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
backoff.reset();
|
|
57
|
+
cdnBypass = true;
|
|
58
|
+
__handleSplitUpdateCall();
|
|
59
|
+
}
|
|
54
60
|
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Invoked by NotificationProcessor on SPLIT_UPDATE event
|
|
64
|
-
*
|
|
65
|
-
* @param changeNumber - change number of the SPLIT_UPDATE notification
|
|
66
|
-
*/
|
|
67
|
-
function put(_a, _payload) {
|
|
68
|
-
var changeNumber = _a.changeNumber, pcn = _a.pcn;
|
|
69
|
-
var currentChangeNumber = splitsCache.getChangeNumber();
|
|
70
|
-
if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber)
|
|
71
|
-
return;
|
|
72
|
-
maxChangeNumber = changeNumber;
|
|
73
|
-
handleNewEvent = true;
|
|
74
|
-
cdnBypass = false;
|
|
75
|
-
payload = undefined;
|
|
76
|
-
if (_payload && currentChangeNumber === pcn) {
|
|
77
|
-
payload = _payload;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
isHandlingEvent = false;
|
|
65
|
+
}
|
|
78
66
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
67
|
+
return {
|
|
68
|
+
/**
|
|
69
|
+
* Invoked by NotificationProcessor on SPLIT_UPDATE or RB_SEGMENT_UPDATE event
|
|
70
|
+
*
|
|
71
|
+
* @param changeNumber - change number of the notification
|
|
72
|
+
*/
|
|
73
|
+
put: function (_a, payload) {
|
|
74
|
+
var changeNumber = _a.changeNumber, pcn = _a.pcn, type = _a.type;
|
|
75
|
+
var currentChangeNumber = cache.getChangeNumber();
|
|
76
|
+
if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber)
|
|
77
|
+
return;
|
|
78
|
+
maxChangeNumber = changeNumber;
|
|
79
|
+
handleNewEvent = true;
|
|
80
|
+
cdnBypass = false;
|
|
81
|
+
instantUpdate = undefined;
|
|
82
|
+
if (payload && currentChangeNumber === pcn) {
|
|
83
|
+
instantUpdate = { payload: payload, changeNumber: changeNumber, type: type };
|
|
84
|
+
}
|
|
85
|
+
if (backoff.timeoutID || !isHandlingEvent)
|
|
86
|
+
__handleSplitUpdateCall();
|
|
87
|
+
backoff.reset();
|
|
88
|
+
},
|
|
89
|
+
stop: function () {
|
|
90
|
+
isHandlingEvent = false;
|
|
91
|
+
backoff.reset();
|
|
92
|
+
},
|
|
93
|
+
isSync: function () {
|
|
94
|
+
return maxChangeNumber <= cache.getChangeNumber();
|
|
95
|
+
}
|
|
96
|
+
};
|
|
82
97
|
}
|
|
83
98
|
return {
|
|
84
|
-
put:
|
|
99
|
+
put: function (parsedData) {
|
|
100
|
+
if (parsedData.d && parsedData.c !== undefined) {
|
|
101
|
+
try {
|
|
102
|
+
var payload = (0, parseUtils_1.parseFFUpdatePayload)(parsedData.c, parsedData.d);
|
|
103
|
+
if (payload) {
|
|
104
|
+
(parsedData.type === constants_4.RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData, payload);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
log.warn(constants_1.STREAMING_PARSING_SPLIT_UPDATE, [parsedData.type, e]);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
(parsedData.type === constants_4.RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData);
|
|
113
|
+
},
|
|
85
114
|
/**
|
|
86
115
|
* Invoked by NotificationProcessor on SPLIT_KILL event
|
|
87
116
|
*
|
|
88
|
-
* @param changeNumber - change number of the
|
|
117
|
+
* @param changeNumber - change number of the notification
|
|
89
118
|
* @param splitName - name of split to kill
|
|
90
119
|
* @param defaultTreatment - default treatment value
|
|
91
120
|
*/
|
|
92
121
|
killSplit: function (_a) {
|
|
93
122
|
var changeNumber = _a.changeNumber, splitName = _a.splitName, defaultTreatment = _a.defaultTreatment;
|
|
94
|
-
if (
|
|
123
|
+
if (storage.splits.killLocally(splitName, defaultTreatment, changeNumber)) {
|
|
95
124
|
// trigger an SDK_UPDATE if Split was killed locally
|
|
96
|
-
splitsEventEmitter.emit(
|
|
125
|
+
splitsEventEmitter.emit(constants_2.SDK_SPLITS_ARRIVED, true);
|
|
97
126
|
}
|
|
98
127
|
// queues the SplitChanges fetch (only if changeNumber is newer)
|
|
99
|
-
put({ changeNumber: changeNumber });
|
|
128
|
+
ff.put({ changeNumber: changeNumber });
|
|
100
129
|
},
|
|
101
130
|
stop: function () {
|
|
102
|
-
|
|
103
|
-
|
|
131
|
+
ff.stop();
|
|
132
|
+
rbs.stop();
|
|
104
133
|
}
|
|
105
134
|
};
|
|
106
135
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ControlType = exports.OCCUPANCY = exports.CONTROL = exports.SPLIT_UPDATE = exports.SPLIT_KILL = exports.SEGMENT_UPDATE = exports.MEMBERSHIPS_LS_UPDATE = exports.MEMBERSHIPS_MS_UPDATE = exports.PUSH_SUBSYSTEM_DOWN = exports.PUSH_SUBSYSTEM_UP = exports.PUSH_RETRYABLE_ERROR = exports.PUSH_NONRETRYABLE_ERROR = exports.SECONDS_BEFORE_EXPIRATION = void 0;
|
|
3
|
+
exports.ControlType = exports.OCCUPANCY = exports.CONTROL = exports.RB_SEGMENT_UPDATE = exports.SPLIT_UPDATE = exports.SPLIT_KILL = exports.SEGMENT_UPDATE = exports.MEMBERSHIPS_LS_UPDATE = exports.MEMBERSHIPS_MS_UPDATE = exports.PUSH_SUBSYSTEM_DOWN = exports.PUSH_SUBSYSTEM_UP = exports.PUSH_RETRYABLE_ERROR = exports.PUSH_NONRETRYABLE_ERROR = exports.SECONDS_BEFORE_EXPIRATION = void 0;
|
|
4
4
|
// time for refresh token
|
|
5
5
|
exports.SECONDS_BEFORE_EXPIRATION = 600;
|
|
6
6
|
// Internal SDK events, subscribed by SyncManager and PushManager
|
|
@@ -30,6 +30,7 @@ exports.MEMBERSHIPS_LS_UPDATE = 'MEMBERSHIPS_LS_UPDATE';
|
|
|
30
30
|
exports.SEGMENT_UPDATE = 'SEGMENT_UPDATE';
|
|
31
31
|
exports.SPLIT_KILL = 'SPLIT_KILL';
|
|
32
32
|
exports.SPLIT_UPDATE = 'SPLIT_UPDATE';
|
|
33
|
+
exports.RB_SEGMENT_UPDATE = 'RB_SEGMENT_UPDATE';
|
|
33
34
|
// Control-type push notifications, handled by NotificationKeeper
|
|
34
35
|
exports.CONTROL = 'CONTROL';
|
|
35
36
|
exports.OCCUPANCY = 'OCCUPANCY';
|
|
@@ -46,7 +46,7 @@ function pushManagerFactory(params, pollingManager) {
|
|
|
46
46
|
// MySegmentsUpdateWorker (client-side) are initiated in `add` method
|
|
47
47
|
var segmentsUpdateWorker = userKey ? undefined : (0, SegmentsUpdateWorker_1.SegmentsUpdateWorker)(log, pollingManager.segmentsSyncTask, storage.segments);
|
|
48
48
|
// For server-side we pass the segmentsSyncTask, used by SplitsUpdateWorker to fetch new segments
|
|
49
|
-
var splitsUpdateWorker = (0, SplitsUpdateWorker_1.SplitsUpdateWorker)(log, storage
|
|
49
|
+
var splitsUpdateWorker = (0, SplitsUpdateWorker_1.SplitsUpdateWorker)(log, storage, pollingManager.splitsSyncTask, readiness.splits, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask);
|
|
50
50
|
// [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
|
|
51
51
|
var userKeyHashes = {};
|
|
52
52
|
// [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
|
|
@@ -182,21 +182,8 @@ function pushManagerFactory(params, pollingManager) {
|
|
|
182
182
|
});
|
|
183
183
|
/** Functions related to synchronization (Queues and Workers in the spec) */
|
|
184
184
|
pushEmitter.on(constants_1.SPLIT_KILL, splitsUpdateWorker.killSplit);
|
|
185
|
-
pushEmitter.on(constants_1.SPLIT_UPDATE,
|
|
186
|
-
|
|
187
|
-
try {
|
|
188
|
-
var payload = (0, parseUtils_1.parseFFUpdatePayload)(parsedData.c, parsedData.d);
|
|
189
|
-
if (payload) {
|
|
190
|
-
splitsUpdateWorker.put(parsedData, payload);
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
catch (e) {
|
|
195
|
-
log.warn(constants_2.STREAMING_PARSING_SPLIT_UPDATE, [e]);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
splitsUpdateWorker.put(parsedData);
|
|
199
|
-
});
|
|
185
|
+
pushEmitter.on(constants_1.SPLIT_UPDATE, splitsUpdateWorker.put);
|
|
186
|
+
pushEmitter.on(constants_1.RB_SEGMENT_UPDATE, splitsUpdateWorker.put);
|
|
200
187
|
function handleMySegmentsUpdate(parsedData) {
|
|
201
188
|
switch (parsedData.u) {
|
|
202
189
|
case types_1.UpdateStrategy.BoundedFetchRequest: {
|
|
@@ -130,7 +130,7 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
130
130
|
if (pushManager) {
|
|
131
131
|
if (pollingManager.isRunning()) {
|
|
132
132
|
// if doing polling, we must start the periodic fetch of data
|
|
133
|
-
if (storage.splits.usesSegments())
|
|
133
|
+
if (storage.splits.usesSegments() || storage.rbSegments.usesSegments())
|
|
134
134
|
mySegmentsSyncTask.start();
|
|
135
135
|
}
|
|
136
136
|
else {
|
|
@@ -140,7 +140,7 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
else {
|
|
143
|
-
if (storage.splits.usesSegments())
|
|
143
|
+
if (storage.splits.usesSegments() || storage.rbSegments.usesSegments())
|
|
144
144
|
mySegmentsSyncTask.start();
|
|
145
145
|
}
|
|
146
146
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MEMBERSHIPS = exports.SEGMENT = exports.TOKEN = exports.TELEMETRY = exports.EVENTS = exports.IMPRESSIONS_COUNT = exports.IMPRESSIONS = exports.SPLITS = exports.NONE_ENUM = exports.DEBUG_ENUM = exports.OPTIMIZED_ENUM = exports.CONSUMER_PARTIAL_ENUM = exports.CONSUMER_ENUM = exports.STANDALONE_ENUM = exports.DEDUPED = exports.DROPPED = exports.QUEUED = exports.NAMES_FN_LABEL = exports.SPLITS_FN_LABEL = exports.SPLIT_FN_LABEL = exports.TRACK_FN_LABEL = exports.GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS = exports.GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET = exports.GET_TREATMENTS_BY_FLAG_SETS = exports.GET_TREATMENTS_BY_FLAG_SET = exports.GET_TREATMENTS_WITH_CONFIG = exports.GET_TREATMENT_WITH_CONFIG = exports.GET_TREATMENTS = exports.GET_TREATMENT = exports.CONSENT_UNKNOWN = exports.CONSENT_DECLINED = exports.CONSENT_GRANTED = exports.STORAGE_PLUGGABLE = exports.STORAGE_REDIS = exports.STORAGE_LOCALSTORAGE = exports.STORAGE_MEMORY = exports.CONSUMER_PARTIAL_MODE = exports.CONSUMER_MODE = exports.PRODUCER_MODE = exports.STANDALONE_MODE = exports.LOCALHOST_MODE = exports.NONE = exports.OPTIMIZED = exports.DEBUG = exports.SPLIT_EVENT = exports.SPLIT_IMPRESSION = exports.NA = exports.UNKNOWN = exports.CONTROL_WITH_CONFIG = exports.CONTROL = void 0;
|
|
4
|
-
exports.IN_LARGE_SEGMENT = exports.IN_SEGMENT = exports.FLAG_SPEC_VERSION = exports.PAUSED = exports.ENABLED = exports.DISABLED = exports.NON_REQUESTED = exports.REQUESTED = exports.POLLING = exports.STREAMING = exports.AUTH_REJECTION = exports.SYNC_MODE_UPDATE = exports.ABLY_ERROR = exports.TOKEN_REFRESH = exports.SSE_CONNECTION_ERROR = exports.STREAMING_STATUS = exports.OCCUPANCY_SEC = exports.OCCUPANCY_PRI = exports.CONNECTION_ESTABLISHED = exports.TRACK = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSETS = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSET = exports.TREATMENTS_BY_FLAGSETS = exports.TREATMENTS_BY_FLAGSET = exports.TREATMENTS_WITH_CONFIG = exports.TREATMENT_WITH_CONFIG = exports.TREATMENTS = exports.TREATMENT = void 0;
|
|
4
|
+
exports.RULE_BASED_SEGMENT = exports.LARGE_SEGMENT = exports.STANDARD_SEGMENT = exports.IN_RULE_BASED_SEGMENT = exports.IN_LARGE_SEGMENT = exports.IN_SEGMENT = exports.FLAG_SPEC_VERSION = exports.PAUSED = exports.ENABLED = exports.DISABLED = exports.NON_REQUESTED = exports.REQUESTED = exports.POLLING = exports.STREAMING = exports.AUTH_REJECTION = exports.SYNC_MODE_UPDATE = exports.ABLY_ERROR = exports.TOKEN_REFRESH = exports.SSE_CONNECTION_ERROR = exports.STREAMING_STATUS = exports.OCCUPANCY_SEC = exports.OCCUPANCY_PRI = exports.CONNECTION_ESTABLISHED = exports.TRACK = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSETS = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSET = exports.TREATMENTS_BY_FLAGSETS = exports.TREATMENTS_BY_FLAGSET = exports.TREATMENTS_WITH_CONFIG = exports.TREATMENT_WITH_CONFIG = exports.TREATMENTS = exports.TREATMENT = void 0;
|
|
5
5
|
// Special treatments
|
|
6
6
|
exports.CONTROL = 'control';
|
|
7
7
|
exports.CONTROL_WITH_CONFIG = {
|
|
@@ -90,7 +90,11 @@ exports.NON_REQUESTED = 1;
|
|
|
90
90
|
exports.DISABLED = 0;
|
|
91
91
|
exports.ENABLED = 1;
|
|
92
92
|
exports.PAUSED = 2;
|
|
93
|
-
exports.FLAG_SPEC_VERSION = '1.
|
|
93
|
+
exports.FLAG_SPEC_VERSION = '1.3';
|
|
94
94
|
// Matcher types
|
|
95
95
|
exports.IN_SEGMENT = 'IN_SEGMENT';
|
|
96
96
|
exports.IN_LARGE_SEGMENT = 'IN_LARGE_SEGMENT';
|
|
97
|
+
exports.IN_RULE_BASED_SEGMENT = 'IN_RULE_BASED_SEGMENT';
|
|
98
|
+
exports.STANDARD_SEGMENT = 'standard';
|
|
99
|
+
exports.LARGE_SEGMENT = 'large';
|
|
100
|
+
exports.RULE_BASED_SEGMENT = 'rule-based';
|
|
@@ -12,7 +12,7 @@ var ConsentStatus = {
|
|
|
12
12
|
* The public user consent API exposed via SplitFactory, used to control if the SDK tracks and sends impressions and events or not.
|
|
13
13
|
*/
|
|
14
14
|
export function createUserConsentAPI(params) {
|
|
15
|
-
var settings = params.settings, log = params.settings.log, syncManager = params.syncManager, _a = params.storage, events = _a.events, impressions = _a.impressions, impressionCounts = _a.impressionCounts;
|
|
15
|
+
var settings = params.settings, log = params.settings.log, syncManager = params.syncManager, _a = params.storage, events = _a.events, impressions = _a.impressions, impressionCounts = _a.impressionCounts, uniqueKeys = _a.uniqueKeys;
|
|
16
16
|
if (!isConsentGranted(settings))
|
|
17
17
|
log.info(USER_CONSENT_INITIAL, [settings.userConsent]);
|
|
18
18
|
return {
|
|
@@ -37,8 +37,10 @@ export function createUserConsentAPI(params) {
|
|
|
37
37
|
events.clear(); // @ts-ignore
|
|
38
38
|
if (impressions.clear)
|
|
39
39
|
impressions.clear(); // @ts-ignore
|
|
40
|
-
if (impressionCounts
|
|
41
|
-
impressionCounts.clear();
|
|
40
|
+
if (impressionCounts.clear)
|
|
41
|
+
impressionCounts.clear(); // @ts-ignore
|
|
42
|
+
if (uniqueKeys.clear)
|
|
43
|
+
uniqueKeys.clear();
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
else {
|
|
@@ -8,12 +8,8 @@ export function andCombinerContext(log, matchers) {
|
|
|
8
8
|
log.debug(ENGINE_COMBINER_AND, [hasMatchedAll]);
|
|
9
9
|
return hasMatchedAll;
|
|
10
10
|
}
|
|
11
|
-
return function andCombiner() {
|
|
12
|
-
var
|
|
13
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
14
|
-
params[_i] = arguments[_i];
|
|
15
|
-
}
|
|
16
|
-
var matcherResults = matchers.map(function (matcher) { return matcher.apply(void 0, params); });
|
|
11
|
+
return function andCombiner(key, attributes, splitEvaluator) {
|
|
12
|
+
var matcherResults = matchers.map(function (matcher) { return matcher(key, attributes, splitEvaluator); });
|
|
17
13
|
// If any matching result is a thenable we should use Promise.all
|
|
18
14
|
if (findIndex(matcherResults, thenable) !== -1) {
|
|
19
15
|
return Promise.all(matcherResults).then(andResults);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { findIndex } from '../../utils/lang';
|
|
1
|
+
import { findIndex, isBoolean } from '../../utils/lang';
|
|
2
2
|
import { thenable } from '../../utils/promise/thenable';
|
|
3
3
|
import { UNSUPPORTED_MATCHER_TYPE } from '../../utils/labels';
|
|
4
4
|
import { CONTROL } from '../../utils/constants';
|
|
@@ -11,12 +11,12 @@ export function ifElseIfCombinerContext(log, predicates) {
|
|
|
11
11
|
label: UNSUPPORTED_MATCHER_TYPE
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
|
-
function
|
|
15
|
-
var len = predicateResults.length;
|
|
16
|
-
for (var i = 0; i < len; i++) {
|
|
14
|
+
function computeEvaluation(predicateResults) {
|
|
15
|
+
for (var i = 0, len = predicateResults.length; i < len; i++) {
|
|
17
16
|
var evaluation = predicateResults[i];
|
|
18
17
|
if (evaluation !== undefined) {
|
|
19
|
-
|
|
18
|
+
if (!isBoolean(evaluation))
|
|
19
|
+
log.debug(ENGINE_COMBINER_IFELSEIF, [evaluation.treatment]);
|
|
20
20
|
return evaluation;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -30,9 +30,9 @@ export function ifElseIfCombinerContext(log, predicates) {
|
|
|
30
30
|
var predicateResults = predicates.map(function (evaluator) { return evaluator(key, seed, trafficAllocation, trafficAllocationSeed, attributes, splitEvaluator); });
|
|
31
31
|
// if we find a thenable
|
|
32
32
|
if (findIndex(predicateResults, thenable) !== -1) {
|
|
33
|
-
return Promise.all(predicateResults).then(function (results) { return
|
|
33
|
+
return Promise.all(predicateResults).then(function (results) { return computeEvaluation(results); });
|
|
34
34
|
}
|
|
35
|
-
return
|
|
35
|
+
return computeEvaluation(predicateResults);
|
|
36
36
|
}
|
|
37
37
|
// if there is none predicates, then there was an error in parsing phase
|
|
38
38
|
if (!Array.isArray(predicates) || predicates.length === 0) {
|
|
@@ -4,11 +4,12 @@ import { NOT_IN_SPLIT } from '../../utils/labels';
|
|
|
4
4
|
// Build Evaluation object if and only if matchingResult is true
|
|
5
5
|
function match(log, matchingResult, bucketingKey, seed, treatments, label) {
|
|
6
6
|
if (matchingResult) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
return treatments ? // Feature flag
|
|
8
|
+
{
|
|
9
|
+
treatment: getTreatment(log, bucketingKey, seed, treatments),
|
|
10
|
+
label: label
|
|
11
|
+
} : // Rule-based segment
|
|
12
|
+
true;
|
|
12
13
|
}
|
|
13
14
|
// else we should notify the engine to continue evaluating
|
|
14
15
|
return undefined;
|
package/esm/evaluator/index.js
CHANGED
|
@@ -26,12 +26,12 @@ export function evaluateFeature(log, key, splitName, attributes, storage) {
|
|
|
26
26
|
return treatmentException;
|
|
27
27
|
}
|
|
28
28
|
if (thenable(parsedSplit)) {
|
|
29
|
-
return parsedSplit.then(function (split) { return getEvaluation(log,
|
|
29
|
+
return parsedSplit.then(function (split) { return getEvaluation(log, key, split, attributes, storage); }).catch(
|
|
30
30
|
// Exception on async `getSplit` storage. For example, when the storage is redis or
|
|
31
31
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
32
32
|
function () { return treatmentException; });
|
|
33
33
|
}
|
|
34
|
-
return getEvaluation(log,
|
|
34
|
+
return getEvaluation(log, key, parsedSplit, attributes, storage);
|
|
35
35
|
}
|
|
36
36
|
export function evaluateFeatures(log, key, splitNames, attributes, storage) {
|
|
37
37
|
var parsedSplits;
|
|
@@ -43,13 +43,13 @@ export function evaluateFeatures(log, key, splitNames, attributes, storage) {
|
|
|
43
43
|
return treatmentsException(splitNames);
|
|
44
44
|
}
|
|
45
45
|
return thenable(parsedSplits) ?
|
|
46
|
-
parsedSplits.then(function (splits) { return getEvaluations(log, splitNames, splits,
|
|
46
|
+
parsedSplits.then(function (splits) { return getEvaluations(log, key, splitNames, splits, attributes, storage); })
|
|
47
47
|
.catch(function () {
|
|
48
48
|
// Exception on async `getSplits` storage. For example, when the storage is redis or
|
|
49
49
|
// pluggable and there is a connection issue and we can't retrieve the split to be evaluated
|
|
50
50
|
return treatmentsException(splitNames);
|
|
51
51
|
}) :
|
|
52
|
-
getEvaluations(log, splitNames, parsedSplits,
|
|
52
|
+
getEvaluations(log, key, splitNames, parsedSplits, attributes, storage);
|
|
53
53
|
}
|
|
54
54
|
export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method) {
|
|
55
55
|
var storedFlagNames;
|
|
@@ -84,7 +84,7 @@ export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, stora
|
|
|
84
84
|
}) :
|
|
85
85
|
evaluate(storedFlagNames);
|
|
86
86
|
}
|
|
87
|
-
function getEvaluation(log,
|
|
87
|
+
function getEvaluation(log, key, splitJSON, attributes, storage) {
|
|
88
88
|
var evaluation = {
|
|
89
89
|
treatment: CONTROL,
|
|
90
90
|
label: SPLIT_NOT_FOUND,
|
|
@@ -110,11 +110,11 @@ function getEvaluation(log, splitJSON, key, attributes, storage) {
|
|
|
110
110
|
}
|
|
111
111
|
return evaluation;
|
|
112
112
|
}
|
|
113
|
-
function getEvaluations(log, splitNames, splits,
|
|
113
|
+
function getEvaluations(log, key, splitNames, splits, attributes, storage) {
|
|
114
114
|
var result = {};
|
|
115
115
|
var thenables = [];
|
|
116
116
|
splitNames.forEach(function (splitName) {
|
|
117
|
-
var evaluation = getEvaluation(log, splits[splitName],
|
|
117
|
+
var evaluation = getEvaluation(log, key, splits[splitName], attributes, storage);
|
|
118
118
|
if (thenable(evaluation)) {
|
|
119
119
|
thenables.push(evaluation.then(function (res) {
|
|
120
120
|
result[splitName] = res;
|