@splitsoftware/splitio-commons 2.7.9-rc.1 → 2.7.9-rc.3
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 +1 -0
- package/cjs/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +8 -4
- package/cjs/logger/messages/info.js +1 -1
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/readiness/sdkReadinessManager.js +14 -11
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +2 -1
- package/cjs/storages/pluggable/index.js +2 -1
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +2 -1
- package/cjs/sync/streaming/SSEClient/index.js +2 -1
- package/cjs/sync/streaming/pushManager.js +1 -1
- package/cjs/sync/submitters/telemetrySubmitter.js +4 -3
- package/cjs/utils/key/index.js +5 -1
- package/esm/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +5 -1
- package/esm/logger/messages/info.js +1 -1
- package/esm/logger/messages/warn.js +1 -1
- package/esm/readiness/sdkReadinessManager.js +14 -11
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +2 -1
- package/esm/storages/pluggable/index.js +2 -1
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +2 -1
- package/esm/sync/streaming/SSEClient/index.js +2 -1
- package/esm/sync/streaming/pushManager.js +2 -2
- package/esm/sync/submitters/telemetrySubmitter.js +4 -3
- package/esm/utils/key/index.js +3 -0
- package/package.json +1 -1
- package/src/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.ts +4 -1
- package/src/logger/messages/info.ts +1 -1
- package/src/logger/messages/warn.ts +1 -1
- package/src/readiness/sdkReadinessManager.ts +14 -11
- package/src/readiness/types.ts +1 -2
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +2 -1
- package/src/storages/pluggable/index.ts +2 -1
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +2 -1
- package/src/sync/streaming/SSEClient/index.ts +2 -1
- package/src/sync/streaming/pushManager.ts +2 -2
- package/src/sync/submitters/telemetrySubmitter.ts +4 -3
- package/src/types.ts +0 -15
- package/src/utils/key/index.ts +5 -0
- package/types/splitio.d.ts +56 -0
- package/cjs/evaluator/fallbackTreatmentsCalculator/constants.js +0 -8
- package/esm/evaluator/fallbackTreatmentsCalculator/constants.js +0 -5
- package/src/evaluator/fallbackTreatmentsCalculator/constants.ts +0 -4
package/CHANGES.txt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
2.8.0 (October 28, 2025)
|
|
2
2
|
- Added new configuration for Fallback Treatments, which allows setting a treatment value and optional config to be returned in place of "control", either globally or by flag. Read more in our docs.
|
|
3
|
+
- Added `client.getStatus()` method to retrieve the client readiness status properties (`isReady`, `isReadyFromCache`, etc).
|
|
3
4
|
- Added `client.whenReady()` and `client.whenReadyFromCache()` methods to replace the deprecated `client.ready()` method, which has an issue causing the returned promise to hang when using async/await syntax if it was rejected.
|
|
4
5
|
- Updated the SDK_READY_FROM_CACHE event to be emitted alongside the SDK_READY event if it hasn’t already been emitted.
|
|
5
6
|
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FallbacksSanitizer = void 0;
|
|
4
4
|
var lang_1 = require("../../../utils/lang");
|
|
5
|
-
var
|
|
5
|
+
var FallbackDiscardReason;
|
|
6
|
+
(function (FallbackDiscardReason) {
|
|
7
|
+
FallbackDiscardReason["FlagName"] = "Invalid flag name (max 100 chars, no spaces)";
|
|
8
|
+
FallbackDiscardReason["Treatment"] = "Invalid treatment (max 100 chars and must match pattern)";
|
|
9
|
+
})(FallbackDiscardReason || (FallbackDiscardReason = {}));
|
|
6
10
|
var FallbacksSanitizer = /** @class */ (function () {
|
|
7
11
|
function FallbacksSanitizer() {
|
|
8
12
|
}
|
|
@@ -18,7 +22,7 @@ var FallbacksSanitizer = /** @class */ (function () {
|
|
|
18
22
|
};
|
|
19
23
|
FallbacksSanitizer.sanitizeGlobal = function (logger, treatment) {
|
|
20
24
|
if (!this.isValidTreatment(treatment)) {
|
|
21
|
-
logger.error("Fallback treatments - Discarded fallback: " +
|
|
25
|
+
logger.error("Fallback treatments - Discarded fallback: " + FallbackDiscardReason.Treatment);
|
|
22
26
|
return undefined;
|
|
23
27
|
}
|
|
24
28
|
return treatment;
|
|
@@ -30,11 +34,11 @@ var FallbacksSanitizer = /** @class */ (function () {
|
|
|
30
34
|
entries.forEach(function (flag) {
|
|
31
35
|
var t = byFlagFallbacks[flag];
|
|
32
36
|
if (!_this.isValidFlagName(flag)) {
|
|
33
|
-
logger.error("Fallback treatments - Discarded flag '" + flag + "': " +
|
|
37
|
+
logger.error("Fallback treatments - Discarded flag '" + flag + "': " + FallbackDiscardReason.FlagName);
|
|
34
38
|
return;
|
|
35
39
|
}
|
|
36
40
|
if (!_this.isValidTreatment(t)) {
|
|
37
|
-
logger.error("Fallback treatments - Discarded treatment for flag '" + flag + "': " +
|
|
41
|
+
logger.error("Fallback treatments - Discarded treatment for flag '" + flag + "': " + FallbackDiscardReason.Treatment);
|
|
38
42
|
return;
|
|
39
43
|
}
|
|
40
44
|
sanitizedByFlag[flag] = t;
|
|
@@ -23,7 +23,7 @@ exports.codesInfo = warn_1.codesWarn.concat([
|
|
|
23
23
|
[c.POLLING_SMART_PAUSING, c.LOG_PREFIX_SYNC_POLLING + 'Turning segments data polling %s.'],
|
|
24
24
|
[c.POLLING_START, c.LOG_PREFIX_SYNC_POLLING + 'Starting polling'],
|
|
25
25
|
[c.POLLING_STOP, c.LOG_PREFIX_SYNC_POLLING + 'Stopping polling'],
|
|
26
|
-
[c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying
|
|
26
|
+
[c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying fetch of feature flags (attempt #%s). Reason: %s'],
|
|
27
27
|
[c.SUBMITTERS_PUSH_FULL_QUEUE, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing full %s queue and resetting timer.'],
|
|
28
28
|
[c.SUBMITTERS_PUSH, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Pushing %s.'],
|
|
29
29
|
[c.SUBMITTERS_PUSH_PAGE_HIDDEN, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing %s because page became hidden.'],
|
|
@@ -9,7 +9,7 @@ exports.codesWarn = error_1.codesError.concat([
|
|
|
9
9
|
[c.ENGINE_VALUE_INVALID, c.LOG_PREFIX_ENGINE_VALUE + 'Value %s doesn\'t match with expected type.'],
|
|
10
10
|
[c.ENGINE_VALUE_NO_ATTRIBUTES, c.LOG_PREFIX_ENGINE_VALUE + 'Defined attribute `%s`. No attributes received.'],
|
|
11
11
|
// synchronizer
|
|
12
|
-
[c.SYNC_MYSEGMENTS_FETCH_RETRY, c.LOG_PREFIX_SYNC_MYSEGMENTS + 'Retrying
|
|
12
|
+
[c.SYNC_MYSEGMENTS_FETCH_RETRY, c.LOG_PREFIX_SYNC_MYSEGMENTS + 'Retrying fetch of memberships (attempt #%s). Reason: %s'],
|
|
13
13
|
[c.SYNC_SPLITS_FETCH_FAILS, c.LOG_PREFIX_SYNC_SPLITS + 'Error while doing fetch of feature flags. %s'],
|
|
14
14
|
[c.STREAMING_PARSING_ERROR_FAILS, c.LOG_PREFIX_SYNC_STREAMING + 'Error parsing SSE error notification: %s'],
|
|
15
15
|
[c.STREAMING_PARSING_MESSAGE_FAILS, c.LOG_PREFIX_SYNC_STREAMING + 'Error parsing SSE message notification: %s'],
|
|
@@ -62,6 +62,17 @@ function sdkReadinessManagerFactory(EventEmitter, settings, readinessManager) {
|
|
|
62
62
|
}), defaultOnRejected);
|
|
63
63
|
return promise;
|
|
64
64
|
}
|
|
65
|
+
function getStatus() {
|
|
66
|
+
return {
|
|
67
|
+
isReady: readinessManager.isReady(),
|
|
68
|
+
isReadyFromCache: readinessManager.isReadyFromCache(),
|
|
69
|
+
isTimedout: readinessManager.isTimedout(),
|
|
70
|
+
hasTimedout: readinessManager.hasTimedout(),
|
|
71
|
+
isDestroyed: readinessManager.isDestroyed(),
|
|
72
|
+
isOperational: readinessManager.isOperational(),
|
|
73
|
+
lastUpdate: readinessManager.lastUpdate(),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
65
76
|
return {
|
|
66
77
|
readinessManager: readinessManager,
|
|
67
78
|
shared: function () {
|
|
@@ -120,17 +131,9 @@ function sdkReadinessManagerFactory(EventEmitter, settings, readinessManager) {
|
|
|
120
131
|
}
|
|
121
132
|
});
|
|
122
133
|
},
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
isReadyFromCache: readinessManager.isReadyFromCache(),
|
|
127
|
-
isTimedout: readinessManager.isTimedout(),
|
|
128
|
-
hasTimedout: readinessManager.hasTimedout(),
|
|
129
|
-
isDestroyed: readinessManager.isDestroyed(),
|
|
130
|
-
isOperational: readinessManager.isOperational(),
|
|
131
|
-
lastUpdate: readinessManager.lastUpdate(),
|
|
132
|
-
};
|
|
133
|
-
},
|
|
134
|
+
getStatus: getStatus,
|
|
135
|
+
// @TODO: remove in next major
|
|
136
|
+
__getStatus: getStatus
|
|
134
137
|
})
|
|
135
138
|
};
|
|
136
139
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TelemetryCacheInMemory = exports.shouldRecordTelemetry = exports.newBuckets = exports.MAX_LATENCY_BUCKET_COUNT = void 0;
|
|
4
4
|
var constants_1 = require("../../utils/constants");
|
|
5
|
+
var key_1 = require("../../utils/key");
|
|
5
6
|
var findLatencyIndex_1 = require("../findLatencyIndex");
|
|
6
7
|
var MAX_STREAMING_EVENTS = 20;
|
|
7
8
|
var MAX_TAGS = 10;
|
|
@@ -19,7 +20,7 @@ var ACCEPTANCE_RANGE = 0.001;
|
|
|
19
20
|
*/
|
|
20
21
|
function shouldRecordTelemetry(_a) {
|
|
21
22
|
var settings = _a.settings;
|
|
22
|
-
return settings.mode !== constants_1.LOCALHOST_MODE && (settings
|
|
23
|
+
return settings.mode !== constants_1.LOCALHOST_MODE && ((0, key_1.checkIfServerSide)(settings) || Math.random() <= ACCEPTANCE_RANGE);
|
|
23
24
|
}
|
|
24
25
|
exports.shouldRecordTelemetry = shouldRecordTelemetry;
|
|
25
26
|
var TelemetryCacheInMemory = /** @class */ (function () {
|
|
@@ -23,6 +23,7 @@ var UniqueKeysCacheInMemoryCS_1 = require("../inMemory/UniqueKeysCacheInMemoryCS
|
|
|
23
23
|
var utils_1 = require("../utils");
|
|
24
24
|
var constants_2 = require("../pluggable/constants");
|
|
25
25
|
var RBSegmentsCachePluggable_1 = require("./RBSegmentsCachePluggable");
|
|
26
|
+
var key_1 = require("../../utils/key");
|
|
26
27
|
var NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.';
|
|
27
28
|
var NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.';
|
|
28
29
|
/**
|
|
@@ -70,7 +71,7 @@ function PluggableStorage(options) {
|
|
|
70
71
|
new ImpressionCountsCacheInMemory_1.ImpressionCountsCacheInMemory() :
|
|
71
72
|
new ImpressionCountsCachePluggable_1.ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper);
|
|
72
73
|
var uniqueKeysCache = isPartialConsumer ?
|
|
73
|
-
settings
|
|
74
|
+
(0, key_1.checkIfServerSide)(settings) ? new UniqueKeysCacheInMemory_1.UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS_1.UniqueKeysCacheInMemoryCS() :
|
|
74
75
|
new UniqueKeysCachePluggable_1.UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper);
|
|
75
76
|
// Connects to wrapper and emits SDK_READY event on main client
|
|
76
77
|
var connectPromise = wrapper.connect().then(function () {
|
|
@@ -4,6 +4,7 @@ exports.splitChangesFetcherFactory = void 0;
|
|
|
4
4
|
var constants_1 = require("../../../utils/constants");
|
|
5
5
|
var settingsValidation_1 = require("../../../utils/settingsValidation");
|
|
6
6
|
var constants_2 = require("../../../logger/constants");
|
|
7
|
+
var key_1 = require("../../../utils/key");
|
|
7
8
|
var PROXY_CHECK_INTERVAL_MILLIS_CS = 60 * 60 * 1000; // 1 hour in Client Side
|
|
8
9
|
var PROXY_CHECK_INTERVAL_MILLIS_SS = 24 * PROXY_CHECK_INTERVAL_MILLIS_CS; // 24 hours in Server Side
|
|
9
10
|
function sdkEndpointOverridden(settings) {
|
|
@@ -16,7 +17,7 @@ function sdkEndpointOverridden(settings) {
|
|
|
16
17
|
// @TODO breaking: drop support for Split Proxy below v5.10.0 and simplify the implementation
|
|
17
18
|
function splitChangesFetcherFactory(fetchSplitChanges, settings, storage) {
|
|
18
19
|
var log = settings.log;
|
|
19
|
-
var PROXY_CHECK_INTERVAL_MILLIS = settings
|
|
20
|
+
var PROXY_CHECK_INTERVAL_MILLIS = (0, key_1.checkIfServerSide)(settings) ? PROXY_CHECK_INTERVAL_MILLIS_SS : PROXY_CHECK_INTERVAL_MILLIS_CS;
|
|
20
21
|
var lastProxyCheckTimestamp;
|
|
21
22
|
return function splitChangesFetcher(since, noCache, till, rbSince,
|
|
22
23
|
// Optional decorator for `fetchSplitChanges` promise, such as timeout or time tracker
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SSEClient = void 0;
|
|
4
4
|
var decorateHeaders_1 = require("../../../services/decorateHeaders");
|
|
5
|
+
var key_1 = require("../../../utils/key");
|
|
5
6
|
var lang_1 = require("../../../utils/lang");
|
|
6
7
|
var objectAssign_1 = require("../../../utils/lang/objectAssign");
|
|
7
8
|
var ABLY_API_VERSION = '1.1';
|
|
@@ -60,7 +61,7 @@ var SSEClient = /** @class */ (function () {
|
|
|
60
61
|
return encodeURIComponent(params + channel);
|
|
61
62
|
}).join(',');
|
|
62
63
|
var url = this.settings.urls.streaming + "/sse?channels=" + channelsQueryParam + "&accessToken=" + authToken.token + "&v=" + ABLY_API_VERSION + "&heartbeats=true"; // same results using `&heartbeats=false`
|
|
63
|
-
var isServerSide =
|
|
64
|
+
var isServerSide = (0, key_1.checkIfServerSide)(this.settings);
|
|
64
65
|
this.connection = new this.eventSource(
|
|
65
66
|
// For client-side SDKs, metadata is passed as query param to avoid CORS issues and because native EventSource implementations in browsers do not support headers
|
|
66
67
|
isServerSide ? url : url + ("&SplitSDKVersion=" + this.headers.SplitSDKVersion + "&SplitSDKClientKey=" + this.headers.SplitSDKClientKey),
|
|
@@ -26,7 +26,7 @@ function pushManagerFactory(params, pollingManager) {
|
|
|
26
26
|
var settings = params.settings, storage = params.storage, splitApi = params.splitApi, readiness = params.readiness, platform = params.platform, telemetryTracker = params.telemetryTracker;
|
|
27
27
|
// `userKey` is the matching key of main client in client-side SDK.
|
|
28
28
|
// It can be used to check if running on client-side or server-side SDK.
|
|
29
|
-
var userKey = settings
|
|
29
|
+
var userKey = (0, key_1.checkIfServerSide)(settings) ? undefined : (0, key_1.getMatching)(settings.core.key);
|
|
30
30
|
var log = settings.log;
|
|
31
31
|
var sseClient;
|
|
32
32
|
try {
|
|
@@ -9,6 +9,7 @@ var settingsValidation_1 = require("../../utils/settingsValidation");
|
|
|
9
9
|
var apiKey_1 = require("../../utils/inputValidation/apiKey");
|
|
10
10
|
var timer_1 = require("../../utils/timeTracker/timer");
|
|
11
11
|
var objectAssign_1 = require("../../utils/lang/objectAssign");
|
|
12
|
+
var key_1 = require("../../utils/key");
|
|
12
13
|
var OPERATION_MODE_MAP = (_a = {},
|
|
13
14
|
_a[constants_1.STANDALONE_MODE] = constants_1.STANDALONE_ENUM,
|
|
14
15
|
_a[constants_1.CONSUMER_MODE] = constants_1.CONSUMER_ENUM,
|
|
@@ -62,14 +63,14 @@ function telemetryCacheConfigAdapter(telemetry, settings) {
|
|
|
62
63
|
clear: function () { },
|
|
63
64
|
pop: function () {
|
|
64
65
|
var urls = settings.urls, scheduler = settings.scheduler;
|
|
65
|
-
var
|
|
66
|
+
var isServerSide = (0, key_1.checkIfServerSide)(settings);
|
|
66
67
|
var _a = getTelemetryFlagSetsStats(settings.sync.__splitFiltersValidation), flagSetsTotal = _a.flagSetsTotal, flagSetsIgnored = _a.flagSetsIgnored;
|
|
67
68
|
return (0, objectAssign_1.objectAssign)(getTelemetryConfigStats(settings.mode, settings.storage.type), {
|
|
68
69
|
sE: settings.streamingEnabled,
|
|
69
70
|
rR: {
|
|
70
71
|
sp: scheduler.featuresRefreshRate / 1000,
|
|
71
|
-
se:
|
|
72
|
-
ms:
|
|
72
|
+
se: isServerSide ? scheduler.segmentsRefreshRate / 1000 : undefined,
|
|
73
|
+
ms: isServerSide ? undefined : scheduler.segmentsRefreshRate / 1000,
|
|
73
74
|
im: scheduler.impressionsRefreshRate / 1000,
|
|
74
75
|
ev: scheduler.eventsPushRate / 1000,
|
|
75
76
|
te: scheduler.telemetryRefreshRate / 1000,
|
package/cjs/utils/key/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.keyParser = exports.getBucketing = exports.getMatching = void 0;
|
|
3
|
+
exports.checkIfServerSide = exports.keyParser = exports.getBucketing = exports.getMatching = void 0;
|
|
4
4
|
var lang_1 = require("../lang");
|
|
5
5
|
// function isSplitKeyObject(key: any): key is SplitIO.SplitKeyObject {
|
|
6
6
|
// return key !== undefined && key !== null && typeof key.matchingKey === 'string';
|
|
@@ -34,3 +34,7 @@ function keyParser(key) {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
exports.keyParser = keyParser;
|
|
37
|
+
function checkIfServerSide(settings) {
|
|
38
|
+
return !settings.core.key;
|
|
39
|
+
}
|
|
40
|
+
exports.checkIfServerSide = checkIfServerSide;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { isObject, isString } from '../../../utils/lang';
|
|
2
|
-
|
|
2
|
+
var FallbackDiscardReason;
|
|
3
|
+
(function (FallbackDiscardReason) {
|
|
4
|
+
FallbackDiscardReason["FlagName"] = "Invalid flag name (max 100 chars, no spaces)";
|
|
5
|
+
FallbackDiscardReason["Treatment"] = "Invalid treatment (max 100 chars and must match pattern)";
|
|
6
|
+
})(FallbackDiscardReason || (FallbackDiscardReason = {}));
|
|
3
7
|
var FallbacksSanitizer = /** @class */ (function () {
|
|
4
8
|
function FallbacksSanitizer() {
|
|
5
9
|
}
|
|
@@ -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 fetch of feature flags (attempt #%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 fetch of memberships (attempt #%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'],
|
|
@@ -59,6 +59,17 @@ export function sdkReadinessManagerFactory(EventEmitter, settings, readinessMana
|
|
|
59
59
|
}), defaultOnRejected);
|
|
60
60
|
return promise;
|
|
61
61
|
}
|
|
62
|
+
function getStatus() {
|
|
63
|
+
return {
|
|
64
|
+
isReady: readinessManager.isReady(),
|
|
65
|
+
isReadyFromCache: readinessManager.isReadyFromCache(),
|
|
66
|
+
isTimedout: readinessManager.isTimedout(),
|
|
67
|
+
hasTimedout: readinessManager.hasTimedout(),
|
|
68
|
+
isDestroyed: readinessManager.isDestroyed(),
|
|
69
|
+
isOperational: readinessManager.isOperational(),
|
|
70
|
+
lastUpdate: readinessManager.lastUpdate(),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
62
73
|
return {
|
|
63
74
|
readinessManager: readinessManager,
|
|
64
75
|
shared: function () {
|
|
@@ -117,17 +128,9 @@ export function sdkReadinessManagerFactory(EventEmitter, settings, readinessMana
|
|
|
117
128
|
}
|
|
118
129
|
});
|
|
119
130
|
},
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
isReadyFromCache: readinessManager.isReadyFromCache(),
|
|
124
|
-
isTimedout: readinessManager.isTimedout(),
|
|
125
|
-
hasTimedout: readinessManager.hasTimedout(),
|
|
126
|
-
isDestroyed: readinessManager.isDestroyed(),
|
|
127
|
-
isOperational: readinessManager.isOperational(),
|
|
128
|
-
lastUpdate: readinessManager.lastUpdate(),
|
|
129
|
-
};
|
|
130
|
-
},
|
|
131
|
+
getStatus: getStatus,
|
|
132
|
+
// @TODO: remove in next major
|
|
133
|
+
__getStatus: getStatus
|
|
131
134
|
})
|
|
132
135
|
};
|
|
133
136
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DEDUPED, DROPPED, LOCALHOST_MODE, QUEUED } from '../../utils/constants';
|
|
2
|
+
import { checkIfServerSide } from '../../utils/key';
|
|
2
3
|
import { findLatencyIndex } from '../findLatencyIndex';
|
|
3
4
|
var MAX_STREAMING_EVENTS = 20;
|
|
4
5
|
var MAX_TAGS = 10;
|
|
@@ -15,7 +16,7 @@ var ACCEPTANCE_RANGE = 0.001;
|
|
|
15
16
|
*/
|
|
16
17
|
export function shouldRecordTelemetry(_a) {
|
|
17
18
|
var settings = _a.settings;
|
|
18
|
-
return settings.mode !== LOCALHOST_MODE && (settings
|
|
19
|
+
return settings.mode !== LOCALHOST_MODE && (checkIfServerSide(settings) || Math.random() <= ACCEPTANCE_RANGE);
|
|
19
20
|
}
|
|
20
21
|
var TelemetryCacheInMemory = /** @class */ (function () {
|
|
21
22
|
function TelemetryCacheInMemory(splits, segments, largeSegments) {
|
|
@@ -20,6 +20,7 @@ import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS
|
|
|
20
20
|
import { metadataBuilder } from '../utils';
|
|
21
21
|
import { LOG_PREFIX } from '../pluggable/constants';
|
|
22
22
|
import { RBSegmentsCachePluggable } from './RBSegmentsCachePluggable';
|
|
23
|
+
import { checkIfServerSide } from '../../utils/key';
|
|
23
24
|
var NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.';
|
|
24
25
|
var NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.';
|
|
25
26
|
/**
|
|
@@ -67,7 +68,7 @@ export function PluggableStorage(options) {
|
|
|
67
68
|
new ImpressionCountsCacheInMemory() :
|
|
68
69
|
new ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper);
|
|
69
70
|
var uniqueKeysCache = isPartialConsumer ?
|
|
70
|
-
settings
|
|
71
|
+
checkIfServerSide(settings) ? new UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS() :
|
|
71
72
|
new UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper);
|
|
72
73
|
// Connects to wrapper and emits SDK_READY event on main client
|
|
73
74
|
var connectPromise = wrapper.connect().then(function () {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FLAG_SPEC_VERSION } from '../../../utils/constants';
|
|
2
2
|
import { base } from '../../../utils/settingsValidation';
|
|
3
3
|
import { LOG_PREFIX_SYNC_SPLITS } from '../../../logger/constants';
|
|
4
|
+
import { checkIfServerSide } from '../../../utils/key';
|
|
4
5
|
var PROXY_CHECK_INTERVAL_MILLIS_CS = 60 * 60 * 1000; // 1 hour in Client Side
|
|
5
6
|
var PROXY_CHECK_INTERVAL_MILLIS_SS = 24 * PROXY_CHECK_INTERVAL_MILLIS_CS; // 24 hours in Server Side
|
|
6
7
|
function sdkEndpointOverridden(settings) {
|
|
@@ -13,7 +14,7 @@ function sdkEndpointOverridden(settings) {
|
|
|
13
14
|
// @TODO breaking: drop support for Split Proxy below v5.10.0 and simplify the implementation
|
|
14
15
|
export function splitChangesFetcherFactory(fetchSplitChanges, settings, storage) {
|
|
15
16
|
var log = settings.log;
|
|
16
|
-
var PROXY_CHECK_INTERVAL_MILLIS = settings
|
|
17
|
+
var PROXY_CHECK_INTERVAL_MILLIS = checkIfServerSide(settings) ? PROXY_CHECK_INTERVAL_MILLIS_SS : PROXY_CHECK_INTERVAL_MILLIS_CS;
|
|
17
18
|
var lastProxyCheckTimestamp;
|
|
18
19
|
return function splitChangesFetcher(since, noCache, till, rbSince,
|
|
19
20
|
// Optional decorator for `fetchSplitChanges` promise, such as timeout or time tracker
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { decorateHeaders } from '../../../services/decorateHeaders';
|
|
2
|
+
import { checkIfServerSide } from '../../../utils/key';
|
|
2
3
|
import { isString } from '../../../utils/lang';
|
|
3
4
|
import { objectAssign } from '../../../utils/lang/objectAssign';
|
|
4
5
|
var ABLY_API_VERSION = '1.1';
|
|
@@ -57,7 +58,7 @@ var SSEClient = /** @class */ (function () {
|
|
|
57
58
|
return encodeURIComponent(params + channel);
|
|
58
59
|
}).join(',');
|
|
59
60
|
var url = this.settings.urls.streaming + "/sse?channels=" + channelsQueryParam + "&accessToken=" + authToken.token + "&v=" + ABLY_API_VERSION + "&heartbeats=true"; // same results using `&heartbeats=false`
|
|
60
|
-
var isServerSide =
|
|
61
|
+
var isServerSide = checkIfServerSide(this.settings);
|
|
61
62
|
this.connection = new this.eventSource(
|
|
62
63
|
// For client-side SDKs, metadata is passed as query param to avoid CORS issues and because native EventSource implementations in browsers do not support headers
|
|
63
64
|
isServerSide ? url : url + ("&SplitSDKVersion=" + this.headers.SplitSDKVersion + "&SplitSDKClientKey=" + this.headers.SplitSDKClientKey),
|
|
@@ -7,7 +7,7 @@ import { SplitsUpdateWorker } from './UpdateWorkers/SplitsUpdateWorker';
|
|
|
7
7
|
import { authenticateFactory, hashUserKey } from './AuthClient';
|
|
8
8
|
import { forOwn } from '../../utils/lang';
|
|
9
9
|
import { SSEClient } from './SSEClient';
|
|
10
|
-
import { getMatching } from '../../utils/key';
|
|
10
|
+
import { checkIfServerSide, getMatching } from '../../utils/key';
|
|
11
11
|
import { MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, RB_SEGMENT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType } from './constants';
|
|
12
12
|
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MEMBERSHIPS_UPDATE } from '../../logger/constants';
|
|
13
13
|
import { UpdateStrategy } from './SSEHandler/types';
|
|
@@ -23,7 +23,7 @@ export function pushManagerFactory(params, pollingManager) {
|
|
|
23
23
|
var settings = params.settings, storage = params.storage, splitApi = params.splitApi, readiness = params.readiness, platform = params.platform, telemetryTracker = params.telemetryTracker;
|
|
24
24
|
// `userKey` is the matching key of main client in client-side SDK.
|
|
25
25
|
// It can be used to check if running on client-side or server-side SDK.
|
|
26
|
-
var userKey = settings
|
|
26
|
+
var userKey = checkIfServerSide(settings) ? undefined : getMatching(settings.core.key);
|
|
27
27
|
var log = settings.log;
|
|
28
28
|
var sseClient;
|
|
29
29
|
try {
|
|
@@ -6,6 +6,7 @@ import { base } from '../../utils/settingsValidation';
|
|
|
6
6
|
import { usedKeysMap } from '../../utils/inputValidation/apiKey';
|
|
7
7
|
import { timer } from '../../utils/timeTracker/timer';
|
|
8
8
|
import { objectAssign } from '../../utils/lang/objectAssign';
|
|
9
|
+
import { checkIfServerSide } from '../../utils/key';
|
|
9
10
|
var OPERATION_MODE_MAP = (_a = {},
|
|
10
11
|
_a[STANDALONE_MODE] = STANDALONE_ENUM,
|
|
11
12
|
_a[CONSUMER_MODE] = CONSUMER_ENUM,
|
|
@@ -58,14 +59,14 @@ export function telemetryCacheConfigAdapter(telemetry, settings) {
|
|
|
58
59
|
clear: function () { },
|
|
59
60
|
pop: function () {
|
|
60
61
|
var urls = settings.urls, scheduler = settings.scheduler;
|
|
61
|
-
var
|
|
62
|
+
var isServerSide = checkIfServerSide(settings);
|
|
62
63
|
var _a = getTelemetryFlagSetsStats(settings.sync.__splitFiltersValidation), flagSetsTotal = _a.flagSetsTotal, flagSetsIgnored = _a.flagSetsIgnored;
|
|
63
64
|
return objectAssign(getTelemetryConfigStats(settings.mode, settings.storage.type), {
|
|
64
65
|
sE: settings.streamingEnabled,
|
|
65
66
|
rR: {
|
|
66
67
|
sp: scheduler.featuresRefreshRate / 1000,
|
|
67
|
-
se:
|
|
68
|
-
ms:
|
|
68
|
+
se: isServerSide ? scheduler.segmentsRefreshRate / 1000 : undefined,
|
|
69
|
+
ms: isServerSide ? undefined : scheduler.segmentsRefreshRate / 1000,
|
|
69
70
|
im: scheduler.impressionsRefreshRate / 1000,
|
|
70
71
|
ev: scheduler.eventsPushRate / 1000,
|
|
71
72
|
te: scheduler.telemetryRefreshRate / 1000,
|
package/esm/utils/key/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { Treatment, TreatmentWithConfig } from '../../../../types/splitio';
|
|
2
2
|
import { ILogger } from '../../../logger/types';
|
|
3
3
|
import { isObject, isString } from '../../../utils/lang';
|
|
4
|
-
import { FallbackDiscardReason } from '../constants';
|
|
5
4
|
|
|
5
|
+
enum FallbackDiscardReason {
|
|
6
|
+
FlagName = 'Invalid flag name (max 100 chars, no spaces)',
|
|
7
|
+
Treatment = 'Invalid treatment (max 100 chars and must match pattern)',
|
|
8
|
+
}
|
|
6
9
|
|
|
7
10
|
export class FallbacksSanitizer {
|
|
8
11
|
|
|
@@ -22,7 +22,7 @@ export const codesInfo: [number, string][] = codesWarn.concat([
|
|
|
22
22
|
[c.POLLING_SMART_PAUSING, c.LOG_PREFIX_SYNC_POLLING + 'Turning segments data polling %s.'],
|
|
23
23
|
[c.POLLING_START, c.LOG_PREFIX_SYNC_POLLING + 'Starting polling'],
|
|
24
24
|
[c.POLLING_STOP, c.LOG_PREFIX_SYNC_POLLING + 'Stopping polling'],
|
|
25
|
-
[c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying
|
|
25
|
+
[c.SYNC_SPLITS_FETCH_RETRY, c.LOG_PREFIX_SYNC_SPLITS + 'Retrying fetch of feature flags (attempt #%s). Reason: %s'],
|
|
26
26
|
[c.SUBMITTERS_PUSH_FULL_QUEUE, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing full %s queue and resetting timer.'],
|
|
27
27
|
[c.SUBMITTERS_PUSH, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Pushing %s.'],
|
|
28
28
|
[c.SUBMITTERS_PUSH_PAGE_HIDDEN, c.LOG_PREFIX_SYNC_SUBMITTERS + 'Flushing %s because page became hidden.'],
|
|
@@ -6,7 +6,7 @@ export const codesWarn: [number, string][] = codesError.concat([
|
|
|
6
6
|
[c.ENGINE_VALUE_INVALID, c.LOG_PREFIX_ENGINE_VALUE + 'Value %s doesn\'t match with expected type.'],
|
|
7
7
|
[c.ENGINE_VALUE_NO_ATTRIBUTES, c.LOG_PREFIX_ENGINE_VALUE + 'Defined attribute `%s`. No attributes received.'],
|
|
8
8
|
// synchronizer
|
|
9
|
-
[c.SYNC_MYSEGMENTS_FETCH_RETRY, c.LOG_PREFIX_SYNC_MYSEGMENTS + 'Retrying
|
|
9
|
+
[c.SYNC_MYSEGMENTS_FETCH_RETRY, c.LOG_PREFIX_SYNC_MYSEGMENTS + 'Retrying fetch of memberships (attempt #%s). Reason: %s'],
|
|
10
10
|
[c.SYNC_SPLITS_FETCH_FAILS, c.LOG_PREFIX_SYNC_SPLITS + 'Error while doing fetch of feature flags. %s'],
|
|
11
11
|
[c.STREAMING_PARSING_ERROR_FAILS, c.LOG_PREFIX_SYNC_STREAMING + 'Error parsing SSE error notification: %s'],
|
|
12
12
|
[c.STREAMING_PARSING_MESSAGE_FAILS, c.LOG_PREFIX_SYNC_STREAMING + 'Error parsing SSE message notification: %s'],
|
|
@@ -72,6 +72,17 @@ export function sdkReadinessManagerFactory(
|
|
|
72
72
|
return promise;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
function getStatus() {
|
|
76
|
+
return {
|
|
77
|
+
isReady: readinessManager.isReady(),
|
|
78
|
+
isReadyFromCache: readinessManager.isReadyFromCache(),
|
|
79
|
+
isTimedout: readinessManager.isTimedout(),
|
|
80
|
+
hasTimedout: readinessManager.hasTimedout(),
|
|
81
|
+
isDestroyed: readinessManager.isDestroyed(),
|
|
82
|
+
isOperational: readinessManager.isOperational(),
|
|
83
|
+
lastUpdate: readinessManager.lastUpdate(),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
75
86
|
|
|
76
87
|
return {
|
|
77
88
|
readinessManager,
|
|
@@ -134,17 +145,9 @@ export function sdkReadinessManagerFactory(
|
|
|
134
145
|
});
|
|
135
146
|
},
|
|
136
147
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
isReadyFromCache: readinessManager.isReadyFromCache(),
|
|
141
|
-
isTimedout: readinessManager.isTimedout(),
|
|
142
|
-
hasTimedout: readinessManager.hasTimedout(),
|
|
143
|
-
isDestroyed: readinessManager.isDestroyed(),
|
|
144
|
-
isOperational: readinessManager.isOperational(),
|
|
145
|
-
lastUpdate: readinessManager.lastUpdate(),
|
|
146
|
-
};
|
|
147
|
-
},
|
|
148
|
+
getStatus,
|
|
149
|
+
// @TODO: remove in next major
|
|
150
|
+
__getStatus: getStatus
|
|
148
151
|
}
|
|
149
152
|
)
|
|
150
153
|
};
|
package/src/readiness/types.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { IStatusInterface } from '../types';
|
|
2
1
|
import SplitIO from '../../types/splitio';
|
|
3
2
|
|
|
4
3
|
/** Splits data emitter */
|
|
@@ -72,7 +71,7 @@ export interface IReadinessManager {
|
|
|
72
71
|
|
|
73
72
|
export interface ISdkReadinessManager {
|
|
74
73
|
readinessManager: IReadinessManager
|
|
75
|
-
sdkStatus: IStatusInterface
|
|
74
|
+
sdkStatus: SplitIO.IStatusInterface
|
|
76
75
|
|
|
77
76
|
/**
|
|
78
77
|
* Increment internalReadyCbCount, an offset value of SDK_READY listeners that are added/removed internally
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies, TelemetryUsageStatsPayload, UpdatesFromSSEEnum, UpdatesFromSSE } from '../../sync/submitters/types';
|
|
2
2
|
import { DEDUPED, DROPPED, LOCALHOST_MODE, QUEUED } from '../../utils/constants';
|
|
3
|
+
import { checkIfServerSide } from '../../utils/key';
|
|
3
4
|
import { findLatencyIndex } from '../findLatencyIndex';
|
|
4
5
|
import { ISegmentsCacheSync, ISplitsCacheSync, IStorageFactoryParams, ITelemetryCacheSync } from '../types';
|
|
5
6
|
|
|
@@ -20,7 +21,7 @@ const ACCEPTANCE_RANGE = 0.001;
|
|
|
20
21
|
* All factory instances track telemetry on server-side, and 0.1% on client-side.
|
|
21
22
|
*/
|
|
22
23
|
export function shouldRecordTelemetry({ settings }: IStorageFactoryParams) {
|
|
23
|
-
return settings.mode !== LOCALHOST_MODE && (settings
|
|
24
|
+
return settings.mode !== LOCALHOST_MODE && (checkIfServerSide(settings) || Math.random() <= ACCEPTANCE_RANGE);
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
export class TelemetryCacheInMemory implements ITelemetryCacheSync {
|
|
@@ -21,6 +21,7 @@ import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS
|
|
|
21
21
|
import { metadataBuilder } from '../utils';
|
|
22
22
|
import { LOG_PREFIX } from '../pluggable/constants';
|
|
23
23
|
import { RBSegmentsCachePluggable } from './RBSegmentsCachePluggable';
|
|
24
|
+
import { checkIfServerSide } from '../../utils/key';
|
|
24
25
|
|
|
25
26
|
const NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.';
|
|
26
27
|
const NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.';
|
|
@@ -83,7 +84,7 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
83
84
|
new ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper);
|
|
84
85
|
|
|
85
86
|
const uniqueKeysCache = isPartialConsumer ?
|
|
86
|
-
settings
|
|
87
|
+
checkIfServerSide(settings) ? new UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS() :
|
|
87
88
|
new UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper);
|
|
88
89
|
|
|
89
90
|
// Connects to wrapper and emits SDK_READY event on main client
|
|
@@ -6,6 +6,7 @@ import { FLAG_SPEC_VERSION } from '../../../utils/constants';
|
|
|
6
6
|
import { base } from '../../../utils/settingsValidation';
|
|
7
7
|
import { ISplitChangesFetcher } from './types';
|
|
8
8
|
import { LOG_PREFIX_SYNC_SPLITS } from '../../../logger/constants';
|
|
9
|
+
import { checkIfServerSide } from '../../../utils/key';
|
|
9
10
|
|
|
10
11
|
const PROXY_CHECK_INTERVAL_MILLIS_CS = 60 * 60 * 1000; // 1 hour in Client Side
|
|
11
12
|
const PROXY_CHECK_INTERVAL_MILLIS_SS = 24 * PROXY_CHECK_INTERVAL_MILLIS_CS; // 24 hours in Server Side
|
|
@@ -22,7 +23,7 @@ function sdkEndpointOverridden(settings: ISettings) {
|
|
|
22
23
|
export function splitChangesFetcherFactory(fetchSplitChanges: IFetchSplitChanges, settings: ISettings, storage: Pick<IStorageBase, 'splits' | 'rbSegments'>): ISplitChangesFetcher {
|
|
23
24
|
|
|
24
25
|
const log = settings.log;
|
|
25
|
-
const PROXY_CHECK_INTERVAL_MILLIS = settings
|
|
26
|
+
const PROXY_CHECK_INTERVAL_MILLIS = checkIfServerSide(settings) ? PROXY_CHECK_INTERVAL_MILLIS_SS : PROXY_CHECK_INTERVAL_MILLIS_CS;
|
|
26
27
|
let lastProxyCheckTimestamp: number | undefined;
|
|
27
28
|
|
|
28
29
|
return function splitChangesFetcher(
|
|
@@ -2,6 +2,7 @@ import { IPlatform } from '../../../sdkFactory/types';
|
|
|
2
2
|
import { decorateHeaders } from '../../../services/decorateHeaders';
|
|
3
3
|
import { IEventSourceConstructor } from '../../../services/types';
|
|
4
4
|
import { ISettings } from '../../../types';
|
|
5
|
+
import { checkIfServerSide } from '../../../utils/key';
|
|
5
6
|
import { isString } from '../../../utils/lang';
|
|
6
7
|
import { objectAssign } from '../../../utils/lang/objectAssign';
|
|
7
8
|
import { IAuthTokenPushEnabled } from '../AuthClient/types';
|
|
@@ -73,7 +74,7 @@ export class SSEClient implements ISSEClient {
|
|
|
73
74
|
return encodeURIComponent(params + channel);
|
|
74
75
|
}).join(',');
|
|
75
76
|
const url = `${this.settings.urls.streaming}/sse?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${ABLY_API_VERSION}&heartbeats=true`; // same results using `&heartbeats=false`
|
|
76
|
-
const isServerSide =
|
|
77
|
+
const isServerSide = checkIfServerSide(this.settings);
|
|
77
78
|
|
|
78
79
|
this.connection = new this.eventSource!(
|
|
79
80
|
// For client-side SDKs, metadata is passed as query param to avoid CORS issues and because native EventSource implementations in browsers do not support headers
|
|
@@ -10,7 +10,7 @@ import { SplitsUpdateWorker } from './UpdateWorkers/SplitsUpdateWorker';
|
|
|
10
10
|
import { authenticateFactory, hashUserKey } from './AuthClient';
|
|
11
11
|
import { forOwn } from '../../utils/lang';
|
|
12
12
|
import { SSEClient } from './SSEClient';
|
|
13
|
-
import { getMatching } from '../../utils/key';
|
|
13
|
+
import { checkIfServerSide, getMatching } from '../../utils/key';
|
|
14
14
|
import { MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, RB_SEGMENT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType } from './constants';
|
|
15
15
|
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MEMBERSHIPS_UPDATE } from '../../logger/constants';
|
|
16
16
|
import { IMembershipMSUpdateData, IMembershipLSUpdateData, KeyList, UpdateStrategy } from './SSEHandler/types';
|
|
@@ -34,7 +34,7 @@ export function pushManagerFactory(
|
|
|
34
34
|
|
|
35
35
|
// `userKey` is the matching key of main client in client-side SDK.
|
|
36
36
|
// It can be used to check if running on client-side or server-side SDK.
|
|
37
|
-
const userKey = settings
|
|
37
|
+
const userKey = checkIfServerSide(settings) ? undefined : getMatching(settings.core.key);
|
|
38
38
|
const log = settings.log;
|
|
39
39
|
|
|
40
40
|
let sseClient: ISSEClient;
|
|
@@ -11,6 +11,7 @@ import { timer } from '../../utils/timeTracker/timer';
|
|
|
11
11
|
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
12
12
|
import { objectAssign } from '../../utils/lang/objectAssign';
|
|
13
13
|
import { ISplitFiltersValidation } from '../../dtos/types';
|
|
14
|
+
import { checkIfServerSide } from '../../utils/key';
|
|
14
15
|
|
|
15
16
|
const OPERATION_MODE_MAP = {
|
|
16
17
|
[STANDALONE_MODE]: STANDALONE_ENUM,
|
|
@@ -72,7 +73,7 @@ export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, sett
|
|
|
72
73
|
|
|
73
74
|
pop(): TelemetryConfigStatsPayload {
|
|
74
75
|
const { urls, scheduler } = settings;
|
|
75
|
-
const
|
|
76
|
+
const isServerSide = checkIfServerSide(settings);
|
|
76
77
|
|
|
77
78
|
const { flagSetsTotal, flagSetsIgnored } = getTelemetryFlagSetsStats(settings.sync.__splitFiltersValidation);
|
|
78
79
|
|
|
@@ -80,8 +81,8 @@ export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, sett
|
|
|
80
81
|
sE: settings.streamingEnabled,
|
|
81
82
|
rR: {
|
|
82
83
|
sp: scheduler.featuresRefreshRate / 1000,
|
|
83
|
-
se:
|
|
84
|
-
ms:
|
|
84
|
+
se: isServerSide ? scheduler.segmentsRefreshRate / 1000 : undefined,
|
|
85
|
+
ms: isServerSide ? undefined : scheduler.segmentsRefreshRate / 1000,
|
|
85
86
|
im: scheduler.impressionsRefreshRate / 1000,
|
|
86
87
|
ev: scheduler.eventsPushRate / 1000,
|
|
87
88
|
te: scheduler.telemetryRefreshRate / 1000,
|
package/src/types.ts
CHANGED
|
@@ -14,21 +14,6 @@ export interface ISettings extends SplitIO.ISettings {
|
|
|
14
14
|
readonly initialRolloutPlan?: RolloutPlan;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* SplitIO.IStatusInterface interface extended with private properties for internal use
|
|
19
|
-
*/
|
|
20
|
-
export interface IStatusInterface extends SplitIO.IStatusInterface {
|
|
21
|
-
// Expose status for internal purposes only. Not considered part of the public API, and might be updated eventually.
|
|
22
|
-
__getStatus(): {
|
|
23
|
-
isReady: boolean;
|
|
24
|
-
isReadyFromCache: boolean;
|
|
25
|
-
isTimedout: boolean;
|
|
26
|
-
hasTimedout: boolean;
|
|
27
|
-
isDestroyed: boolean;
|
|
28
|
-
isOperational: boolean;
|
|
29
|
-
lastUpdate: number;
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
17
|
/**
|
|
33
18
|
* SplitIO.IBasicClient interface extended with private properties for internal use
|
|
34
19
|
*/
|
package/src/utils/key/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import SplitIO from '../../../types/splitio';
|
|
2
|
+
import { ISettings } from '../../types';
|
|
2
3
|
import { isObject } from '../lang';
|
|
3
4
|
|
|
4
5
|
// function isSplitKeyObject(key: any): key is SplitIO.SplitKeyObject {
|
|
@@ -32,3 +33,7 @@ export function keyParser(key: SplitIO.SplitKey): SplitIO.SplitKeyObject {
|
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
35
|
}
|
|
36
|
+
|
|
37
|
+
export function checkIfServerSide(settings: ISettings) {
|
|
38
|
+
return !settings.core.key;
|
|
39
|
+
}
|
package/types/splitio.d.ts
CHANGED
|
@@ -96,6 +96,10 @@ interface ISharedSettings {
|
|
|
96
96
|
* Set together with `debug` option to `true` or a log level string to enable logging.
|
|
97
97
|
*/
|
|
98
98
|
logger?: SplitIO.Logger;
|
|
99
|
+
/**
|
|
100
|
+
* Fallback treatments to be used when the SDK is not ready or the flag is not found.
|
|
101
|
+
*/
|
|
102
|
+
fallbackTreatments?: SplitIO.FallbackTreatmentConfiguration;
|
|
99
103
|
}
|
|
100
104
|
/**
|
|
101
105
|
* Common settings properties for SDKs with synchronous API (standalone and localhost modes).
|
|
@@ -695,6 +699,52 @@ declare namespace SplitIO {
|
|
|
695
699
|
[status in ConsentStatus]: ConsentStatus;
|
|
696
700
|
};
|
|
697
701
|
}
|
|
702
|
+
/**
|
|
703
|
+
* Readiness Status interface. It represents the readiness state of an SDK client.
|
|
704
|
+
*/
|
|
705
|
+
interface ReadinessStatus {
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* `isReady` indicates if the client has triggered an `SDK_READY` event and
|
|
709
|
+
* thus is ready to evaluate with cached data synchronized with the backend.
|
|
710
|
+
*/
|
|
711
|
+
isReady: boolean;
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* `isReadyFromCache` indicates if the client has triggered an `SDK_READY_FROM_CACHE` event and
|
|
715
|
+
* thus is ready to evaluate with cached data, although the data in cache might be stale, not synchronized with the backend.
|
|
716
|
+
*/
|
|
717
|
+
isReadyFromCache: boolean;
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* `isTimedout` indicates if the client has triggered an `SDK_READY_TIMED_OUT` event and is not ready to evaluate.
|
|
721
|
+
* In other words, `isTimedout` is equivalent to `hasTimedout && !isReady`.
|
|
722
|
+
*/
|
|
723
|
+
isTimedout: boolean;
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* `hasTimedout` indicates if the client has ever triggered an `SDK_READY_TIMED_OUT` event.
|
|
727
|
+
* It's meant to keep a reference that the SDK emitted a timeout at some point, not the current state.
|
|
728
|
+
*/
|
|
729
|
+
hasTimedout: boolean;
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* `isDestroyed` indicates if the client has been destroyed, i.e., `destroy` method has been called.
|
|
733
|
+
*/
|
|
734
|
+
isDestroyed: boolean;
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* `isOperational` indicates if the client can evaluate feature flags.
|
|
738
|
+
* In this state, `getTreatment` calls will not return `CONTROL` due to the SDK being unready or destroyed.
|
|
739
|
+
* It's equivalent to `isReadyFromCache && !isDestroyed`.
|
|
740
|
+
*/
|
|
741
|
+
isOperational: boolean;
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* `lastUpdate` indicates the timestamp of the most recent status event.
|
|
745
|
+
*/
|
|
746
|
+
lastUpdate: number;
|
|
747
|
+
}
|
|
698
748
|
/**
|
|
699
749
|
* Common API for entities that expose status handlers.
|
|
700
750
|
*/
|
|
@@ -703,6 +753,12 @@ declare namespace SplitIO {
|
|
|
703
753
|
* Constant object containing the SDK events for you to use.
|
|
704
754
|
*/
|
|
705
755
|
Event: EventConsts;
|
|
756
|
+
/**
|
|
757
|
+
* Gets the readiness status.
|
|
758
|
+
*
|
|
759
|
+
* @returns The current readiness status.
|
|
760
|
+
*/
|
|
761
|
+
getStatus(): ReadinessStatus;
|
|
706
762
|
/**
|
|
707
763
|
* Returns a promise that resolves when the SDK has finished initial synchronization with the backend (`SDK_READY` event emitted), or rejected if the SDK has timedout (`SDK_READY_TIMED_OUT` event emitted).
|
|
708
764
|
* As it's meant to provide similar flexibility to the event approach, given that the SDK might be eventually ready after a timeout event, the `ready` method will return a resolved promise once the SDK is ready.
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FallbackDiscardReason = void 0;
|
|
4
|
-
var FallbackDiscardReason;
|
|
5
|
-
(function (FallbackDiscardReason) {
|
|
6
|
-
FallbackDiscardReason["FlagName"] = "Invalid flag name (max 100 chars, no spaces)";
|
|
7
|
-
FallbackDiscardReason["Treatment"] = "Invalid treatment (max 100 chars and must match pattern)";
|
|
8
|
-
})(FallbackDiscardReason = exports.FallbackDiscardReason || (exports.FallbackDiscardReason = {}));
|
|
@@ -1,5 +0,0 @@
|
|
|
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 = {}));
|