@splitsoftware/splitio-commons 2.0.0-rc.0 → 2.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +2 -1
- package/cjs/evaluator/Engine.js +1 -1
- package/cjs/evaluator/index.js +1 -1
- package/cjs/readiness/readinessManager.js +13 -2
- package/cjs/sdkClient/sdkClientMethodCS.js +0 -1
- package/cjs/sdkFactory/index.js +26 -8
- package/cjs/storages/{AbstractSegmentsCacheSync.js → AbstractMySegmentsCacheSync.js} +15 -17
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +5 -5
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +3 -2
- package/cjs/storages/inLocalStorage/index.js +1 -1
- package/cjs/storages/inMemory/InMemoryStorageCS.js +2 -2
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +5 -5
- package/cjs/storages/inMemory/SegmentsCacheInMemory.js +13 -27
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +0 -1
- package/cjs/storages/inMemory/UniqueKeysCacheInMemory.js +2 -1
- package/cjs/storages/inMemory/UniqueKeysCacheInMemoryCS.js +2 -1
- package/cjs/storages/inRedis/RedisAdapter.js +2 -1
- package/cjs/storages/inRedis/SegmentsCacheInRedis.js +13 -19
- package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +2 -1
- package/cjs/storages/pluggable/SegmentsCachePluggable.js +11 -32
- package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +2 -1
- package/cjs/storages/pluggable/inMemoryWrapper.js +2 -1
- package/cjs/sync/offline/syncManagerOffline.js +18 -11
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +12 -28
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +2 -1
- package/cjs/sync/syncManagerOnline.js +20 -21
- package/cjs/trackers/eventTracker.js +12 -10
- package/cjs/trackers/impressionsTracker.js +16 -14
- package/cjs/trackers/uniqueKeysTracker.js +5 -3
- package/cjs/utils/lang/sets.js +12 -2
- package/esm/evaluator/Engine.js +1 -1
- package/esm/evaluator/index.js +2 -2
- package/esm/readiness/readinessManager.js +13 -2
- package/esm/sdkClient/sdkClientMethodCS.js +0 -1
- package/esm/sdkFactory/index.js +26 -8
- package/esm/storages/{AbstractSegmentsCacheSync.js → AbstractMySegmentsCacheSync.js} +14 -16
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +5 -5
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +3 -2
- package/esm/storages/inLocalStorage/index.js +1 -1
- package/esm/storages/inMemory/InMemoryStorageCS.js +2 -2
- package/esm/storages/inMemory/MySegmentsCacheInMemory.js +5 -5
- package/esm/storages/inMemory/SegmentsCacheInMemory.js +13 -27
- package/esm/storages/inMemory/SplitsCacheInMemory.js +0 -1
- package/esm/storages/inMemory/UniqueKeysCacheInMemory.js +2 -1
- package/esm/storages/inMemory/UniqueKeysCacheInMemoryCS.js +2 -1
- package/esm/storages/inRedis/RedisAdapter.js +2 -1
- package/esm/storages/inRedis/SegmentsCacheInRedis.js +13 -19
- package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +2 -1
- package/esm/storages/pluggable/SegmentsCachePluggable.js +11 -32
- package/esm/storages/pluggable/UniqueKeysCachePluggable.js +2 -1
- package/esm/storages/pluggable/inMemoryWrapper.js +2 -1
- package/esm/sync/offline/syncManagerOffline.js +18 -11
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +12 -28
- package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -1
- package/esm/sync/syncManagerOnline.js +20 -21
- package/esm/trackers/eventTracker.js +12 -10
- package/esm/trackers/impressionsTracker.js +16 -14
- package/esm/trackers/uniqueKeysTracker.js +5 -3
- package/esm/utils/lang/sets.js +10 -1
- package/package.json +1 -1
- package/src/evaluator/Engine.ts +1 -1
- package/src/evaluator/index.ts +2 -2
- package/src/readiness/readinessManager.ts +12 -3
- package/src/readiness/types.ts +3 -0
- package/src/sdkClient/sdkClientMethodCS.ts +0 -2
- package/src/sdkFactory/index.ts +28 -9
- package/src/sdkFactory/types.ts +2 -0
- package/src/storages/{AbstractSegmentsCacheSync.ts → AbstractMySegmentsCacheSync.ts} +13 -28
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +5 -5
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +3 -2
- package/src/storages/inLocalStorage/index.ts +1 -1
- package/src/storages/inMemory/InMemoryStorageCS.ts +2 -2
- package/src/storages/inMemory/MySegmentsCacheInMemory.ts +5 -5
- package/src/storages/inMemory/SegmentsCacheInMemory.ts +12 -26
- package/src/storages/inMemory/SplitsCacheInMemory.ts +0 -1
- package/src/storages/inMemory/UniqueKeysCacheInMemory.ts +2 -1
- package/src/storages/inMemory/UniqueKeysCacheInMemoryCS.ts +2 -1
- package/src/storages/inRedis/RedisAdapter.ts +2 -1
- package/src/storages/inRedis/SegmentsCacheInRedis.ts +13 -22
- package/src/storages/inRedis/UniqueKeysCacheInRedis.ts +2 -1
- package/src/storages/pluggable/SegmentsCachePluggable.ts +11 -35
- package/src/storages/pluggable/UniqueKeysCachePluggable.ts +2 -1
- package/src/storages/pluggable/inMemoryWrapper.ts +2 -1
- package/src/storages/types.ts +3 -9
- package/src/sync/offline/syncManagerOffline.ts +21 -13
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +13 -29
- package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -1
- package/src/sync/syncManagerOnline.ts +17 -17
- package/src/sync/types.ts +1 -1
- package/src/trackers/eventTracker.ts +11 -8
- package/src/trackers/impressionsTracker.ts +13 -10
- package/src/trackers/types.ts +1 -0
- package/src/trackers/uniqueKeysTracker.ts +6 -4
- package/src/utils/lang/sets.ts +11 -1
- package/types/readiness/types.d.ts +3 -0
- package/types/sdkFactory/types.d.ts +1 -0
- package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +5 -5
- package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +5 -5
- package/types/storages/inMemory/SegmentsCacheInMemory.d.ts +5 -7
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +0 -1
- package/types/storages/inRedis/SegmentsCacheInRedis.d.ts +6 -3
- package/types/storages/pluggable/SegmentsCachePluggable.d.ts +4 -16
- package/types/storages/types.d.ts +3 -9
- package/types/sync/types.d.ts +1 -1
- package/types/trackers/eventTracker.d.ts +1 -1
- package/types/trackers/impressionsTracker.d.ts +1 -1
- package/types/trackers/types.d.ts +1 -0
- package/types/utils/lang/sets.d.ts +1 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.inMemoryWrapperFactory = void 0;
|
|
4
4
|
var lang_1 = require("../../utils/lang");
|
|
5
|
+
var sets_1 = require("../../utils/lang/sets");
|
|
5
6
|
/**
|
|
6
7
|
* Creates a IPluggableStorageWrapper implementation that stores items in memory.
|
|
7
8
|
* The `_cache` property is the object were items are stored.
|
|
@@ -118,7 +119,7 @@ function inMemoryWrapperFactory(connDelay) {
|
|
|
118
119
|
if (!set)
|
|
119
120
|
return Promise.resolve([]);
|
|
120
121
|
if (set instanceof Set)
|
|
121
|
-
return Promise.resolve(
|
|
122
|
+
return Promise.resolve((0, sets_1.setToArray)(set));
|
|
122
123
|
return Promise.reject('key is not a set');
|
|
123
124
|
},
|
|
124
125
|
// always connects and disconnects
|
|
@@ -19,23 +19,30 @@ function syncManagerOfflineFactory(splitsParserFactory) {
|
|
|
19
19
|
*/
|
|
20
20
|
return function (_a) {
|
|
21
21
|
var settings = _a.settings, readiness = _a.readiness, storage = _a.storage;
|
|
22
|
-
|
|
22
|
+
var mainSyncManager = (0, fromObjectSyncTask_1.fromObjectSyncTaskFactory)(splitsParserFactory(), storage, readiness, settings);
|
|
23
|
+
var mainStart = mainSyncManager.start;
|
|
24
|
+
var sharedStarts = [];
|
|
25
|
+
return (0, objectAssign_1.objectAssign)(mainSyncManager, {
|
|
26
|
+
start: function () {
|
|
27
|
+
mainStart();
|
|
28
|
+
sharedStarts.forEach(function (cb) { return cb(); });
|
|
29
|
+
sharedStarts.length = 0;
|
|
30
|
+
},
|
|
23
31
|
// fake flush, that resolves immediately
|
|
24
32
|
flush: flush,
|
|
25
33
|
// [Only used for client-side]
|
|
26
34
|
shared: function (matchingKey, readinessManager) {
|
|
35
|
+
// In LOCALHOST mode, shared clients are ready in the next event-loop cycle than created
|
|
36
|
+
// SDK_READY cannot be emitted directly because this will not update the readiness status
|
|
37
|
+
function emitSdkReady() {
|
|
38
|
+
readinessManager.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED); // SDK_SPLITS_ARRIVED emitted by main SyncManager
|
|
39
|
+
}
|
|
40
|
+
if (mainSyncManager.isRunning())
|
|
41
|
+
setTimeout(emitSdkReady);
|
|
42
|
+
else
|
|
43
|
+
sharedStarts.push(emitSdkReady);
|
|
27
44
|
return {
|
|
28
|
-
start: function () {
|
|
29
|
-
// In LOCALHOST mode, shared clients are ready in the next event-loop cycle than created
|
|
30
|
-
// SDK_READY cannot be emitted directly because this will not update the readiness status
|
|
31
|
-
setTimeout(function () {
|
|
32
|
-
readinessManager.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED); // SDK_SPLITS_ARRIVED emitted by main SyncManager
|
|
33
|
-
}, 0);
|
|
34
|
-
},
|
|
35
45
|
stop: function () { },
|
|
36
|
-
isRunning: function () {
|
|
37
|
-
return true;
|
|
38
|
-
},
|
|
39
46
|
flush: flush,
|
|
40
47
|
};
|
|
41
48
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.segmentChangesUpdaterFactory = void 0;
|
|
4
|
-
var lang_1 = require("../../../utils/lang");
|
|
5
4
|
var constants_1 = require("../../../readiness/constants");
|
|
6
5
|
var constants_2 = require("../../../logger/constants");
|
|
7
|
-
var thenable_1 = require("../../../utils/promise/thenable");
|
|
8
6
|
/**
|
|
9
7
|
* Factory of SegmentChanges updater, a task that:
|
|
10
8
|
* - fetches segment changes using `segmentChangesFetcher`
|
|
@@ -23,27 +21,16 @@ function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, read
|
|
|
23
21
|
var sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
|
|
24
22
|
return sincePromise.then(function (since) {
|
|
25
23
|
// if fetchOnlyNew flag, avoid processing already fetched segments
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
results.push(segments.removeFromSegment(segmentName, x.removed));
|
|
36
|
-
if (x.added.length > 0 || x.removed.length > 0) {
|
|
37
|
-
results.push(segments.setChangeNumber(segmentName, x.till));
|
|
38
|
-
changeNumber = x.till;
|
|
39
|
-
}
|
|
40
|
-
log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Processed " + segmentName + " with till = " + x.till + ". Added: " + x.added.length + ". Removed: " + x.removed.length);
|
|
24
|
+
return fetchOnlyNew && since !== -1 ?
|
|
25
|
+
false :
|
|
26
|
+
segmentChangesFetcher(since, segmentName, noCache, till).then(function (changes) {
|
|
27
|
+
return Promise.all(changes.map(function (x) {
|
|
28
|
+
log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Processing " + segmentName + " with till = " + x.till + ". Added: " + x.added.length + ". Removed: " + x.removed.length);
|
|
29
|
+
return segments.update(x.name, x.added, x.removed, x.till);
|
|
30
|
+
})).then(function (updates) {
|
|
31
|
+
return updates.some(function (update) { return update; });
|
|
32
|
+
});
|
|
41
33
|
});
|
|
42
|
-
// If at least one storage operation result is a promise, join all in a single promise.
|
|
43
|
-
if (results.some(function (result) { return (0, thenable_1.thenable)(result); }))
|
|
44
|
-
return Promise.all(results).then(function () { return changeNumber; });
|
|
45
|
-
return changeNumber;
|
|
46
|
-
});
|
|
47
34
|
});
|
|
48
35
|
}
|
|
49
36
|
/**
|
|
@@ -62,14 +49,11 @@ function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, read
|
|
|
62
49
|
// If not a segment name provided, read list of available segments names to be updated.
|
|
63
50
|
var segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
|
|
64
51
|
return segmentsPromise.then(function (segmentNames) {
|
|
65
|
-
// Async fetchers
|
|
66
|
-
var updaters =
|
|
67
|
-
for (var index = 0; index < segmentNames.length; index++) {
|
|
68
|
-
updaters.push(updateSegment(segmentNames[index], noCache, till, fetchOnlyNew));
|
|
69
|
-
}
|
|
52
|
+
// Async fetchers
|
|
53
|
+
var updaters = segmentNames.map(function (segmentName) { return updateSegment(segmentName, noCache, till, fetchOnlyNew); });
|
|
70
54
|
return Promise.all(updaters).then(function (shouldUpdateFlags) {
|
|
71
55
|
// if at least one segment fetch succeeded, mark segments ready
|
|
72
|
-
if (
|
|
56
|
+
if (shouldUpdateFlags.some(function (update) { return update; }) || readyOnAlreadyExistentState) {
|
|
73
57
|
readyOnAlreadyExistentState = false;
|
|
74
58
|
if (readiness)
|
|
75
59
|
readiness.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED);
|
|
@@ -6,6 +6,7 @@ var constants_1 = require("../../../readiness/constants");
|
|
|
6
6
|
var constants_2 = require("../../../logger/constants");
|
|
7
7
|
var lang_1 = require("../../../utils/lang");
|
|
8
8
|
var constants_3 = require("../../../utils/constants");
|
|
9
|
+
var sets_1 = require("../../../utils/lang/sets");
|
|
9
10
|
// Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
|
|
10
11
|
// Returns a promise that could be rejected.
|
|
11
12
|
// @TODO review together with Segments and MySegments storage APIs
|
|
@@ -71,7 +72,7 @@ function computeSplitsMutation(entries, filters) {
|
|
|
71
72
|
}
|
|
72
73
|
return accum;
|
|
73
74
|
}, { added: [], removed: [], segments: [] });
|
|
74
|
-
computed.segments =
|
|
75
|
+
computed.segments = (0, sets_1.setToArray)(segments);
|
|
75
76
|
return computed;
|
|
76
77
|
}
|
|
77
78
|
exports.computeSplitsMutation = computeSplitsMutation;
|
|
@@ -118,33 +118,32 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
118
118
|
if (!pollingManager)
|
|
119
119
|
return;
|
|
120
120
|
var mySegmentsSyncTask = pollingManager.add(matchingKey, readinessManager, storage);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (pollingManager.isRunning()) {
|
|
127
|
-
// if doing polling, we must start the periodic fetch of data
|
|
128
|
-
if (storage.splits.usesSegments())
|
|
129
|
-
mySegmentsSyncTask.start();
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
// if not polling, we must execute the sync task for the initial fetch
|
|
133
|
-
// of segments since `syncAll` was already executed when starting the main client
|
|
134
|
-
mySegmentsSyncTask.execute();
|
|
135
|
-
}
|
|
136
|
-
pushManager.add(matchingKey, mySegmentsSyncTask);
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
121
|
+
if (running) {
|
|
122
|
+
if (syncEnabled) {
|
|
123
|
+
if (pushManager) {
|
|
124
|
+
if (pollingManager.isRunning()) {
|
|
125
|
+
// if doing polling, we must start the periodic fetch of data
|
|
139
126
|
if (storage.splits.usesSegments())
|
|
140
127
|
mySegmentsSyncTask.start();
|
|
141
128
|
}
|
|
129
|
+
else {
|
|
130
|
+
// if not polling, we must execute the sync task for the initial fetch
|
|
131
|
+
// of segments since `syncAll` was already executed when starting the main client
|
|
132
|
+
mySegmentsSyncTask.execute();
|
|
133
|
+
}
|
|
134
|
+
pushManager.add(matchingKey, mySegmentsSyncTask);
|
|
142
135
|
}
|
|
143
136
|
else {
|
|
144
|
-
if (
|
|
145
|
-
mySegmentsSyncTask.
|
|
137
|
+
if (storage.splits.usesSegments())
|
|
138
|
+
mySegmentsSyncTask.start();
|
|
146
139
|
}
|
|
147
|
-
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
if (!readinessManager.isReady())
|
|
143
|
+
mySegmentsSyncTask.execute();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
148
147
|
stop: function () {
|
|
149
148
|
// check in case `client.destroy()` has been invoked more than once for the same client
|
|
150
149
|
var mySegmentsSyncTask = pollingManager.get(matchingKey);
|
|
@@ -12,7 +12,7 @@ var mode_1 = require("../utils/settingsValidation/mode");
|
|
|
12
12
|
* @param eventsCache cache to save events
|
|
13
13
|
* @param integrationsManager optional event handler used for integrations
|
|
14
14
|
*/
|
|
15
|
-
function eventTrackerFactory(settings, eventsCache, integrationsManager, telemetryCache) {
|
|
15
|
+
function eventTrackerFactory(settings, eventsCache, whenInit, integrationsManager, telemetryCache) {
|
|
16
16
|
var log = settings.log, mode = settings.mode;
|
|
17
17
|
var isAsync = (0, mode_1.isConsumerMode)(mode);
|
|
18
18
|
function queueEventsCallback(eventData, tracked) {
|
|
@@ -22,15 +22,17 @@ function eventTrackerFactory(settings, eventsCache, integrationsManager, telemet
|
|
|
22
22
|
if (tracked) {
|
|
23
23
|
log.info(constants_1.EVENTS_TRACKER_SUCCESS, [msg]);
|
|
24
24
|
if (integrationsManager) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
whenInit(function () {
|
|
26
|
+
// Wrap in a timeout because we don't want it to be blocking.
|
|
27
|
+
setTimeout(function () {
|
|
28
|
+
// copy of event, to avoid unexpected behaviour if modified by integrations
|
|
29
|
+
var eventDataCopy = (0, objectAssign_1.objectAssign)({}, eventData);
|
|
30
|
+
if (properties)
|
|
31
|
+
eventDataCopy.properties = (0, objectAssign_1.objectAssign)({}, properties);
|
|
32
|
+
// integrationsManager does not throw errors (they are internally handled by each integration module)
|
|
33
|
+
integrationsManager.handleEvent(eventDataCopy);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
38
|
else {
|
|
@@ -14,7 +14,7 @@ var constants_2 = require("../utils/constants");
|
|
|
14
14
|
* @param integrationsManager optional integrations manager
|
|
15
15
|
* @param strategy strategy for impressions tracking.
|
|
16
16
|
*/
|
|
17
|
-
function impressionsTrackerFactory(settings, impressionsCache, strategy, integrationsManager, telemetryCache) {
|
|
17
|
+
function impressionsTrackerFactory(settings, impressionsCache, strategy, whenInit, integrationsManager, telemetryCache) {
|
|
18
18
|
var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version;
|
|
19
19
|
return {
|
|
20
20
|
track: function (impressions, attributes) {
|
|
@@ -53,19 +53,21 @@ function impressionsTrackerFactory(settings, impressionsCache, strategy, integra
|
|
|
53
53
|
hostname: hostname,
|
|
54
54
|
sdkLanguageVersion: version
|
|
55
55
|
};
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
integrationsManager
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
impressionListener
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
whenInit(function () {
|
|
57
|
+
// Wrap in a timeout because we don't want it to be blocking.
|
|
58
|
+
setTimeout(function () {
|
|
59
|
+
// integrationsManager.handleImpression does not throw errors
|
|
60
|
+
if (integrationsManager)
|
|
61
|
+
integrationsManager.handleImpression(impressionData);
|
|
62
|
+
try { // @ts-ignore. An exception on the listeners should not break the SDK.
|
|
63
|
+
if (impressionListener)
|
|
64
|
+
impressionListener.logImpression(impressionData);
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
log.error(constants_1.ERROR_IMPRESSIONS_LISTENER, [err]);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
69
71
|
};
|
|
70
72
|
for (var i = 0; i < impressionsToListenerCount; i++) {
|
|
71
73
|
_loop_1(i);
|
|
@@ -19,9 +19,6 @@ var noopFilterAdapter = {
|
|
|
19
19
|
function uniqueKeysTrackerFactory(log, uniqueKeysCache, filterAdapter) {
|
|
20
20
|
if (filterAdapter === void 0) { filterAdapter = noopFilterAdapter; }
|
|
21
21
|
var intervalId;
|
|
22
|
-
if (filterAdapter.refreshRate) {
|
|
23
|
-
intervalId = setInterval(filterAdapter.clear, filterAdapter.refreshRate);
|
|
24
|
-
}
|
|
25
22
|
return {
|
|
26
23
|
track: function (key, featureName) {
|
|
27
24
|
if (!filterAdapter.add(key, featureName)) {
|
|
@@ -30,6 +27,11 @@ function uniqueKeysTrackerFactory(log, uniqueKeysCache, filterAdapter) {
|
|
|
30
27
|
}
|
|
31
28
|
uniqueKeysCache.track(key, featureName);
|
|
32
29
|
},
|
|
30
|
+
start: function () {
|
|
31
|
+
if (filterAdapter.refreshRate) {
|
|
32
|
+
intervalId = setInterval(filterAdapter.clear, filterAdapter.refreshRate);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
33
35
|
stop: function () {
|
|
34
36
|
clearInterval(intervalId);
|
|
35
37
|
}
|
package/cjs/utils/lang/sets.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.returnDifference = exports.returnSetsUnion = void 0;
|
|
3
|
+
exports.returnDifference = exports.returnSetsUnion = exports.setToArray = void 0;
|
|
4
|
+
function setToArray(set) {
|
|
5
|
+
if (Array.from)
|
|
6
|
+
return Array.from(set);
|
|
7
|
+
var array = [];
|
|
8
|
+
set.forEach(function (value) {
|
|
9
|
+
array.push(value);
|
|
10
|
+
});
|
|
11
|
+
return array;
|
|
12
|
+
}
|
|
13
|
+
exports.setToArray = setToArray;
|
|
4
14
|
function returnSetsUnion(set, set2) {
|
|
5
|
-
return new Set(
|
|
15
|
+
return new Set(setToArray(set).concat(setToArray(set2)));
|
|
6
16
|
}
|
|
7
17
|
exports.returnSetsUnion = returnSetsUnion;
|
|
8
18
|
function returnDifference(list, list2) {
|
package/esm/evaluator/Engine.js
CHANGED
|
@@ -14,7 +14,7 @@ var Engine = /** @class */ (function () {
|
|
|
14
14
|
function Engine(baseInfo, evaluator) {
|
|
15
15
|
this.baseInfo = baseInfo;
|
|
16
16
|
this.evaluator = evaluator;
|
|
17
|
-
// in case we don't have a default treatment in the
|
|
17
|
+
// in case we don't have a default treatment in the instantiation, use 'control'
|
|
18
18
|
if (typeof this.baseInfo.defaultTreatment !== 'string') {
|
|
19
19
|
this.baseInfo.defaultTreatment = CONTROL;
|
|
20
20
|
}
|
package/esm/evaluator/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Engine } from './Engine';
|
|
|
2
2
|
import { thenable } from '../utils/promise/thenable';
|
|
3
3
|
import { EXCEPTION, SPLIT_NOT_FOUND } from '../utils/labels';
|
|
4
4
|
import { CONTROL } from '../utils/constants';
|
|
5
|
-
import { returnSetsUnion } from '../utils/lang/sets';
|
|
5
|
+
import { returnSetsUnion, setToArray } from '../utils/lang/sets';
|
|
6
6
|
import { WARN_FLAGSET_WITHOUT_FLAGS } from '../logger/constants';
|
|
7
7
|
var treatmentException = {
|
|
8
8
|
treatment: CONTROL,
|
|
@@ -65,7 +65,7 @@ export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, stora
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
return featureFlags.size ?
|
|
68
|
-
evaluateFeatures(log, key,
|
|
68
|
+
evaluateFeatures(log, key, setToArray(featureFlags), attributes, storage) :
|
|
69
69
|
{};
|
|
70
70
|
}
|
|
71
71
|
// get features by flag sets
|
|
@@ -4,6 +4,8 @@ function splitsEventEmitterFactory(EventEmitter) {
|
|
|
4
4
|
var splitsEventEmitter = objectAssign(new EventEmitter(), {
|
|
5
5
|
splitsArrived: false,
|
|
6
6
|
splitsCacheLoaded: false,
|
|
7
|
+
initialized: false,
|
|
8
|
+
initCallbacks: []
|
|
7
9
|
});
|
|
8
10
|
// `isSplitKill` condition avoids an edge-case of wrongly emitting SDK_READY if:
|
|
9
11
|
// - `/memberships` fetch and SPLIT_KILL occurs before `/splitChanges` fetch, and
|
|
@@ -43,7 +45,7 @@ export function readinessManagerFactory(EventEmitter, settings, splits) {
|
|
|
43
45
|
// emit SDK_READY_TIMED_OUT
|
|
44
46
|
var hasTimedout = false;
|
|
45
47
|
function timeout() {
|
|
46
|
-
if (hasTimedout)
|
|
48
|
+
if (hasTimedout || isReady)
|
|
47
49
|
return;
|
|
48
50
|
hasTimedout = true;
|
|
49
51
|
syncLastUpdate();
|
|
@@ -51,7 +53,10 @@ export function readinessManagerFactory(EventEmitter, settings, splits) {
|
|
|
51
53
|
}
|
|
52
54
|
var readyTimeoutId;
|
|
53
55
|
if (readyTimeout > 0) {
|
|
54
|
-
|
|
56
|
+
if (splits.initialized)
|
|
57
|
+
readyTimeoutId = setTimeout(timeout, readyTimeout);
|
|
58
|
+
else
|
|
59
|
+
splits.initCallbacks.push(function () { readyTimeoutId = setTimeout(timeout, readyTimeout); });
|
|
55
60
|
}
|
|
56
61
|
// emit SDK_READY and SDK_UPDATE
|
|
57
62
|
var isReady = false;
|
|
@@ -113,6 +118,12 @@ export function readinessManagerFactory(EventEmitter, settings, splits) {
|
|
|
113
118
|
// Called on 403 error (client-side SDK key on server-side), to set the SDK as destroyed for
|
|
114
119
|
// tracking and evaluations, while keeping event listeners to emit SDK_READY_TIMED_OUT event
|
|
115
120
|
setDestroyed: function () { isDestroyed = true; },
|
|
121
|
+
init: function () {
|
|
122
|
+
if (splits.initialized)
|
|
123
|
+
return;
|
|
124
|
+
splits.initialized = true;
|
|
125
|
+
splits.initCallbacks.forEach(function (cb) { return cb(); });
|
|
126
|
+
},
|
|
116
127
|
destroy: function () {
|
|
117
128
|
isDestroyed = true;
|
|
118
129
|
syncLastUpdate();
|
package/esm/sdkFactory/index.js
CHANGED
|
@@ -16,12 +16,19 @@ import { NONE, OPTIMIZED } from '../utils/constants';
|
|
|
16
16
|
* Modular SDK factory
|
|
17
17
|
*/
|
|
18
18
|
export function sdkFactory(params) {
|
|
19
|
-
var settings = params.settings, platform = params.platform, storageFactory = params.storageFactory, splitApiFactory = params.splitApiFactory, extraProps = params.extraProps, syncManagerFactory = params.syncManagerFactory, SignalListener = params.SignalListener, impressionsObserverFactory = params.impressionsObserverFactory, integrationsManagerFactory = params.integrationsManagerFactory, sdkManagerFactory = params.sdkManagerFactory, sdkClientMethodFactory = params.sdkClientMethodFactory, filterAdapterFactory = params.filterAdapterFactory;
|
|
19
|
+
var settings = params.settings, platform = params.platform, storageFactory = params.storageFactory, splitApiFactory = params.splitApiFactory, extraProps = params.extraProps, syncManagerFactory = params.syncManagerFactory, SignalListener = params.SignalListener, impressionsObserverFactory = params.impressionsObserverFactory, integrationsManagerFactory = params.integrationsManagerFactory, sdkManagerFactory = params.sdkManagerFactory, sdkClientMethodFactory = params.sdkClientMethodFactory, filterAdapterFactory = params.filterAdapterFactory, lazyInit = params.lazyInit;
|
|
20
20
|
var log = settings.log, impressionsMode = settings.sync.impressionsMode;
|
|
21
21
|
// @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid SDK Key, etc.
|
|
22
22
|
// On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
|
|
23
|
-
//
|
|
24
|
-
|
|
23
|
+
// initialization
|
|
24
|
+
var hasInit = false;
|
|
25
|
+
var initCallbacks = [];
|
|
26
|
+
function whenInit(cb) {
|
|
27
|
+
if (hasInit)
|
|
28
|
+
cb();
|
|
29
|
+
else
|
|
30
|
+
initCallbacks.push(cb);
|
|
31
|
+
}
|
|
25
32
|
var sdkReadinessManager = sdkReadinessManagerFactory(platform.EventEmitter, settings);
|
|
26
33
|
var readiness = sdkReadinessManager.readinessManager;
|
|
27
34
|
var storage = storageFactory({
|
|
@@ -53,8 +60,8 @@ export function sdkFactory(params) {
|
|
|
53
60
|
default:
|
|
54
61
|
strategy = strategyDebugFactory(observer);
|
|
55
62
|
}
|
|
56
|
-
var impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, strategy, integrationsManager, storage.telemetry);
|
|
57
|
-
var eventTracker = eventTrackerFactory(settings, storage.events, integrationsManager, storage.telemetry);
|
|
63
|
+
var impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, strategy, whenInit, integrationsManager, storage.telemetry);
|
|
64
|
+
var eventTracker = eventTrackerFactory(settings, storage.events, whenInit, integrationsManager, storage.telemetry);
|
|
58
65
|
// splitApi is used by SyncManager and Browser signal listener
|
|
59
66
|
var splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
|
|
60
67
|
var ctx = { clients: clients, splitApi: splitApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, uniqueKeysTracker: uniqueKeysTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform };
|
|
@@ -65,8 +72,19 @@ export function sdkFactory(params) {
|
|
|
65
72
|
// SDK client and manager
|
|
66
73
|
var clientMethod = sdkClientMethodFactory(ctx);
|
|
67
74
|
var managerInstance = sdkManagerFactory(settings, storage.splits, sdkReadinessManager);
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
function init() {
|
|
76
|
+
if (hasInit)
|
|
77
|
+
return;
|
|
78
|
+
hasInit = true;
|
|
79
|
+
// We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle.
|
|
80
|
+
validateAndTrackApiKey(log, settings.core.authorizationKey);
|
|
81
|
+
readiness.init();
|
|
82
|
+
uniqueKeysTracker && uniqueKeysTracker.start();
|
|
83
|
+
syncManager && syncManager.start();
|
|
84
|
+
signalListener && signalListener.start();
|
|
85
|
+
initCallbacks.forEach(function (cb) { return cb(); });
|
|
86
|
+
initCallbacks.length = 0;
|
|
87
|
+
}
|
|
70
88
|
log.info(NEW_FACTORY);
|
|
71
89
|
// @ts-ignore
|
|
72
90
|
return objectAssign({
|
|
@@ -83,5 +101,5 @@ export function sdkFactory(params) {
|
|
|
83
101
|
destroy: function () {
|
|
84
102
|
return Promise.all(Object.keys(clients).map(function (key) { return clients[key].destroy(); })).then(function () { });
|
|
85
103
|
}
|
|
86
|
-
}, extraProps && extraProps(ctx));
|
|
104
|
+
}, extraProps && extraProps(ctx), lazyInit ? { init: init } : init());
|
|
87
105
|
}
|
|
@@ -2,35 +2,33 @@
|
|
|
2
2
|
* This class provides a skeletal implementation of the ISegmentsCacheSync interface
|
|
3
3
|
* to minimize the effort required to implement this interface.
|
|
4
4
|
*/
|
|
5
|
-
var
|
|
6
|
-
function
|
|
5
|
+
var AbstractMySegmentsCacheSync = /** @class */ (function () {
|
|
6
|
+
function AbstractMySegmentsCacheSync() {
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* clear the cache.
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
AbstractMySegmentsCacheSync.prototype.clear = function () {
|
|
12
12
|
this.resetSegments({});
|
|
13
13
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*/
|
|
18
|
-
AbstractSegmentsCacheSync.prototype.registerSegments = function (names) { return false; };
|
|
14
|
+
// No-op. Not used in client-side.
|
|
15
|
+
AbstractMySegmentsCacheSync.prototype.registerSegments = function () { return false; };
|
|
16
|
+
AbstractMySegmentsCacheSync.prototype.update = function () { return false; };
|
|
19
17
|
/**
|
|
20
18
|
* For server-side synchronizer: the method is not used.
|
|
21
19
|
* For client-side synchronizer: it resets or updates the cache.
|
|
22
20
|
*/
|
|
23
|
-
|
|
21
|
+
AbstractMySegmentsCacheSync.prototype.resetSegments = function (segmentsData) {
|
|
24
22
|
var _this = this;
|
|
25
|
-
this.setChangeNumber(
|
|
23
|
+
this.setChangeNumber(segmentsData.cn);
|
|
26
24
|
var _a = segmentsData, added = _a.added, removed = _a.removed;
|
|
27
25
|
if (added && removed) {
|
|
28
26
|
var isDiff_1 = false;
|
|
29
27
|
added.forEach(function (segment) {
|
|
30
|
-
isDiff_1 = _this.
|
|
28
|
+
isDiff_1 = _this.addSegment(segment) || isDiff_1;
|
|
31
29
|
});
|
|
32
30
|
removed.forEach(function (segment) {
|
|
33
|
-
isDiff_1 = _this.
|
|
31
|
+
isDiff_1 = _this.removeSegment(segment) || isDiff_1;
|
|
34
32
|
});
|
|
35
33
|
return isDiff_1;
|
|
36
34
|
}
|
|
@@ -47,13 +45,13 @@ var AbstractSegmentsCacheSync = /** @class */ (function () {
|
|
|
47
45
|
return false;
|
|
48
46
|
// Slowest path => add and/or remove segments
|
|
49
47
|
for (var removeIndex = index; removeIndex < storedSegmentKeys.length; removeIndex++) {
|
|
50
|
-
this.
|
|
48
|
+
this.removeSegment(storedSegmentKeys[removeIndex]);
|
|
51
49
|
}
|
|
52
50
|
for (var addIndex = index; addIndex < names.length; addIndex++) {
|
|
53
|
-
this.
|
|
51
|
+
this.addSegment(names[addIndex]);
|
|
54
52
|
}
|
|
55
53
|
return true;
|
|
56
54
|
};
|
|
57
|
-
return
|
|
55
|
+
return AbstractMySegmentsCacheSync;
|
|
58
56
|
}());
|
|
59
|
-
export {
|
|
57
|
+
export { AbstractMySegmentsCacheSync };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __extends } from "tslib";
|
|
2
2
|
import { isNaNNumber } from '../../utils/lang';
|
|
3
|
-
import {
|
|
3
|
+
import { AbstractMySegmentsCacheSync } from '../AbstractMySegmentsCacheSync';
|
|
4
4
|
import { LOG_PREFIX, DEFINED } from './constants';
|
|
5
5
|
var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
6
6
|
__extends(MySegmentsCacheInLocal, _super);
|
|
@@ -11,7 +11,7 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
11
11
|
return _this;
|
|
12
12
|
// There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
|
|
13
13
|
}
|
|
14
|
-
MySegmentsCacheInLocal.prototype.
|
|
14
|
+
MySegmentsCacheInLocal.prototype.addSegment = function (name) {
|
|
15
15
|
var segmentKey = this.keys.buildSegmentNameKey(name);
|
|
16
16
|
try {
|
|
17
17
|
if (localStorage.getItem(segmentKey) === DEFINED)
|
|
@@ -24,7 +24,7 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
|
-
MySegmentsCacheInLocal.prototype.
|
|
27
|
+
MySegmentsCacheInLocal.prototype.removeSegment = function (name) {
|
|
28
28
|
var segmentKey = this.keys.buildSegmentNameKey(name);
|
|
29
29
|
try {
|
|
30
30
|
if (localStorage.getItem(segmentKey) !== DEFINED)
|
|
@@ -53,7 +53,7 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
53
53
|
MySegmentsCacheInLocal.prototype.getKeysCount = function () {
|
|
54
54
|
return 1;
|
|
55
55
|
};
|
|
56
|
-
MySegmentsCacheInLocal.prototype.setChangeNumber = function (
|
|
56
|
+
MySegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
57
57
|
try {
|
|
58
58
|
if (changeNumber)
|
|
59
59
|
localStorage.setItem(this.keys.buildTillKey(), changeNumber + '');
|
|
@@ -74,5 +74,5 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
74
74
|
return n;
|
|
75
75
|
};
|
|
76
76
|
return MySegmentsCacheInLocal;
|
|
77
|
-
}(
|
|
77
|
+
}(AbstractMySegmentsCacheSync));
|
|
78
78
|
export { MySegmentsCacheInLocal };
|
|
@@ -3,6 +3,7 @@ import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSyn
|
|
|
3
3
|
import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
|
|
4
4
|
import { LOG_PREFIX } from './constants';
|
|
5
5
|
import { getStorageHash } from '../KeyBuilder';
|
|
6
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
6
7
|
/**
|
|
7
8
|
* ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
|
|
8
9
|
*/
|
|
@@ -240,7 +241,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
240
241
|
var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
241
242
|
var flagSetCache = new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
242
243
|
flagSetCache.add(featureFlag.name);
|
|
243
|
-
localStorage.setItem(flagSetKey, JSON.stringify(
|
|
244
|
+
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
|
|
244
245
|
});
|
|
245
246
|
};
|
|
246
247
|
SplitsCacheInLocal.prototype.removeFromFlagSets = function (featureFlagName, flagSets) {
|
|
@@ -262,7 +263,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
262
263
|
localStorage.removeItem(flagSetKey);
|
|
263
264
|
return;
|
|
264
265
|
}
|
|
265
|
-
localStorage.setItem(flagSetKey, JSON.stringify(
|
|
266
|
+
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
|
|
266
267
|
};
|
|
267
268
|
return SplitsCacheInLocal;
|
|
268
269
|
}(AbstractSplitsCacheSync));
|
|
@@ -53,7 +53,7 @@ export function InLocalStorage(options) {
|
|
|
53
53
|
this.events.clear();
|
|
54
54
|
(_a = this.uniqueKeys) === null || _a === void 0 ? void 0 : _a.clear();
|
|
55
55
|
},
|
|
56
|
-
// When using shared
|
|
56
|
+
// When using shared instantiation with MEMORY we reuse everything but segments (they are customer per key).
|
|
57
57
|
shared: function (matchingKey) {
|
|
58
58
|
return {
|
|
59
59
|
splits: this.splits,
|
|
@@ -35,7 +35,7 @@ export function InMemoryStorageCSFactory(params) {
|
|
|
35
35
|
this.events.clear();
|
|
36
36
|
this.uniqueKeys && this.uniqueKeys.clear();
|
|
37
37
|
},
|
|
38
|
-
// When using shared
|
|
38
|
+
// When using shared instantiation with MEMORY we reuse everything but segments (they are unique per key)
|
|
39
39
|
shared: function () {
|
|
40
40
|
return {
|
|
41
41
|
splits: this.splits,
|
|
@@ -55,7 +55,7 @@ export function InMemoryStorageCSFactory(params) {
|
|
|
55
55
|
},
|
|
56
56
|
};
|
|
57
57
|
// @TODO revisit storage logic in localhost mode
|
|
58
|
-
// No tracking
|
|
58
|
+
// No tracking in localhost mode to avoid memory leaks: https://github.com/splitio/javascript-commons/issues/181
|
|
59
59
|
if (params.settings.mode === LOCALHOST_MODE) {
|
|
60
60
|
var noopTrack = function () { return true; };
|
|
61
61
|
storage.impressions.track = noopTrack;
|