@splitsoftware/splitio-commons 1.3.2-rc.0 → 1.3.2-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/cjs/readiness/sdkReadinessManager.js +7 -7
- package/cjs/sdkFactory/index.js +1 -1
- package/cjs/services/splitApi.js +2 -2
- package/cjs/sync/polling/pollingManagerCS.js +1 -1
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +2 -2
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +2 -2
- package/cjs/sync/submitters/submitter.js +5 -4
- package/cjs/sync/submitters/telemetrySubmitter.js +2 -1
- package/cjs/trackers/telemetryTracker.js +4 -2
- package/cjs/utils/settingsValidation/index.js +16 -6
- package/cjs/utils/settingsValidation/url.js +1 -1
- package/esm/readiness/sdkReadinessManager.js +7 -7
- package/esm/sdkFactory/index.js +1 -1
- package/esm/services/splitApi.js +2 -2
- package/esm/sync/polling/pollingManagerCS.js +1 -1
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +2 -2
- package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -2
- package/esm/sync/submitters/submitter.js +5 -4
- package/esm/sync/submitters/telemetrySubmitter.js +2 -1
- package/esm/trackers/telemetryTracker.js +4 -2
- package/esm/utils/settingsValidation/index.js +17 -7
- package/esm/utils/settingsValidation/url.js +1 -1
- package/package.json +1 -1
- package/src/readiness/sdkReadinessManager.ts +7 -5
- package/src/readiness/types.ts +7 -1
- package/src/sdkFactory/index.ts +1 -1
- package/src/sdkFactory/types.ts +1 -1
- package/src/services/splitApi.ts +2 -2
- package/src/sync/polling/pollingManagerCS.ts +1 -1
- package/src/sync/polling/syncTasks/splitsSyncTask.ts +2 -0
- package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -1
- package/src/sync/submitters/submitter.ts +4 -4
- package/src/sync/submitters/telemetrySubmitter.ts +2 -1
- package/src/trackers/telemetryTracker.ts +3 -3
- package/src/types.ts +1 -1
- package/src/utils/settingsValidation/index.ts +18 -8
- package/src/utils/settingsValidation/url.ts +1 -1
- package/types/readiness/sdkReadinessManager.d.ts +1 -3
- package/types/readiness/types.d.ts +6 -1
- package/types/sdkFactory/types.d.ts +1 -1
- package/types/sync/polling/syncTasks/splitsSyncTask.d.ts +1 -1
- package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -1
- package/types/types.d.ts +1 -1
|
@@ -13,15 +13,13 @@ var REMOVE_LISTENER_EVENT = 'removeListener';
|
|
|
13
13
|
* It also updates logs related warnings and errors.
|
|
14
14
|
*
|
|
15
15
|
* @param readyTimeout time in millis to emit SDK_READY_TIME_OUT event
|
|
16
|
-
* @param internalReadyCbCount offset value of SDK_READY listeners that are added/removed internally
|
|
17
|
-
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
18
16
|
* @param readinessManager optional readinessManager to use. only used internally for `shared` method
|
|
19
17
|
*/
|
|
20
|
-
function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout,
|
|
18
|
+
function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager) {
|
|
21
19
|
if (readyTimeout === void 0) { readyTimeout = 0; }
|
|
22
|
-
if (internalReadyCbCount === void 0) { internalReadyCbCount = 0; }
|
|
23
20
|
if (readinessManager === void 0) { readinessManager = (0, readinessManager_1.readinessManagerFactory)(EventEmitter, readyTimeout); }
|
|
24
21
|
/** Ready callback warning */
|
|
22
|
+
var internalReadyCbCount = 0;
|
|
25
23
|
var readyCbCount = 0;
|
|
26
24
|
readinessManager.gate.on(REMOVE_LISTENER_EVENT, function (event) {
|
|
27
25
|
if (event === constants_1.SDK_READY)
|
|
@@ -62,10 +60,12 @@ function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, internalRea
|
|
|
62
60
|
}
|
|
63
61
|
return {
|
|
64
62
|
readinessManager: readinessManager,
|
|
65
|
-
shared: function (readyTimeout
|
|
63
|
+
shared: function (readyTimeout) {
|
|
66
64
|
if (readyTimeout === void 0) { readyTimeout = 0; }
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
return sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager.shared(readyTimeout));
|
|
66
|
+
},
|
|
67
|
+
incInternalReadyCbCount: function () {
|
|
68
|
+
internalReadyCbCount++;
|
|
69
69
|
},
|
|
70
70
|
sdkStatus: (0, objectAssign_1.objectAssign)(
|
|
71
71
|
// Expose Event Emitter functionality
|
package/cjs/sdkFactory/index.js
CHANGED
|
@@ -55,7 +55,7 @@ function sdkFactory(params) {
|
|
|
55
55
|
var eventTracker = (0, eventTracker_1.eventTrackerFactory)(settings, storage.events, integrationsManager, storage.telemetry);
|
|
56
56
|
var telemetryTracker = (0, telemetryTracker_1.telemetryTrackerFactory)(storage.telemetry, platform.now);
|
|
57
57
|
// splitApi is used by SyncManager and Browser signal listener
|
|
58
|
-
var splitApi = splitApiFactory && splitApiFactory(settings, platform);
|
|
58
|
+
var splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
|
|
59
59
|
var ctx = { splitApi: splitApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform };
|
|
60
60
|
var syncManager = syncManagerFactory && syncManagerFactory(ctx);
|
|
61
61
|
ctx.syncManager = syncManager;
|
package/cjs/services/splitApi.js
CHANGED
|
@@ -91,11 +91,11 @@ function splitApiFactory(settings, platform, telemetryTracker) {
|
|
|
91
91
|
return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.IMPRESSIONS_COUNT));
|
|
92
92
|
},
|
|
93
93
|
postMetricsConfig: function (body) {
|
|
94
|
-
var url = urls.telemetry + "/metrics/config";
|
|
94
|
+
var url = urls.telemetry + "/v1/metrics/config";
|
|
95
95
|
return splitHttpClient(url, { method: 'POST', body: body }, telemetryTracker.trackHttp(constants_1.TELEMETRY), true);
|
|
96
96
|
},
|
|
97
97
|
postMetricsUsage: function (body) {
|
|
98
|
-
var url = urls.telemetry + "/metrics/usage";
|
|
98
|
+
var url = urls.telemetry + "/v1/metrics/usage";
|
|
99
99
|
return splitHttpClient(url, { method: 'POST', body: body }, telemetryTracker.trackHttp(constants_1.TELEMETRY), true);
|
|
100
100
|
}
|
|
101
101
|
};
|
|
@@ -14,7 +14,7 @@ var constants_2 = require("../../logger/constants");
|
|
|
14
14
|
function pollingManagerCSFactory(params) {
|
|
15
15
|
var splitApi = params.splitApi, storage = params.storage, readiness = params.readiness, settings = params.settings;
|
|
16
16
|
var log = settings.log;
|
|
17
|
-
var splitsSyncTask = (0, splitsSyncTask_1.splitsSyncTaskFactory)(splitApi.fetchSplitChanges, storage, readiness, settings);
|
|
17
|
+
var splitsSyncTask = (0, splitsSyncTask_1.splitsSyncTaskFactory)(splitApi.fetchSplitChanges, storage, readiness, settings, true);
|
|
18
18
|
// Map of matching keys to their corresponding MySegmentsSyncTask.
|
|
19
19
|
var mySegmentsSyncTasks = {};
|
|
20
20
|
var matchingKey = (0, key_1.getMatching)(settings.core.key);
|
|
@@ -7,7 +7,7 @@ var splitChangesUpdater_1 = require("../updaters/splitChangesUpdater");
|
|
|
7
7
|
/**
|
|
8
8
|
* Creates a sync task that periodically executes a `splitChangesUpdater` task
|
|
9
9
|
*/
|
|
10
|
-
function splitsSyncTaskFactory(fetchSplitChanges, storage, readiness, settings) {
|
|
11
|
-
return (0, syncTask_1.syncTaskFactory)(settings.log, (0, splitChangesUpdater_1.splitChangesUpdaterFactory)(settings.log, (0, splitChangesFetcher_1.splitChangesFetcherFactory)(fetchSplitChanges), storage.splits, storage.segments, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
|
|
10
|
+
function splitsSyncTaskFactory(fetchSplitChanges, storage, readiness, settings, isClientSide) {
|
|
11
|
+
return (0, syncTask_1.syncTaskFactory)(settings.log, (0, splitChangesUpdater_1.splitChangesUpdaterFactory)(settings.log, (0, splitChangesFetcher_1.splitChangesFetcherFactory)(fetchSplitChanges), storage.splits, storage.segments, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
|
|
12
12
|
}
|
|
13
13
|
exports.splitsSyncTaskFactory = splitsSyncTaskFactory;
|
|
@@ -69,7 +69,7 @@ exports.computeSplitsMutation = computeSplitsMutation;
|
|
|
69
69
|
* @param requestTimeoutBeforeReady How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
|
|
70
70
|
* @param retriesOnFailureBeforeReady How many retries on `/splitChanges` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
|
|
71
71
|
*/
|
|
72
|
-
function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady) {
|
|
72
|
+
function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
|
|
73
73
|
if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
|
|
74
74
|
if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
|
|
75
75
|
var startingUp = true;
|
|
@@ -111,7 +111,7 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
|
|
|
111
111
|
]).then(function () {
|
|
112
112
|
if (splitsEventEmitter) {
|
|
113
113
|
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
114
|
-
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && checkAllSegmentsExist(segments)))
|
|
114
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && (isClientSide || checkAllSegmentsExist(segments))))
|
|
115
115
|
.catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
116
116
|
.then(function (emitSplitsArrivedEvent) {
|
|
117
117
|
// emit SDK events
|
|
@@ -6,7 +6,8 @@ var constants_1 = require("../../logger/constants");
|
|
|
6
6
|
/**
|
|
7
7
|
* Base function to create submitters, such as ImpressionsSubmitter and EventsSubmitter
|
|
8
8
|
*/
|
|
9
|
-
function submitterFactory(log, postClient, sourceCache, postRate, dataName, fromCacheToPayload, maxRetries, debugLogs
|
|
9
|
+
function submitterFactory(log, postClient, sourceCache, postRate, dataName, fromCacheToPayload, maxRetries, debugLogs // true for telemetry submitters
|
|
10
|
+
) {
|
|
10
11
|
if (maxRetries === void 0) { maxRetries = 0; }
|
|
11
12
|
var retries = 0;
|
|
12
13
|
function postData() {
|
|
@@ -24,16 +25,16 @@ function submitterFactory(log, postClient, sourceCache, postRate, dataName, from
|
|
|
24
25
|
sourceCache.clear(); // we clear the queue if request successes.
|
|
25
26
|
}).catch(function (err) {
|
|
26
27
|
if (!maxRetries) {
|
|
27
|
-
log
|
|
28
|
+
log[debugLogs ? 'debug' : 'warn'](constants_1.SUBMITTERS_PUSH_FAILS, [dataCountMessage, err]);
|
|
28
29
|
}
|
|
29
30
|
else if (retries === maxRetries) {
|
|
30
31
|
retries = 0;
|
|
31
32
|
sourceCache.clear(); // we clear the queue if request fails after retries.
|
|
32
|
-
log
|
|
33
|
+
log[debugLogs ? 'debug' : 'warn'](constants_1.SUBMITTERS_PUSH_FAILS, [dataCountMessage, err]);
|
|
33
34
|
}
|
|
34
35
|
else {
|
|
35
36
|
retries++;
|
|
36
|
-
log
|
|
37
|
+
log[debugLogs ? 'debug' : 'warn'](constants_1.SUBMITTERS_PUSH_RETRY, [dataCountMessage, err]);
|
|
37
38
|
}
|
|
38
39
|
});
|
|
39
40
|
}
|
|
@@ -109,12 +109,13 @@ function telemetrySubmitterFactory(params) {
|
|
|
109
109
|
var _a = params.storage, splits = _a.splits, segments = _a.segments, telemetry = _a.telemetry;
|
|
110
110
|
if (!telemetry)
|
|
111
111
|
return; // No submitter created if telemetry cache is not defined
|
|
112
|
-
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, now = params.platform.now, readiness = params.readiness;
|
|
112
|
+
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, now = params.platform.now, readiness = params.readiness, sdkReadinessManager = params.sdkReadinessManager;
|
|
113
113
|
var startTime = (0, timer_1.timer)(now || Date.now);
|
|
114
114
|
var submitter = (0, submitter_1.firstPushWindowDecorator)((0, submitter_1.submitterFactory)(log, splitApi.postMetricsUsage, telemetryCacheStatsAdapter(telemetry, splits, segments), telemetryRefreshRate, 'telemetry stats', undefined, 0, true), telemetryRefreshRate);
|
|
115
115
|
readiness.gate.once(constants_2.SDK_READY_FROM_CACHE, function () {
|
|
116
116
|
telemetry.recordTimeUntilReadyFromCache(startTime());
|
|
117
117
|
});
|
|
118
|
+
sdkReadinessManager.incInternalReadyCbCount();
|
|
118
119
|
readiness.gate.once(constants_2.SDK_READY, function () {
|
|
119
120
|
telemetry.recordTimeUntilReady(startTime());
|
|
120
121
|
// Post config data when the SDK is ready and if the telemetry submitter was started
|
|
@@ -16,7 +16,8 @@ function telemetryTrackerFactory(telemetryCache, now) {
|
|
|
16
16
|
telemetryCache.recordException(method);
|
|
17
17
|
return; // Don't track latency on exceptions
|
|
18
18
|
case labels_1.SDK_NOT_READY: // @ts-ignore ITelemetryCacheAsync doesn't implement the method
|
|
19
|
-
|
|
19
|
+
if (telemetryCache.recordNonReadyUsage)
|
|
20
|
+
telemetryCache.recordNonReadyUsage();
|
|
20
21
|
}
|
|
21
22
|
telemetryCache.recordLatency(method, evalTime());
|
|
22
23
|
};
|
|
@@ -32,7 +33,8 @@ function telemetryTrackerFactory(telemetryCache, now) {
|
|
|
32
33
|
};
|
|
33
34
|
},
|
|
34
35
|
sessionLength: function () {
|
|
35
|
-
telemetryCache.recordSessionLength
|
|
36
|
+
if (telemetryCache.recordSessionLength)
|
|
37
|
+
telemetryCache.recordSessionLength(startTime_1());
|
|
36
38
|
},
|
|
37
39
|
streamingEvent: function (e, d) {
|
|
38
40
|
if (e === constants_1.AUTH_REJECTION) {
|
|
@@ -32,8 +32,8 @@ exports.base = {
|
|
|
32
32
|
segmentsRefreshRate: 60,
|
|
33
33
|
// publish telemetry stats each 3600 secs (1 hour)
|
|
34
34
|
telemetryRefreshRate: 3600,
|
|
35
|
-
// publish evaluations each
|
|
36
|
-
impressionsRefreshRate:
|
|
35
|
+
// publish evaluations each 300 sec (default value for OPTIMIZED impressions mode)
|
|
36
|
+
impressionsRefreshRate: 300,
|
|
37
37
|
// fetch offline changes each 15 sec
|
|
38
38
|
offlineRefreshRate: 15,
|
|
39
39
|
// publish events every 60 seconds after the first flush
|
|
@@ -55,7 +55,7 @@ exports.base = {
|
|
|
55
55
|
// Streaming Server
|
|
56
56
|
streaming: 'https://streaming.split.io',
|
|
57
57
|
// Telemetry Server
|
|
58
|
-
telemetry: 'https://telemetry.split.io',
|
|
58
|
+
telemetry: 'https://telemetry.split.io/api',
|
|
59
59
|
},
|
|
60
60
|
// Defines which kind of storage we should instanciate.
|
|
61
61
|
storage: undefined,
|
|
@@ -96,6 +96,8 @@ function settingsValidation(config, validationParams) {
|
|
|
96
96
|
// First thing to validate, since other validators might use the logger.
|
|
97
97
|
var log = logger(withDefaults); // @ts-ignore, modify readonly prop
|
|
98
98
|
withDefaults.log = log;
|
|
99
|
+
// ensure a valid impressionsMode
|
|
100
|
+
withDefaults.sync.impressionsMode = (0, impressionsMode_1.validImpressionsMode)(log, withDefaults.sync.impressionsMode);
|
|
99
101
|
function validateMinValue(paramName, actualValue, minValue) {
|
|
100
102
|
if (actualValue >= minValue)
|
|
101
103
|
return actualValue;
|
|
@@ -107,10 +109,20 @@ function settingsValidation(config, validationParams) {
|
|
|
107
109
|
var scheduler = withDefaults.scheduler, startup = withDefaults.startup;
|
|
108
110
|
scheduler.featuresRefreshRate = fromSecondsToMillis(scheduler.featuresRefreshRate);
|
|
109
111
|
scheduler.segmentsRefreshRate = fromSecondsToMillis(scheduler.segmentsRefreshRate);
|
|
110
|
-
scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
|
|
111
112
|
scheduler.offlineRefreshRate = fromSecondsToMillis(scheduler.offlineRefreshRate);
|
|
112
113
|
scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate);
|
|
113
114
|
scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
|
|
115
|
+
if (scheduler.impressionsRefreshRate !== exports.base.scheduler.impressionsRefreshRate) {
|
|
116
|
+
// Validate impressionsRefreshRate defined by user
|
|
117
|
+
scheduler.impressionsRefreshRate = validateMinValue('impressionsRefreshRate', scheduler.impressionsRefreshRate, withDefaults.sync.impressionsMode === constants_1.DEBUG ? 1 : 60 // Min is 1 sec for DEBUG and 60 secs for OPTIMIZED
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
// Default impressionsRefreshRate for DEBUG mode is 60 secs
|
|
122
|
+
if (withDefaults.sync.impressionsMode === constants_1.DEBUG)
|
|
123
|
+
scheduler.impressionsRefreshRate = 60;
|
|
124
|
+
}
|
|
125
|
+
scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
|
|
114
126
|
// Log deprecation for old telemetry param
|
|
115
127
|
if (scheduler.metricsRefreshRate)
|
|
116
128
|
log.warn('`metricsRefreshRate` will be deprecated soon. For configuring telemetry rates, update `telemetryRefreshRate` value in configs');
|
|
@@ -166,8 +178,6 @@ function settingsValidation(config, validationParams) {
|
|
|
166
178
|
var splitFiltersValidation = (0, splitFilters_1.validateSplitFilters)(log, withDefaults.sync.splitFilters, withDefaults.mode);
|
|
167
179
|
withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
|
|
168
180
|
withDefaults.sync.__splitFiltersValidation = splitFiltersValidation;
|
|
169
|
-
// ensure a valid impressionsMode
|
|
170
|
-
withDefaults.sync.impressionsMode = (0, impressionsMode_1.validImpressionsMode)(log, withDefaults.sync.impressionsMode);
|
|
171
181
|
// ensure a valid user consent value
|
|
172
182
|
// @ts-ignore, modify readonly prop
|
|
173
183
|
withDefaults.userConsent = consent(withDefaults);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.url = void 0;
|
|
4
|
-
var telemetryEndpointMatcher = /^\/metrics\/(config|usage)/;
|
|
4
|
+
var telemetryEndpointMatcher = /^\/v1\/metrics\/(config|usage)/;
|
|
5
5
|
var eventsEndpointMatcher = /^\/(testImpressions|metrics|events)/;
|
|
6
6
|
var authEndpointMatcher = /^\/v2\/auth/;
|
|
7
7
|
var streamingEndpointMatcher = /^\/(sse|event-stream)/;
|
|
@@ -10,15 +10,13 @@ var REMOVE_LISTENER_EVENT = 'removeListener';
|
|
|
10
10
|
* It also updates logs related warnings and errors.
|
|
11
11
|
*
|
|
12
12
|
* @param readyTimeout time in millis to emit SDK_READY_TIME_OUT event
|
|
13
|
-
* @param internalReadyCbCount offset value of SDK_READY listeners that are added/removed internally
|
|
14
|
-
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
15
13
|
* @param readinessManager optional readinessManager to use. only used internally for `shared` method
|
|
16
14
|
*/
|
|
17
|
-
export function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout,
|
|
15
|
+
export function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager) {
|
|
18
16
|
if (readyTimeout === void 0) { readyTimeout = 0; }
|
|
19
|
-
if (internalReadyCbCount === void 0) { internalReadyCbCount = 0; }
|
|
20
17
|
if (readinessManager === void 0) { readinessManager = readinessManagerFactory(EventEmitter, readyTimeout); }
|
|
21
18
|
/** Ready callback warning */
|
|
19
|
+
var internalReadyCbCount = 0;
|
|
22
20
|
var readyCbCount = 0;
|
|
23
21
|
readinessManager.gate.on(REMOVE_LISTENER_EVENT, function (event) {
|
|
24
22
|
if (event === SDK_READY)
|
|
@@ -59,10 +57,12 @@ export function sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, inte
|
|
|
59
57
|
}
|
|
60
58
|
return {
|
|
61
59
|
readinessManager: readinessManager,
|
|
62
|
-
shared: function (readyTimeout
|
|
60
|
+
shared: function (readyTimeout) {
|
|
63
61
|
if (readyTimeout === void 0) { readyTimeout = 0; }
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
return sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager.shared(readyTimeout));
|
|
63
|
+
},
|
|
64
|
+
incInternalReadyCbCount: function () {
|
|
65
|
+
internalReadyCbCount++;
|
|
66
66
|
},
|
|
67
67
|
sdkStatus: objectAssign(
|
|
68
68
|
// Expose Event Emitter functionality
|
package/esm/sdkFactory/index.js
CHANGED
|
@@ -52,7 +52,7 @@ export function sdkFactory(params) {
|
|
|
52
52
|
var eventTracker = eventTrackerFactory(settings, storage.events, integrationsManager, storage.telemetry);
|
|
53
53
|
var telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
|
|
54
54
|
// splitApi is used by SyncManager and Browser signal listener
|
|
55
|
-
var splitApi = splitApiFactory && splitApiFactory(settings, platform);
|
|
55
|
+
var splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
|
|
56
56
|
var ctx = { splitApi: splitApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform };
|
|
57
57
|
var syncManager = syncManagerFactory && syncManagerFactory(ctx);
|
|
58
58
|
ctx.syncManager = syncManager;
|
package/esm/services/splitApi.js
CHANGED
|
@@ -88,11 +88,11 @@ export function splitApiFactory(settings, platform, telemetryTracker) {
|
|
|
88
88
|
return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(IMPRESSIONS_COUNT));
|
|
89
89
|
},
|
|
90
90
|
postMetricsConfig: function (body) {
|
|
91
|
-
var url = urls.telemetry + "/metrics/config";
|
|
91
|
+
var url = urls.telemetry + "/v1/metrics/config";
|
|
92
92
|
return splitHttpClient(url, { method: 'POST', body: body }, telemetryTracker.trackHttp(TELEMETRY), true);
|
|
93
93
|
},
|
|
94
94
|
postMetricsUsage: function (body) {
|
|
95
|
-
var url = urls.telemetry + "/metrics/usage";
|
|
95
|
+
var url = urls.telemetry + "/v1/metrics/usage";
|
|
96
96
|
return splitHttpClient(url, { method: 'POST', body: body }, telemetryTracker.trackHttp(TELEMETRY), true);
|
|
97
97
|
}
|
|
98
98
|
};
|
|
@@ -11,7 +11,7 @@ import { POLLING_SMART_PAUSING, POLLING_START, POLLING_STOP } from '../../logger
|
|
|
11
11
|
export function pollingManagerCSFactory(params) {
|
|
12
12
|
var splitApi = params.splitApi, storage = params.storage, readiness = params.readiness, settings = params.settings;
|
|
13
13
|
var log = settings.log;
|
|
14
|
-
var splitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings);
|
|
14
|
+
var splitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings, true);
|
|
15
15
|
// Map of matching keys to their corresponding MySegmentsSyncTask.
|
|
16
16
|
var mySegmentsSyncTasks = {};
|
|
17
17
|
var matchingKey = getMatching(settings.core.key);
|
|
@@ -4,6 +4,6 @@ import { splitChangesUpdaterFactory } from '../updaters/splitChangesUpdater';
|
|
|
4
4
|
/**
|
|
5
5
|
* Creates a sync task that periodically executes a `splitChangesUpdater` task
|
|
6
6
|
*/
|
|
7
|
-
export function splitsSyncTaskFactory(fetchSplitChanges, storage, readiness, settings) {
|
|
8
|
-
return syncTaskFactory(settings.log, splitChangesUpdaterFactory(settings.log, splitChangesFetcherFactory(fetchSplitChanges), storage.splits, storage.segments, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
|
|
7
|
+
export function splitsSyncTaskFactory(fetchSplitChanges, storage, readiness, settings, isClientSide) {
|
|
8
|
+
return syncTaskFactory(settings.log, splitChangesUpdaterFactory(settings.log, splitChangesFetcherFactory(fetchSplitChanges), storage.splits, storage.segments, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
|
|
9
9
|
}
|
|
@@ -64,7 +64,7 @@ export function computeSplitsMutation(entries) {
|
|
|
64
64
|
* @param requestTimeoutBeforeReady How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
|
|
65
65
|
* @param retriesOnFailureBeforeReady How many retries on `/splitChanges` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
|
|
66
66
|
*/
|
|
67
|
-
export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady) {
|
|
67
|
+
export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
|
|
68
68
|
if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
|
|
69
69
|
if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
|
|
70
70
|
var startingUp = true;
|
|
@@ -106,7 +106,7 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
|
|
|
106
106
|
]).then(function () {
|
|
107
107
|
if (splitsEventEmitter) {
|
|
108
108
|
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
109
|
-
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && checkAllSegmentsExist(segments)))
|
|
109
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && (isClientSide || checkAllSegmentsExist(segments))))
|
|
110
110
|
.catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
111
111
|
.then(function (emitSplitsArrivedEvent) {
|
|
112
112
|
// emit SDK events
|
|
@@ -3,7 +3,8 @@ import { SUBMITTERS_PUSH, SUBMITTERS_PUSH_FAILS, SUBMITTERS_PUSH_RETRY } from '.
|
|
|
3
3
|
/**
|
|
4
4
|
* Base function to create submitters, such as ImpressionsSubmitter and EventsSubmitter
|
|
5
5
|
*/
|
|
6
|
-
export function submitterFactory(log, postClient, sourceCache, postRate, dataName, fromCacheToPayload, maxRetries, debugLogs
|
|
6
|
+
export function submitterFactory(log, postClient, sourceCache, postRate, dataName, fromCacheToPayload, maxRetries, debugLogs // true for telemetry submitters
|
|
7
|
+
) {
|
|
7
8
|
if (maxRetries === void 0) { maxRetries = 0; }
|
|
8
9
|
var retries = 0;
|
|
9
10
|
function postData() {
|
|
@@ -21,16 +22,16 @@ export function submitterFactory(log, postClient, sourceCache, postRate, dataNam
|
|
|
21
22
|
sourceCache.clear(); // we clear the queue if request successes.
|
|
22
23
|
}).catch(function (err) {
|
|
23
24
|
if (!maxRetries) {
|
|
24
|
-
log
|
|
25
|
+
log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_FAILS, [dataCountMessage, err]);
|
|
25
26
|
}
|
|
26
27
|
else if (retries === maxRetries) {
|
|
27
28
|
retries = 0;
|
|
28
29
|
sourceCache.clear(); // we clear the queue if request fails after retries.
|
|
29
|
-
log
|
|
30
|
+
log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_FAILS, [dataCountMessage, err]);
|
|
30
31
|
}
|
|
31
32
|
else {
|
|
32
33
|
retries++;
|
|
33
|
-
log
|
|
34
|
+
log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_RETRY, [dataCountMessage, err]);
|
|
34
35
|
}
|
|
35
36
|
});
|
|
36
37
|
}
|
|
@@ -104,12 +104,13 @@ export function telemetrySubmitterFactory(params) {
|
|
|
104
104
|
var _a = params.storage, splits = _a.splits, segments = _a.segments, telemetry = _a.telemetry;
|
|
105
105
|
if (!telemetry)
|
|
106
106
|
return; // No submitter created if telemetry cache is not defined
|
|
107
|
-
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, now = params.platform.now, readiness = params.readiness;
|
|
107
|
+
var settings = params.settings, _b = params.settings, log = _b.log, telemetryRefreshRate = _b.scheduler.telemetryRefreshRate, splitApi = params.splitApi, now = params.platform.now, readiness = params.readiness, sdkReadinessManager = params.sdkReadinessManager;
|
|
108
108
|
var startTime = timer(now || Date.now);
|
|
109
109
|
var submitter = firstPushWindowDecorator(submitterFactory(log, splitApi.postMetricsUsage, telemetryCacheStatsAdapter(telemetry, splits, segments), telemetryRefreshRate, 'telemetry stats', undefined, 0, true), telemetryRefreshRate);
|
|
110
110
|
readiness.gate.once(SDK_READY_FROM_CACHE, function () {
|
|
111
111
|
telemetry.recordTimeUntilReadyFromCache(startTime());
|
|
112
112
|
});
|
|
113
|
+
sdkReadinessManager.incInternalReadyCbCount();
|
|
113
114
|
readiness.gate.once(SDK_READY, function () {
|
|
114
115
|
telemetry.recordTimeUntilReady(startTime());
|
|
115
116
|
// Post config data when the SDK is ready and if the telemetry submitter was started
|
|
@@ -13,7 +13,8 @@ export function telemetryTrackerFactory(telemetryCache, now) {
|
|
|
13
13
|
telemetryCache.recordException(method);
|
|
14
14
|
return; // Don't track latency on exceptions
|
|
15
15
|
case SDK_NOT_READY: // @ts-ignore ITelemetryCacheAsync doesn't implement the method
|
|
16
|
-
|
|
16
|
+
if (telemetryCache.recordNonReadyUsage)
|
|
17
|
+
telemetryCache.recordNonReadyUsage();
|
|
17
18
|
}
|
|
18
19
|
telemetryCache.recordLatency(method, evalTime());
|
|
19
20
|
};
|
|
@@ -29,7 +30,8 @@ export function telemetryTrackerFactory(telemetryCache, now) {
|
|
|
29
30
|
};
|
|
30
31
|
},
|
|
31
32
|
sessionLength: function () {
|
|
32
|
-
telemetryCache.recordSessionLength
|
|
33
|
+
if (telemetryCache.recordSessionLength)
|
|
34
|
+
telemetryCache.recordSessionLength(startTime_1());
|
|
33
35
|
},
|
|
34
36
|
streamingEvent: function (e, d) {
|
|
35
37
|
if (e === AUTH_REJECTION) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { merge } from '../lang';
|
|
2
2
|
import { mode } from './mode';
|
|
3
3
|
import { validateSplitFilters } from './splitFilters';
|
|
4
|
-
import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE } from '../constants';
|
|
4
|
+
import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE, DEBUG } from '../constants';
|
|
5
5
|
import { validImpressionsMode } from './impressionsMode';
|
|
6
6
|
import { validateKey } from '../inputValidation/key';
|
|
7
7
|
import { validateTrafficType } from '../inputValidation/trafficType';
|
|
@@ -29,8 +29,8 @@ export var base = {
|
|
|
29
29
|
segmentsRefreshRate: 60,
|
|
30
30
|
// publish telemetry stats each 3600 secs (1 hour)
|
|
31
31
|
telemetryRefreshRate: 3600,
|
|
32
|
-
// publish evaluations each
|
|
33
|
-
impressionsRefreshRate:
|
|
32
|
+
// publish evaluations each 300 sec (default value for OPTIMIZED impressions mode)
|
|
33
|
+
impressionsRefreshRate: 300,
|
|
34
34
|
// fetch offline changes each 15 sec
|
|
35
35
|
offlineRefreshRate: 15,
|
|
36
36
|
// publish events every 60 seconds after the first flush
|
|
@@ -52,7 +52,7 @@ export var base = {
|
|
|
52
52
|
// Streaming Server
|
|
53
53
|
streaming: 'https://streaming.split.io',
|
|
54
54
|
// Telemetry Server
|
|
55
|
-
telemetry: 'https://telemetry.split.io',
|
|
55
|
+
telemetry: 'https://telemetry.split.io/api',
|
|
56
56
|
},
|
|
57
57
|
// Defines which kind of storage we should instanciate.
|
|
58
58
|
storage: undefined,
|
|
@@ -93,6 +93,8 @@ export function settingsValidation(config, validationParams) {
|
|
|
93
93
|
// First thing to validate, since other validators might use the logger.
|
|
94
94
|
var log = logger(withDefaults); // @ts-ignore, modify readonly prop
|
|
95
95
|
withDefaults.log = log;
|
|
96
|
+
// ensure a valid impressionsMode
|
|
97
|
+
withDefaults.sync.impressionsMode = validImpressionsMode(log, withDefaults.sync.impressionsMode);
|
|
96
98
|
function validateMinValue(paramName, actualValue, minValue) {
|
|
97
99
|
if (actualValue >= minValue)
|
|
98
100
|
return actualValue;
|
|
@@ -104,10 +106,20 @@ export function settingsValidation(config, validationParams) {
|
|
|
104
106
|
var scheduler = withDefaults.scheduler, startup = withDefaults.startup;
|
|
105
107
|
scheduler.featuresRefreshRate = fromSecondsToMillis(scheduler.featuresRefreshRate);
|
|
106
108
|
scheduler.segmentsRefreshRate = fromSecondsToMillis(scheduler.segmentsRefreshRate);
|
|
107
|
-
scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
|
|
108
109
|
scheduler.offlineRefreshRate = fromSecondsToMillis(scheduler.offlineRefreshRate);
|
|
109
110
|
scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate);
|
|
110
111
|
scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
|
|
112
|
+
if (scheduler.impressionsRefreshRate !== base.scheduler.impressionsRefreshRate) {
|
|
113
|
+
// Validate impressionsRefreshRate defined by user
|
|
114
|
+
scheduler.impressionsRefreshRate = validateMinValue('impressionsRefreshRate', scheduler.impressionsRefreshRate, withDefaults.sync.impressionsMode === DEBUG ? 1 : 60 // Min is 1 sec for DEBUG and 60 secs for OPTIMIZED
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
// Default impressionsRefreshRate for DEBUG mode is 60 secs
|
|
119
|
+
if (withDefaults.sync.impressionsMode === DEBUG)
|
|
120
|
+
scheduler.impressionsRefreshRate = 60;
|
|
121
|
+
}
|
|
122
|
+
scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
|
|
111
123
|
// Log deprecation for old telemetry param
|
|
112
124
|
if (scheduler.metricsRefreshRate)
|
|
113
125
|
log.warn('`metricsRefreshRate` will be deprecated soon. For configuring telemetry rates, update `telemetryRefreshRate` value in configs');
|
|
@@ -163,8 +175,6 @@ export function settingsValidation(config, validationParams) {
|
|
|
163
175
|
var splitFiltersValidation = validateSplitFilters(log, withDefaults.sync.splitFilters, withDefaults.mode);
|
|
164
176
|
withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
|
|
165
177
|
withDefaults.sync.__splitFiltersValidation = splitFiltersValidation;
|
|
166
|
-
// ensure a valid impressionsMode
|
|
167
|
-
withDefaults.sync.impressionsMode = validImpressionsMode(log, withDefaults.sync.impressionsMode);
|
|
168
178
|
// ensure a valid user consent value
|
|
169
179
|
// @ts-ignore, modify readonly prop
|
|
170
180
|
withDefaults.userConsent = consent(withDefaults);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var telemetryEndpointMatcher = /^\/metrics\/(config|usage)/;
|
|
1
|
+
var telemetryEndpointMatcher = /^\/v1\/metrics\/(config|usage)/;
|
|
2
2
|
var eventsEndpointMatcher = /^\/(testImpressions|metrics|events)/;
|
|
3
3
|
var authEndpointMatcher = /^\/v2\/auth/;
|
|
4
4
|
var streamingEndpointMatcher = /^\/(sse|event-stream)/;
|
package/package.json
CHANGED
|
@@ -15,18 +15,16 @@ const REMOVE_LISTENER_EVENT = 'removeListener';
|
|
|
15
15
|
* It also updates logs related warnings and errors.
|
|
16
16
|
*
|
|
17
17
|
* @param readyTimeout time in millis to emit SDK_READY_TIME_OUT event
|
|
18
|
-
* @param internalReadyCbCount offset value of SDK_READY listeners that are added/removed internally
|
|
19
|
-
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
20
18
|
* @param readinessManager optional readinessManager to use. only used internally for `shared` method
|
|
21
19
|
*/
|
|
22
20
|
export function sdkReadinessManagerFactory(
|
|
23
21
|
log: ILogger,
|
|
24
22
|
EventEmitter: new () => IEventEmitter,
|
|
25
23
|
readyTimeout = 0,
|
|
26
|
-
internalReadyCbCount = 0,
|
|
27
24
|
readinessManager = readinessManagerFactory(EventEmitter, readyTimeout)): ISdkReadinessManager {
|
|
28
25
|
|
|
29
26
|
/** Ready callback warning */
|
|
27
|
+
let internalReadyCbCount = 0;
|
|
30
28
|
let readyCbCount = 0;
|
|
31
29
|
readinessManager.gate.on(REMOVE_LISTENER_EVENT, (event: any) => {
|
|
32
30
|
if (event === SDK_READY) readyCbCount--;
|
|
@@ -74,8 +72,12 @@ export function sdkReadinessManagerFactory(
|
|
|
74
72
|
return {
|
|
75
73
|
readinessManager,
|
|
76
74
|
|
|
77
|
-
shared(readyTimeout = 0
|
|
78
|
-
return sdkReadinessManagerFactory(log, EventEmitter, readyTimeout,
|
|
75
|
+
shared(readyTimeout = 0) {
|
|
76
|
+
return sdkReadinessManagerFactory(log, EventEmitter, readyTimeout, readinessManager.shared(readyTimeout));
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
incInternalReadyCbCount() {
|
|
80
|
+
internalReadyCbCount++;
|
|
79
81
|
},
|
|
80
82
|
|
|
81
83
|
sdkStatus: objectAssign(
|
package/src/readiness/types.ts
CHANGED
|
@@ -66,6 +66,12 @@ export interface ISdkReadinessManager {
|
|
|
66
66
|
readinessManager: IReadinessManager
|
|
67
67
|
sdkStatus: IStatusInterface
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Increment internalReadyCbCount, an offset value of SDK_READY listeners that are added/removed internally
|
|
71
|
+
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
72
|
+
*/
|
|
73
|
+
incInternalReadyCbCount(): void
|
|
74
|
+
|
|
69
75
|
/** for client-side */
|
|
70
|
-
shared(readyTimeout?: number
|
|
76
|
+
shared(readyTimeout?: number): ISdkReadinessManager
|
|
71
77
|
}
|
package/src/sdkFactory/index.ts
CHANGED
|
@@ -69,7 +69,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
69
69
|
const telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
|
|
70
70
|
|
|
71
71
|
// splitApi is used by SyncManager and Browser signal listener
|
|
72
|
-
const splitApi = splitApiFactory && splitApiFactory(settings, platform);
|
|
72
|
+
const splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
|
|
73
73
|
|
|
74
74
|
const ctx: ISdkFactoryContext = { splitApi, eventTracker, impressionsTracker, telemetryTracker, sdkReadinessManager, readiness, settings, storage, platform };
|
|
75
75
|
|
package/src/sdkFactory/types.ts
CHANGED
|
@@ -64,7 +64,7 @@ export interface ISdkFactoryParams {
|
|
|
64
64
|
|
|
65
65
|
// Factory of Split Api (HTTP Client Service).
|
|
66
66
|
// It is not required when providing an asynchronous storage or offline SyncManager
|
|
67
|
-
splitApiFactory?: (settings: ISettings, platform: IPlatform) => ISplitApi,
|
|
67
|
+
splitApiFactory?: (settings: ISettings, platform: IPlatform, telemetryTracker: ITelemetryTracker) => ISplitApi,
|
|
68
68
|
|
|
69
69
|
// SyncManager factory.
|
|
70
70
|
// Not required when providing an asynchronous storage (consumer mode), but required in standalone mode to avoid SDK timeout.
|
package/src/services/splitApi.ts
CHANGED
|
@@ -108,12 +108,12 @@ export function splitApiFactory(
|
|
|
108
108
|
},
|
|
109
109
|
|
|
110
110
|
postMetricsConfig(body: string) {
|
|
111
|
-
const url = `${urls.telemetry}/metrics/config`;
|
|
111
|
+
const url = `${urls.telemetry}/v1/metrics/config`;
|
|
112
112
|
return splitHttpClient(url, { method: 'POST', body }, telemetryTracker.trackHttp(TELEMETRY), true);
|
|
113
113
|
},
|
|
114
114
|
|
|
115
115
|
postMetricsUsage(body: string) {
|
|
116
|
-
const url = `${urls.telemetry}/metrics/usage`;
|
|
116
|
+
const url = `${urls.telemetry}/v1/metrics/usage`;
|
|
117
117
|
return splitHttpClient(url, { method: 'POST', body }, telemetryTracker.trackHttp(TELEMETRY), true);
|
|
118
118
|
}
|
|
119
119
|
};
|
|
@@ -20,7 +20,7 @@ export function pollingManagerCSFactory(
|
|
|
20
20
|
const { splitApi, storage, readiness, settings } = params;
|
|
21
21
|
const log = settings.log;
|
|
22
22
|
|
|
23
|
-
const splitsSyncTask: ISplitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings);
|
|
23
|
+
const splitsSyncTask: ISplitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings, true);
|
|
24
24
|
|
|
25
25
|
// Map of matching keys to their corresponding MySegmentsSyncTask.
|
|
26
26
|
const mySegmentsSyncTasks: Record<string, ISegmentsSyncTask> = {};
|
|
@@ -15,6 +15,7 @@ export function splitsSyncTaskFactory(
|
|
|
15
15
|
storage: IStorageSync,
|
|
16
16
|
readiness: IReadinessManager,
|
|
17
17
|
settings: ISettings,
|
|
18
|
+
isClientSide?: boolean
|
|
18
19
|
): ISplitsSyncTask {
|
|
19
20
|
return syncTaskFactory(
|
|
20
21
|
settings.log,
|
|
@@ -26,6 +27,7 @@ export function splitsSyncTaskFactory(
|
|
|
26
27
|
readiness.splits,
|
|
27
28
|
settings.startup.requestTimeoutBeforeReady,
|
|
28
29
|
settings.startup.retriesOnFailureBeforeReady,
|
|
30
|
+
isClientSide
|
|
29
31
|
),
|
|
30
32
|
settings.scheduler.featuresRefreshRate,
|
|
31
33
|
'splitChangesUpdater',
|
|
@@ -93,6 +93,7 @@ export function splitChangesUpdaterFactory(
|
|
|
93
93
|
splitsEventEmitter?: ISplitsEventEmitter,
|
|
94
94
|
requestTimeoutBeforeReady: number = 0,
|
|
95
95
|
retriesOnFailureBeforeReady: number = 0,
|
|
96
|
+
isClientSide?: boolean
|
|
96
97
|
): ISplitChangesUpdater {
|
|
97
98
|
|
|
98
99
|
let startingUp = true;
|
|
@@ -140,7 +141,7 @@ export function splitChangesUpdaterFactory(
|
|
|
140
141
|
|
|
141
142
|
if (splitsEventEmitter) {
|
|
142
143
|
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
143
|
-
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && checkAllSegmentsExist(segments)))
|
|
144
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && (isClientSide || checkAllSegmentsExist(segments))))
|
|
144
145
|
.catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
145
146
|
.then(emitSplitsArrivedEvent => {
|
|
146
147
|
// emit SDK events
|
|
@@ -16,7 +16,7 @@ export function submitterFactory<TState>(
|
|
|
16
16
|
dataName: string,
|
|
17
17
|
fromCacheToPayload?: (cacheData: TState) => any,
|
|
18
18
|
maxRetries: number = 0,
|
|
19
|
-
debugLogs?: boolean
|
|
19
|
+
debugLogs?: boolean // true for telemetry submitters
|
|
20
20
|
): ISyncTask<[], void> {
|
|
21
21
|
|
|
22
22
|
let retries = 0;
|
|
@@ -37,14 +37,14 @@ export function submitterFactory<TState>(
|
|
|
37
37
|
sourceCache.clear(); // we clear the queue if request successes.
|
|
38
38
|
}).catch(err => {
|
|
39
39
|
if (!maxRetries) {
|
|
40
|
-
log
|
|
40
|
+
log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_FAILS, [dataCountMessage, err]);
|
|
41
41
|
} else if (retries === maxRetries) {
|
|
42
42
|
retries = 0;
|
|
43
43
|
sourceCache.clear(); // we clear the queue if request fails after retries.
|
|
44
|
-
log
|
|
44
|
+
log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_FAILS, [dataCountMessage, err]);
|
|
45
45
|
} else {
|
|
46
46
|
retries++;
|
|
47
|
-
log
|
|
47
|
+
log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_RETRY, [dataCountMessage, err]);
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
}
|
|
@@ -117,7 +117,7 @@ export function telemetrySubmitterFactory(params: ISdkFactoryContextSync) {
|
|
|
117
117
|
const { storage: { splits, segments, telemetry } } = params;
|
|
118
118
|
if (!telemetry) return; // No submitter created if telemetry cache is not defined
|
|
119
119
|
|
|
120
|
-
const { settings, settings: { log, scheduler: { telemetryRefreshRate } }, splitApi, platform: { now }, readiness } = params;
|
|
120
|
+
const { settings, settings: { log, scheduler: { telemetryRefreshRate } }, splitApi, platform: { now }, readiness, sdkReadinessManager } = params;
|
|
121
121
|
const startTime = timer(now || Date.now);
|
|
122
122
|
|
|
123
123
|
const submitter = firstPushWindowDecorator(
|
|
@@ -129,6 +129,7 @@ export function telemetrySubmitterFactory(params: ISdkFactoryContextSync) {
|
|
|
129
129
|
telemetry.recordTimeUntilReadyFromCache(startTime());
|
|
130
130
|
});
|
|
131
131
|
|
|
132
|
+
sdkReadinessManager.incInternalReadyCbCount();
|
|
132
133
|
readiness.gate.once(SDK_READY, () => {
|
|
133
134
|
telemetry.recordTimeUntilReady(startTime());
|
|
134
135
|
|
|
@@ -22,7 +22,7 @@ export function telemetryTrackerFactory(
|
|
|
22
22
|
telemetryCache.recordException(method);
|
|
23
23
|
return; // Don't track latency on exceptions
|
|
24
24
|
case SDK_NOT_READY: // @ts-ignore ITelemetryCacheAsync doesn't implement the method
|
|
25
|
-
telemetryCache
|
|
25
|
+
if (telemetryCache.recordNonReadyUsage) telemetryCache.recordNonReadyUsage();
|
|
26
26
|
}
|
|
27
27
|
telemetryCache.recordLatency(method, evalTime());
|
|
28
28
|
};
|
|
@@ -36,8 +36,8 @@ export function telemetryTrackerFactory(
|
|
|
36
36
|
else (telemetryCache as ITelemetryCacheSync).recordSuccessfulSync(operation, now());
|
|
37
37
|
};
|
|
38
38
|
},
|
|
39
|
-
sessionLength() {
|
|
40
|
-
(telemetryCache
|
|
39
|
+
sessionLength() { // @ts-ignore ITelemetryCacheAsync doesn't implement the method
|
|
40
|
+
if (telemetryCache.recordSessionLength) telemetryCache.recordSessionLength(startTime());
|
|
41
41
|
},
|
|
42
42
|
streamingEvent(e, d) {
|
|
43
43
|
if (e === AUTH_REJECTION) {
|
package/src/types.ts
CHANGED
|
@@ -684,7 +684,7 @@ export namespace SplitIO {
|
|
|
684
684
|
/**
|
|
685
685
|
* String property to override the base URL where the SDK will post telemetry data.
|
|
686
686
|
* @property {string} telemetry
|
|
687
|
-
* @default 'https://telemetry.split.io'
|
|
687
|
+
* @default 'https://telemetry.split.io/api'
|
|
688
688
|
*/
|
|
689
689
|
telemetry?: string
|
|
690
690
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { merge } from '../lang';
|
|
2
2
|
import { mode } from './mode';
|
|
3
3
|
import { validateSplitFilters } from './splitFilters';
|
|
4
|
-
import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE } from '../constants';
|
|
4
|
+
import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE, DEBUG } from '../constants';
|
|
5
5
|
import { validImpressionsMode } from './impressionsMode';
|
|
6
6
|
import { ISettingsValidationParams } from './types';
|
|
7
7
|
import { ISettings } from '../../types';
|
|
@@ -34,8 +34,8 @@ export const base = {
|
|
|
34
34
|
segmentsRefreshRate: 60,
|
|
35
35
|
// publish telemetry stats each 3600 secs (1 hour)
|
|
36
36
|
telemetryRefreshRate: 3600,
|
|
37
|
-
// publish evaluations each
|
|
38
|
-
impressionsRefreshRate:
|
|
37
|
+
// publish evaluations each 300 sec (default value for OPTIMIZED impressions mode)
|
|
38
|
+
impressionsRefreshRate: 300,
|
|
39
39
|
// fetch offline changes each 15 sec
|
|
40
40
|
offlineRefreshRate: 15,
|
|
41
41
|
// publish events every 60 seconds after the first flush
|
|
@@ -58,7 +58,7 @@ export const base = {
|
|
|
58
58
|
// Streaming Server
|
|
59
59
|
streaming: 'https://streaming.split.io',
|
|
60
60
|
// Telemetry Server
|
|
61
|
-
telemetry: 'https://telemetry.split.io',
|
|
61
|
+
telemetry: 'https://telemetry.split.io/api',
|
|
62
62
|
},
|
|
63
63
|
|
|
64
64
|
// Defines which kind of storage we should instanciate.
|
|
@@ -113,6 +113,9 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
|
|
|
113
113
|
const log = logger(withDefaults); // @ts-ignore, modify readonly prop
|
|
114
114
|
withDefaults.log = log;
|
|
115
115
|
|
|
116
|
+
// ensure a valid impressionsMode
|
|
117
|
+
withDefaults.sync.impressionsMode = validImpressionsMode(log, withDefaults.sync.impressionsMode);
|
|
118
|
+
|
|
116
119
|
function validateMinValue(paramName: string, actualValue: number, minValue: number) {
|
|
117
120
|
if (actualValue >= minValue) return actualValue;
|
|
118
121
|
// actualValue is not a number or is lower than minValue
|
|
@@ -124,11 +127,21 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
|
|
|
124
127
|
const { scheduler, startup } = withDefaults;
|
|
125
128
|
scheduler.featuresRefreshRate = fromSecondsToMillis(scheduler.featuresRefreshRate);
|
|
126
129
|
scheduler.segmentsRefreshRate = fromSecondsToMillis(scheduler.segmentsRefreshRate);
|
|
127
|
-
scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
|
|
128
130
|
scheduler.offlineRefreshRate = fromSecondsToMillis(scheduler.offlineRefreshRate);
|
|
129
131
|
scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate);
|
|
130
132
|
scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
|
|
131
133
|
|
|
134
|
+
if (scheduler.impressionsRefreshRate !== base.scheduler.impressionsRefreshRate) {
|
|
135
|
+
// Validate impressionsRefreshRate defined by user
|
|
136
|
+
scheduler.impressionsRefreshRate = validateMinValue('impressionsRefreshRate', scheduler.impressionsRefreshRate,
|
|
137
|
+
withDefaults.sync.impressionsMode === DEBUG ? 1 : 60 // Min is 1 sec for DEBUG and 60 secs for OPTIMIZED
|
|
138
|
+
);
|
|
139
|
+
} else {
|
|
140
|
+
// Default impressionsRefreshRate for DEBUG mode is 60 secs
|
|
141
|
+
if (withDefaults.sync.impressionsMode === DEBUG) scheduler.impressionsRefreshRate = 60;
|
|
142
|
+
}
|
|
143
|
+
scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
|
|
144
|
+
|
|
132
145
|
// Log deprecation for old telemetry param
|
|
133
146
|
if (scheduler.metricsRefreshRate) log.warn('`metricsRefreshRate` will be deprecated soon. For configuring telemetry rates, update `telemetryRefreshRate` value in configs');
|
|
134
147
|
|
|
@@ -190,9 +203,6 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
|
|
|
190
203
|
withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
|
|
191
204
|
withDefaults.sync.__splitFiltersValidation = splitFiltersValidation;
|
|
192
205
|
|
|
193
|
-
// ensure a valid impressionsMode
|
|
194
|
-
withDefaults.sync.impressionsMode = validImpressionsMode(log, withDefaults.sync.impressionsMode);
|
|
195
|
-
|
|
196
206
|
// ensure a valid user consent value
|
|
197
207
|
// @ts-ignore, modify readonly prop
|
|
198
208
|
withDefaults.userConsent = consent(withDefaults);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ISettings } from '../../types';
|
|
2
2
|
|
|
3
|
-
const telemetryEndpointMatcher = /^\/metrics\/(config|usage)/;
|
|
3
|
+
const telemetryEndpointMatcher = /^\/v1\/metrics\/(config|usage)/;
|
|
4
4
|
const eventsEndpointMatcher = /^\/(testImpressions|metrics|events)/;
|
|
5
5
|
const authEndpointMatcher = /^\/v2\/auth/;
|
|
6
6
|
const streamingEndpointMatcher = /^\/(sse|event-stream)/;
|
|
@@ -6,8 +6,6 @@ import { ILogger } from '../logger/types';
|
|
|
6
6
|
* It also updates logs related warnings and errors.
|
|
7
7
|
*
|
|
8
8
|
* @param readyTimeout time in millis to emit SDK_READY_TIME_OUT event
|
|
9
|
-
* @param internalReadyCbCount offset value of SDK_READY listeners that are added/removed internally
|
|
10
|
-
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
11
9
|
* @param readinessManager optional readinessManager to use. only used internally for `shared` method
|
|
12
10
|
*/
|
|
13
|
-
export declare function sdkReadinessManagerFactory(log: ILogger, EventEmitter: new () => IEventEmitter, readyTimeout?: number,
|
|
11
|
+
export declare function sdkReadinessManagerFactory(log: ILogger, EventEmitter: new () => IEventEmitter, readyTimeout?: number, readinessManager?: import("./types").IReadinessManager): ISdkReadinessManager;
|
|
@@ -49,7 +49,12 @@ export interface IReadinessManager {
|
|
|
49
49
|
export interface ISdkReadinessManager {
|
|
50
50
|
readinessManager: IReadinessManager;
|
|
51
51
|
sdkStatus: IStatusInterface;
|
|
52
|
+
/**
|
|
53
|
+
* Increment internalReadyCbCount, an offset value of SDK_READY listeners that are added/removed internally
|
|
54
|
+
* by the SDK. It is required to properly log the warning 'No listeners for SDK Readiness detected'
|
|
55
|
+
*/
|
|
56
|
+
incInternalReadyCbCount(): void;
|
|
52
57
|
/** for client-side */
|
|
53
|
-
shared(readyTimeout?: number
|
|
58
|
+
shared(readyTimeout?: number): ISdkReadinessManager;
|
|
54
59
|
}
|
|
55
60
|
export {};
|
|
@@ -49,7 +49,7 @@ export interface ISdkFactoryParams {
|
|
|
49
49
|
settings: ISettings;
|
|
50
50
|
platform: IPlatform;
|
|
51
51
|
storageFactory: (params: IStorageFactoryParams) => IStorageSync | IStorageAsync;
|
|
52
|
-
splitApiFactory?: (settings: ISettings, platform: IPlatform) => ISplitApi;
|
|
52
|
+
splitApiFactory?: (settings: ISettings, platform: IPlatform, telemetryTracker: ITelemetryTracker) => ISplitApi;
|
|
53
53
|
syncManagerFactory?: (params: ISdkFactoryContextSync) => ISyncManager;
|
|
54
54
|
sdkManagerFactory: (log: ILogger, splits: ISplitsCacheSync | ISplitsCacheAsync, sdkReadinessManager: ISdkReadinessManager) => SplitIO.IManager | SplitIO.IAsyncManager;
|
|
55
55
|
sdkClientMethodFactory: (params: ISdkFactoryContext) => ({
|
|
@@ -6,4 +6,4 @@ import { ISettings } from '../../../types';
|
|
|
6
6
|
/**
|
|
7
7
|
* Creates a sync task that periodically executes a `splitChangesUpdater` task
|
|
8
8
|
*/
|
|
9
|
-
export declare function splitsSyncTaskFactory(fetchSplitChanges: IFetchSplitChanges, storage: IStorageSync, readiness: IReadinessManager, settings: ISettings): ISplitsSyncTask;
|
|
9
|
+
export declare function splitsSyncTaskFactory(fetchSplitChanges: IFetchSplitChanges, storage: IStorageSync, readiness: IReadinessManager, settings: ISettings, isClientSide?: boolean): ISplitsSyncTask;
|
|
@@ -35,5 +35,5 @@ export declare function computeSplitsMutation(entries: ISplit[]): ISplitMutation
|
|
|
35
35
|
* @param requestTimeoutBeforeReady How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
|
|
36
36
|
* @param retriesOnFailureBeforeReady How many retries on `/splitChanges` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
|
|
37
37
|
*/
|
|
38
|
-
export declare function splitChangesUpdaterFactory(log: ILogger, splitChangesFetcher: ISplitChangesFetcher, splits: ISplitsCacheBase, segments: ISegmentsCacheBase, splitsEventEmitter?: ISplitsEventEmitter, requestTimeoutBeforeReady?: number, retriesOnFailureBeforeReady?: number): ISplitChangesUpdater;
|
|
38
|
+
export declare function splitChangesUpdaterFactory(log: ILogger, splitChangesFetcher: ISplitChangesFetcher, splits: ISplitsCacheBase, segments: ISegmentsCacheBase, splitsEventEmitter?: ISplitsEventEmitter, requestTimeoutBeforeReady?: number, retriesOnFailureBeforeReady?: number, isClientSide?: boolean): ISplitChangesUpdater;
|
|
39
39
|
export {};
|
package/types/types.d.ts
CHANGED
|
@@ -681,7 +681,7 @@ export declare namespace SplitIO {
|
|
|
681
681
|
/**
|
|
682
682
|
* String property to override the base URL where the SDK will post telemetry data.
|
|
683
683
|
* @property {string} telemetry
|
|
684
|
-
* @default 'https://telemetry.split.io'
|
|
684
|
+
* @default 'https://telemetry.split.io/api'
|
|
685
685
|
*/
|
|
686
686
|
telemetry?: string;
|
|
687
687
|
};
|