@splitsoftware/splitio-commons 2.7.2-rc.0 → 2.7.9-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +4 -2
- package/cjs/evaluator/fallbackTreatmentsCalculator/constants.js +8 -0
- package/cjs/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +47 -0
- package/cjs/evaluator/fallbackTreatmentsCalculator/index.js +48 -0
- package/cjs/logger/constants.js +2 -2
- package/cjs/logger/messages/info.js +1 -1
- package/cjs/logger/messages/warn.js +3 -3
- package/cjs/readiness/readinessManager.js +3 -5
- package/cjs/readiness/sdkReadinessManager.js +33 -0
- package/cjs/sdkClient/client.js +12 -5
- package/cjs/sdkClient/clientInputValidation.js +18 -7
- package/cjs/sdkClient/sdkClient.js +1 -1
- package/cjs/sdkFactory/index.js +3 -1
- package/cjs/sdkManager/index.js +3 -3
- package/cjs/sync/polling/syncTasks/segmentsSyncTask.js +1 -1
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +5 -16
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +2 -2
- package/cjs/sync/streaming/SSEHandler/index.js +1 -1
- package/cjs/sync/submitters/telemetrySubmitter.js +3 -3
- package/cjs/trackers/telemetryTracker.js +6 -6
- package/cjs/utils/inputValidation/index.js +2 -1
- package/cjs/utils/inputValidation/isOperational.js +9 -4
- package/cjs/utils/inputValidation/splitExistence.js +3 -3
- package/cjs/utils/labels/index.js +3 -1
- package/esm/evaluator/fallbackTreatmentsCalculator/constants.js +5 -0
- package/esm/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +44 -0
- package/esm/evaluator/fallbackTreatmentsCalculator/index.js +45 -0
- package/esm/logger/constants.js +1 -1
- package/esm/logger/messages/info.js +1 -1
- package/esm/logger/messages/warn.js +3 -3
- package/esm/readiness/readinessManager.js +3 -5
- package/esm/readiness/sdkReadinessManager.js +33 -0
- package/esm/sdkClient/client.js +12 -5
- package/esm/sdkClient/clientInputValidation.js +20 -9
- package/esm/sdkClient/sdkClient.js +1 -1
- package/esm/sdkFactory/index.js +3 -1
- package/esm/sdkManager/index.js +4 -4
- package/esm/sync/polling/syncTasks/segmentsSyncTask.js +1 -1
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +5 -16
- package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -2
- package/esm/sync/streaming/SSEHandler/index.js +1 -1
- package/esm/sync/submitters/telemetrySubmitter.js +3 -3
- package/esm/trackers/telemetryTracker.js +6 -6
- package/esm/utils/inputValidation/index.js +1 -1
- package/esm/utils/inputValidation/isOperational.js +8 -4
- package/esm/utils/inputValidation/splitExistence.js +4 -4
- package/esm/utils/labels/index.js +2 -0
- package/package.json +1 -1
- package/src/evaluator/fallbackTreatmentsCalculator/constants.ts +4 -0
- package/src/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.ts +62 -0
- package/src/evaluator/fallbackTreatmentsCalculator/index.ts +57 -0
- package/src/logger/constants.ts +1 -1
- package/src/logger/messages/info.ts +1 -1
- package/src/logger/messages/warn.ts +3 -3
- package/src/readiness/readinessManager.ts +3 -4
- package/src/readiness/sdkReadinessManager.ts +30 -0
- package/src/sdkClient/client.ts +14 -5
- package/src/sdkClient/clientInputValidation.ts +24 -9
- package/src/sdkClient/sdkClient.ts +2 -1
- package/src/sdkFactory/index.ts +4 -1
- package/src/sdkFactory/types.ts +2 -0
- package/src/sdkManager/index.ts +4 -4
- package/src/sync/polling/syncTasks/segmentsSyncTask.ts +0 -2
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +4 -17
- package/src/sync/polling/updaters/splitChangesUpdater.ts +5 -4
- package/src/sync/streaming/SSEHandler/index.ts +1 -1
- package/src/sync/submitters/telemetrySubmitter.ts +3 -3
- package/src/trackers/telemetryTracker.ts +6 -6
- package/src/utils/inputValidation/index.ts +1 -1
- package/src/utils/inputValidation/isOperational.ts +9 -4
- package/src/utils/inputValidation/splitExistence.ts +4 -4
- package/src/utils/labels/index.ts +3 -0
- package/types/splitio.d.ts +37 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateEvaluationOptions = exports.validateTrafficTypeExistence = exports.validateSplitExistence = exports.validateIfOperational = exports.validateIfNotDestroyed = exports.validateTrafficType = exports.validateSplits = exports.validateSplit = exports.validateKey = exports.validateEventProperties = exports.validateEventValue = exports.validateEvent = exports.validateAttributes = exports.releaseApiKey = exports.validateAndTrackApiKey = exports.validateApiKey = void 0;
|
|
3
|
+
exports.validateEvaluationOptions = exports.validateTrafficTypeExistence = exports.validateSplitExistence = exports.validateIfOperational = exports.validateIfReadyFromCache = exports.validateIfNotDestroyed = exports.validateTrafficType = exports.validateSplits = exports.validateSplit = exports.validateKey = exports.validateEventProperties = exports.validateEventValue = exports.validateEvent = exports.validateAttributes = exports.releaseApiKey = exports.validateAndTrackApiKey = exports.validateApiKey = void 0;
|
|
4
4
|
var apiKey_1 = require("./apiKey");
|
|
5
5
|
Object.defineProperty(exports, "validateApiKey", { enumerable: true, get: function () { return apiKey_1.validateApiKey; } });
|
|
6
6
|
Object.defineProperty(exports, "validateAndTrackApiKey", { enumerable: true, get: function () { return apiKey_1.validateAndTrackApiKey; } });
|
|
@@ -23,6 +23,7 @@ var trafficType_1 = require("./trafficType");
|
|
|
23
23
|
Object.defineProperty(exports, "validateTrafficType", { enumerable: true, get: function () { return trafficType_1.validateTrafficType; } });
|
|
24
24
|
var isOperational_1 = require("./isOperational");
|
|
25
25
|
Object.defineProperty(exports, "validateIfNotDestroyed", { enumerable: true, get: function () { return isOperational_1.validateIfNotDestroyed; } });
|
|
26
|
+
Object.defineProperty(exports, "validateIfReadyFromCache", { enumerable: true, get: function () { return isOperational_1.validateIfReadyFromCache; } });
|
|
26
27
|
Object.defineProperty(exports, "validateIfOperational", { enumerable: true, get: function () { return isOperational_1.validateIfOperational; } });
|
|
27
28
|
var splitExistence_1 = require("./splitExistence");
|
|
28
29
|
Object.defineProperty(exports, "validateSplitExistence", { enumerable: true, get: function () { return splitExistence_1.validateSplitExistence; } });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.validateIfOperational = exports.validateIfNotDestroyed = void 0;
|
|
3
|
+
exports.validateIfOperational = exports.validateIfReadyFromCache = exports.validateIfNotDestroyed = void 0;
|
|
4
4
|
var constants_1 = require("../../logger/constants");
|
|
5
5
|
function validateIfNotDestroyed(log, readinessManager, method) {
|
|
6
6
|
if (!readinessManager.isDestroyed())
|
|
@@ -9,10 +9,15 @@ function validateIfNotDestroyed(log, readinessManager, method) {
|
|
|
9
9
|
return false;
|
|
10
10
|
}
|
|
11
11
|
exports.validateIfNotDestroyed = validateIfNotDestroyed;
|
|
12
|
-
function
|
|
13
|
-
if (readinessManager.
|
|
12
|
+
function validateIfReadyFromCache(log, readinessManager, method, featureFlagNameOrNames) {
|
|
13
|
+
if (readinessManager.isReadyFromCache())
|
|
14
14
|
return true;
|
|
15
|
-
log.warn(constants_1.
|
|
15
|
+
log.warn(constants_1.CLIENT_NOT_READY_FROM_CACHE, [method, featureFlagNameOrNames ? " for feature flag " + featureFlagNameOrNames.toString() : '']);
|
|
16
16
|
return false;
|
|
17
17
|
}
|
|
18
|
+
exports.validateIfReadyFromCache = validateIfReadyFromCache;
|
|
19
|
+
// Operational means that the SDK is ready to evaluate (not destroyed and ready from cache)
|
|
20
|
+
function validateIfOperational(log, readinessManager, method, featureFlagNameOrNames) {
|
|
21
|
+
return validateIfNotDestroyed(log, readinessManager, method) && validateIfReadyFromCache(log, readinessManager, method, featureFlagNameOrNames);
|
|
22
|
+
}
|
|
18
23
|
exports.validateIfOperational = validateIfOperational;
|
|
@@ -5,11 +5,11 @@ var labels_1 = require("../labels");
|
|
|
5
5
|
var constants_1 = require("../../logger/constants");
|
|
6
6
|
/**
|
|
7
7
|
* This is defined here and in this format mostly because of the logger and the fact that it's considered a validation at product level.
|
|
8
|
-
* But it's not going to run on the input validation layer. In any case, the most
|
|
8
|
+
* But it's not going to run on the input validation layer. In any case, the most compelling reason to use it as we do is to avoid going to Redis and get a split twice.
|
|
9
9
|
*/
|
|
10
10
|
function validateSplitExistence(log, readinessManager, splitName, labelOrSplitObj, method) {
|
|
11
|
-
if (readinessManager.isReady()) { // Only if it's ready we validate this, otherwise it may just be that the SDK is
|
|
12
|
-
if (labelOrSplitObj === labels_1.SPLIT_NOT_FOUND || labelOrSplitObj == null) {
|
|
11
|
+
if (readinessManager.isReady()) { // Only if it's ready (synced with BE) we validate this, otherwise it may just be that the SDK is still syncing
|
|
12
|
+
if (labelOrSplitObj === labels_1.SPLIT_NOT_FOUND || labelOrSplitObj === labels_1.FALLBACK_SPLIT_NOT_FOUND || labelOrSplitObj == null) {
|
|
13
13
|
log.warn(constants_1.WARN_NOT_EXISTENT_SPLIT, [method, splitName]);
|
|
14
14
|
return false;
|
|
15
15
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PREREQUISITES_NOT_MET = exports.UNSUPPORTED_MATCHER_TYPE = exports.NOT_IN_SPLIT = exports.SPLIT_ARCHIVED = exports.EXCEPTION = exports.SDK_NOT_READY = exports.SPLIT_NOT_FOUND = exports.NO_CONDITION_MATCH = exports.SPLIT_KILLED = void 0;
|
|
3
|
+
exports.FALLBACK_SPLIT_NOT_FOUND = exports.PREREQUISITES_NOT_MET = exports.UNSUPPORTED_MATCHER_TYPE = exports.NOT_IN_SPLIT = exports.SPLIT_ARCHIVED = exports.EXCEPTION = exports.SDK_NOT_READY = exports.SPLIT_NOT_FOUND = exports.NO_CONDITION_MATCH = exports.SPLIT_KILLED = void 0;
|
|
4
|
+
var fallbackTreatmentsCalculator_1 = require("../../evaluator/fallbackTreatmentsCalculator");
|
|
4
5
|
exports.SPLIT_KILLED = 'killed';
|
|
5
6
|
exports.NO_CONDITION_MATCH = 'default rule';
|
|
6
7
|
exports.SPLIT_NOT_FOUND = 'definition not found';
|
|
@@ -10,3 +11,4 @@ exports.SPLIT_ARCHIVED = 'archived';
|
|
|
10
11
|
exports.NOT_IN_SPLIT = 'not in split';
|
|
11
12
|
exports.UNSUPPORTED_MATCHER_TYPE = 'targeting rule type unsupported by sdk';
|
|
12
13
|
exports.PREREQUISITES_NOT_MET = 'prerequisites not met';
|
|
14
|
+
exports.FALLBACK_SPLIT_NOT_FOUND = fallbackTreatmentsCalculator_1.FALLBACK_PREFIX + exports.SPLIT_NOT_FOUND;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export var FallbackDiscardReason;
|
|
2
|
+
(function (FallbackDiscardReason) {
|
|
3
|
+
FallbackDiscardReason["FlagName"] = "Invalid flag name (max 100 chars, no spaces)";
|
|
4
|
+
FallbackDiscardReason["Treatment"] = "Invalid treatment (max 100 chars and must match pattern)";
|
|
5
|
+
})(FallbackDiscardReason || (FallbackDiscardReason = {}));
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { isObject, isString } from '../../../utils/lang';
|
|
2
|
+
import { FallbackDiscardReason } from '../constants';
|
|
3
|
+
var FallbacksSanitizer = /** @class */ (function () {
|
|
4
|
+
function FallbacksSanitizer() {
|
|
5
|
+
}
|
|
6
|
+
FallbacksSanitizer.isValidFlagName = function (name) {
|
|
7
|
+
return name.length <= 100 && !name.includes(' ');
|
|
8
|
+
};
|
|
9
|
+
FallbacksSanitizer.isValidTreatment = function (t) {
|
|
10
|
+
var treatment = isObject(t) ? t.treatment : t;
|
|
11
|
+
if (!isString(treatment) || treatment.length > 100) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
return FallbacksSanitizer.pattern.test(treatment);
|
|
15
|
+
};
|
|
16
|
+
FallbacksSanitizer.sanitizeGlobal = function (logger, treatment) {
|
|
17
|
+
if (!this.isValidTreatment(treatment)) {
|
|
18
|
+
logger.error("Fallback treatments - Discarded fallback: " + FallbackDiscardReason.Treatment);
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
return treatment;
|
|
22
|
+
};
|
|
23
|
+
FallbacksSanitizer.sanitizeByFlag = function (logger, byFlagFallbacks) {
|
|
24
|
+
var _this = this;
|
|
25
|
+
var sanitizedByFlag = {};
|
|
26
|
+
var entries = Object.keys(byFlagFallbacks);
|
|
27
|
+
entries.forEach(function (flag) {
|
|
28
|
+
var t = byFlagFallbacks[flag];
|
|
29
|
+
if (!_this.isValidFlagName(flag)) {
|
|
30
|
+
logger.error("Fallback treatments - Discarded flag '" + flag + "': " + FallbackDiscardReason.FlagName);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (!_this.isValidTreatment(t)) {
|
|
34
|
+
logger.error("Fallback treatments - Discarded treatment for flag '" + flag + "': " + FallbackDiscardReason.Treatment);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
sanitizedByFlag[flag] = t;
|
|
38
|
+
});
|
|
39
|
+
return sanitizedByFlag;
|
|
40
|
+
};
|
|
41
|
+
FallbacksSanitizer.pattern = /^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$/;
|
|
42
|
+
return FallbacksSanitizer;
|
|
43
|
+
}());
|
|
44
|
+
export { FallbacksSanitizer };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { FallbacksSanitizer } from './fallbackSanitizer';
|
|
2
|
+
import { CONTROL } from '../../utils/constants';
|
|
3
|
+
import { isString } from '../../utils/lang';
|
|
4
|
+
export var FALLBACK_PREFIX = 'fallback - ';
|
|
5
|
+
var FallbackTreatmentsCalculator = /** @class */ (function () {
|
|
6
|
+
function FallbackTreatmentsCalculator(logger, fallbacks) {
|
|
7
|
+
var sanitizedGlobal = (fallbacks === null || fallbacks === void 0 ? void 0 : fallbacks.global) ? FallbacksSanitizer.sanitizeGlobal(logger, fallbacks.global) : undefined;
|
|
8
|
+
var sanitizedByFlag = (fallbacks === null || fallbacks === void 0 ? void 0 : fallbacks.byFlag) ? FallbacksSanitizer.sanitizeByFlag(logger, fallbacks.byFlag) : {};
|
|
9
|
+
this.fallbacks = {
|
|
10
|
+
global: sanitizedGlobal,
|
|
11
|
+
byFlag: sanitizedByFlag
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
FallbackTreatmentsCalculator.prototype.resolve = function (flagName, label) {
|
|
15
|
+
var _a;
|
|
16
|
+
var treatment = (_a = this.fallbacks.byFlag) === null || _a === void 0 ? void 0 : _a[flagName];
|
|
17
|
+
if (treatment) {
|
|
18
|
+
return this.copyWithLabel(treatment, label);
|
|
19
|
+
}
|
|
20
|
+
if (this.fallbacks.global) {
|
|
21
|
+
return this.copyWithLabel(this.fallbacks.global, label);
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
treatment: CONTROL,
|
|
25
|
+
config: null,
|
|
26
|
+
label: label,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
FallbackTreatmentsCalculator.prototype.copyWithLabel = function (fallback, label) {
|
|
30
|
+
if (isString(fallback)) {
|
|
31
|
+
return {
|
|
32
|
+
treatment: fallback,
|
|
33
|
+
config: null,
|
|
34
|
+
label: "" + FALLBACK_PREFIX + label,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
treatment: fallback.treatment,
|
|
39
|
+
config: fallback.config,
|
|
40
|
+
label: "" + FALLBACK_PREFIX + label,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
return FallbackTreatmentsCalculator;
|
|
44
|
+
}());
|
|
45
|
+
export { FallbackTreatmentsCalculator };
|
package/esm/logger/constants.js
CHANGED
|
@@ -58,7 +58,7 @@ export var SUBMITTERS_PUSH_PAGE_HIDDEN = 125;
|
|
|
58
58
|
export var ENGINE_VALUE_INVALID = 200;
|
|
59
59
|
export var ENGINE_VALUE_NO_ATTRIBUTES = 201;
|
|
60
60
|
export var CLIENT_NO_LISTENER = 202;
|
|
61
|
-
export var
|
|
61
|
+
export var CLIENT_NOT_READY_FROM_CACHE = 203;
|
|
62
62
|
export var SYNC_MYSEGMENTS_FETCH_RETRY = 204;
|
|
63
63
|
export var SYNC_SPLITS_FETCH_FAILS = 205;
|
|
64
64
|
export var STREAMING_PARSING_ERROR_FAILS = 206;
|
|
@@ -19,7 +19,7 @@ export var codesInfo = codesWarn.concat([
|
|
|
19
19
|
[c.POLLING_SMART_PAUSING, c.LOG_PREFIX_SYNC_POLLING + 'Turning segments data polling %s.'],
|
|
20
20
|
[c.POLLING_START, c.LOG_PREFIX_SYNC_POLLING + 'Starting polling'],
|
|
21
21
|
[c.POLLING_STOP, c.LOG_PREFIX_SYNC_POLLING + 'Stopping polling'],
|
|
22
|
-
[c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying
|
|
22
|
+
[c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying download of feature flags #%s. Reason: %s'],
|
|
23
23
|
[c.SUBMITTERS_PUSH_FULL_QUEUE, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing full %s queue and resetting timer.'],
|
|
24
24
|
[c.SUBMITTERS_PUSH, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Pushing %s.'],
|
|
25
25
|
[c.SUBMITTERS_PUSH_PAGE_HIDDEN, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing %s because page became hidden.'],
|
|
@@ -5,7 +5,7 @@ export var codesWarn = codesError.concat([
|
|
|
5
5
|
[c.ENGINE_VALUE_INVALID, c.LOG_PREFIX_ENGINE_VALUE + 'Value %s doesn\'t match with expected type.'],
|
|
6
6
|
[c.ENGINE_VALUE_NO_ATTRIBUTES, c.LOG_PREFIX_ENGINE_VALUE + 'Defined attribute `%s`. No attributes received.'],
|
|
7
7
|
// synchronizer
|
|
8
|
-
[c.SYNC_MYSEGMENTS_FETCH_RETRY, c.LOG_PREFIX_SYNC_MYSEGMENTS + 'Retrying
|
|
8
|
+
[c.SYNC_MYSEGMENTS_FETCH_RETRY, c.LOG_PREFIX_SYNC_MYSEGMENTS + 'Retrying download of segments #%s. Reason: %s'],
|
|
9
9
|
[c.SYNC_SPLITS_FETCH_FAILS, c.LOG_PREFIX_SYNC_SPLITS + 'Error while doing fetch of feature flags. %s'],
|
|
10
10
|
[c.STREAMING_PARSING_ERROR_FAILS, c.LOG_PREFIX_SYNC_STREAMING + 'Error parsing SSE error notification: %s'],
|
|
11
11
|
[c.STREAMING_PARSING_MESSAGE_FAILS, c.LOG_PREFIX_SYNC_STREAMING + 'Error parsing SSE message notification: %s'],
|
|
@@ -13,8 +13,8 @@ export var codesWarn = codesError.concat([
|
|
|
13
13
|
[c.SUBMITTERS_PUSH_FAILS, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Dropping %s after retry. Reason: %s.'],
|
|
14
14
|
[c.SUBMITTERS_PUSH_RETRY, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Failed to push %s, keeping data to retry on next iteration. Reason: %s.'],
|
|
15
15
|
// client status
|
|
16
|
-
[c.
|
|
17
|
-
[c.CLIENT_NO_LISTENER, 'No listeners for
|
|
16
|
+
[c.CLIENT_NOT_READY_FROM_CACHE, '%s: the SDK is not ready to evaluate. Results may be incorrect%s. Make sure to wait for SDK readiness before using this method.'],
|
|
17
|
+
[c.CLIENT_NO_LISTENER, 'No listeners for SDK_READY event detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet synchronized with the backend.'],
|
|
18
18
|
// input validation
|
|
19
19
|
[c.WARN_SETTING_NULL, '%s: Property "%s" is of invalid type. Setting value to null.'],
|
|
20
20
|
[c.WARN_TRIMMING_PROPERTIES, '%s: more than 300 properties were provided. Some of them will be trimmed when processed.'],
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
2
2
|
import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED, SDK_SEGMENTS_ARRIVED, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE, SDK_READY } from './constants';
|
|
3
|
-
import { STORAGE_LOCALSTORAGE } from '../utils/constants';
|
|
4
3
|
function splitsEventEmitterFactory(EventEmitter) {
|
|
5
4
|
var splitsEventEmitter = objectAssign(new EventEmitter(), {
|
|
6
5
|
splitsArrived: false,
|
|
@@ -72,7 +71,7 @@ export function readinessManagerFactory(EventEmitter, settings, splits, isShared
|
|
|
72
71
|
if (!isReady && !isDestroyed) {
|
|
73
72
|
try {
|
|
74
73
|
syncLastUpdate();
|
|
75
|
-
gate.emit(SDK_READY_FROM_CACHE);
|
|
74
|
+
gate.emit(SDK_READY_FROM_CACHE, isReady);
|
|
76
75
|
}
|
|
77
76
|
catch (e) {
|
|
78
77
|
// throws user callback exceptions in next tick
|
|
@@ -81,7 +80,6 @@ export function readinessManagerFactory(EventEmitter, settings, splits, isShared
|
|
|
81
80
|
}
|
|
82
81
|
}
|
|
83
82
|
function checkIsReadyOrUpdate(diff) {
|
|
84
|
-
var _a;
|
|
85
83
|
if (isDestroyed)
|
|
86
84
|
return;
|
|
87
85
|
if (isReady) {
|
|
@@ -100,9 +98,9 @@ export function readinessManagerFactory(EventEmitter, settings, splits, isShared
|
|
|
100
98
|
isReady = true;
|
|
101
99
|
try {
|
|
102
100
|
syncLastUpdate();
|
|
103
|
-
if (!isReadyFromCache
|
|
101
|
+
if (!isReadyFromCache) {
|
|
104
102
|
isReadyFromCache = true;
|
|
105
|
-
gate.emit(SDK_READY_FROM_CACHE);
|
|
103
|
+
gate.emit(SDK_READY_FROM_CACHE, isReady);
|
|
106
104
|
}
|
|
107
105
|
gate.emit(SDK_READY);
|
|
108
106
|
}
|
|
@@ -5,6 +5,7 @@ import { SDK_READY, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE } from
|
|
|
5
5
|
import { ERROR_CLIENT_LISTENER, CLIENT_READY_FROM_CACHE, CLIENT_READY, CLIENT_NO_LISTENER } from '../logger/constants';
|
|
6
6
|
var NEW_LISTENER_EVENT = 'newListener';
|
|
7
7
|
var REMOVE_LISTENER_EVENT = 'removeListener';
|
|
8
|
+
var TIMEOUT_ERROR = new Error(SDK_READY_TIMED_OUT);
|
|
8
9
|
/**
|
|
9
10
|
* SdkReadinessManager factory, which provides the public status API of SDK clients and manager: ready promise, readiness event emitter and constants (SDK_READY, etc).
|
|
10
11
|
* It also updates logs related warnings and errors.
|
|
@@ -31,6 +32,9 @@ export function sdkReadinessManagerFactory(EventEmitter, settings, readinessMana
|
|
|
31
32
|
readyCbCount++;
|
|
32
33
|
}
|
|
33
34
|
}
|
|
35
|
+
else if (event === SDK_READY_FROM_CACHE && readinessManager.isReadyFromCache()) {
|
|
36
|
+
log.error(ERROR_CLIENT_LISTENER, ['SDK_READY_FROM_CACHE']);
|
|
37
|
+
}
|
|
34
38
|
});
|
|
35
39
|
/** Ready promise */
|
|
36
40
|
var readyPromise = generateReadyPromise();
|
|
@@ -73,6 +77,7 @@ export function sdkReadinessManagerFactory(EventEmitter, settings, readinessMana
|
|
|
73
77
|
SDK_UPDATE: SDK_UPDATE,
|
|
74
78
|
SDK_READY_TIMED_OUT: SDK_READY_TIMED_OUT,
|
|
75
79
|
},
|
|
80
|
+
// @TODO: remove in next major
|
|
76
81
|
ready: function () {
|
|
77
82
|
if (readinessManager.hasTimedout()) {
|
|
78
83
|
if (!readinessManager.isReady()) {
|
|
@@ -84,6 +89,34 @@ export function sdkReadinessManagerFactory(EventEmitter, settings, readinessMana
|
|
|
84
89
|
}
|
|
85
90
|
return readyPromise;
|
|
86
91
|
},
|
|
92
|
+
whenReady: function () {
|
|
93
|
+
return new Promise(function (resolve, reject) {
|
|
94
|
+
if (readinessManager.isReady()) {
|
|
95
|
+
resolve();
|
|
96
|
+
}
|
|
97
|
+
else if (readinessManager.hasTimedout()) {
|
|
98
|
+
reject(TIMEOUT_ERROR);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
readinessManager.gate.once(SDK_READY, resolve);
|
|
102
|
+
readinessManager.gate.once(SDK_READY_TIMED_OUT, function () { return reject(TIMEOUT_ERROR); });
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
whenReadyFromCache: function () {
|
|
107
|
+
return new Promise(function (resolve, reject) {
|
|
108
|
+
if (readinessManager.isReadyFromCache()) {
|
|
109
|
+
resolve(readinessManager.isReady());
|
|
110
|
+
}
|
|
111
|
+
else if (readinessManager.hasTimedout()) {
|
|
112
|
+
reject(TIMEOUT_ERROR);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
readinessManager.gate.once(SDK_READY_FROM_CACHE, function () { return resolve(readinessManager.isReady()); });
|
|
116
|
+
readinessManager.gate.once(SDK_READY_TIMED_OUT, function () { return reject(TIMEOUT_ERROR); });
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
},
|
|
87
120
|
__getStatus: function () {
|
|
88
121
|
return {
|
|
89
122
|
isReady: readinessManager.isReady(),
|
package/esm/sdkClient/client.js
CHANGED
|
@@ -27,7 +27,7 @@ function stringify(options) {
|
|
|
27
27
|
* Creator of base client with getTreatments and track methods.
|
|
28
28
|
*/
|
|
29
29
|
export function clientFactory(params) {
|
|
30
|
-
var readinessManager = params.sdkReadinessManager.readinessManager, storage = params.storage, settings = params.settings, impressionsTracker = params.impressionsTracker, eventTracker = params.eventTracker, telemetryTracker = params.telemetryTracker;
|
|
30
|
+
var readinessManager = params.sdkReadinessManager.readinessManager, storage = params.storage, settings = params.settings, impressionsTracker = params.impressionsTracker, eventTracker = params.eventTracker, telemetryTracker = params.telemetryTracker, fallbackTreatmentsCalculator = params.fallbackTreatmentsCalculator;
|
|
31
31
|
var log = settings.log, mode = settings.mode;
|
|
32
32
|
var isAsync = isConsumerMode(mode);
|
|
33
33
|
function getTreatment(key, featureFlagName, attributes, options, withConfig, methodName) {
|
|
@@ -41,7 +41,7 @@ export function clientFactory(params) {
|
|
|
41
41
|
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
42
42
|
return treatment;
|
|
43
43
|
};
|
|
44
|
-
var evaluation = readinessManager.
|
|
44
|
+
var evaluation = readinessManager.isReadyFromCache() ?
|
|
45
45
|
evaluateFeature(log, key, featureFlagName, attributes, storage) :
|
|
46
46
|
isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
|
|
47
47
|
Promise.resolve(treatmentNotReady) :
|
|
@@ -66,7 +66,7 @@ export function clientFactory(params) {
|
|
|
66
66
|
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
67
67
|
return treatments;
|
|
68
68
|
};
|
|
69
|
-
var evaluations = readinessManager.
|
|
69
|
+
var evaluations = readinessManager.isReadyFromCache() ?
|
|
70
70
|
evaluateFeatures(log, key, featureFlagNames, attributes, storage) :
|
|
71
71
|
isAsync ? // If the SDK is not ready, treatment may be incorrect due to having splits but not segments data, or storage is not connected
|
|
72
72
|
Promise.resolve(treatmentsNotReady(featureFlagNames)) :
|
|
@@ -92,7 +92,7 @@ export function clientFactory(params) {
|
|
|
92
92
|
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
93
93
|
return treatments;
|
|
94
94
|
};
|
|
95
|
-
var evaluations = readinessManager.
|
|
95
|
+
var evaluations = readinessManager.isReadyFromCache() ?
|
|
96
96
|
evaluateFeaturesByFlagSets(log, key, flagSetNames, attributes, storage, methodName) :
|
|
97
97
|
isAsync ?
|
|
98
98
|
Promise.resolve({}) :
|
|
@@ -112,7 +112,14 @@ export function clientFactory(params) {
|
|
|
112
112
|
function processEvaluation(evaluation, featureFlagName, key, properties, withConfig, invokingMethodName, queue) {
|
|
113
113
|
var matchingKey = getMatching(key);
|
|
114
114
|
var bucketingKey = getBucketing(key);
|
|
115
|
-
var
|
|
115
|
+
var changeNumber = evaluation.changeNumber, impressionsDisabled = evaluation.impressionsDisabled;
|
|
116
|
+
var treatment = evaluation.treatment, label = evaluation.label, _a = evaluation.config, config = _a === void 0 ? null : _a;
|
|
117
|
+
if (treatment === CONTROL) {
|
|
118
|
+
var fallbackTreatment = fallbackTreatmentsCalculator.resolve(featureFlagName, label);
|
|
119
|
+
treatment = fallbackTreatment.treatment;
|
|
120
|
+
label = fallbackTreatment.label;
|
|
121
|
+
config = fallbackTreatment.config;
|
|
122
|
+
}
|
|
116
123
|
log.info(IMPRESSION, [featureFlagName, matchingKey, treatment, label]);
|
|
117
124
|
if (validateSplitExistence(log, readinessManager, featureFlagName, label, invokingMethodName)) {
|
|
118
125
|
log.info(IMPRESSION_QUEUEING);
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { validateAttributes, validateEvent, validateEventValue, validateEventProperties, validateKey, validateSplit, validateSplits, validateTrafficType, validateIfNotDestroyed, validateIfOperational, validateEvaluationOptions } from '../utils/inputValidation';
|
|
1
|
+
import { validateAttributes, validateEvent, validateEventValue, validateEventProperties, validateKey, validateSplit, validateSplits, validateTrafficType, validateIfNotDestroyed, validateIfReadyFromCache, validateEvaluationOptions } from '../utils/inputValidation';
|
|
3
2
|
import { startsWith } from '../utils/lang';
|
|
4
|
-
import {
|
|
3
|
+
import { GET_TREATMENT, GET_TREATMENTS, GET_TREATMENTS_BY_FLAG_SET, GET_TREATMENTS_BY_FLAG_SETS, GET_TREATMENTS_WITH_CONFIG, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, GET_TREATMENT_WITH_CONFIG, TRACK_FN_LABEL } from '../utils/constants';
|
|
5
4
|
import { isConsumerMode } from '../utils/settingsValidation/mode';
|
|
6
5
|
import { validateFlagSets } from '../utils/settingsValidation/splitFilters';
|
|
7
6
|
/**
|
|
8
7
|
* Decorator that validates the input before actually executing the client methods.
|
|
9
8
|
* We should "guard" the client here, while not polluting the "real" implementation of those methods.
|
|
10
9
|
*/
|
|
11
|
-
export function clientInputValidationDecorator(settings, client, readinessManager) {
|
|
10
|
+
export function clientInputValidationDecorator(settings, client, readinessManager, fallbackTreatmentsCalculator) {
|
|
12
11
|
var log = settings.log, mode = settings.mode;
|
|
13
12
|
var isAsync = isConsumerMode(mode);
|
|
14
13
|
/**
|
|
@@ -24,7 +23,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
24
23
|
var attributes = validateAttributes(log, maybeAttributes, methodName);
|
|
25
24
|
var isNotDestroyed = validateIfNotDestroyed(log, readinessManager, methodName);
|
|
26
25
|
var options = validateEvaluationOptions(log, maybeOptions, methodName);
|
|
27
|
-
|
|
26
|
+
validateIfReadyFromCache(log, readinessManager, methodName, nameOrNames);
|
|
28
27
|
var valid = isNotDestroyed && key && nameOrNames && attributes !== false;
|
|
29
28
|
return {
|
|
30
29
|
valid: valid,
|
|
@@ -34,6 +33,16 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
34
33
|
options: options
|
|
35
34
|
};
|
|
36
35
|
}
|
|
36
|
+
function evaluateFallBackTreatment(featureFlagName, withConfig) {
|
|
37
|
+
var _a = fallbackTreatmentsCalculator.resolve(featureFlagName, ''), treatment = _a.treatment, config = _a.config;
|
|
38
|
+
if (withConfig) {
|
|
39
|
+
return {
|
|
40
|
+
treatment: treatment,
|
|
41
|
+
config: config
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return treatment;
|
|
45
|
+
}
|
|
37
46
|
function wrapResult(value) {
|
|
38
47
|
return isAsync ? Promise.resolve(value) : value;
|
|
39
48
|
}
|
|
@@ -43,7 +52,8 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
43
52
|
return client.getTreatment(params.key, params.nameOrNames, params.attributes, params.options);
|
|
44
53
|
}
|
|
45
54
|
else {
|
|
46
|
-
|
|
55
|
+
var result = evaluateFallBackTreatment(params.nameOrNames, false);
|
|
56
|
+
return wrapResult(result);
|
|
47
57
|
}
|
|
48
58
|
}
|
|
49
59
|
function getTreatmentWithConfig(maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions) {
|
|
@@ -52,7 +62,8 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
52
62
|
return client.getTreatmentWithConfig(params.key, params.nameOrNames, params.attributes, params.options);
|
|
53
63
|
}
|
|
54
64
|
else {
|
|
55
|
-
|
|
65
|
+
var result = evaluateFallBackTreatment(params.nameOrNames, true);
|
|
66
|
+
return wrapResult(result);
|
|
56
67
|
}
|
|
57
68
|
}
|
|
58
69
|
function getTreatments(maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions) {
|
|
@@ -63,7 +74,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
63
74
|
else {
|
|
64
75
|
var res_1 = {};
|
|
65
76
|
if (params.nameOrNames)
|
|
66
|
-
params.nameOrNames.forEach(function (split) { return res_1[split] =
|
|
77
|
+
params.nameOrNames.forEach(function (split) { return res_1[split] = evaluateFallBackTreatment(split, false); });
|
|
67
78
|
return wrapResult(res_1);
|
|
68
79
|
}
|
|
69
80
|
}
|
|
@@ -75,7 +86,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
|
|
|
75
86
|
else {
|
|
76
87
|
var res_2 = {};
|
|
77
88
|
if (params.nameOrNames)
|
|
78
|
-
params.nameOrNames.forEach(function (split) { return res_2[split] =
|
|
89
|
+
params.nameOrNames.forEach(function (split) { return res_2[split] = evaluateFallBackTreatment(split, true); });
|
|
79
90
|
return wrapResult(res_2);
|
|
80
91
|
}
|
|
81
92
|
}
|
|
@@ -32,7 +32,7 @@ export function sdkClientFactory(params, isSharedClient) {
|
|
|
32
32
|
// Proto-linkage of the readiness Event Emitter
|
|
33
33
|
Object.create(sdkReadinessManager.sdkStatus),
|
|
34
34
|
// Client API (getTreatment* & track methods)
|
|
35
|
-
clientInputValidationDecorator(settings, clientFactory(params), sdkReadinessManager.readinessManager),
|
|
35
|
+
clientInputValidationDecorator(settings, clientFactory(params), sdkReadinessManager.readinessManager, params.fallbackTreatmentsCalculator),
|
|
36
36
|
// Sdk destroy
|
|
37
37
|
{
|
|
38
38
|
flush: function () {
|
package/esm/sdkFactory/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import { uniqueKeysTrackerFactory } from '../trackers/uniqueKeysTracker';
|
|
|
14
14
|
import { DEBUG, OPTIMIZED } from '../utils/constants';
|
|
15
15
|
import { setRolloutPlan } from '../storages/setRolloutPlan';
|
|
16
16
|
import { getMatching } from '../utils/key';
|
|
17
|
+
import { FallbackTreatmentsCalculator } from '../evaluator/fallbackTreatmentsCalculator';
|
|
17
18
|
/**
|
|
18
19
|
* Modular SDK factory
|
|
19
20
|
*/
|
|
@@ -48,6 +49,7 @@ export function sdkFactory(params) {
|
|
|
48
49
|
readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
|
|
49
50
|
}
|
|
50
51
|
});
|
|
52
|
+
var fallbackTreatmentsCalculator = new FallbackTreatmentsCalculator(settings.log, settings.fallbackTreatments);
|
|
51
53
|
if (initialRolloutPlan) {
|
|
52
54
|
setRolloutPlan(log, initialRolloutPlan, storage, key && getMatching(key));
|
|
53
55
|
if (storage.splits.getChangeNumber() > -1)
|
|
@@ -68,7 +70,7 @@ export function sdkFactory(params) {
|
|
|
68
70
|
var eventTracker = eventTrackerFactory(settings, storage.events, whenInit, integrationsManager, storage.telemetry);
|
|
69
71
|
// splitApi is used by SyncManager and Browser signal listener
|
|
70
72
|
var splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
|
|
71
|
-
var ctx = { clients: clients, splitApi: splitApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, uniqueKeysTracker: uniqueKeysTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform };
|
|
73
|
+
var ctx = { clients: clients, splitApi: splitApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, uniqueKeysTracker: uniqueKeysTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform, fallbackTreatmentsCalculator: fallbackTreatmentsCalculator };
|
|
72
74
|
var syncManager = syncManagerFactory && syncManagerFactory(ctx);
|
|
73
75
|
ctx.syncManager = syncManager;
|
|
74
76
|
var signalListener = SignalListener && new SignalListener(syncManager, settings, storage, splitApi);
|
package/esm/sdkManager/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
2
2
|
import { thenable } from '../utils/promise/thenable';
|
|
3
3
|
import { find } from '../utils/lang';
|
|
4
|
-
import { validateSplit, validateSplitExistence,
|
|
4
|
+
import { validateSplit, validateSplitExistence, validateIfOperational } from '../utils/inputValidation';
|
|
5
5
|
import { isConsumerMode } from '../utils/settingsValidation/mode';
|
|
6
6
|
import { SPLIT_FN_LABEL, SPLITS_FN_LABEL, NAMES_FN_LABEL } from '../utils/constants';
|
|
7
7
|
function collectTreatments(splitObject) {
|
|
@@ -51,7 +51,7 @@ export function sdkManagerFactory(settings, splits, _a) {
|
|
|
51
51
|
*/
|
|
52
52
|
split: function (featureFlagName) {
|
|
53
53
|
var splitName = validateSplit(log, featureFlagName, SPLIT_FN_LABEL);
|
|
54
|
-
if (!
|
|
54
|
+
if (!validateIfOperational(log, readinessManager, SPLIT_FN_LABEL) || !splitName) {
|
|
55
55
|
return isAsync ? Promise.resolve(null) : null;
|
|
56
56
|
}
|
|
57
57
|
var split = splits.getSplit(splitName);
|
|
@@ -68,7 +68,7 @@ export function sdkManagerFactory(settings, splits, _a) {
|
|
|
68
68
|
* Get the feature flag objects present on the factory storage
|
|
69
69
|
*/
|
|
70
70
|
splits: function () {
|
|
71
|
-
if (!
|
|
71
|
+
if (!validateIfOperational(log, readinessManager, SPLITS_FN_LABEL)) {
|
|
72
72
|
return isAsync ? Promise.resolve([]) : [];
|
|
73
73
|
}
|
|
74
74
|
var currentSplits = splits.getAll();
|
|
@@ -80,7 +80,7 @@ export function sdkManagerFactory(settings, splits, _a) {
|
|
|
80
80
|
* Get the feature flag names present on the factory storage
|
|
81
81
|
*/
|
|
82
82
|
names: function () {
|
|
83
|
-
if (!
|
|
83
|
+
if (!validateIfOperational(log, readinessManager, NAMES_FN_LABEL)) {
|
|
84
84
|
return isAsync ? Promise.resolve([]) : [];
|
|
85
85
|
}
|
|
86
86
|
var splitNames = splits.getSplitNames();
|
|
@@ -5,5 +5,5 @@ import { segmentChangesUpdaterFactory } from '../updaters/segmentChangesUpdater'
|
|
|
5
5
|
* Creates a sync task that periodically executes a `segmentChangesUpdater` task
|
|
6
6
|
*/
|
|
7
7
|
export function segmentsSyncTaskFactory(fetchSegmentChanges, storage, readiness, settings) {
|
|
8
|
-
return syncTaskFactory(settings.log, segmentChangesUpdaterFactory(settings.log, segmentChangesFetcherFactory(fetchSegmentChanges), storage.segments, readiness
|
|
8
|
+
return syncTaskFactory(settings.log, segmentChangesUpdaterFactory(settings.log, segmentChangesFetcherFactory(fetchSegmentChanges), storage.segments, readiness), settings.scheduler.segmentsRefreshRate, 'segmentChangesUpdater');
|
|
9
9
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
|
|
2
2
|
import { LOG_PREFIX_INSTANTIATION, LOG_PREFIX_SYNC_SEGMENTS } from '../../../logger/constants';
|
|
3
|
-
import { timeout } from '../../../utils/promise/timeout';
|
|
4
3
|
/**
|
|
5
4
|
* Factory of SegmentChanges updater, a task that:
|
|
6
5
|
* - fetches segment changes using `segmentChangesFetcher`
|
|
@@ -12,33 +11,22 @@ import { timeout } from '../../../utils/promise/timeout';
|
|
|
12
11
|
* @param segments - segments storage, with sync or async methods
|
|
13
12
|
* @param readiness - optional readiness manager. Not required for synchronizer or producer mode.
|
|
14
13
|
*/
|
|
15
|
-
export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, readiness
|
|
14
|
+
export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, readiness) {
|
|
16
15
|
var readyOnAlreadyExistentState = true;
|
|
17
|
-
function
|
|
18
|
-
if (readyOnAlreadyExistentState && requestTimeoutBeforeReady)
|
|
19
|
-
promise = timeout(requestTimeoutBeforeReady, promise);
|
|
20
|
-
return promise;
|
|
21
|
-
}
|
|
22
|
-
function updateSegment(segmentName, noCache, till, fetchOnlyNew, retries) {
|
|
16
|
+
function updateSegment(segmentName, noCache, till, fetchOnlyNew) {
|
|
23
17
|
log.debug(LOG_PREFIX_SYNC_SEGMENTS + "Processing segment " + segmentName);
|
|
24
18
|
var sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
|
|
25
19
|
return sincePromise.then(function (since) {
|
|
26
20
|
// if fetchOnlyNew flag, avoid processing already fetched segments
|
|
27
21
|
return fetchOnlyNew && since !== undefined ?
|
|
28
22
|
false :
|
|
29
|
-
segmentChangesFetcher(since || -1, segmentName, noCache, till
|
|
23
|
+
segmentChangesFetcher(since || -1, segmentName, noCache, till).then(function (changes) {
|
|
30
24
|
return Promise.all(changes.map(function (x) {
|
|
31
25
|
log.debug(LOG_PREFIX_SYNC_SEGMENTS + "Processing " + segmentName + " with till = " + x.till + ". Added: " + x.added.length + ". Removed: " + x.removed.length);
|
|
32
26
|
return segments.update(segmentName, x.added, x.removed, x.till);
|
|
33
27
|
})).then(function (updates) {
|
|
34
28
|
return updates.some(function (update) { return update; });
|
|
35
29
|
});
|
|
36
|
-
}).catch(function (error) {
|
|
37
|
-
if (retries) {
|
|
38
|
-
log.warn(LOG_PREFIX_SYNC_SEGMENTS + "Retrying fetch of segment " + segmentName + " (attempt #" + retries + "). Reason: " + error);
|
|
39
|
-
return updateSegment(segmentName, noCache, till, fetchOnlyNew, retries - 1);
|
|
40
|
-
}
|
|
41
|
-
throw error;
|
|
42
30
|
});
|
|
43
31
|
});
|
|
44
32
|
}
|
|
@@ -58,7 +46,8 @@ export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segment
|
|
|
58
46
|
// If not a segment name provided, read list of available segments names to be updated.
|
|
59
47
|
var segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
|
|
60
48
|
return segmentsPromise.then(function (segmentNames) {
|
|
61
|
-
|
|
49
|
+
// Async fetchers
|
|
50
|
+
var updaters = segmentNames.map(function (segmentName) { return updateSegment(segmentName, noCache, till, fetchOnlyNew); });
|
|
62
51
|
return Promise.all(updaters).then(function (shouldUpdateFlags) {
|
|
63
52
|
// if at least one segment fetch succeeded, mark segments ready
|
|
64
53
|
if (shouldUpdateFlags.some(function (update) { return update; }) || readyOnAlreadyExistentState) {
|
|
@@ -166,14 +166,14 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, sp
|
|
|
166
166
|
});
|
|
167
167
|
})
|
|
168
168
|
.catch(function (error) {
|
|
169
|
+
log.warn(SYNC_SPLITS_FETCH_FAILS, [error]);
|
|
169
170
|
if (startingUp && retriesOnFailureBeforeReady > retry) {
|
|
170
171
|
retry += 1;
|
|
171
|
-
log.
|
|
172
|
+
log.info(SYNC_SPLITS_FETCH_RETRY, [retry, error]);
|
|
172
173
|
return _splitChangesUpdater(sinces, retry);
|
|
173
174
|
}
|
|
174
175
|
else {
|
|
175
176
|
startingUp = false;
|
|
176
|
-
log.warn(SYNC_SPLITS_FETCH_FAILS, [error]);
|
|
177
177
|
}
|
|
178
178
|
return false;
|
|
179
179
|
});
|
|
@@ -16,7 +16,7 @@ export function SSEHandlerFactory(log, pushEmitter, telemetryTracker) {
|
|
|
16
16
|
// Ably error
|
|
17
17
|
var code = error.parsedData.code;
|
|
18
18
|
telemetryTracker.streamingEvent(ABLY_ERROR, code);
|
|
19
|
-
// 401 errors due to invalid or expired token (e.g., if refresh token
|
|
19
|
+
// 401 errors due to invalid or expired token (e.g., if refresh token couldn't be executed)
|
|
20
20
|
if (40140 <= code && code <= 40149)
|
|
21
21
|
return true;
|
|
22
22
|
// Others 4XX errors (e.g., bad request from the SDK)
|
|
@@ -102,14 +102,14 @@ export function telemetrySubmitterFactory(params) {
|
|
|
102
102
|
if (!telemetry || !now)
|
|
103
103
|
return; // No submitter created if telemetry cache is not defined
|
|
104
104
|
var settings = params.settings, _a = params.settings, log = _a.log, telemetryRefreshRate = _a.scheduler.telemetryRefreshRate, splitApi = params.splitApi, readiness = params.readiness, sdkReadinessManager = params.sdkReadinessManager;
|
|
105
|
-
var
|
|
105
|
+
var stopTimer = timer(now);
|
|
106
106
|
var submitter = firstPushWindowDecorator(submitterFactory(log, splitApi.postMetricsUsage, telemetry, telemetryRefreshRate, undefined, 0, true), telemetryRefreshRate);
|
|
107
107
|
readiness.gate.once(SDK_READY_FROM_CACHE, function () {
|
|
108
|
-
telemetry.recordTimeUntilReadyFromCache(
|
|
108
|
+
telemetry.recordTimeUntilReadyFromCache(stopTimer());
|
|
109
109
|
});
|
|
110
110
|
sdkReadinessManager.incInternalReadyCbCount();
|
|
111
111
|
readiness.gate.once(SDK_READY, function () {
|
|
112
|
-
telemetry.recordTimeUntilReady(
|
|
112
|
+
telemetry.recordTimeUntilReady(stopTimer());
|
|
113
113
|
// Post config data when the SDK is ready and if the telemetry submitter was started
|
|
114
114
|
if (submitter.isRunning()) {
|
|
115
115
|
var postMetricsConfigTask = submitterFactory(log, splitApi.postMetricsConfig, telemetryCacheConfigAdapter(telemetry, settings), 0, undefined, 0, true);
|