@splitsoftware/splitio-commons 3.1.1-rc.11 → 3.1.1-rc.13
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/services/authProvider.js +2 -2
- package/cjs/{sync/streaming/AuthClient/index.js → services/fetchAuth.js} +2 -2
- package/cjs/services/splitApi.js +2 -2
- package/cjs/storages/AbstractDefinitionsCacheAsync.js +2 -1
- package/cjs/storages/AbstractDefinitionsCacheSync.js +2 -2
- package/cjs/storages/inLocalStorage/DefinitionsCacheInLocal.js +4 -1
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +6 -3
- package/cjs/storages/inMemory/DefinitionsCacheInMemory.js +4 -1
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +6 -3
- package/cjs/storages/inRedis/DefinitionsCacheInRedis.js +12 -8
- package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +21 -11
- package/cjs/storages/pluggable/DefinitionsCachePluggable.js +12 -8
- package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +21 -11
- package/cjs/sync/offline/splitsParser/definitionChangesBuilder.js +37 -0
- package/cjs/sync/offline/splitsParser/splitsParserFromSettings.js +5 -32
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +26 -46
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +1 -1
- package/cjs/sync/polling/updaters/definitionChangesUpdater.js +22 -15
- package/cjs/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.js +6 -4
- package/cjs/sync/streaming/parseUtils.js +4 -4
- package/cjs/sync/streaming/pushManager.js +4 -3
- package/esm/services/authProvider.js +1 -1
- package/esm/{sync/streaming/AuthClient/index.js → services/fetchAuth.js} +2 -2
- package/esm/services/splitApi.js +1 -1
- package/esm/storages/AbstractDefinitionsCacheAsync.js +2 -1
- package/esm/storages/AbstractDefinitionsCacheSync.js +2 -2
- package/esm/storages/inLocalStorage/DefinitionsCacheInLocal.js +4 -1
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +6 -3
- package/esm/storages/inMemory/DefinitionsCacheInMemory.js +4 -1
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +6 -3
- package/esm/storages/inRedis/DefinitionsCacheInRedis.js +12 -8
- package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +21 -11
- package/esm/storages/pluggable/DefinitionsCachePluggable.js +12 -8
- package/esm/storages/pluggable/RBSegmentsCachePluggable.js +21 -11
- package/esm/sync/offline/splitsParser/definitionChangesBuilder.js +33 -0
- package/esm/sync/offline/splitsParser/splitsParserFromSettings.js +6 -33
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +23 -43
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +1 -1
- package/esm/sync/polling/updaters/definitionChangesUpdater.js +22 -15
- package/esm/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.js +8 -6
- package/esm/sync/streaming/parseUtils.js +2 -2
- package/esm/sync/streaming/pushManager.js +4 -3
- package/package.json +1 -1
- package/src/dtos/types.ts +4 -4
- package/src/services/authProvider.ts +2 -2
- package/src/{sync/streaming/AuthClient/index.ts → services/fetchAuth.ts} +3 -4
- package/src/services/splitApi.ts +1 -1
- package/src/services/types.ts +21 -4
- package/src/storages/AbstractDefinitionsCacheAsync.ts +5 -4
- package/src/storages/AbstractDefinitionsCacheSync.ts +4 -4
- package/src/storages/inLocalStorage/DefinitionsCacheInLocal.ts +5 -3
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +7 -5
- package/src/storages/inMemory/DefinitionsCacheInMemory.ts +3 -2
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +5 -4
- package/src/storages/inRedis/DefinitionsCacheInRedis.ts +15 -11
- package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +26 -15
- package/src/storages/pluggable/DefinitionsCachePluggable.ts +14 -9
- package/src/storages/pluggable/RBSegmentsCachePluggable.ts +24 -13
- package/src/storages/types.ts +6 -6
- package/src/sync/offline/splitsParser/definitionChangesBuilder.ts +49 -0
- package/src/sync/offline/splitsParser/splitsParserFromSettings.ts +8 -38
- package/src/sync/offline/splitsParser/types.ts +7 -3
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +25 -45
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +5 -5
- package/src/sync/polling/types.ts +22 -1
- package/src/sync/polling/updaters/definitionChangesUpdater.ts +35 -33
- package/src/sync/streaming/SSEClient/index.ts +1 -1
- package/src/sync/streaming/SSEClient/types.ts +1 -1
- package/src/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.ts +17 -13
- package/src/sync/streaming/UpdateWorkers/types.ts +6 -0
- package/src/sync/streaming/parseUtils.ts +3 -4
- package/src/sync/streaming/pushManager.ts +4 -3
- package/src/sync/syncManagerOnline.ts +0 -1
- package/cjs/sync/streaming/AuthClient/types.js +0 -2
- package/esm/sync/streaming/AuthClient/types.js +0 -1
- package/src/sync/streaming/AuthClient/types.ts +0 -19
|
@@ -8,6 +8,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
10
|
var constants_4 = require("../../streaming/constants");
|
|
11
|
+
var thenable_1 = require("../../../utils/promise/thenable");
|
|
11
12
|
/**
|
|
12
13
|
* Collect segments from a raw FF or RBS definition.
|
|
13
14
|
* Exported for testing purposes.
|
|
@@ -71,9 +72,8 @@ function computeMutation(update, segments, filters) {
|
|
|
71
72
|
else {
|
|
72
73
|
accum.removed.push(ruleEntity.name);
|
|
73
74
|
}
|
|
74
|
-
accum.names.push(ruleEntity.name);
|
|
75
75
|
return accum;
|
|
76
|
-
}, { updated: [], removed: update.removed
|
|
76
|
+
}, { updated: [], removed: update.removed });
|
|
77
77
|
}
|
|
78
78
|
exports.computeMutation = computeMutation;
|
|
79
79
|
function convertInstantUpdateToDefinitionChanges(instantUpdate) {
|
|
@@ -115,7 +115,7 @@ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage,
|
|
|
115
115
|
* @param noCache - true to revalidate data to fetch
|
|
116
116
|
* @param till - query param to bypass CDN requests
|
|
117
117
|
*/
|
|
118
|
-
return function definitionChangesUpdater(noCache, till, instantUpdate) {
|
|
118
|
+
return function definitionChangesUpdater(noCache, till, instantUpdate, pcns) {
|
|
119
119
|
/**
|
|
120
120
|
* @param since - current changeNumber at definitionsCache
|
|
121
121
|
* @param retry - current number of retry attempts
|
|
@@ -123,8 +123,14 @@ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage,
|
|
|
123
123
|
function _definitionChangesUpdater(sinces, retry) {
|
|
124
124
|
if (retry === void 0) { retry = 0; }
|
|
125
125
|
var since = sinces[0], rbSince = sinces[1];
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
// If provided, `since` and `rbSince` must not be higher than it, to avoid missing an update that the scoped `pcn` indicates hasn't been fetched yet.
|
|
127
|
+
if (pcns) {
|
|
128
|
+
if (pcns.since !== undefined && pcns.since < since)
|
|
129
|
+
since = pcns.since;
|
|
130
|
+
if (pcns.rbSince !== undefined && pcns.rbSince < rbSince)
|
|
131
|
+
rbSince = pcns.rbSince;
|
|
132
|
+
}
|
|
133
|
+
var definitionChangesRequest = instantUpdate ?
|
|
128
134
|
instantUpdate.type === constants_4.RB_SEGMENT_UPDATE ?
|
|
129
135
|
{ rbs: convertInstantUpdateToDefinitionChanges(instantUpdate) } :
|
|
130
136
|
// IFFU edge case: a change to definition that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
|
|
@@ -133,34 +139,35 @@ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage,
|
|
|
133
139
|
{ d: convertInstantUpdateToDefinitionChanges(instantUpdate) } :
|
|
134
140
|
definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
|
|
135
141
|
}) :
|
|
136
|
-
definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator)
|
|
142
|
+
definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
|
|
143
|
+
if ((0, thenable_1.thenable)(definitionChangesRequest))
|
|
144
|
+
log.debug(constants_2.SYNC_FETCH, [definitionChangesFetcher.type, since, rbSince]);
|
|
145
|
+
return Promise.resolve(definitionChangesRequest)
|
|
137
146
|
.then(function (definitionChanges) {
|
|
138
147
|
var usedSegments = new Set();
|
|
139
148
|
var updatedDefinitions = [];
|
|
140
|
-
var ffUpdate = false;
|
|
141
149
|
if (definitionChanges.d) {
|
|
142
|
-
var _a = computeMutation(definitionChanges.d, usedSegments, splitFiltersValidation), updated = _a.updated, removed = _a.removed
|
|
143
|
-
updatedDefinitions = names;
|
|
150
|
+
var _a = computeMutation(definitionChanges.d, usedSegments, splitFiltersValidation), updated = _a.updated, removed = _a.removed;
|
|
144
151
|
log.debug(constants_2.SYNC_UPDATE, [definitionChangesFetcher.type, updated.length, removed.length]);
|
|
145
|
-
|
|
152
|
+
updatedDefinitions = definitions.update(updated, removed, definitionChanges.d.till);
|
|
146
153
|
}
|
|
147
|
-
var
|
|
154
|
+
var updatedRBSNames = [];
|
|
148
155
|
if (definitionChanges.rbs) {
|
|
149
156
|
var _b = computeMutation(definitionChanges.rbs, usedSegments), updated = _b.updated, removed = _b.removed;
|
|
150
157
|
log.debug(constants_2.SYNC_UPDATE, ['rule-based segments', updated.length, removed.length]);
|
|
151
|
-
|
|
158
|
+
updatedRBSNames = rbSegments.update(updated, removed, definitionChanges.rbs.till);
|
|
152
159
|
}
|
|
153
|
-
return Promise.all([
|
|
160
|
+
return Promise.all([updatedDefinitions, updatedRBSNames,
|
|
154
161
|
// @TODO if at least 1 segment fetch fails due to 404 and other segments are updated in the storage, SDK_UPDATE is not emitted
|
|
155
162
|
segments.registerSegments((0, sets_1.setToArray)(usedSegments))
|
|
156
163
|
]).then(function (_a) {
|
|
157
|
-
var
|
|
164
|
+
var updatedDefinitions = _a[0], updatedRBSNames = _a[1];
|
|
158
165
|
if (storage.save)
|
|
159
166
|
storage.save();
|
|
160
167
|
startingUp = false;
|
|
161
168
|
if (definitionsEventEmitter) {
|
|
162
169
|
// To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must wait for all registered segments to be fetched
|
|
163
|
-
return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((
|
|
170
|
+
return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((updatedDefinitions.length > 0 || updatedRBSNames.length > 0) && (!segmentsSyncTask || segmentsSyncTask.execute(true))))
|
|
164
171
|
.catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
165
172
|
.then(function (emitSplitsArrivedEvent) {
|
|
166
173
|
// emit SDK events
|
|
@@ -9,9 +9,11 @@ var constants_4 = require("../constants");
|
|
|
9
9
|
var parseUtils_1 = require("../parseUtils");
|
|
10
10
|
var constants_5 = require("./constants");
|
|
11
11
|
/**
|
|
12
|
-
* DefinitionsUpdateWorker factory
|
|
12
|
+
* DefinitionsUpdateWorker factory for Flags SDKs, where notifications pcn and changeNumber are environment-scoped
|
|
13
13
|
*/
|
|
14
|
-
function DefinitionsUpdateWorker(
|
|
14
|
+
function DefinitionsUpdateWorker(params, pollingManager) {
|
|
15
|
+
var log = params.settings.log, storage = params.storage, telemetryTracker = params.telemetryTracker, definitionsEventEmitter = params.readiness.definitions;
|
|
16
|
+
var definitionsSyncTask = pollingManager.definitionsSyncTask;
|
|
15
17
|
var ff = DefinitionsUpdateWorker(storage.definitions);
|
|
16
18
|
var rbs = DefinitionsUpdateWorker(storage.rbSegments);
|
|
17
19
|
function DefinitionsUpdateWorker(cache) {
|
|
@@ -96,7 +98,7 @@ function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsE
|
|
|
96
98
|
put: function (parsedData) {
|
|
97
99
|
if (parsedData.d && parsedData.c !== undefined) {
|
|
98
100
|
try {
|
|
99
|
-
var payload = (0, parseUtils_1.
|
|
101
|
+
var payload = (0, parseUtils_1.parseUpdatePayload)(parsedData.c, parsedData.d);
|
|
100
102
|
if (payload) {
|
|
101
103
|
(parsedData.type === constants_4.RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData, payload);
|
|
102
104
|
return;
|
|
@@ -119,7 +121,7 @@ function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsE
|
|
|
119
121
|
var changeNumber = _a.changeNumber, splitName = _a.splitName, defaultTreatment = _a.defaultTreatment;
|
|
120
122
|
if (storage.definitions.killLocally(splitName, defaultTreatment, changeNumber)) {
|
|
121
123
|
// trigger an SDK_UPDATE if Split was killed locally
|
|
122
|
-
definitionsEventEmitter.emit(constants_2.SDK_DEFINITIONS_ARRIVED, true);
|
|
124
|
+
definitionsEventEmitter.emit(constants_2.SDK_DEFINITIONS_ARRIVED, { type: constants_2.FLAGS_UPDATE, names: [splitName] }, true /* isSplitKill */);
|
|
123
125
|
}
|
|
124
126
|
// queues the SplitChanges fetch (only if changeNumber is newer)
|
|
125
127
|
ff.put({ changeNumber: changeNumber });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getDelay = exports.
|
|
3
|
+
exports.getDelay = exports.parseUpdatePayload = exports.isInBitmap = exports.parseBitmap = exports.parseCompressedData = void 0;
|
|
4
4
|
var decompress_1 = require("../../utils/decompress");
|
|
5
5
|
var base64_1 = require("../../utils/base64");
|
|
6
6
|
var murmur3_1 = require("../../utils/murmur3/murmur3");
|
|
@@ -79,14 +79,14 @@ function isInBitmap(bitmap, hash64hex) {
|
|
|
79
79
|
}
|
|
80
80
|
exports.isInBitmap = isInBitmap;
|
|
81
81
|
/**
|
|
82
|
-
* Parse
|
|
82
|
+
* Parse notifications for instant updates
|
|
83
83
|
*/
|
|
84
|
-
function
|
|
84
|
+
function parseUpdatePayload(compression, data) {
|
|
85
85
|
return compression > 0 ?
|
|
86
86
|
parseCompressedData(data, compression, false) :
|
|
87
87
|
JSON.parse((0, base64_1.decodeFromBase64)(data));
|
|
88
88
|
}
|
|
89
|
-
exports.
|
|
89
|
+
exports.parseUpdatePayload = parseUpdatePayload;
|
|
90
90
|
var DEFAULT_MAX_INTERVAL = 60000;
|
|
91
91
|
function getDelay(parsedData, matchingKey) {
|
|
92
92
|
if (parsedData.h === 0)
|
|
@@ -21,8 +21,9 @@ var constants_3 = require("../../utils/constants");
|
|
|
21
21
|
* - for server-side if key is not provided in settings.
|
|
22
22
|
* - for client-side, with support for multiple clients, if key is provided in settings
|
|
23
23
|
*/
|
|
24
|
-
function pushManagerFactory(params, pollingManager) {
|
|
25
|
-
|
|
24
|
+
function pushManagerFactory(params, pollingManager, definitionsUpdateWorkerFactory) {
|
|
25
|
+
if (definitionsUpdateWorkerFactory === void 0) { definitionsUpdateWorkerFactory = DefinitionsUpdateWorker_1.DefinitionsUpdateWorker; }
|
|
26
|
+
var settings = params.settings, storage = params.storage, serviceApi = params.serviceApi, platform = params.platform, telemetryTracker = params.telemetryTracker;
|
|
26
27
|
// `userKey` is the matching key of main client in client-side SDK.
|
|
27
28
|
// It can be used to check if running on client-side or server-side SDK.
|
|
28
29
|
var userKey = (0, key_1.checkIfServerSide)(settings) ? undefined : (0, key_1.getMatching)(settings.core.key);
|
|
@@ -44,7 +45,7 @@ function pushManagerFactory(params, pollingManager) {
|
|
|
44
45
|
// MySegmentsUpdateWorker (client-side) are initiated in `add` method
|
|
45
46
|
var segmentsUpdateWorker = userKey ? undefined : (0, SegmentsUpdateWorker_1.SegmentsUpdateWorker)(log, pollingManager.segmentsSyncTask, storage.segments);
|
|
46
47
|
// For server-side we pass the segmentsSyncTask, used by DefinitionsUpdateWorker to fetch new segments
|
|
47
|
-
var definitionsUpdateWorker = (
|
|
48
|
+
var definitionsUpdateWorker = definitionsUpdateWorkerFactory(params, pollingManager);
|
|
48
49
|
// [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
|
|
49
50
|
// Hash64 is used to process membership update events and dispatch actions to the corresponding MySegmentsUpdateWorker.
|
|
50
51
|
var clients = {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { objectAssign } from '
|
|
2
|
-
import { decodeJWTtoken } from '
|
|
1
|
+
import { objectAssign } from '../utils/lang/objectAssign';
|
|
2
|
+
import { decodeJWTtoken } from '../utils/jwt';
|
|
3
3
|
/**
|
|
4
4
|
* Factory of authentication function.
|
|
5
5
|
*
|
package/esm/services/splitApi.js
CHANGED
|
@@ -2,7 +2,7 @@ import { splitHttpClientFactory } from './splitHttpClient';
|
|
|
2
2
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
3
3
|
import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MEMBERSHIPS } from '../utils/constants';
|
|
4
4
|
import { ERROR_TOO_MANY_SETS } from '../logger/constants';
|
|
5
|
-
import { fetchAuthFactory } from '
|
|
5
|
+
import { fetchAuthFactory } from './fetchAuth';
|
|
6
6
|
var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
|
|
7
7
|
function userKeyToQueryParam(userKey) {
|
|
8
8
|
return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
|
|
@@ -14,7 +14,8 @@ var AbstractDefinitionsCacheAsync = /** @class */ (function () {
|
|
|
14
14
|
Promise.all(toRemove.map(function (removedFF) { return _this.remove(removedFF); }))
|
|
15
15
|
]).then(function (_a) {
|
|
16
16
|
var added = _a[1], removed = _a[2];
|
|
17
|
-
return
|
|
17
|
+
return toRemove.filter(function (_, i) { return removed[i]; })
|
|
18
|
+
.concat(toAdd.filter(function (_, i) { return added[i]; }).map(function (addedFF) { return addedFF.name; }));
|
|
18
19
|
});
|
|
19
20
|
};
|
|
20
21
|
// @TODO revisit segment-related methods ('usesSegments', 'getRegisteredSegments', 'registerSegments')
|
|
@@ -9,8 +9,8 @@ var AbstractDefinitionsCacheSync = /** @class */ (function () {
|
|
|
9
9
|
}
|
|
10
10
|
AbstractDefinitionsCacheSync.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
11
11
|
var _this = this;
|
|
12
|
-
var updated =
|
|
13
|
-
|
|
12
|
+
var updated = toRemove.filter(function (removedFF) { return _this.remove(removedFF); })
|
|
13
|
+
.concat(toAdd.filter(function (addedFF) { return _this.add(addedFF); }).map(function (addedFF) { return addedFF.name; }));
|
|
14
14
|
this.setChangeNumber(changeNumber);
|
|
15
15
|
return updated;
|
|
16
16
|
};
|
|
@@ -72,6 +72,8 @@ var DefinitionsCacheInLocal = /** @class */ (function (_super) {
|
|
|
72
72
|
var definitionFromStorage = this.storage.getItem(definitionKey);
|
|
73
73
|
var previousDefinition = definitionFromStorage ? JSON.parse(definitionFromStorage) : null;
|
|
74
74
|
if (previousDefinition) {
|
|
75
|
+
if (previousDefinition.changeNumber >= definition.changeNumber)
|
|
76
|
+
return false;
|
|
75
77
|
this._decrementCounts(previousDefinition);
|
|
76
78
|
this.removeFromSets(previousDefinition.name, previousDefinition.sets);
|
|
77
79
|
}
|
|
@@ -95,7 +97,8 @@ var DefinitionsCacheInLocal = /** @class */ (function (_super) {
|
|
|
95
97
|
};
|
|
96
98
|
DefinitionsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
97
99
|
try {
|
|
98
|
-
|
|
100
|
+
if (changeNumber !== undefined)
|
|
101
|
+
this.storage.setItem(this.keys.buildDefinitionsTillKey(), changeNumber + '');
|
|
99
102
|
// update "last updated" timestamp with current time
|
|
100
103
|
this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
|
|
101
104
|
this.hasSync = true;
|
|
@@ -15,14 +15,15 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
15
15
|
};
|
|
16
16
|
RBSegmentsCacheInLocal.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
17
17
|
var _this = this;
|
|
18
|
-
var updated =
|
|
19
|
-
|
|
18
|
+
var updated = toRemove.filter(function (name) { return _this.remove(name); })
|
|
19
|
+
.concat(toAdd.filter(function (rbSegment) { return _this.add(rbSegment); }).map(function (rbSegment) { return rbSegment.name; }));
|
|
20
20
|
this.setChangeNumber(changeNumber);
|
|
21
21
|
return updated;
|
|
22
22
|
};
|
|
23
23
|
RBSegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
24
24
|
try {
|
|
25
|
-
|
|
25
|
+
if (changeNumber !== undefined)
|
|
26
|
+
this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
|
|
26
27
|
this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
|
|
27
28
|
}
|
|
28
29
|
catch (e) {
|
|
@@ -42,6 +43,8 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
42
43
|
var rbSegmentKey = this.keys.buildRBSegmentKey(name);
|
|
43
44
|
var rbSegmentFromStorage = this.storage.getItem(rbSegmentKey);
|
|
44
45
|
var previous = rbSegmentFromStorage ? JSON.parse(rbSegmentFromStorage) : null;
|
|
46
|
+
if (previous && previous.changeNumber >= rbSegment.changeNumber)
|
|
47
|
+
return false;
|
|
45
48
|
this.storage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
|
|
46
49
|
var usesSegmentsDiff = 0;
|
|
47
50
|
if (previous && usesSegments(previous))
|
|
@@ -27,6 +27,8 @@ var DefinitionsCacheInMemory = /** @class */ (function (_super) {
|
|
|
27
27
|
var name = definition.name;
|
|
28
28
|
var previousDefinition = this.get(name);
|
|
29
29
|
if (previousDefinition) { // We had this Split already
|
|
30
|
+
if (previousDefinition.changeNumber >= definition.changeNumber)
|
|
31
|
+
return false;
|
|
30
32
|
var previousTtName = previousDefinition.trafficTypeName;
|
|
31
33
|
this.ttCache[previousTtName]--;
|
|
32
34
|
if (!this.ttCache[previousTtName])
|
|
@@ -67,7 +69,8 @@ var DefinitionsCacheInMemory = /** @class */ (function (_super) {
|
|
|
67
69
|
return this.definitionsCache[name] || null;
|
|
68
70
|
};
|
|
69
71
|
DefinitionsCacheInMemory.prototype.setChangeNumber = function (changeNumber) {
|
|
70
|
-
|
|
72
|
+
if (changeNumber !== undefined)
|
|
73
|
+
this.changeNumber = changeNumber;
|
|
71
74
|
return true;
|
|
72
75
|
};
|
|
73
76
|
DefinitionsCacheInMemory.prototype.getChangeNumber = function () {
|
|
@@ -13,14 +13,17 @@ var RBSegmentsCacheInMemory = /** @class */ (function () {
|
|
|
13
13
|
};
|
|
14
14
|
RBSegmentsCacheInMemory.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
15
15
|
var _this = this;
|
|
16
|
-
var updated =
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
var updated = toRemove.filter(function (name) { return _this.remove(name); })
|
|
17
|
+
.concat(toAdd.filter(function (rbSegment) { return _this.add(rbSegment); }).map(function (rbSegment) { return rbSegment.name; }));
|
|
18
|
+
if (changeNumber !== undefined)
|
|
19
|
+
this.changeNumber = changeNumber;
|
|
19
20
|
return updated;
|
|
20
21
|
};
|
|
21
22
|
RBSegmentsCacheInMemory.prototype.add = function (rbSegment) {
|
|
22
23
|
var name = rbSegment.name;
|
|
23
24
|
var previous = this.get(name);
|
|
25
|
+
if (previous && previous.changeNumber >= rbSegment.changeNumber)
|
|
26
|
+
return false;
|
|
24
27
|
if (previous && usesSegments(previous))
|
|
25
28
|
this.segmentsCount--;
|
|
26
29
|
this.cache[name] = rbSegment;
|
|
@@ -73,6 +73,8 @@ var DefinitionsCacheInRedis = /** @class */ (function (_super) {
|
|
|
73
73
|
var parsedPreviousDefinition, stringifiedNewDefinition;
|
|
74
74
|
try {
|
|
75
75
|
parsedPreviousDefinition = definitionFromStorage ? JSON.parse(definitionFromStorage) : undefined;
|
|
76
|
+
if (parsedPreviousDefinition && parsedPreviousDefinition.changeNumber >= definition.changeNumber)
|
|
77
|
+
return false;
|
|
76
78
|
stringifiedNewDefinition = JSON.stringify(definition);
|
|
77
79
|
}
|
|
78
80
|
catch (e) {
|
|
@@ -87,8 +89,8 @@ var DefinitionsCacheInRedis = /** @class */ (function (_super) {
|
|
|
87
89
|
if (parsedPreviousDefinition)
|
|
88
90
|
return _this._decrementCounts(parsedPreviousDefinition);
|
|
89
91
|
});
|
|
90
|
-
}).then(function () { return _this._updateSets(name, parsedPreviousDefinition && parsedPreviousDefinition.sets, definition.sets); });
|
|
91
|
-
})
|
|
92
|
+
}).then(function () { return _this._updateSets(name, parsedPreviousDefinition && parsedPreviousDefinition.sets, definition.sets); }).then(function () { return true; });
|
|
93
|
+
});
|
|
92
94
|
};
|
|
93
95
|
/**
|
|
94
96
|
* Remove a given definition.
|
|
@@ -98,11 +100,11 @@ var DefinitionsCacheInRedis = /** @class */ (function (_super) {
|
|
|
98
100
|
DefinitionsCacheInRedis.prototype.remove = function (name) {
|
|
99
101
|
var _this = this;
|
|
100
102
|
return this.get(name).then(function (definition) {
|
|
101
|
-
if (definition)
|
|
102
|
-
return
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
if (!definition)
|
|
104
|
+
return false;
|
|
105
|
+
return _this._decrementCounts(definition).then(function () { return _this._updateSets(name, definition.sets); }).then(function () {
|
|
106
|
+
return _this.redis.del(_this.keys.buildDefinitionKey(name)).then(function (status) { return status === 1; });
|
|
107
|
+
});
|
|
106
108
|
});
|
|
107
109
|
};
|
|
108
110
|
/**
|
|
@@ -123,7 +125,9 @@ var DefinitionsCacheInRedis = /** @class */ (function (_super) {
|
|
|
123
125
|
* or rejected if it fails.
|
|
124
126
|
*/
|
|
125
127
|
DefinitionsCacheInRedis.prototype.setChangeNumber = function (changeNumber) {
|
|
126
|
-
|
|
128
|
+
if (changeNumber !== undefined) {
|
|
129
|
+
return this.redis.set(this.keys.buildDefinitionsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
|
|
130
|
+
}
|
|
127
131
|
};
|
|
128
132
|
/**
|
|
129
133
|
* Get till number or -1 if it's not defined.
|
|
@@ -25,22 +25,32 @@ var RBSegmentsCacheInRedis = /** @class */ (function () {
|
|
|
25
25
|
var _this = this;
|
|
26
26
|
return Promise.all([
|
|
27
27
|
this.setChangeNumber(changeNumber),
|
|
28
|
-
Promise.all(toAdd.map(function (
|
|
29
|
-
|
|
30
|
-
var stringifiedNewRBSegment = JSON.stringify(toAdd);
|
|
31
|
-
return _this.redis.set(key, stringifiedNewRBSegment).then(function () { return true; });
|
|
32
|
-
})),
|
|
33
|
-
Promise.all(toRemove.map(function (toRemove) {
|
|
34
|
-
var key = _this.keys.buildRBSegmentKey(toRemove);
|
|
35
|
-
return _this.redis.del(key).then(function (status) { return status === 1; });
|
|
36
|
-
}))
|
|
28
|
+
Promise.all(toAdd.map(function (rbSegment) { return _this.add(rbSegment); })),
|
|
29
|
+
Promise.all(toRemove.map(function (name) { return _this.remove(name); }))
|
|
37
30
|
]).then(function (_a) {
|
|
38
31
|
var added = _a[1], removed = _a[2];
|
|
39
|
-
return
|
|
32
|
+
return toRemove.filter(function (_, i) { return removed[i]; })
|
|
33
|
+
.concat(toAdd.filter(function (_, i) { return added[i]; }).map(function (rbSegment) { return rbSegment.name; }));
|
|
40
34
|
});
|
|
41
35
|
};
|
|
36
|
+
RBSegmentsCacheInRedis.prototype.add = function (rbSegment) {
|
|
37
|
+
var _this = this;
|
|
38
|
+
var key = this.keys.buildRBSegmentKey(rbSegment.name);
|
|
39
|
+
return this.get(rbSegment.name).then(function (previous) {
|
|
40
|
+
if (previous && previous.changeNumber >= rbSegment.changeNumber)
|
|
41
|
+
return false;
|
|
42
|
+
var stringifiedNewRBSegment = JSON.stringify(rbSegment);
|
|
43
|
+
return _this.redis.set(key, stringifiedNewRBSegment).then(function () { return true; });
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
RBSegmentsCacheInRedis.prototype.remove = function (name) {
|
|
47
|
+
var key = this.keys.buildRBSegmentKey(name);
|
|
48
|
+
return this.redis.del(key).then(function (status) { return status === 1; });
|
|
49
|
+
};
|
|
42
50
|
RBSegmentsCacheInRedis.prototype.setChangeNumber = function (changeNumber) {
|
|
43
|
-
|
|
51
|
+
if (changeNumber !== undefined) {
|
|
52
|
+
return this.redis.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
|
|
53
|
+
}
|
|
44
54
|
};
|
|
45
55
|
RBSegmentsCacheInRedis.prototype.getChangeNumber = function () {
|
|
46
56
|
var _this = this;
|
|
@@ -60,6 +60,8 @@ var DefinitionsCachePluggable = /** @class */ (function (_super) {
|
|
|
60
60
|
var parsedPreviousDefinition, stringifiedNewDefinition;
|
|
61
61
|
try {
|
|
62
62
|
parsedPreviousDefinition = definitionFromStorage ? JSON.parse(definitionFromStorage) : undefined;
|
|
63
|
+
if (parsedPreviousDefinition && parsedPreviousDefinition.changeNumber >= definition.changeNumber)
|
|
64
|
+
return false;
|
|
63
65
|
stringifiedNewDefinition = JSON.stringify(definition);
|
|
64
66
|
}
|
|
65
67
|
catch (e) {
|
|
@@ -74,8 +76,8 @@ var DefinitionsCachePluggable = /** @class */ (function (_super) {
|
|
|
74
76
|
if (parsedPreviousDefinition)
|
|
75
77
|
return _this._decrementCounts(parsedPreviousDefinition);
|
|
76
78
|
});
|
|
77
|
-
}).then(function () { return _this._updateSets(name, parsedPreviousDefinition && parsedPreviousDefinition.sets, definition.sets); });
|
|
78
|
-
})
|
|
79
|
+
}).then(function () { return _this._updateSets(name, parsedPreviousDefinition && parsedPreviousDefinition.sets, definition.sets); }).then(function () { return true; });
|
|
80
|
+
});
|
|
79
81
|
};
|
|
80
82
|
/**
|
|
81
83
|
* Remove a given definition.
|
|
@@ -85,11 +87,11 @@ var DefinitionsCachePluggable = /** @class */ (function (_super) {
|
|
|
85
87
|
DefinitionsCachePluggable.prototype.remove = function (name) {
|
|
86
88
|
var _this = this;
|
|
87
89
|
return this.get(name).then(function (definition) {
|
|
88
|
-
if (definition)
|
|
89
|
-
return
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
if (!definition)
|
|
91
|
+
return false;
|
|
92
|
+
return _this._decrementCounts(definition).then(function () { return _this._updateSets(name, definition.sets); }).then(function () {
|
|
93
|
+
return _this.wrapper.del(_this.keys.buildDefinitionKey(name));
|
|
94
|
+
});
|
|
93
95
|
});
|
|
94
96
|
};
|
|
95
97
|
/**
|
|
@@ -183,7 +185,9 @@ var DefinitionsCachePluggable = /** @class */ (function (_super) {
|
|
|
183
185
|
* or rejected if it fails (e.g., wrapper operation fails).
|
|
184
186
|
*/
|
|
185
187
|
DefinitionsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
|
|
186
|
-
|
|
188
|
+
if (changeNumber !== undefined) {
|
|
189
|
+
return this.wrapper.set(this.keys.buildDefinitionsTillKey(), changeNumber + '');
|
|
190
|
+
}
|
|
187
191
|
};
|
|
188
192
|
/**
|
|
189
193
|
* Get till number or -1 if it's not defined.
|
|
@@ -25,22 +25,32 @@ var RBSegmentsCachePluggable = /** @class */ (function () {
|
|
|
25
25
|
var _this = this;
|
|
26
26
|
return Promise.all([
|
|
27
27
|
this.setChangeNumber(changeNumber),
|
|
28
|
-
Promise.all(toAdd.map(function (
|
|
29
|
-
|
|
30
|
-
var stringifiedNewRBSegment = JSON.stringify(toAdd);
|
|
31
|
-
return _this.wrapper.set(key, stringifiedNewRBSegment).then(function () { return true; });
|
|
32
|
-
})),
|
|
33
|
-
Promise.all(toRemove.map(function (toRemove) {
|
|
34
|
-
var key = _this.keys.buildRBSegmentKey(toRemove);
|
|
35
|
-
return _this.wrapper.del(key);
|
|
36
|
-
}))
|
|
28
|
+
Promise.all(toAdd.map(function (rbSegment) { return _this.add(rbSegment); })),
|
|
29
|
+
Promise.all(toRemove.map(function (name) { return _this.remove(name); }))
|
|
37
30
|
]).then(function (_a) {
|
|
38
31
|
var added = _a[1], removed = _a[2];
|
|
39
|
-
return
|
|
32
|
+
return toRemove.filter(function (_, i) { return removed[i]; })
|
|
33
|
+
.concat(toAdd.filter(function (_, i) { return added[i]; }).map(function (rbSegment) { return rbSegment.name; }));
|
|
40
34
|
});
|
|
41
35
|
};
|
|
36
|
+
RBSegmentsCachePluggable.prototype.add = function (rbSegment) {
|
|
37
|
+
var _this = this;
|
|
38
|
+
var key = this.keys.buildRBSegmentKey(rbSegment.name);
|
|
39
|
+
return this.get(rbSegment.name).then(function (previous) {
|
|
40
|
+
if (previous && previous.changeNumber >= rbSegment.changeNumber)
|
|
41
|
+
return false;
|
|
42
|
+
var stringifiedNewRBSegment = JSON.stringify(rbSegment);
|
|
43
|
+
return _this.wrapper.set(key, stringifiedNewRBSegment).then(function () { return true; });
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
RBSegmentsCachePluggable.prototype.remove = function (name) {
|
|
47
|
+
var key = this.keys.buildRBSegmentKey(name);
|
|
48
|
+
return this.wrapper.del(key);
|
|
49
|
+
};
|
|
42
50
|
RBSegmentsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
|
|
43
|
-
|
|
51
|
+
if (changeNumber !== undefined) {
|
|
52
|
+
return this.wrapper.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
|
|
53
|
+
}
|
|
44
54
|
};
|
|
45
55
|
RBSegmentsCachePluggable.prototype.getChangeNumber = function () {
|
|
46
56
|
var _this = this;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { __assign } from "tslib";
|
|
2
|
+
import { CONTROL } from '../../../utils/constants';
|
|
3
|
+
/**
|
|
4
|
+
* Factory of a stateful function that, given the current mocked definitions, returns the changes since the previous call
|
|
5
|
+
* as an `IDefinitionChangesResponse`, i.e., the full definitions that were added or modified, and the names of the removed ones.
|
|
6
|
+
* Definitions are compared by value. The response `till` is an incrementing value based on the current time.
|
|
7
|
+
* Definitions have no `changeNumber`, so storages never consider them outdated.
|
|
8
|
+
*
|
|
9
|
+
* The response has no `d` property if there are no changes, except for the first call, which reports the (possibly empty) mock.
|
|
10
|
+
* It is meant to be used by `IDefinitionsParser` implementations, such as `splitsParserFromSettings`.
|
|
11
|
+
*/
|
|
12
|
+
export function definitionChangesBuilderFactory() {
|
|
13
|
+
var previous; // serialized definitions of the last reported mock, by name
|
|
14
|
+
var lastTill = 0;
|
|
15
|
+
return function definitionChangesBuilder(mock) {
|
|
16
|
+
var current = {};
|
|
17
|
+
var updatedNames = Object.keys(mock).reduce(function (updatedNames, name) {
|
|
18
|
+
current[name] = JSON.stringify(mock[name]);
|
|
19
|
+
if (!previous || previous[name] !== current[name])
|
|
20
|
+
updatedNames.push(name);
|
|
21
|
+
return updatedNames;
|
|
22
|
+
}, []);
|
|
23
|
+
var removed = previous ? Object.keys(previous).filter(function (name) { return current[name] === undefined; }) : [];
|
|
24
|
+
// Only the first call reports an empty change
|
|
25
|
+
if (previous && updatedNames.length === 0 && removed.length === 0)
|
|
26
|
+
return {};
|
|
27
|
+
previous = current;
|
|
28
|
+
// Incrementing `till` based on the current time
|
|
29
|
+
var till = lastTill = Math.max(Date.now(), lastTill + 1);
|
|
30
|
+
var updated = updatedNames.map(function (name) { return (__assign({ name: name, status: 'ACTIVE', killed: false, trafficAllocation: 100, defaultTreatment: CONTROL }, mock[name])); });
|
|
31
|
+
return { d: { updated: updated, removed: removed, till: till } };
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -1,42 +1,15 @@
|
|
|
1
|
-
import { isObject, forOwn
|
|
1
|
+
import { isObject, forOwn } from '../../../utils/lang';
|
|
2
2
|
import { parseCondition } from './parseCondition';
|
|
3
|
-
|
|
4
|
-
if (typeof prev !== typeof curr)
|
|
5
|
-
return true;
|
|
6
|
-
if (typeof prev === 'string') { // strings treatments, just compare
|
|
7
|
-
return prev !== curr;
|
|
8
|
-
}
|
|
9
|
-
else { // has treatment and config, compare both
|
|
10
|
-
return prev.treatment !== curr.treatment || prev.config !== curr.config;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
3
|
+
import { definitionChangesBuilderFactory } from './definitionChangesBuilder';
|
|
13
4
|
export function splitsParserFromSettingsFactory() {
|
|
14
|
-
var
|
|
15
|
-
function mockUpdated(currentData) {
|
|
16
|
-
var names = Object.keys(currentData);
|
|
17
|
-
// Different amount of items
|
|
18
|
-
if (names.length !== Object.keys(previousMock).length) {
|
|
19
|
-
previousMock = merge({}, currentData);
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
return names.some(function (name) {
|
|
23
|
-
var newSplit = !previousMock[name];
|
|
24
|
-
var newTreatment = hasTreatmentChanged(previousMock[name], currentData[name]);
|
|
25
|
-
var changed = newSplit || newTreatment;
|
|
26
|
-
if (changed)
|
|
27
|
-
previousMock = merge({}, currentData);
|
|
28
|
-
return changed;
|
|
29
|
-
});
|
|
30
|
-
}
|
|
5
|
+
var definitionChangesBuilder = definitionChangesBuilderFactory();
|
|
31
6
|
/**
|
|
32
7
|
*
|
|
33
8
|
* @param settings - validated object with mocked features mapping.
|
|
34
9
|
*/
|
|
35
10
|
return function splitsParserFromSettings(settings) {
|
|
36
11
|
var features = settings.features || {};
|
|
37
|
-
|
|
38
|
-
return false;
|
|
39
|
-
var splitObjects = {};
|
|
12
|
+
var mock = {};
|
|
40
13
|
forOwn(features, function (data, splitName) {
|
|
41
14
|
var treatment = data;
|
|
42
15
|
var config = null;
|
|
@@ -47,12 +20,12 @@ export function splitsParserFromSettingsFactory() {
|
|
|
47
20
|
var configurations = {};
|
|
48
21
|
if (config !== null)
|
|
49
22
|
configurations[treatment] = config;
|
|
50
|
-
|
|
23
|
+
mock[splitName] = {
|
|
51
24
|
trafficTypeName: 'localhost',
|
|
52
25
|
conditions: [parseCondition({ treatment: treatment })],
|
|
53
26
|
configurations: configurations
|
|
54
27
|
};
|
|
55
28
|
});
|
|
56
|
-
return
|
|
29
|
+
return definitionChangesBuilder(mock);
|
|
57
30
|
};
|
|
58
31
|
}
|