@splitsoftware/splitio-commons 2.0.3-rc.0 → 2.1.0-rc.0
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 +0 -4
- package/README.md +2 -2
- package/cjs/evaluator/index.js +0 -2
- package/cjs/listeners/browser.js +6 -4
- package/cjs/listeners/node.js +2 -2
- package/cjs/sdkClient/client.js +13 -13
- package/cjs/sdkClient/sdkClient.js +1 -1
- package/cjs/sdkFactory/index.js +14 -9
- package/cjs/sdkManager/index.js +1 -2
- package/cjs/storages/AbstractSplitsCacheAsync.js +0 -7
- package/cjs/storages/AbstractSplitsCacheSync.js +0 -7
- package/cjs/storages/KeyBuilderCS.js +3 -0
- package/cjs/storages/dataLoader.js +3 -2
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +1 -57
- package/cjs/storages/inLocalStorage/index.js +8 -7
- package/cjs/storages/inLocalStorage/validateCache.js +80 -0
- package/cjs/storages/inMemory/InMemoryStorage.js +3 -3
- package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -4
- package/cjs/storages/inRedis/index.js +13 -9
- package/cjs/storages/pluggable/index.js +21 -16
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -10
- package/cjs/sync/streaming/pushManager.js +8 -6
- package/cjs/sync/submitters/impressionCountsSubmitter.js +4 -2
- package/cjs/sync/submitters/submitterManager.js +6 -3
- package/cjs/sync/syncManagerOnline.js +10 -4
- package/cjs/trackers/eventTracker.js +1 -1
- package/cjs/trackers/impressionsTracker.js +19 -18
- package/cjs/trackers/strategy/strategyDebug.js +11 -4
- package/cjs/trackers/strategy/strategyNone.js +16 -11
- package/cjs/trackers/strategy/strategyOptimized.js +21 -11
- package/cjs/utils/settingsValidation/index.js +1 -1
- package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
- package/esm/evaluator/index.js +0 -2
- package/esm/listeners/browser.js +3 -1
- package/esm/listeners/node.js +2 -2
- package/esm/sdkClient/client.js +13 -13
- package/esm/sdkClient/sdkClient.js +1 -1
- package/esm/sdkFactory/index.js +15 -10
- package/esm/sdkManager/index.js +1 -2
- package/esm/storages/AbstractSplitsCacheAsync.js +0 -7
- package/esm/storages/AbstractSplitsCacheSync.js +0 -7
- package/esm/storages/KeyBuilderCS.js +3 -0
- package/esm/storages/dataLoader.js +2 -1
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +1 -57
- package/esm/storages/inLocalStorage/index.js +9 -8
- package/esm/storages/inLocalStorage/validateCache.js +76 -0
- package/esm/storages/inMemory/InMemoryStorage.js +4 -4
- package/esm/storages/inMemory/InMemoryStorageCS.js +4 -5
- package/esm/storages/inRedis/index.js +14 -10
- package/esm/storages/pluggable/index.js +22 -17
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
- package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -11
- package/esm/sync/streaming/pushManager.js +8 -6
- package/esm/sync/submitters/impressionCountsSubmitter.js +4 -2
- package/esm/sync/submitters/submitterManager.js +6 -3
- package/esm/sync/syncManagerOnline.js +10 -4
- package/esm/trackers/eventTracker.js +1 -1
- package/esm/trackers/impressionsTracker.js +19 -18
- package/esm/trackers/strategy/strategyDebug.js +11 -4
- package/esm/trackers/strategy/strategyNone.js +16 -11
- package/esm/trackers/strategy/strategyOptimized.js +21 -11
- package/esm/utils/settingsValidation/index.js +1 -1
- package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
- package/package.json +1 -1
- package/src/dtos/types.ts +1 -2
- package/src/evaluator/index.ts +0 -2
- package/src/evaluator/types.ts +1 -1
- package/src/listeners/browser.ts +3 -1
- package/src/listeners/node.ts +2 -2
- package/src/sdkClient/client.ts +11 -11
- package/src/sdkClient/sdkClient.ts +1 -1
- package/src/sdkFactory/index.ts +16 -11
- package/src/sdkFactory/types.ts +1 -1
- package/src/sdkManager/index.ts +1 -2
- package/src/storages/AbstractSplitsCacheAsync.ts +0 -8
- package/src/storages/AbstractSplitsCacheSync.ts +0 -8
- package/src/storages/KeyBuilderCS.ts +4 -0
- package/src/storages/dataLoader.ts +3 -1
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +1 -66
- package/src/storages/inLocalStorage/index.ts +12 -13
- package/src/storages/inLocalStorage/validateCache.ts +92 -0
- package/src/storages/inMemory/InMemoryStorage.ts +4 -4
- package/src/storages/inMemory/InMemoryStorageCS.ts +4 -5
- package/src/storages/inRedis/index.ts +10 -10
- package/src/storages/pluggable/index.ts +22 -17
- package/src/storages/types.ts +3 -6
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +6 -5
- package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -11
- package/src/sync/streaming/pushManager.ts +8 -6
- package/src/sync/submitters/impressionCountsSubmitter.ts +4 -2
- package/src/sync/submitters/submitterManager.ts +4 -3
- package/src/sync/submitters/uniqueKeysSubmitter.ts +3 -2
- package/src/sync/syncManagerOnline.ts +11 -5
- package/src/trackers/eventTracker.ts +1 -1
- package/src/trackers/impressionsTracker.ts +19 -18
- package/src/trackers/strategy/strategyDebug.ts +11 -4
- package/src/trackers/strategy/strategyNone.ts +17 -11
- package/src/trackers/strategy/strategyOptimized.ts +20 -10
- package/src/trackers/types.ts +8 -2
- package/src/utils/lang/index.ts +1 -1
- package/src/utils/settingsValidation/index.ts +1 -1
- package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
- package/types/index.d.ts +1 -1
- package/types/splitio.d.ts +26 -6
- package/cjs/utils/constants/browser.js +0 -5
- package/esm/utils/constants/browser.js +0 -2
- package/src/utils/constants/browser.ts +0 -2
|
@@ -54,27 +54,32 @@ function PluggableStorage(options) {
|
|
|
54
54
|
validatePluggableStorageOptions(options);
|
|
55
55
|
var prefix = (0, KeyBuilder_1.validatePrefix)(options.prefix);
|
|
56
56
|
function PluggableStorageFactory(params) {
|
|
57
|
-
var onReadyCb = params.onReadyCb, settings = params.settings, _a = params.settings, log = _a.log, mode = _a.mode, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
|
|
57
|
+
var onReadyCb = params.onReadyCb, settings = params.settings, _a = params.settings, log = _a.log, mode = _a.mode, impressionsMode = _a.sync.impressionsMode, _b = _a.scheduler, impressionsQueueSize = _b.impressionsQueueSize, eventsQueueSize = _b.eventsQueueSize;
|
|
58
58
|
var metadata = (0, utils_1.metadataBuilder)(settings);
|
|
59
59
|
var keys = new KeyBuilderSS_1.KeyBuilderSS(prefix, metadata);
|
|
60
60
|
var wrapper = (0, wrapperAdapter_1.wrapperAdapter)(log, options.wrapper);
|
|
61
|
-
var
|
|
61
|
+
var isSyncronizer = mode === undefined; // If mode is not defined, the synchronizer is running
|
|
62
62
|
var isPartialConsumer = mode === constants_1.CONSUMER_PARTIAL_MODE;
|
|
63
|
-
var telemetry = (0, TelemetryCacheInMemory_1.shouldRecordTelemetry)(params) ||
|
|
63
|
+
var telemetry = (0, TelemetryCacheInMemory_1.shouldRecordTelemetry)(params) || isSyncronizer ?
|
|
64
64
|
isPartialConsumer ?
|
|
65
65
|
new TelemetryCacheInMemory_1.TelemetryCacheInMemory() :
|
|
66
66
|
new TelemetryCachePluggable_1.TelemetryCachePluggable(log, keys, wrapper) :
|
|
67
67
|
undefined;
|
|
68
|
-
var impressionCountsCache =
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
var impressionCountsCache = impressionsMode !== constants_1.DEBUG || isSyncronizer ?
|
|
69
|
+
isPartialConsumer ?
|
|
70
|
+
new ImpressionCountsCacheInMemory_1.ImpressionCountsCacheInMemory() :
|
|
71
|
+
new ImpressionCountsCachePluggable_1.ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper) :
|
|
72
|
+
undefined;
|
|
73
|
+
var uniqueKeysCache = impressionsMode === constants_1.NONE || isSyncronizer ?
|
|
74
|
+
isPartialConsumer ?
|
|
75
|
+
settings.core.key === undefined ? new UniqueKeysCacheInMemory_1.UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS_1.UniqueKeysCacheInMemoryCS() :
|
|
76
|
+
new UniqueKeysCachePluggable_1.UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper) :
|
|
77
|
+
undefined;
|
|
74
78
|
// Connects to wrapper and emits SDK_READY event on main client
|
|
75
79
|
var connectPromise = wrapper.connect().then(function () {
|
|
76
|
-
if (
|
|
77
|
-
//
|
|
80
|
+
if (isSyncronizer) {
|
|
81
|
+
// @TODO reuse InLocalStorage::validateCache logic
|
|
82
|
+
// In standalone or producer mode, clear storage if SDK key, flags filter criteria or flags spec version was modified
|
|
78
83
|
return wrapper.get(keys.buildHashKey()).then(function (hash) {
|
|
79
84
|
var currentHash = (0, KeyBuilder_1.getStorageHash)(settings);
|
|
80
85
|
if (hash !== currentHash) {
|
|
@@ -89,9 +94,9 @@ function PluggableStorage(options) {
|
|
|
89
94
|
}
|
|
90
95
|
else {
|
|
91
96
|
// Start periodic flush of async storages if not running synchronizer (producer mode)
|
|
92
|
-
if (impressionCountsCache.start)
|
|
97
|
+
if (impressionCountsCache && impressionCountsCache.start)
|
|
93
98
|
impressionCountsCache.start();
|
|
94
|
-
if (uniqueKeysCache.start)
|
|
99
|
+
if (uniqueKeysCache && uniqueKeysCache.start)
|
|
95
100
|
uniqueKeysCache.start();
|
|
96
101
|
if (telemetry && telemetry.recordConfig)
|
|
97
102
|
telemetry.recordConfig();
|
|
@@ -112,9 +117,9 @@ function PluggableStorage(options) {
|
|
|
112
117
|
uniqueKeys: uniqueKeysCache,
|
|
113
118
|
// Stop periodic flush and disconnect the underlying storage
|
|
114
119
|
destroy: function () {
|
|
115
|
-
return Promise.all(
|
|
116
|
-
impressionCountsCache.stop && impressionCountsCache.stop(),
|
|
117
|
-
uniqueKeysCache.stop && uniqueKeysCache.stop(),
|
|
120
|
+
return Promise.all(isSyncronizer ? [] : [
|
|
121
|
+
impressionCountsCache && impressionCountsCache.stop && impressionCountsCache.stop(),
|
|
122
|
+
uniqueKeysCache && uniqueKeysCache.stop && uniqueKeysCache.stop(),
|
|
118
123
|
]).then(function () { return wrapper.disconnect(); });
|
|
119
124
|
},
|
|
120
125
|
// emits SDK_READY event on shared clients and returns a reference to the storage
|
|
@@ -46,9 +46,10 @@ function fromObjectUpdaterFactory(splitsParser, storage, readiness, settings) {
|
|
|
46
46
|
readiness.splits.emit(constants_2.SDK_SPLITS_ARRIVED);
|
|
47
47
|
if (startingUp) {
|
|
48
48
|
startingUp = false;
|
|
49
|
-
|
|
49
|
+
var isCacheLoaded_1 = storage.validateCache ? storage.validateCache() : false;
|
|
50
|
+
Promise.resolve().then(function () {
|
|
50
51
|
// Emits SDK_READY_FROM_CACHE
|
|
51
|
-
if (
|
|
52
|
+
if (isCacheLoaded_1)
|
|
52
53
|
readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED);
|
|
53
54
|
// Emits SDK_READY
|
|
54
55
|
readiness.segments.emit(constants_2.SDK_SEGMENTS_ARRIVED);
|
|
@@ -126,7 +126,7 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
|
|
|
126
126
|
function _splitChangesUpdater(since, retry) {
|
|
127
127
|
if (retry === void 0) { retry = 0; }
|
|
128
128
|
log.debug(constants_2.SYNC_SPLITS_FETCH, [since]);
|
|
129
|
-
|
|
129
|
+
return Promise.resolve(splitUpdateNotification ?
|
|
130
130
|
{ splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
|
|
131
131
|
splitChangesFetcher(since, noCache, till, _promiseDecorator))
|
|
132
132
|
.then(function (splitChanges) {
|
|
@@ -170,15 +170,6 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
|
|
|
170
170
|
}
|
|
171
171
|
return false;
|
|
172
172
|
});
|
|
173
|
-
// After triggering the requests, if we have cached splits information let's notify that to emit SDK_READY_FROM_CACHE.
|
|
174
|
-
// Wrapping in a promise since checkCache can be async.
|
|
175
|
-
if (splitsEventEmitter && startingUp) {
|
|
176
|
-
Promise.resolve(splits.checkCache()).then(function (isCacheReady) {
|
|
177
|
-
if (isCacheReady)
|
|
178
|
-
splitsEventEmitter.emit(constants_1.SDK_SPLITS_CACHE_LOADED);
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
return fetcherPromise;
|
|
182
173
|
}
|
|
183
174
|
var sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error
|
|
184
175
|
return sincePromise.then(_splitChangesUpdater);
|
|
@@ -309,12 +309,14 @@ function pushManagerFactory(params, pollingManager) {
|
|
|
309
309
|
// Reconnects in case of a new client.
|
|
310
310
|
// Run in next event-loop cycle to save authentication calls
|
|
311
311
|
// in case multiple clients are created in the current cycle.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
connectForNewClient
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
312
|
+
if (this.isRunning()) {
|
|
313
|
+
setTimeout(function checkForReconnect() {
|
|
314
|
+
if (connectForNewClient) {
|
|
315
|
+
connectForNewClient = false;
|
|
316
|
+
connectPush();
|
|
317
|
+
}
|
|
318
|
+
}, 0);
|
|
319
|
+
}
|
|
318
320
|
}
|
|
319
321
|
},
|
|
320
322
|
// [Only for client-side]
|
|
@@ -30,7 +30,9 @@ var IMPRESSIONS_COUNT_RATE = 1800000; // 30 minutes
|
|
|
30
30
|
*/
|
|
31
31
|
function impressionCountsSubmitterFactory(params) {
|
|
32
32
|
var log = params.settings.log, postTestImpressionsCount = params.splitApi.postTestImpressionsCount, impressionCounts = params.storage.impressionCounts;
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
if (impressionCounts) {
|
|
34
|
+
// retry impressions counts only once.
|
|
35
|
+
return (0, submitter_1.submitterFactory)(log, postTestImpressionsCount, impressionCounts, IMPRESSIONS_COUNT_RATE, 'impression counts', fromImpressionCountsCollector, 1);
|
|
36
|
+
}
|
|
35
37
|
}
|
|
36
38
|
exports.impressionCountsSubmitterFactory = impressionCountsSubmitterFactory;
|
|
@@ -9,11 +9,14 @@ var uniqueKeysSubmitter_1 = require("./uniqueKeysSubmitter");
|
|
|
9
9
|
function submitterManagerFactory(params) {
|
|
10
10
|
var submitters = [
|
|
11
11
|
(0, impressionsSubmitter_1.impressionsSubmitterFactory)(params),
|
|
12
|
-
(0, eventsSubmitter_1.eventsSubmitterFactory)(params)
|
|
13
|
-
(0, impressionCountsSubmitter_1.impressionCountsSubmitterFactory)(params),
|
|
14
|
-
(0, uniqueKeysSubmitter_1.uniqueKeysSubmitterFactory)(params)
|
|
12
|
+
(0, eventsSubmitter_1.eventsSubmitterFactory)(params)
|
|
15
13
|
];
|
|
14
|
+
var impressionCountsSubmitter = (0, impressionCountsSubmitter_1.impressionCountsSubmitterFactory)(params);
|
|
15
|
+
if (impressionCountsSubmitter)
|
|
16
|
+
submitters.push(impressionCountsSubmitter);
|
|
16
17
|
var telemetrySubmitter = (0, telemetrySubmitter_1.telemetrySubmitterFactory)(params);
|
|
18
|
+
if (params.storage.uniqueKeys)
|
|
19
|
+
submitters.push((0, uniqueKeysSubmitter_1.uniqueKeysSubmitterFactory)(params));
|
|
17
20
|
return {
|
|
18
21
|
// `onlyTelemetry` true if SDK is created with userConsent not GRANTED
|
|
19
22
|
start: function (onlyTelemetry) {
|
|
@@ -6,6 +6,7 @@ var constants_1 = require("./streaming/constants");
|
|
|
6
6
|
var constants_2 = require("../logger/constants");
|
|
7
7
|
var consent_1 = require("../consent");
|
|
8
8
|
var constants_3 = require("../utils/constants");
|
|
9
|
+
var constants_4 = require("../readiness/constants");
|
|
9
10
|
/**
|
|
10
11
|
* Online SyncManager factory.
|
|
11
12
|
* Can be used for server-side API, and client-side API with or without multiple clients.
|
|
@@ -19,7 +20,7 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
19
20
|
* SyncManager factory for modular SDK
|
|
20
21
|
*/
|
|
21
22
|
return function (params) {
|
|
22
|
-
var settings = params.settings, _a = params.settings, log = _a.log, streamingEnabled = _a.streamingEnabled, syncEnabled = _a.sync.enabled, telemetryTracker = params.telemetryTracker;
|
|
23
|
+
var settings = params.settings, _a = params.settings, log = _a.log, streamingEnabled = _a.streamingEnabled, syncEnabled = _a.sync.enabled, telemetryTracker = params.telemetryTracker, storage = params.storage, readiness = params.readiness;
|
|
23
24
|
/** Polling Manager */
|
|
24
25
|
var pollingManager = pollingManagerFactory && pollingManagerFactory(params);
|
|
25
26
|
/** Push Manager */
|
|
@@ -67,6 +68,11 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
67
68
|
*/
|
|
68
69
|
start: function () {
|
|
69
70
|
running = true;
|
|
71
|
+
if (startFirstTime) {
|
|
72
|
+
var isCacheLoaded = storage.validateCache ? storage.validateCache() : false;
|
|
73
|
+
if (isCacheLoaded)
|
|
74
|
+
Promise.resolve().then(function () { readiness.splits.emit(constants_4.SDK_SPLITS_CACHE_LOADED); });
|
|
75
|
+
}
|
|
70
76
|
// start syncing splits and segments
|
|
71
77
|
if (pollingManager) {
|
|
72
78
|
// If synchronization is disabled pushManager and pollingManager should not start
|
|
@@ -75,7 +81,6 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
75
81
|
// Doesn't call `syncAll` when the syncManager is resuming
|
|
76
82
|
if (startFirstTime) {
|
|
77
83
|
pollingManager.syncAll();
|
|
78
|
-
startFirstTime = false;
|
|
79
84
|
}
|
|
80
85
|
pushManager.start();
|
|
81
86
|
}
|
|
@@ -86,12 +91,12 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
86
91
|
else {
|
|
87
92
|
if (startFirstTime) {
|
|
88
93
|
pollingManager.syncAll();
|
|
89
|
-
startFirstTime = false;
|
|
90
94
|
}
|
|
91
95
|
}
|
|
92
96
|
}
|
|
93
97
|
// start periodic data recording (events, impressions, telemetry).
|
|
94
98
|
submitterManager.start(!(0, consent_1.isConsentGranted)(settings));
|
|
99
|
+
startFirstTime = false;
|
|
95
100
|
},
|
|
96
101
|
/**
|
|
97
102
|
* Method used to stop/pause the syncManager.
|
|
@@ -118,6 +123,8 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
118
123
|
if (!pollingManager)
|
|
119
124
|
return;
|
|
120
125
|
var mySegmentsSyncTask = pollingManager.add(matchingKey, readinessManager, storage);
|
|
126
|
+
if (syncEnabled && pushManager)
|
|
127
|
+
pushManager.add(matchingKey, mySegmentsSyncTask);
|
|
121
128
|
if (running) {
|
|
122
129
|
if (syncEnabled) {
|
|
123
130
|
if (pushManager) {
|
|
@@ -131,7 +138,6 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
131
138
|
// of segments since `syncAll` was already executed when starting the main client
|
|
132
139
|
mySegmentsSyncTask.execute();
|
|
133
140
|
}
|
|
134
|
-
pushManager.add(matchingKey, mySegmentsSyncTask);
|
|
135
141
|
}
|
|
136
142
|
else {
|
|
137
143
|
if (storage.splits.usesSegments())
|
|
@@ -25,7 +25,7 @@ function eventTrackerFactory(settings, eventsCache, whenInit, integrationsManage
|
|
|
25
25
|
whenInit(function () {
|
|
26
26
|
// Wrap in a timeout because we don't want it to be blocking.
|
|
27
27
|
setTimeout(function () {
|
|
28
|
-
// copy of event, to avoid unexpected
|
|
28
|
+
// copy of event, to avoid unexpected behavior if modified by integrations
|
|
29
29
|
var eventDataCopy = (0, objectAssign_1.objectAssign)({}, eventData);
|
|
30
30
|
if (properties)
|
|
31
31
|
eventDataCopy.properties = (0, objectAssign_1.objectAssign)({}, properties);
|
|
@@ -7,37 +7,38 @@ var constants_1 = require("../logger/constants");
|
|
|
7
7
|
var constants_2 = require("../utils/constants");
|
|
8
8
|
/**
|
|
9
9
|
* Impressions tracker stores impressions in cache and pass them to the listener and integrations manager if provided.
|
|
10
|
+
*
|
|
11
|
+
* @param impressionsCache - cache to save impressions
|
|
12
|
+
* @param metadata - runtime metadata (ip, hostname and version)
|
|
13
|
+
* @param impressionListener - optional impression listener
|
|
14
|
+
* @param integrationsManager - optional integrations manager
|
|
15
|
+
* @param strategy - strategy for impressions tracking.
|
|
10
16
|
*/
|
|
11
|
-
function impressionsTrackerFactory(settings, impressionsCache,
|
|
17
|
+
function impressionsTrackerFactory(settings, impressionsCache, strategy, whenInit, integrationsManager, telemetryCache) {
|
|
12
18
|
var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version;
|
|
13
19
|
return {
|
|
14
20
|
track: function (impressions, attributes) {
|
|
15
21
|
if (settings.userConsent === constants_2.CONSENT_DECLINED)
|
|
16
22
|
return;
|
|
17
|
-
var
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
23
|
-
var impressionsLength = impressions.length;
|
|
24
|
-
var impressionsToStoreLength = impressionsToStore.length;
|
|
25
|
-
if (impressionsToStoreLength) {
|
|
26
|
-
var res = impressionsCache.track(impressionsToStore.map(function (item) { return item[0]; }));
|
|
23
|
+
var impressionsCount = impressions.length;
|
|
24
|
+
var _a = strategy.process(impressions), impressionsToStore = _a.impressionsToStore, impressionsToListener = _a.impressionsToListener, deduped = _a.deduped;
|
|
25
|
+
var impressionsToListenerCount = impressionsToListener.length;
|
|
26
|
+
if (impressionsToStore.length > 0) {
|
|
27
|
+
var res = impressionsCache.track(impressionsToStore);
|
|
27
28
|
// If we're on an async storage, handle error and log it.
|
|
28
29
|
if ((0, thenable_1.thenable)(res)) {
|
|
29
30
|
res.then(function () {
|
|
30
|
-
log.info(constants_1.IMPRESSIONS_TRACKER_SUCCESS, [
|
|
31
|
+
log.info(constants_1.IMPRESSIONS_TRACKER_SUCCESS, [impressionsCount]);
|
|
31
32
|
}).catch(function (err) {
|
|
32
|
-
log.error(constants_1.ERROR_IMPRESSIONS_TRACKER, [
|
|
33
|
+
log.error(constants_1.ERROR_IMPRESSIONS_TRACKER, [impressionsCount, err]);
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
36
|
else {
|
|
36
37
|
// Record when impressionsCache is sync only (standalone mode)
|
|
37
38
|
// @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
|
|
38
39
|
if (telemetryCache) {
|
|
39
|
-
telemetryCache.recordImpressionStats(constants_2.QUEUED,
|
|
40
|
-
telemetryCache.recordImpressionStats(constants_2.DEDUPED,
|
|
40
|
+
telemetryCache.recordImpressionStats(constants_2.QUEUED, impressionsToStore.length);
|
|
41
|
+
telemetryCache.recordImpressionStats(constants_2.DEDUPED, deduped);
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
}
|
|
@@ -45,8 +46,8 @@ function impressionsTrackerFactory(settings, impressionsCache, noneStrategy, str
|
|
|
45
46
|
if (impressionListener || integrationsManager) {
|
|
46
47
|
var _loop_1 = function (i) {
|
|
47
48
|
var impressionData = {
|
|
48
|
-
// copy of impression, to avoid unexpected
|
|
49
|
-
impression: (0, objectAssign_1.objectAssign)({},
|
|
49
|
+
// copy of impression, to avoid unexpected behavior if modified by integrations or impressionListener
|
|
50
|
+
impression: (0, objectAssign_1.objectAssign)({}, impressionsToListener[i]),
|
|
50
51
|
attributes: attributes,
|
|
51
52
|
ip: ip,
|
|
52
53
|
hostname: hostname,
|
|
@@ -68,7 +69,7 @@ function impressionsTrackerFactory(settings, impressionsCache, noneStrategy, str
|
|
|
68
69
|
});
|
|
69
70
|
});
|
|
70
71
|
};
|
|
71
|
-
for (var i = 0; i <
|
|
72
|
+
for (var i = 0; i < impressionsToListenerCount; i++) {
|
|
72
73
|
_loop_1(i);
|
|
73
74
|
}
|
|
74
75
|
}
|
|
@@ -5,13 +5,20 @@ exports.strategyDebugFactory = void 0;
|
|
|
5
5
|
* Debug strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
|
|
6
6
|
*
|
|
7
7
|
* @param impressionsObserver - impression observer. Previous time (pt property) is included in impression instances
|
|
8
|
-
* @returns
|
|
8
|
+
* @returns IStrategyResult
|
|
9
9
|
*/
|
|
10
10
|
function strategyDebugFactory(impressionsObserver) {
|
|
11
11
|
return {
|
|
12
|
-
process: function (
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
process: function (impressions) {
|
|
13
|
+
impressions.forEach(function (impression) {
|
|
14
|
+
// Adds previous time if it is enabled
|
|
15
|
+
impression.pt = impressionsObserver.testAndSet(impression);
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
impressionsToStore: impressions,
|
|
19
|
+
impressionsToListener: impressions,
|
|
20
|
+
deduped: 0
|
|
21
|
+
};
|
|
15
22
|
}
|
|
16
23
|
};
|
|
17
24
|
}
|
|
@@ -4,20 +4,25 @@ exports.strategyNoneFactory = void 0;
|
|
|
4
4
|
/**
|
|
5
5
|
* None strategy for impressions tracker.
|
|
6
6
|
*
|
|
7
|
-
* @param
|
|
7
|
+
* @param impressionsCounter - cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
|
|
8
8
|
* @param uniqueKeysTracker - unique keys tracker in charge of tracking the unique keys per split.
|
|
9
|
-
* @returns
|
|
9
|
+
* @returns IStrategyResult
|
|
10
10
|
*/
|
|
11
|
-
function strategyNoneFactory(
|
|
11
|
+
function strategyNoneFactory(impressionsCounter, uniqueKeysTracker) {
|
|
12
12
|
return {
|
|
13
|
-
process: function (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
process: function (impressions) {
|
|
14
|
+
impressions.forEach(function (impression) {
|
|
15
|
+
var now = Date.now();
|
|
16
|
+
// Increments impression counter per featureName
|
|
17
|
+
impressionsCounter.track(impression.feature, now, 1);
|
|
18
|
+
// Keep track by unique key
|
|
19
|
+
uniqueKeysTracker.track(impression.keyName, impression.feature);
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
impressionsToStore: [],
|
|
23
|
+
impressionsToListener: impressions,
|
|
24
|
+
deduped: 0
|
|
25
|
+
};
|
|
21
26
|
}
|
|
22
27
|
};
|
|
23
28
|
}
|
|
@@ -6,19 +6,29 @@ var time_1 = require("../../utils/time");
|
|
|
6
6
|
* Optimized strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
|
|
7
7
|
*
|
|
8
8
|
* @param impressionsObserver - impression observer. previous time (pt property) is included in impression instances
|
|
9
|
-
* @param
|
|
10
|
-
* @returns
|
|
9
|
+
* @param impressionsCounter - cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
|
|
10
|
+
* @returns IStrategyResult
|
|
11
11
|
*/
|
|
12
|
-
function strategyOptimizedFactory(impressionsObserver,
|
|
12
|
+
function strategyOptimizedFactory(impressionsObserver, impressionsCounter) {
|
|
13
13
|
return {
|
|
14
|
-
process: function (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
process: function (impressions) {
|
|
15
|
+
var impressionsToStore = [];
|
|
16
|
+
impressions.forEach(function (impression) {
|
|
17
|
+
impression.pt = impressionsObserver.testAndSet(impression);
|
|
18
|
+
var now = Date.now();
|
|
19
|
+
// Increments impression counter per featureName
|
|
20
|
+
if (impression.pt)
|
|
21
|
+
impressionsCounter.track(impression.feature, now, 1);
|
|
22
|
+
// Checks if the impression should be added in queue to be sent
|
|
23
|
+
if (!impression.pt || impression.pt < (0, time_1.truncateTimeFrame)(now)) {
|
|
24
|
+
impressionsToStore.push(impression);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
impressionsToStore: impressionsToStore,
|
|
29
|
+
impressionsToListener: impressions,
|
|
30
|
+
deduped: impressions.length - impressionsToStore.length
|
|
31
|
+
};
|
|
22
32
|
}
|
|
23
33
|
};
|
|
24
34
|
}
|
|
@@ -139,7 +139,7 @@ function settingsValidation(config, validationParams) {
|
|
|
139
139
|
withDefaults.core.key = 'localhost_key';
|
|
140
140
|
}
|
|
141
141
|
else {
|
|
142
|
-
// Keeping same
|
|
142
|
+
// Keeping same behavior than JS SDK: if settings key or TT are invalid,
|
|
143
143
|
// `false` value is used as bound key/TT of the default client, which leads to some issues.
|
|
144
144
|
// @ts-ignore, @TODO handle invalid keys as a non-recoverable error?
|
|
145
145
|
withDefaults.core.key = (0, key_1.validateKey)(log, maybeKey, constants_2.LOG_PREFIX_CLIENT_INSTANTIATION);
|
|
@@ -6,7 +6,7 @@ var constants_1 = require("../../../logger/constants");
|
|
|
6
6
|
var constants_2 = require("../../../utils/constants");
|
|
7
7
|
function __InLocalStorageMockFactory(params) {
|
|
8
8
|
var result = (0, InMemoryStorageCS_1.InMemoryStorageCSFactory)(params);
|
|
9
|
-
result.
|
|
9
|
+
result.validateCache = function () { return true; }; // to emit SDK_READY_FROM_CACHE
|
|
10
10
|
return result;
|
|
11
11
|
}
|
|
12
12
|
exports.__InLocalStorageMockFactory = __InLocalStorageMockFactory;
|
package/esm/evaluator/index.js
CHANGED
|
@@ -98,14 +98,12 @@ function getEvaluation(log, splitJSON, key, attributes, storage) {
|
|
|
98
98
|
return evaluation.then(function (result) {
|
|
99
99
|
result.changeNumber = split_1.getChangeNumber();
|
|
100
100
|
result.config = splitJSON.configurations && splitJSON.configurations[result.treatment] || null;
|
|
101
|
-
result.track = splitJSON.trackImpressions;
|
|
102
101
|
return result;
|
|
103
102
|
});
|
|
104
103
|
}
|
|
105
104
|
else {
|
|
106
105
|
evaluation.changeNumber = split_1.getChangeNumber(); // Always sync and optional
|
|
107
106
|
evaluation.config = splitJSON.configurations && splitJSON.configurations[evaluation.treatment] || null;
|
|
108
|
-
evaluation.track = splitJSON.trackImpressions;
|
|
109
107
|
}
|
|
110
108
|
}
|
|
111
109
|
return evaluation;
|
package/esm/listeners/browser.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fromImpressionsCollector } from '../sync/submitters/impressionsSubmitter';
|
|
2
2
|
import { fromImpressionCountsCollector } from '../sync/submitters/impressionCountsSubmitter';
|
|
3
|
+
import { OPTIMIZED, DEBUG, NONE } from '../utils/constants';
|
|
3
4
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
4
5
|
import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
|
|
5
6
|
import { isConsentGranted } from '../consent';
|
|
@@ -59,9 +60,10 @@ var BrowserSignalListener = /** @class */ (function () {
|
|
|
59
60
|
var _a = this.settings.urls, events = _a.events, telemetry = _a.telemetry;
|
|
60
61
|
// Flush impressions & events data if there is user consent
|
|
61
62
|
if (isConsentGranted(this.settings)) {
|
|
63
|
+
var sim = this.settings.sync.impressionsMode;
|
|
62
64
|
var extraMetadata = {
|
|
63
65
|
// sim stands for Sync/Split Impressions Mode
|
|
64
|
-
sim:
|
|
66
|
+
sim: sim === OPTIMIZED ? OPTIMIZED : sim === DEBUG ? DEBUG : NONE
|
|
65
67
|
};
|
|
66
68
|
this._flushData(events + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata);
|
|
67
69
|
this._flushData(events + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
|
package/esm/listeners/node.js
CHANGED
|
@@ -40,7 +40,7 @@ var NodeSignalListener = /** @class */ (function () {
|
|
|
40
40
|
var wrapUp = function () {
|
|
41
41
|
// Cleaned up, remove handlers.
|
|
42
42
|
_this.stop();
|
|
43
|
-
// This handler prevented the default
|
|
43
|
+
// This handler prevented the default behavior, start again.
|
|
44
44
|
// eslint-disable-next-line no-undef
|
|
45
45
|
process.kill(process.pid, SIGTERM);
|
|
46
46
|
};
|
|
@@ -53,7 +53,7 @@ var NodeSignalListener = /** @class */ (function () {
|
|
|
53
53
|
this.settings.log.error(LOG_PREFIX_CLEANUP + "Error with Split SDK graceful shutdown: " + err);
|
|
54
54
|
}
|
|
55
55
|
if (thenable(handlerResult)) {
|
|
56
|
-
// Always exit, even with errors. The promise is returned for UT
|
|
56
|
+
// Always exit, even with errors. The promise is returned for UT purposes.
|
|
57
57
|
return handlerResult.then(wrapUp).catch(wrapUp);
|
|
58
58
|
}
|
|
59
59
|
else {
|
package/esm/sdkClient/client.js
CHANGED
|
@@ -30,7 +30,7 @@ export function clientFactory(params) {
|
|
|
30
30
|
var queue = [];
|
|
31
31
|
var treatment = processEvaluation(evaluationResult, featureFlagName, key, attributes, withConfig, methodName, queue);
|
|
32
32
|
impressionsTracker.track(queue, attributes);
|
|
33
|
-
stopTelemetryTracker(queue[0] && queue[0]
|
|
33
|
+
stopTelemetryTracker(queue[0] && queue[0].label);
|
|
34
34
|
return treatment;
|
|
35
35
|
};
|
|
36
36
|
var evaluation = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
|
|
@@ -54,7 +54,7 @@ export function clientFactory(params) {
|
|
|
54
54
|
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, attributes, withConfig, methodName, queue);
|
|
55
55
|
});
|
|
56
56
|
impressionsTracker.track(queue, attributes);
|
|
57
|
-
stopTelemetryTracker(queue[0] && queue[0]
|
|
57
|
+
stopTelemetryTracker(queue[0] && queue[0].label);
|
|
58
58
|
return treatments;
|
|
59
59
|
};
|
|
60
60
|
var evaluations = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
|
|
@@ -80,7 +80,7 @@ export function clientFactory(params) {
|
|
|
80
80
|
treatments[featureFlagName] = processEvaluation(evaluations[featureFlagName], featureFlagName, key, attributes, withConfig, methodName, queue);
|
|
81
81
|
});
|
|
82
82
|
impressionsTracker.track(queue, attributes);
|
|
83
|
-
stopTelemetryTracker(queue[0] && queue[0]
|
|
83
|
+
stopTelemetryTracker(queue[0] && queue[0].label);
|
|
84
84
|
return treatments;
|
|
85
85
|
};
|
|
86
86
|
var evaluations = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
|
|
@@ -103,19 +103,19 @@ export function clientFactory(params) {
|
|
|
103
103
|
function processEvaluation(evaluation, featureFlagName, key, attributes, withConfig, invokingMethodName, queue) {
|
|
104
104
|
var matchingKey = getMatching(key);
|
|
105
105
|
var bucketingKey = getBucketing(key);
|
|
106
|
-
var treatment = evaluation.treatment, label = evaluation.label, changeNumber = evaluation.changeNumber, _a = evaluation.config, config = _a === void 0 ? null : _a
|
|
106
|
+
var treatment = evaluation.treatment, label = evaluation.label, changeNumber = evaluation.changeNumber, _a = evaluation.config, config = _a === void 0 ? null : _a;
|
|
107
107
|
log.info(IMPRESSION, [featureFlagName, matchingKey, treatment, label]);
|
|
108
108
|
if (validateSplitExistence(log, readinessManager, featureFlagName, label, invokingMethodName)) {
|
|
109
109
|
log.info(IMPRESSION_QUEUEING);
|
|
110
|
-
queue.push(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
110
|
+
queue.push({
|
|
111
|
+
feature: featureFlagName,
|
|
112
|
+
keyName: matchingKey,
|
|
113
|
+
treatment: treatment,
|
|
114
|
+
time: Date.now(),
|
|
115
|
+
bucketingKey: bucketingKey,
|
|
116
|
+
label: label,
|
|
117
|
+
changeNumber: changeNumber
|
|
118
|
+
});
|
|
119
119
|
}
|
|
120
120
|
if (withConfig) {
|
|
121
121
|
return {
|
|
@@ -47,7 +47,7 @@ export function sdkClientFactory(params, isSharedClient) {
|
|
|
47
47
|
releaseApiKey(settings.core.authorizationKey);
|
|
48
48
|
telemetryTracker.sessionLength();
|
|
49
49
|
signalListener && signalListener.stop();
|
|
50
|
-
uniqueKeysTracker.stop();
|
|
50
|
+
uniqueKeysTracker && uniqueKeysTracker.stop();
|
|
51
51
|
}
|
|
52
52
|
// Stop background jobs
|
|
53
53
|
syncManager && syncManager.stop();
|
package/esm/sdkFactory/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { strategyDebugFactory } from '../trackers/strategy/strategyDebug';
|
|
|
11
11
|
import { strategyOptimizedFactory } from '../trackers/strategy/strategyOptimized';
|
|
12
12
|
import { strategyNoneFactory } from '../trackers/strategy/strategyNone';
|
|
13
13
|
import { uniqueKeysTrackerFactory } from '../trackers/uniqueKeysTracker';
|
|
14
|
-
import {
|
|
14
|
+
import { NONE, OPTIMIZED } from '../utils/constants';
|
|
15
15
|
/**
|
|
16
16
|
* Modular SDK factory
|
|
17
17
|
*/
|
|
@@ -48,14 +48,19 @@ export function sdkFactory(params) {
|
|
|
48
48
|
var telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
|
|
49
49
|
var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage, telemetryTracker: telemetryTracker });
|
|
50
50
|
var observer = impressionsObserverFactory();
|
|
51
|
-
var uniqueKeysTracker = uniqueKeysTrackerFactory(log, storage.uniqueKeys, filterAdapterFactory && filterAdapterFactory());
|
|
52
|
-
var
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
var uniqueKeysTracker = impressionsMode === NONE ? uniqueKeysTrackerFactory(log, storage.uniqueKeys, filterAdapterFactory && filterAdapterFactory()) : undefined;
|
|
52
|
+
var strategy;
|
|
53
|
+
switch (impressionsMode) {
|
|
54
|
+
case OPTIMIZED:
|
|
55
|
+
strategy = strategyOptimizedFactory(observer, storage.impressionCounts);
|
|
56
|
+
break;
|
|
57
|
+
case NONE:
|
|
58
|
+
strategy = strategyNoneFactory(storage.impressionCounts, uniqueKeysTracker);
|
|
59
|
+
break;
|
|
60
|
+
default:
|
|
61
|
+
strategy = strategyDebugFactory(observer);
|
|
62
|
+
}
|
|
63
|
+
var impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, strategy, whenInit, integrationsManager, storage.telemetry);
|
|
59
64
|
var eventTracker = eventTrackerFactory(settings, storage.events, whenInit, integrationsManager, storage.telemetry);
|
|
60
65
|
// splitApi is used by SyncManager and Browser signal listener
|
|
61
66
|
var splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
|
|
@@ -74,7 +79,7 @@ export function sdkFactory(params) {
|
|
|
74
79
|
// We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle.
|
|
75
80
|
validateAndTrackApiKey(log, settings.core.authorizationKey);
|
|
76
81
|
readiness.init();
|
|
77
|
-
uniqueKeysTracker.start();
|
|
82
|
+
uniqueKeysTracker && uniqueKeysTracker.start();
|
|
78
83
|
syncManager && syncManager.start();
|
|
79
84
|
signalListener && signalListener.start();
|
|
80
85
|
initCallbacks.forEach(function (cb) { return cb(); });
|
package/esm/sdkManager/index.js
CHANGED
|
@@ -25,8 +25,7 @@ function objectToView(splitObject) {
|
|
|
25
25
|
treatments: collectTreatments(splitObject),
|
|
26
26
|
configs: splitObject.configurations || {},
|
|
27
27
|
sets: splitObject.sets || [],
|
|
28
|
-
defaultTreatment: splitObject.defaultTreatment
|
|
29
|
-
trackImpressions: splitObject.trackImpressions !== false
|
|
28
|
+
defaultTreatment: splitObject.defaultTreatment
|
|
30
29
|
};
|
|
31
30
|
}
|
|
32
31
|
function objectsToViews(splitObjects) {
|