@splitsoftware/splitio-commons 3.1.1-rc.10 → 3.1.1-rc.11
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 +2 -0
- package/cjs/evaluator/condition/index.js +2 -2
- package/cjs/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +5 -8
- package/cjs/evaluator/index.js +81 -71
- package/cjs/listeners/browser.js +2 -1
- package/cjs/listeners/node.js +4 -4
- package/cjs/logger/constants.js +15 -20
- package/cjs/logger/messages/debug.js +5 -6
- package/cjs/logger/messages/error.js +3 -3
- package/cjs/logger/messages/info.js +3 -4
- package/cjs/logger/messages/warn.js +6 -7
- package/cjs/platform/browser.js +15 -0
- package/cjs/platform/getEventSource/browser.js +8 -0
- package/cjs/platform/getEventSource/eventsource.js +480 -0
- package/cjs/platform/getEventSource/node.js +26 -0
- package/cjs/platform/getFetch/browser.js +9 -0
- package/cjs/platform/getFetch/node.js +27 -0
- package/cjs/platform/getOptions/node.js +25 -0
- package/cjs/platform/node.js +17 -0
- package/cjs/presets/serverSide.js +2 -2
- package/cjs/readiness/constants.js +5 -4
- package/cjs/readiness/readinessManager.js +23 -23
- package/cjs/readiness/sdkReadinessManager.js +1 -17
- package/cjs/sdkClient/client.js +24 -50
- package/cjs/sdkClient/clientInputValidation.js +6 -17
- package/cjs/sdkClient/sdkClient.js +3 -60
- package/cjs/sdkClient/sdkLifecycle.js +74 -0
- package/cjs/sdkClient/trackMethod.js +56 -0
- package/cjs/sdkFactory/index.js +11 -15
- package/cjs/sdkManager/index.js +5 -5
- package/cjs/services/authProvider.js +80 -0
- package/cjs/services/decorateHeaders.js +2 -1
- package/cjs/services/secureSplitHttpClient.js +36 -0
- package/cjs/services/serviceApi.js +147 -0
- package/cjs/services/splitApi.js +24 -10
- package/cjs/services/splitHttpClient.js +3 -5
- package/cjs/storages/AbstractDefinitionsCacheAsync.js +51 -0
- package/cjs/storages/AbstractDefinitionsCacheSync.js +76 -0
- package/cjs/storages/KeyBuilder.js +6 -6
- package/cjs/storages/KeyBuilderCS.js +5 -5
- package/cjs/storages/KeyBuilderSS.js +2 -2
- package/cjs/storages/getRolloutPlan.js +3 -3
- package/cjs/storages/inLocalStorage/DefinitionsCacheInLocal.js +194 -0
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -2
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +10 -10
- package/cjs/storages/inLocalStorage/index.js +6 -6
- package/cjs/storages/inLocalStorage/validateCache.js +3 -3
- package/cjs/storages/inMemory/DefinitionsCacheInMemory.js +121 -0
- package/cjs/storages/inMemory/InMemoryStorage.js +4 -4
- package/cjs/storages/inMemory/InMemoryStorageCS.js +5 -5
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +5 -5
- package/cjs/storages/inMemory/SegmentsCacheInMemory.js +1 -1
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +5 -5
- package/cjs/storages/inRedis/{SplitsCacheInRedis.js → DefinitionsCacheInRedis.js} +77 -77
- package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/index.js +2 -2
- package/cjs/storages/pluggable/DefinitionsCachePluggable.js +212 -0
- package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +1 -1
- package/cjs/storages/pluggable/index.js +2 -2
- package/cjs/storages/setRolloutPlan.js +4 -4
- package/cjs/storages/utils.js +1 -0
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +5 -5
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +24 -15
- package/cjs/sync/polling/pollingManagerCS.js +86 -81
- package/cjs/sync/polling/pollingManagerSS.js +44 -36
- package/cjs/sync/polling/syncTasks/definitionsSyncTask.js +13 -0
- package/cjs/sync/polling/syncTasks/segmentsSyncTask.js +2 -3
- package/cjs/sync/polling/updaters/{splitChangesUpdater.js → definitionChangesUpdater.js} +66 -69
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +3 -3
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +6 -6
- package/cjs/sync/streaming/AuthClient/index.js +13 -14
- package/cjs/sync/streaming/SSEHandler/NotificationKeeper.js +1 -1
- package/cjs/sync/streaming/SSEHandler/index.js +2 -1
- package/cjs/sync/streaming/UpdateWorkers/{SplitsUpdateWorker.js → DefinitionsUpdateWorker.js} +16 -19
- package/cjs/sync/streaming/constants.js +4 -3
- package/cjs/sync/streaming/parseUtils.js +11 -11
- package/cjs/sync/streaming/pushManager.js +20 -25
- package/cjs/sync/submitters/eventsSubmitter.js +1 -1
- package/cjs/sync/submitters/impressionCountsSubmitter.js +1 -1
- package/cjs/sync/submitters/impressionsSubmitter.js +5 -4
- package/cjs/sync/submitters/telemetrySubmitter.js +3 -4
- package/cjs/sync/submitters/uniqueKeysSubmitter.js +1 -1
- package/cjs/sync/syncManagerOnline.js +5 -5
- package/cjs/utils/Backoff.js +35 -3
- package/cjs/utils/EventEmitter.js +391 -0
- package/cjs/utils/filter/bloomFilter.js +37 -0
- package/cjs/utils/inputValidation/{split.js → definition.js} +10 -10
- package/cjs/utils/inputValidation/{splitExistence.js → definitionExistence.js} +6 -6
- package/cjs/utils/inputValidation/definitions.js +25 -0
- package/cjs/utils/inputValidation/index.js +7 -7
- package/cjs/utils/inputValidation/isOperational.js +4 -4
- package/cjs/utils/inputValidation/target.js +22 -0
- package/cjs/utils/labels/index.js +3 -3
- package/cjs/utils/settingsValidation/index.js +2 -0
- package/cjs/utils/settingsValidation/splitFilters.js +3 -3
- package/cjs/utils/settingsValidation/url.js +6 -2
- package/esm/evaluator/condition/index.js +2 -2
- package/esm/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +5 -8
- package/esm/evaluator/index.js +80 -71
- package/esm/listeners/browser.js +2 -1
- package/esm/listeners/node.js +4 -4
- package/esm/logger/constants.js +12 -17
- package/esm/logger/messages/debug.js +5 -6
- package/esm/logger/messages/error.js +3 -3
- package/esm/logger/messages/info.js +3 -4
- package/esm/logger/messages/warn.js +6 -7
- package/esm/platform/browser.js +12 -0
- package/esm/platform/getEventSource/browser.js +4 -0
- package/esm/platform/getEventSource/eventsource.js +480 -0
- package/esm/platform/getEventSource/node.js +20 -0
- package/esm/platform/getFetch/browser.js +5 -0
- package/esm/platform/getFetch/node.js +22 -0
- package/esm/platform/getOptions/node.js +20 -0
- package/esm/platform/node.js +14 -0
- package/esm/presets/serverSide.js +2 -2
- package/esm/readiness/constants.js +4 -3
- package/esm/readiness/readinessManager.js +24 -24
- package/esm/readiness/sdkReadinessManager.js +2 -18
- package/esm/sdkClient/client.js +23 -50
- package/esm/sdkClient/clientInputValidation.js +8 -19
- package/esm/sdkClient/sdkClient.js +3 -60
- package/esm/sdkClient/sdkLifecycle.js +70 -0
- package/esm/sdkClient/trackMethod.js +52 -0
- package/esm/sdkFactory/index.js +12 -16
- package/esm/sdkManager/index.js +6 -6
- package/esm/services/authProvider.js +76 -0
- package/esm/services/decorateHeaders.js +2 -1
- package/esm/services/secureSplitHttpClient.js +32 -0
- package/esm/services/serviceApi.js +143 -0
- package/esm/services/splitApi.js +24 -10
- package/esm/services/splitHttpClient.js +3 -5
- package/esm/storages/AbstractDefinitionsCacheAsync.js +48 -0
- package/esm/storages/AbstractDefinitionsCacheSync.js +71 -0
- package/esm/storages/KeyBuilder.js +6 -6
- package/esm/storages/KeyBuilderCS.js +5 -5
- package/esm/storages/KeyBuilderSS.js +2 -2
- package/esm/storages/getRolloutPlan.js +3 -3
- package/esm/storages/inLocalStorage/DefinitionsCacheInLocal.js +191 -0
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -2
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +7 -7
- package/esm/storages/inLocalStorage/index.js +6 -6
- package/esm/storages/inLocalStorage/validateCache.js +3 -3
- package/esm/storages/inMemory/DefinitionsCacheInMemory.js +118 -0
- package/esm/storages/inMemory/InMemoryStorage.js +4 -4
- package/esm/storages/inMemory/InMemoryStorageCS.js +5 -5
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +2 -2
- package/esm/storages/inMemory/SegmentsCacheInMemory.js +1 -1
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +5 -5
- package/esm/storages/inRedis/{SplitsCacheInRedis.js → DefinitionsCacheInRedis.js} +76 -76
- package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +1 -1
- package/esm/storages/inRedis/index.js +2 -2
- package/esm/storages/pluggable/DefinitionsCachePluggable.js +209 -0
- package/esm/storages/pluggable/RBSegmentsCachePluggable.js +1 -1
- package/esm/storages/pluggable/index.js +2 -2
- package/esm/storages/setRolloutPlan.js +4 -4
- package/esm/storages/utils.js +1 -0
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +6 -6
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +25 -16
- package/esm/sync/polling/pollingManagerCS.js +87 -82
- package/esm/sync/polling/pollingManagerSS.js +44 -36
- package/esm/sync/polling/syncTasks/definitionsSyncTask.js +9 -0
- package/esm/sync/polling/syncTasks/segmentsSyncTask.js +2 -3
- package/esm/sync/polling/updaters/definitionChangesUpdater.js +191 -0
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +3 -3
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +7 -7
- package/esm/sync/streaming/AuthClient/index.js +11 -11
- package/esm/sync/streaming/SSEHandler/NotificationKeeper.js +2 -2
- package/esm/sync/streaming/SSEHandler/index.js +3 -2
- package/esm/sync/streaming/UpdateWorkers/{SplitsUpdateWorker.js → DefinitionsUpdateWorker.js} +15 -18
- package/esm/sync/streaming/constants.js +3 -2
- package/esm/sync/streaming/parseUtils.js +9 -9
- package/esm/sync/streaming/pushManager.js +22 -27
- package/esm/sync/submitters/eventsSubmitter.js +1 -1
- package/esm/sync/submitters/impressionCountsSubmitter.js +1 -1
- package/esm/sync/submitters/impressionsSubmitter.js +5 -4
- package/esm/sync/submitters/telemetrySubmitter.js +3 -4
- package/esm/sync/submitters/uniqueKeysSubmitter.js +1 -1
- package/esm/sync/syncManagerOnline.js +4 -4
- package/esm/utils/Backoff.js +35 -3
- package/esm/utils/EventEmitter.js +387 -0
- package/esm/utils/filter/bloomFilter.js +33 -0
- package/esm/utils/inputValidation/{split.js → definition.js} +8 -8
- package/esm/utils/inputValidation/definitionExistence.js +15 -0
- package/esm/utils/inputValidation/definitions.js +21 -0
- package/esm/utils/inputValidation/index.js +3 -3
- package/esm/utils/inputValidation/isOperational.js +4 -4
- package/esm/utils/inputValidation/target.js +18 -0
- package/esm/utils/labels/index.js +2 -2
- package/esm/utils/settingsValidation/index.js +2 -0
- package/esm/utils/settingsValidation/splitFilters.js +3 -3
- package/esm/utils/settingsValidation/url.js +6 -2
- package/package.json +1 -1
- package/cjs/storages/AbstractSplitsCacheAsync.js +0 -51
- package/cjs/storages/AbstractSplitsCacheSync.js +0 -76
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +0 -194
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +0 -121
- package/cjs/storages/pluggable/SplitsCachePluggable.js +0 -212
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +0 -13
- package/cjs/utils/inputValidation/splits.js +0 -25
- package/esm/storages/AbstractSplitsCacheAsync.js +0 -48
- package/esm/storages/AbstractSplitsCacheSync.js +0 -71
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +0 -191
- package/esm/storages/inMemory/SplitsCacheInMemory.js +0 -118
- package/esm/storages/pluggable/SplitsCachePluggable.js +0 -209
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +0 -9
- package/esm/sync/polling/updaters/splitChangesUpdater.js +0 -194
- package/esm/utils/inputValidation/splitExistence.js +0 -15
- package/esm/utils/inputValidation/splits.js +0 -21
package/cjs/sdkFactory/index.js
CHANGED
|
@@ -16,7 +16,7 @@ var fallbackTreatmentsCalculator_1 = require("../evaluator/fallbackTreatmentsCal
|
|
|
16
16
|
* Modular SDK factory
|
|
17
17
|
*/
|
|
18
18
|
function sdkFactory(params) {
|
|
19
|
-
var settings = params.settings, platform = params.platform, storageFactory = params.storageFactory,
|
|
19
|
+
var settings = params.settings, platform = params.platform, storageFactory = params.storageFactory, serviceApiFactory = params.serviceApiFactory, extraProps = params.extraProps, syncManagerFactory = params.syncManagerFactory, integrationsManagerFactory = params.integrationsManagerFactory, sdkManagerFactory = params.sdkManagerFactory, sdkClientMethodFactory = params.sdkClientMethodFactory, lazyInit = params.lazyInit;
|
|
20
20
|
var log = settings.log, initialRolloutPlan = settings.initialRolloutPlan, key = settings.core.key;
|
|
21
21
|
// @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid SDK Key, etc.
|
|
22
22
|
// On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
|
|
@@ -30,35 +30,31 @@ function sdkFactory(params) {
|
|
|
30
30
|
readiness.timeout();
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
readiness.
|
|
33
|
+
readiness.definitions.emit(constants_2.SDK_DEFINITIONS_ARRIVED);
|
|
34
34
|
readiness.segments.emit(constants_2.SDK_SEGMENTS_ARRIVED);
|
|
35
35
|
},
|
|
36
36
|
onReadyFromCacheCb: function () {
|
|
37
|
-
readiness.
|
|
37
|
+
readiness.definitions.emit(constants_2.SDK_DEFINITIONS_CACHE_LOADED);
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
|
-
var
|
|
40
|
+
var fallbackCalculator = (0, fallbackTreatmentsCalculator_1.FallbackTreatmentsCalculator)(settings.fallbackTreatments);
|
|
41
41
|
if (initialRolloutPlan) {
|
|
42
42
|
(0, setRolloutPlan_1.setRolloutPlan)(log, initialRolloutPlan, storage, key && (0, key_1.getMatching)(key));
|
|
43
|
-
if (storage.
|
|
44
|
-
readiness.
|
|
43
|
+
if (storage.definitions.getChangeNumber() > -1)
|
|
44
|
+
readiness.definitions.emit(constants_2.SDK_DEFINITIONS_CACHE_LOADED, { initialCacheLoad: false /* Not an initial load, cache exists */ });
|
|
45
45
|
}
|
|
46
46
|
var clients = {};
|
|
47
47
|
var telemetryTracker = (0, telemetryTracker_1.telemetryTrackerFactory)(storage.telemetry, platform.now);
|
|
48
48
|
var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage, telemetryTracker: telemetryTracker });
|
|
49
49
|
var impressionsTracker = (0, impressionsTracker_1.impressionsTrackerFactory)(params, storage, integrationsManager);
|
|
50
50
|
var eventTracker = (0, eventTracker_1.eventTrackerFactory)(settings, storage.events, integrationsManager, storage.telemetry);
|
|
51
|
-
//
|
|
52
|
-
var
|
|
53
|
-
var ctx = { clients: clients,
|
|
54
|
-
|
|
55
|
-
ctx.syncManager = syncManager;
|
|
56
|
-
// @TODO: move into platform, and call inside sdkClientFactory (if it's used only there)
|
|
57
|
-
var signalListener = SignalListener && new SignalListener(syncManager, settings, storage, splitApi);
|
|
58
|
-
ctx.signalListener = signalListener;
|
|
51
|
+
// serviceApi is used by SyncManager and Browser signal listener
|
|
52
|
+
var serviceApi = serviceApiFactory && serviceApiFactory(settings, platform, telemetryTracker);
|
|
53
|
+
var ctx = { clients: clients, serviceApi: serviceApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform, fallbackCalculator: fallbackCalculator };
|
|
54
|
+
ctx.syncManager = syncManagerFactory && syncManagerFactory(ctx);
|
|
59
55
|
// SDK client and manager
|
|
60
56
|
var clientMethod = sdkClientMethodFactory(ctx);
|
|
61
|
-
var managerInstance = sdkManagerFactory(settings, storage.
|
|
57
|
+
var managerInstance = sdkManagerFactory(settings, storage.definitions, sdkReadinessManager);
|
|
62
58
|
function init() {
|
|
63
59
|
Object.keys(clients).map(function (key) { return clients[key].init(); });
|
|
64
60
|
}
|
package/cjs/sdkManager/index.js
CHANGED
|
@@ -53,18 +53,18 @@ function sdkManagerFactory(settings, splits, _a) {
|
|
|
53
53
|
* Get the feature flag object corresponding to the given feature flag name if valid
|
|
54
54
|
*/
|
|
55
55
|
split: function (featureFlagName) {
|
|
56
|
-
var splitName = (0, inputValidation_1.
|
|
56
|
+
var splitName = (0, inputValidation_1.validateDefinition)(log, featureFlagName, constants_1.SPLIT_FN_LABEL);
|
|
57
57
|
if (!(0, inputValidation_1.validateIfOperational)(log, readinessManager, constants_1.SPLIT_FN_LABEL) || !splitName) {
|
|
58
58
|
return isAsync ? Promise.resolve(null) : null;
|
|
59
59
|
}
|
|
60
|
-
var split = splits.
|
|
60
|
+
var split = splits.get(splitName);
|
|
61
61
|
if ((0, thenable_1.thenable)(split)) {
|
|
62
62
|
return split.catch(function () { return null; }).then(function (result) {
|
|
63
|
-
(0, inputValidation_1.
|
|
63
|
+
(0, inputValidation_1.validateDefinitionExistence)(log, readinessManager, splitName, result, constants_1.SPLIT_FN_LABEL);
|
|
64
64
|
return objectToView(result);
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
|
-
(0, inputValidation_1.
|
|
67
|
+
(0, inputValidation_1.validateDefinitionExistence)(log, readinessManager, splitName, split, constants_1.SPLIT_FN_LABEL);
|
|
68
68
|
return objectToView(split);
|
|
69
69
|
},
|
|
70
70
|
/**
|
|
@@ -86,7 +86,7 @@ function sdkManagerFactory(settings, splits, _a) {
|
|
|
86
86
|
if (!(0, inputValidation_1.validateIfOperational)(log, readinessManager, constants_1.NAMES_FN_LABEL)) {
|
|
87
87
|
return isAsync ? Promise.resolve([]) : [];
|
|
88
88
|
}
|
|
89
|
-
var splitNames = splits.
|
|
89
|
+
var splitNames = splits.getNames();
|
|
90
90
|
return (0, thenable_1.thenable)(splitNames) ?
|
|
91
91
|
splitNames.catch(function () { return []; }) : // handle possible rejections when using pluggable storage
|
|
92
92
|
splitNames;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.authProviderFactory = void 0;
|
|
4
|
+
var AuthClient_1 = require("../sync/streaming/AuthClient");
|
|
5
|
+
var Backoff_1 = require("../utils/Backoff");
|
|
6
|
+
var constants_1 = require("../logger/constants");
|
|
7
|
+
var constants_2 = require("../utils/constants");
|
|
8
|
+
var SKEW_SECONDS = 30;
|
|
9
|
+
function isExpired(credential) {
|
|
10
|
+
return Date.now() / 1000 + SKEW_SECONDS >= credential.decodedToken.exp;
|
|
11
|
+
}
|
|
12
|
+
function noCachedCredentialError() {
|
|
13
|
+
return new Error(constants_1.LOG_PREFIX_SYNC_AUTH + 'stopped without a cached credential');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Factory of AuthProvider, which provides JWT credentials for authenticated HTTP requests.
|
|
17
|
+
* Credentials are fetched lazily on demand, cached in memory, and retried with backoff on failure.
|
|
18
|
+
*/
|
|
19
|
+
function authProviderFactory(settings, splitHttpClient, telemetryTracker) {
|
|
20
|
+
var urls = settings.urls, log = settings.log;
|
|
21
|
+
var fetchAuth = (0, AuthClient_1.fetchAuthFactory)(function () {
|
|
22
|
+
var url = "".concat(urls.auth, "/api/v3/auth?capabilities=config,aiconfig");
|
|
23
|
+
return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_2.TOKEN), false, true);
|
|
24
|
+
});
|
|
25
|
+
var backoff = new Backoff_1.Backoff(fetchCredential);
|
|
26
|
+
var cachedCredential;
|
|
27
|
+
var inFlightPromise;
|
|
28
|
+
var stopped = false;
|
|
29
|
+
function fetchCredential() {
|
|
30
|
+
return fetchAuth().then(function (credential) {
|
|
31
|
+
log.info(constants_1.LOG_PREFIX_SYNC_AUTH + 'credential fetched successfully');
|
|
32
|
+
cachedCredential = credential;
|
|
33
|
+
inFlightPromise = undefined;
|
|
34
|
+
backoff.reset();
|
|
35
|
+
return credential;
|
|
36
|
+
}).catch(function (error) {
|
|
37
|
+
// Avoid unnecessary retries after stop(): fall back to any cached credential, or reject
|
|
38
|
+
// (never resolve with `undefined`, which callers would otherwise send as an unauthenticated request).
|
|
39
|
+
if (stopped)
|
|
40
|
+
return cachedCredential || Promise.reject(noCachedCredentialError());
|
|
41
|
+
if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500) {
|
|
42
|
+
log.error(constants_1.LOG_PREFIX_SYNC_AUTH + 'non-retryable error fetching credential (status ' + error.statusCode + '): ' + error.message);
|
|
43
|
+
inFlightPromise = undefined;
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
log.warn(constants_1.LOG_PREFIX_SYNC_AUTH + 'credential fetch failed (attempt ' + (backoff.attempts + 1) + '). Error: ' + error.message);
|
|
47
|
+
return backoff.scheduleCallAsync();
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
credential: function () {
|
|
52
|
+
if (cachedCredential && !isExpired(cachedCredential)) {
|
|
53
|
+
return Promise.resolve(cachedCredential);
|
|
54
|
+
}
|
|
55
|
+
// Reuse any fetch already in flight (e.g. one started just before stop()), instead of firing a redundant one.
|
|
56
|
+
if (inFlightPromise)
|
|
57
|
+
return inFlightPromise;
|
|
58
|
+
// No cached credential to fall back to and stopped: reject so callers don't send an unauthenticated request.
|
|
59
|
+
if (stopped && !cachedCredential) {
|
|
60
|
+
return Promise.reject(noCachedCredentialError());
|
|
61
|
+
}
|
|
62
|
+
if (cachedCredential)
|
|
63
|
+
log.debug(constants_1.LOG_PREFIX_SYNC_AUTH + 'cached credential expired');
|
|
64
|
+
// If stopped, this is a last, bounded refetch: fetchCredential()'s catch short-circuits (no backoff retry)
|
|
65
|
+
// once stopped, so it's a single attempt that falls back to the stale cached credential on failure.
|
|
66
|
+
return inFlightPromise = fetchCredential();
|
|
67
|
+
},
|
|
68
|
+
invalidate: function () {
|
|
69
|
+
cachedCredential = undefined;
|
|
70
|
+
},
|
|
71
|
+
stop: function () {
|
|
72
|
+
stopped = true;
|
|
73
|
+
// Keep any in-flight fetch and already-cached credential usable (e.g. by a final flush on destroy).
|
|
74
|
+
// If a retry is only pending (not actively in flight), settle it immediately instead of waiting out the
|
|
75
|
+
// backoff delay: with the cached credential if there is one, or rejected otherwise.
|
|
76
|
+
backoff.reset(cachedCredential ? { value: cachedCredential } : { error: noCachedCredentialError() });
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
exports.authProviderFactory = authProviderFactory;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.secureSplitHttpClientFactory = void 0;
|
|
4
|
+
var tslib_1 = require("tslib");
|
|
5
|
+
/**
|
|
6
|
+
* Factory of Secure HTTP client, which authenticates requests using a JWT token.
|
|
7
|
+
* On 401 responses, invalidates the cached credential and retries once with a fresh token.
|
|
8
|
+
*
|
|
9
|
+
* @param splitHttpClient - `splitHttpClientFactory` to use for making requests
|
|
10
|
+
* @param authProvider - `authProviderFactory` to use for authentication
|
|
11
|
+
*/
|
|
12
|
+
function secureSplitHttpClientFactory(splitHttpClient, authProvider) {
|
|
13
|
+
function makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, token) {
|
|
14
|
+
return splitHttpClient(url, token ? tslib_1.__assign(tslib_1.__assign({}, options), { headers: tslib_1.__assign(tslib_1.__assign({}, options === null || options === void 0 ? void 0 : options.headers), { Authorization: "Bearer ".concat(token) }) }) : options, latencyTracker, logErrorsAsInfo, newVersionHeader);
|
|
15
|
+
}
|
|
16
|
+
var httpClient = function (url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt) {
|
|
17
|
+
if (newVersionHeader === void 0) { newVersionHeader = true; }
|
|
18
|
+
if (useJwt === void 0) { useJwt = true; }
|
|
19
|
+
return authProvider.credential().then(function (credential) {
|
|
20
|
+
return makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt ? credential.token : undefined)
|
|
21
|
+
.catch(function (error) {
|
|
22
|
+
if (error.statusCode === 401) {
|
|
23
|
+
// retry once for 401, in case the token has just expired
|
|
24
|
+
authProvider.invalidate();
|
|
25
|
+
return authProvider.credential().then(function (newCredential) {
|
|
26
|
+
return makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt ? newCredential.token : undefined);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
throw error;
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
httpClient.stop = function () { return authProvider.stop(); };
|
|
34
|
+
return httpClient;
|
|
35
|
+
}
|
|
36
|
+
exports.secureSplitHttpClientFactory = secureSplitHttpClientFactory;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serviceApiFactory = void 0;
|
|
4
|
+
var splitHttpClient_1 = require("./splitHttpClient");
|
|
5
|
+
var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
6
|
+
var constants_1 = require("../utils/constants");
|
|
7
|
+
var constants_2 = require("../logger/constants");
|
|
8
|
+
var authProvider_1 = require("./authProvider");
|
|
9
|
+
var secureSplitHttpClient_1 = require("./secureSplitHttpClient");
|
|
10
|
+
var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
|
|
11
|
+
/**
|
|
12
|
+
* Factory of ServiceApi objects, which group the collection of HTTP endpoints used by the SDKs
|
|
13
|
+
*
|
|
14
|
+
* @param settings - validated settings object
|
|
15
|
+
* @param platform - object containing environment-specific dependencies
|
|
16
|
+
* @param telemetryTracker - telemetry tracker
|
|
17
|
+
*/
|
|
18
|
+
function serviceApiFactory(settings, platform, telemetryTracker) {
|
|
19
|
+
var urls = settings.urls;
|
|
20
|
+
var filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
|
|
21
|
+
var SplitSDKImpressionsMode = settings.sync.impressionsMode;
|
|
22
|
+
var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform);
|
|
23
|
+
// Shared authProvider so that the SSE authentication (via `fetchAuth`,
|
|
24
|
+
// used by `pushManager`) and every authenticated HTTP request to the Configs
|
|
25
|
+
// API reuse the same cached credential instead of each fetching their own.
|
|
26
|
+
var authProvider = (0, authProvider_1.authProviderFactory)(settings, splitHttpClient, telemetryTracker);
|
|
27
|
+
var secureSplitHttpClient = (0, secureSplitHttpClient_1.secureSplitHttpClientFactory)(splitHttpClient, authProvider);
|
|
28
|
+
var initialAuth = true;
|
|
29
|
+
return {
|
|
30
|
+
fetchAuth: function () {
|
|
31
|
+
// Guard condition to avoid invalidating the cached credential on the first pushManager authentication
|
|
32
|
+
if (initialAuth)
|
|
33
|
+
initialAuth = false;
|
|
34
|
+
else
|
|
35
|
+
authProvider.invalidate();
|
|
36
|
+
return authProvider.credential();
|
|
37
|
+
},
|
|
38
|
+
// @TODO throw errors if health check requests fail, to log them in the Synchronizer
|
|
39
|
+
getSdkAPIHealthCheck: function () {
|
|
40
|
+
var url = "".concat(urls.sdk, "/api/version");
|
|
41
|
+
return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
|
|
42
|
+
},
|
|
43
|
+
getEventsAPIHealthCheck: function () {
|
|
44
|
+
var url = "".concat(urls.events, "/api/version");
|
|
45
|
+
return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
|
|
46
|
+
},
|
|
47
|
+
fetchSplitChanges: function (since, noCache, till, rbSince) {
|
|
48
|
+
var url = "".concat(urls.sdk, "/api/splitChanges?s=").concat(settings.sync.flagSpecVersion, "&since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
|
|
49
|
+
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SPLITS))
|
|
50
|
+
.catch(function (err) {
|
|
51
|
+
if (err.statusCode === 414)
|
|
52
|
+
settings.log.error(constants_2.ERROR_TOO_MANY_SETS);
|
|
53
|
+
throw err;
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
fetchSegmentChanges: function (since, segmentName, noCache, till) {
|
|
57
|
+
var url = "".concat(urls.sdk, "/api/segmentChanges/").concat(segmentName, "?since=").concat(since).concat(till ? '&till=' + till : '');
|
|
58
|
+
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SEGMENT));
|
|
59
|
+
},
|
|
60
|
+
// @TODO support filterQueryString and handle ERROR_TOO_MANY_SETS error
|
|
61
|
+
fetchConfigs: function (since, noCache, till, rbSince) {
|
|
62
|
+
var url = "".concat(urls.configs, "/api/v1/configs?since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
|
|
63
|
+
return secureSplitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
|
|
64
|
+
},
|
|
65
|
+
fetchConfigsSegmentChanges: function (since, segmentName, noCache, till) {
|
|
66
|
+
var url = "".concat(urls.configs, "/api/v1/segmentChanges/").concat(segmentName, "?since=").concat(since).concat(till ? '&till=' + till : '');
|
|
67
|
+
return secureSplitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
|
|
68
|
+
},
|
|
69
|
+
fetchMemberships: function (userMatchingKey, noCache, till) {
|
|
70
|
+
/**
|
|
71
|
+
* URI encoding of user keys in order to:
|
|
72
|
+
* - avoid 400 responses (due to URI malformed). E.g.: '/api/memberships/%'
|
|
73
|
+
* - avoid 404 responses. E.g.: '/api/memberships/foo/bar'
|
|
74
|
+
* - match user keys with special characters. E.g.: 'foo%bar', 'foo/bar'
|
|
75
|
+
*/
|
|
76
|
+
var url = "".concat(urls.sdk, "/api/memberships/").concat(encodeURIComponent(userMatchingKey)).concat(till ? '?till=' + till : '');
|
|
77
|
+
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.MEMBERSHIPS));
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
* Post events.
|
|
81
|
+
*
|
|
82
|
+
* @param body - Events bulk payload
|
|
83
|
+
* @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
|
|
84
|
+
*/
|
|
85
|
+
postEventsBulk: function (body, headers) {
|
|
86
|
+
var url = "".concat(urls.events, "/api/events/bulk");
|
|
87
|
+
return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.EVENTS), false, false, false);
|
|
88
|
+
},
|
|
89
|
+
/**
|
|
90
|
+
* Post impressions.
|
|
91
|
+
*
|
|
92
|
+
* @param body - Impressions bulk payload
|
|
93
|
+
* @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
|
|
94
|
+
*/
|
|
95
|
+
postTestImpressionsBulk: function (body, headers) {
|
|
96
|
+
var url = "".concat(urls.events, "/api/testImpressions/bulk");
|
|
97
|
+
return secureSplitHttpClient(url, {
|
|
98
|
+
// Adding extra headers to send impressions in OPTIMIZED or DEBUG modes.
|
|
99
|
+
method: 'POST',
|
|
100
|
+
body: body,
|
|
101
|
+
headers: (0, objectAssign_1.objectAssign)({ SplitSDKImpressionsMode: SplitSDKImpressionsMode }, headers)
|
|
102
|
+
}, telemetryTracker.trackHttp(constants_1.IMPRESSIONS), false, false, false);
|
|
103
|
+
},
|
|
104
|
+
/**
|
|
105
|
+
* Post impressions counts.
|
|
106
|
+
*
|
|
107
|
+
* @param body - Impressions counts payload
|
|
108
|
+
* @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
|
|
109
|
+
*/
|
|
110
|
+
postTestImpressionsCount: function (body, headers) {
|
|
111
|
+
var url = "".concat(urls.events, "/api/testImpressions/count");
|
|
112
|
+
return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.IMPRESSIONS_COUNT), false, false, false);
|
|
113
|
+
},
|
|
114
|
+
/**
|
|
115
|
+
* Post unique keys for client side.
|
|
116
|
+
*
|
|
117
|
+
* @param body - unique keys payload
|
|
118
|
+
* @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
|
|
119
|
+
*/
|
|
120
|
+
postUniqueKeysBulkCs: function (body, headers) {
|
|
121
|
+
var url = "".concat(urls.telemetry, "/api/v1/keys/cs");
|
|
122
|
+
return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), false, false, false);
|
|
123
|
+
},
|
|
124
|
+
/**
|
|
125
|
+
* Post unique keys for server side.
|
|
126
|
+
*
|
|
127
|
+
* @param body - unique keys payload
|
|
128
|
+
* @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
|
|
129
|
+
*/
|
|
130
|
+
postUniqueKeysBulkSs: function (body, headers) {
|
|
131
|
+
var url = "".concat(urls.telemetry, "/api/v1/keys/ss");
|
|
132
|
+
return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), false, false, false);
|
|
133
|
+
},
|
|
134
|
+
postMetricsConfig: function (body, headers) {
|
|
135
|
+
var url = "".concat(urls.telemetry, "/api/v1/metrics/config");
|
|
136
|
+
return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), true);
|
|
137
|
+
},
|
|
138
|
+
postMetricsUsage: function (body, headers) {
|
|
139
|
+
var url = "".concat(urls.telemetry, "/api/v1/metrics/usage");
|
|
140
|
+
return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), true);
|
|
141
|
+
},
|
|
142
|
+
stop: function () {
|
|
143
|
+
secureSplitHttpClient.stop();
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
exports.serviceApiFactory = serviceApiFactory;
|
package/cjs/services/splitApi.js
CHANGED
|
@@ -5,12 +5,14 @@ var splitHttpClient_1 = require("./splitHttpClient");
|
|
|
5
5
|
var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
6
6
|
var constants_1 = require("../utils/constants");
|
|
7
7
|
var constants_2 = require("../logger/constants");
|
|
8
|
+
var AuthClient_1 = require("../sync/streaming/AuthClient");
|
|
8
9
|
var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
|
|
9
10
|
function userKeyToQueryParam(userKey) {
|
|
10
11
|
return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
|
|
11
12
|
}
|
|
13
|
+
// @TODO remove when migrating to the new `urls` defaults.
|
|
12
14
|
/**
|
|
13
|
-
* Factory of
|
|
15
|
+
* Factory of ServiceApi objects, which group the collection of Split HTTP endpoints used by the SDK
|
|
14
16
|
*
|
|
15
17
|
* @param settings - validated settings object
|
|
16
18
|
* @param platform - object containing environment-specific dependencies
|
|
@@ -22,6 +24,15 @@ function splitApiFactory(settings, platform, telemetryTracker) {
|
|
|
22
24
|
var SplitSDKImpressionsMode = settings.sync.impressionsMode;
|
|
23
25
|
var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform);
|
|
24
26
|
return {
|
|
27
|
+
fetchAuth: (0, AuthClient_1.fetchAuthFactory)(function (userMatchingKeys) {
|
|
28
|
+
var url = "".concat(urls.auth, "/v2/auth?s=").concat(settings.sync.flagSpecVersion);
|
|
29
|
+
if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
|
|
30
|
+
var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
|
|
31
|
+
if (queryParams)
|
|
32
|
+
url += '&' + queryParams;
|
|
33
|
+
}
|
|
34
|
+
return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_1.TOKEN));
|
|
35
|
+
}),
|
|
25
36
|
// @TODO throw errors if health check requests fail, to log them in the Synchronizer
|
|
26
37
|
getSdkAPIHealthCheck: function () {
|
|
27
38
|
var url = "".concat(urls.sdk, "/version");
|
|
@@ -31,15 +42,6 @@ function splitApiFactory(settings, platform, telemetryTracker) {
|
|
|
31
42
|
var url = "".concat(urls.events, "/version");
|
|
32
43
|
return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
|
|
33
44
|
},
|
|
34
|
-
fetchAuth: function (userMatchingKeys) {
|
|
35
|
-
var url = "".concat(urls.auth, "/v2/auth?s=").concat(settings.sync.flagSpecVersion);
|
|
36
|
-
if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
|
|
37
|
-
var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
|
|
38
|
-
if (queryParams)
|
|
39
|
-
url += '&' + queryParams;
|
|
40
|
-
}
|
|
41
|
-
return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_1.TOKEN));
|
|
42
|
-
},
|
|
43
45
|
fetchSplitChanges: function (since, noCache, till, rbSince) {
|
|
44
46
|
var url = "".concat(urls.sdk, "/splitChanges?s=").concat(settings.sync.flagSpecVersion, "&since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
|
|
45
47
|
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SPLITS))
|
|
@@ -125,6 +127,18 @@ function splitApiFactory(settings, platform, telemetryTracker) {
|
|
|
125
127
|
postMetricsUsage: function (body, headers) {
|
|
126
128
|
var url = "".concat(urls.telemetry, "/v1/metrics/usage");
|
|
127
129
|
return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), true);
|
|
130
|
+
},
|
|
131
|
+
// Not used. Just here to satisfy the IServiceApi interface.
|
|
132
|
+
fetchConfigs: function (since, noCache, till, rbSince) {
|
|
133
|
+
var url = "".concat(urls.configs, "/v1/configs?since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
|
|
134
|
+
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
|
|
135
|
+
},
|
|
136
|
+
fetchConfigsSegmentChanges: function (since, segmentName, noCache, till) {
|
|
137
|
+
var url = "".concat(urls.configs, "/v1/segmentChanges/").concat(segmentName, "?since=").concat(since).concat(till ? '&till=' + till : '');
|
|
138
|
+
return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
|
|
139
|
+
},
|
|
140
|
+
stop: function () {
|
|
141
|
+
// no-op
|
|
128
142
|
}
|
|
129
143
|
};
|
|
130
144
|
}
|
|
@@ -24,19 +24,17 @@ function splitHttpClientFactory(settings, _a) {
|
|
|
24
24
|
var commonHeaders = {
|
|
25
25
|
'Accept': 'application/json',
|
|
26
26
|
'Content-Type': 'application/json',
|
|
27
|
-
'Authorization': "Bearer ".concat(authorizationKey)
|
|
28
|
-
'SplitSDKVersion': version
|
|
27
|
+
'Authorization': "Bearer ".concat(authorizationKey)
|
|
29
28
|
};
|
|
30
29
|
if (ip)
|
|
31
30
|
commonHeaders['SplitSDKMachineIP'] = ip;
|
|
32
31
|
if (hostname)
|
|
33
32
|
commonHeaders['SplitSDKMachineName'] = (0, decorateHeaders_1.removeNonISO88591)(hostname);
|
|
34
|
-
return function httpClient(url, reqOpts, latencyTracker, logErrorsAsInfo) {
|
|
33
|
+
return function httpClient(url, reqOpts, latencyTracker, logErrorsAsInfo, newVersionHeader) {
|
|
35
34
|
if (reqOpts === void 0) { reqOpts = {}; }
|
|
36
35
|
if (latencyTracker === void 0) { latencyTracker = function () { }; }
|
|
37
|
-
if (logErrorsAsInfo === void 0) { logErrorsAsInfo = false; }
|
|
38
36
|
var request = (0, objectAssign_1.objectAssign)({
|
|
39
|
-
headers: (0, decorateHeaders_1.decorateHeaders)(settings, (0, objectAssign_1.objectAssign)({}, commonHeaders, reqOpts.headers || {})),
|
|
37
|
+
headers: (0, decorateHeaders_1.decorateHeaders)(settings, (0, objectAssign_1.objectAssign)(newVersionHeader ? { 'X-Harness-FME-SDK-Version': version } : { 'SplitSDKVersion': version }, commonHeaders, reqOpts.headers || {})),
|
|
40
38
|
method: reqOpts.method || 'GET',
|
|
41
39
|
body: reqOpts.body
|
|
42
40
|
}, options);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AbstractDefinitionsCacheAsync = void 0;
|
|
4
|
+
var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
5
|
+
/**
|
|
6
|
+
* This class provides a skeletal implementation of the IDefinitionsCacheAsync interface
|
|
7
|
+
* to minimize the effort required to implement this interface.
|
|
8
|
+
*/
|
|
9
|
+
var AbstractDefinitionsCacheAsync = /** @class */ (function () {
|
|
10
|
+
function AbstractDefinitionsCacheAsync() {
|
|
11
|
+
}
|
|
12
|
+
AbstractDefinitionsCacheAsync.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
13
|
+
var _this = this;
|
|
14
|
+
return Promise.all([
|
|
15
|
+
this.setChangeNumber(changeNumber),
|
|
16
|
+
Promise.all(toAdd.map(function (addedFF) { return _this.add(addedFF); })),
|
|
17
|
+
Promise.all(toRemove.map(function (removedFF) { return _this.remove(removedFF); }))
|
|
18
|
+
]).then(function (_a) {
|
|
19
|
+
var added = _a[1], removed = _a[2];
|
|
20
|
+
return added.some(function (result) { return result; }) || removed.some(function (result) { return result; });
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
// @TODO revisit segment-related methods ('usesSegments', 'getRegisteredSegments', 'registerSegments')
|
|
24
|
+
// noop, just keeping the interface. This is used by standalone client-side API only, and so only implemented by InMemory and InLocalStorage.
|
|
25
|
+
AbstractDefinitionsCacheAsync.prototype.usesSegments = function () {
|
|
26
|
+
return Promise.resolve(true);
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Kill `name` definition and set `defaultTreatment` and `changeNumber`.
|
|
30
|
+
* Used for SPLIT_KILL push notifications.
|
|
31
|
+
*
|
|
32
|
+
* @returns a promise that is resolved once the definition kill operation is performed. The fulfillment value is a boolean: `true` if the operation succeeded updating the definition or `false` if no definition is updated,
|
|
33
|
+
* for instance, if the `changeNumber` is old, or if the definition is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
|
|
34
|
+
* The promise will never be rejected.
|
|
35
|
+
*/
|
|
36
|
+
AbstractDefinitionsCacheAsync.prototype.killLocally = function (name, defaultTreatment, changeNumber) {
|
|
37
|
+
var _this = this;
|
|
38
|
+
return this.get(name).then(function (definition) {
|
|
39
|
+
if (definition && (!definition.changeNumber || definition.changeNumber < changeNumber)) {
|
|
40
|
+
var newDefinition = (0, objectAssign_1.objectAssign)({}, definition);
|
|
41
|
+
newDefinition.killed = true;
|
|
42
|
+
newDefinition.defaultTreatment = defaultTreatment;
|
|
43
|
+
newDefinition.changeNumber = changeNumber;
|
|
44
|
+
return _this.add(newDefinition);
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}).catch(function () { return false; });
|
|
48
|
+
};
|
|
49
|
+
return AbstractDefinitionsCacheAsync;
|
|
50
|
+
}());
|
|
51
|
+
exports.AbstractDefinitionsCacheAsync = AbstractDefinitionsCacheAsync;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.usesSegmentsSync = exports.usesSegments = exports.AbstractDefinitionsCacheSync = void 0;
|
|
4
|
+
var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
5
|
+
var constants_1 = require("../utils/constants");
|
|
6
|
+
/**
|
|
7
|
+
* This class provides a skeletal implementation of the IDefinitionsCacheSync interface
|
|
8
|
+
* to minimize the effort required to implement this interface.
|
|
9
|
+
*/
|
|
10
|
+
var AbstractDefinitionsCacheSync = /** @class */ (function () {
|
|
11
|
+
function AbstractDefinitionsCacheSync() {
|
|
12
|
+
}
|
|
13
|
+
AbstractDefinitionsCacheSync.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
14
|
+
var _this = this;
|
|
15
|
+
var updated = toAdd.map(function (addedFF) { return _this.add(addedFF); }).some(function (result) { return result; });
|
|
16
|
+
updated = toRemove.map(function (removedFF) { return _this.remove(removedFF); }).some(function (result) { return result; }) || updated;
|
|
17
|
+
this.setChangeNumber(changeNumber);
|
|
18
|
+
return updated;
|
|
19
|
+
};
|
|
20
|
+
AbstractDefinitionsCacheSync.prototype.getMany = function (names) {
|
|
21
|
+
var _this = this;
|
|
22
|
+
var definitions = {};
|
|
23
|
+
names.forEach(function (name) {
|
|
24
|
+
definitions[name] = _this.get(name);
|
|
25
|
+
});
|
|
26
|
+
return definitions;
|
|
27
|
+
};
|
|
28
|
+
AbstractDefinitionsCacheSync.prototype.getAll = function () {
|
|
29
|
+
var _this = this;
|
|
30
|
+
return this.getNames().map(function (key) { return _this.get(key); });
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Kill `name` definition and set `defaultTreatment` and `changeNumber`.
|
|
34
|
+
* Used for SPLIT_KILL push notifications.
|
|
35
|
+
*
|
|
36
|
+
* @returns `true` if the operation successed updating the definition, or `false` if no definition is updated,
|
|
37
|
+
* for instance, if the `changeNumber` is old, or if the definition is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
|
|
38
|
+
*/
|
|
39
|
+
AbstractDefinitionsCacheSync.prototype.killLocally = function (name, defaultTreatment, changeNumber) {
|
|
40
|
+
var definition = this.get(name);
|
|
41
|
+
if (definition && (!definition.changeNumber || definition.changeNumber < changeNumber)) {
|
|
42
|
+
var newDefinition = (0, objectAssign_1.objectAssign)({}, definition);
|
|
43
|
+
newDefinition.killed = true;
|
|
44
|
+
newDefinition.defaultTreatment = defaultTreatment;
|
|
45
|
+
newDefinition.changeNumber = changeNumber;
|
|
46
|
+
return this.add(newDefinition);
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
};
|
|
50
|
+
return AbstractDefinitionsCacheSync;
|
|
51
|
+
}());
|
|
52
|
+
exports.AbstractDefinitionsCacheSync = AbstractDefinitionsCacheSync;
|
|
53
|
+
/**
|
|
54
|
+
* Given a parsed definition, it returns a boolean flagging if its conditions use segments matchers (rules & whitelists).
|
|
55
|
+
* This util is intended to simplify the implementation of `definitionsCache::usesSegments` method
|
|
56
|
+
*/
|
|
57
|
+
function usesSegments(ruleEntity) {
|
|
58
|
+
var conditions = ruleEntity.conditions || [];
|
|
59
|
+
for (var i = 0; i < conditions.length; i++) {
|
|
60
|
+
var matchers = conditions[i].matcherGroup.matchers;
|
|
61
|
+
for (var j = 0; j < matchers.length; j++) {
|
|
62
|
+
var matcher = matchers[j].matcherType;
|
|
63
|
+
if (matcher === constants_1.IN_SEGMENT || matcher === constants_1.IN_LARGE_SEGMENT)
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
var excluded = ruleEntity.excluded;
|
|
68
|
+
if (excluded && excluded.segments && excluded.segments.length > 0)
|
|
69
|
+
return true;
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
exports.usesSegments = usesSegments;
|
|
73
|
+
function usesSegmentsSync(storage) {
|
|
74
|
+
return storage.definitions.usesSegments() || storage.rbSegments.usesSegments();
|
|
75
|
+
}
|
|
76
|
+
exports.usesSegmentsSync = usesSegmentsSync;
|
|
@@ -16,16 +16,16 @@ var KeyBuilder = /** @class */ (function () {
|
|
|
16
16
|
KeyBuilder.prototype.buildTrafficTypeKey = function (trafficType) {
|
|
17
17
|
return "".concat(this.prefix, ".trafficType.").concat(trafficType);
|
|
18
18
|
};
|
|
19
|
-
KeyBuilder.prototype.
|
|
20
|
-
return "".concat(this.prefix, ".flagSet.").concat(
|
|
19
|
+
KeyBuilder.prototype.buildSetKey = function (set) {
|
|
20
|
+
return "".concat(this.prefix, ".flagSet.").concat(set);
|
|
21
21
|
};
|
|
22
|
-
KeyBuilder.prototype.
|
|
23
|
-
return "".concat(this.prefix, ".split.").concat(
|
|
22
|
+
KeyBuilder.prototype.buildDefinitionKey = function (definitionName) {
|
|
23
|
+
return "".concat(this.prefix, ".split.").concat(definitionName);
|
|
24
24
|
};
|
|
25
|
-
KeyBuilder.prototype.
|
|
25
|
+
KeyBuilder.prototype.buildDefinitionsTillKey = function () {
|
|
26
26
|
return "".concat(this.prefix, ".splits.till");
|
|
27
27
|
};
|
|
28
|
-
KeyBuilder.prototype.
|
|
28
|
+
KeyBuilder.prototype.buildDefinitionKeyPrefix = function () {
|
|
29
29
|
return "".concat(this.prefix, ".split.");
|
|
30
30
|
};
|
|
31
31
|
KeyBuilder.prototype.buildRBSegmentKey = function (rbsegmentName) {
|
|
@@ -9,7 +9,7 @@ var KeyBuilderCS = /** @class */ (function (_super) {
|
|
|
9
9
|
function KeyBuilderCS(prefix, matchingKey) {
|
|
10
10
|
var _this = _super.call(this, prefix) || this;
|
|
11
11
|
_this.matchingKey = matchingKey;
|
|
12
|
-
_this.
|
|
12
|
+
_this.regexDefinitionsCacheKey = new RegExp("^".concat(prefix, "\\.(splits?|trafficType|flagSet)\\."));
|
|
13
13
|
return _this;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
@@ -26,19 +26,19 @@ var KeyBuilderCS = /** @class */ (function (_super) {
|
|
|
26
26
|
KeyBuilderCS.prototype.buildLastUpdatedKey = function () {
|
|
27
27
|
return "".concat(this.prefix, ".splits.lastUpdated");
|
|
28
28
|
};
|
|
29
|
-
KeyBuilderCS.prototype.
|
|
30
|
-
return this.
|
|
29
|
+
KeyBuilderCS.prototype.isDefinitionsCacheKey = function (key) {
|
|
30
|
+
return this.regexDefinitionsCacheKey.test(key);
|
|
31
31
|
};
|
|
32
32
|
KeyBuilderCS.prototype.buildTillKey = function () {
|
|
33
33
|
return "".concat(this.prefix, ".").concat(this.matchingKey, ".segments.till");
|
|
34
34
|
};
|
|
35
|
-
KeyBuilderCS.prototype.
|
|
35
|
+
KeyBuilderCS.prototype.isDefinitionKey = function (key) {
|
|
36
36
|
return (0, lang_1.startsWith)(key, "".concat(this.prefix, ".split."));
|
|
37
37
|
};
|
|
38
38
|
KeyBuilderCS.prototype.isRBSegmentKey = function (key) {
|
|
39
39
|
return (0, lang_1.startsWith)(key, "".concat(this.prefix, ".rbsegment."));
|
|
40
40
|
};
|
|
41
|
-
KeyBuilderCS.prototype.
|
|
41
|
+
KeyBuilderCS.prototype.buildDefinitionsWithSegmentCountKey = function () {
|
|
42
42
|
return "".concat(this.prefix, ".splits.usingSegments");
|
|
43
43
|
};
|
|
44
44
|
KeyBuilderCS.prototype.buildLastClear = function () {
|