@splitsoftware/splitio-commons 1.4.2-rc.1 → 1.4.2-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +4 -4
- package/cjs/sdkFactory/index.js +20 -2
- package/cjs/storages/AbstractSplitsCacheSync.js +1 -1
- package/cjs/storages/dataLoader.js +23 -15
- package/cjs/storages/inMemory/InMemoryStorage.js +15 -1
- package/cjs/storages/inMemory/InMemoryStorageCS.js +12 -0
- package/cjs/sync/syncManagerOnline.js +2 -2
- package/cjs/trackers/impressionObserver/impressionObserverCS.js +1 -1
- package/cjs/utils/settingsValidation/index.js +8 -1
- package/esm/sdkFactory/index.js +21 -3
- package/esm/storages/AbstractSplitsCacheSync.js +1 -1
- package/esm/storages/dataLoader.js +21 -13
- package/esm/storages/inMemory/InMemoryStorage.js +15 -1
- package/esm/storages/inMemory/InMemoryStorageCS.js +12 -0
- package/esm/sync/syncManagerOnline.js +2 -2
- package/esm/trackers/impressionObserver/impressionObserverCS.js +1 -1
- package/esm/utils/settingsValidation/index.js +8 -1
- package/package.json +1 -1
- package/src/sdkFactory/index.ts +23 -4
- package/src/storages/AbstractSplitsCacheSync.ts +1 -1
- package/src/storages/dataLoader.ts +20 -13
- package/src/storages/inMemory/InMemoryStorage.ts +16 -1
- package/src/storages/inMemory/InMemoryStorageCS.ts +13 -0
- package/src/sync/syncManagerOnline.ts +2 -2
- package/src/trackers/impressionObserver/impressionObserverCS.ts +1 -1
- package/src/types.ts +5 -3
- package/src/utils/settingsValidation/index.ts +9 -1
- package/types/storages/dataLoader.d.ts +2 -2
- package/types/trackers/impressionObserver/impressionObserverCS.d.ts +2 -2
- package/types/types.d.ts +4 -2
package/CHANGES.txt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
1.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
1.5.0 (June 24, 2022)
|
|
2
|
+
- Added a new config option to control the tasks that listen or poll for updates on feature flags and segments, via the new config sync.enabled . Running online Split will always pull the most recent updates upon initialization, this only affects updates fetching on a running instance. Useful when a consistent session experience is a must or to save resources when updates are not being used.
|
|
3
|
+
- Updated telemetry logic to track the anonymous config for user consent flag set to declined or unknown.
|
|
4
|
+
- Updated submitters logic, to avoid duplicating the post of impressions to Split cloud when the SDK is destroyed while its periodic post of impressions is running.
|
|
5
5
|
|
|
6
6
|
1.4.1 (June 13, 2022)
|
|
7
7
|
- Bugfixing - Updated submitters logic, to avoid dropping impressions and events that are being tracked while POST request is pending.
|
package/cjs/sdkFactory/index.js
CHANGED
|
@@ -25,13 +25,14 @@ function sdkFactory(params) {
|
|
|
25
25
|
(0, apiKey_1.validateAndTrackApiKey)(log, settings.core.authorizationKey);
|
|
26
26
|
var sdkReadinessManager = (0, sdkReadinessManager_1.sdkReadinessManagerFactory)(log, platform.EventEmitter, settings.startup.readyTimeout);
|
|
27
27
|
var readiness = sdkReadinessManager.readinessManager;
|
|
28
|
+
var matchingKey = (0, key_1.getMatching)(settings.core.key);
|
|
28
29
|
// @TODO consider passing the settings object, so that each storage access only what it needs
|
|
29
30
|
var storageFactoryParams = {
|
|
30
31
|
impressionsQueueSize: settings.scheduler.impressionsQueueSize,
|
|
31
32
|
eventsQueueSize: settings.scheduler.eventsQueueSize,
|
|
32
33
|
optimize: (0, utils_1.shouldBeOptimized)(settings),
|
|
33
34
|
// ATM, only used by InLocalStorage
|
|
34
|
-
matchingKey:
|
|
35
|
+
matchingKey: matchingKey,
|
|
35
36
|
splitFiltersValidation: settings.sync.__splitFiltersValidation,
|
|
36
37
|
// ATM, only used by PluggableStorage
|
|
37
38
|
mode: settings.mode,
|
|
@@ -47,7 +48,21 @@ function sdkFactory(params) {
|
|
|
47
48
|
log: log
|
|
48
49
|
};
|
|
49
50
|
var storage = storageFactory(storageFactoryParams);
|
|
50
|
-
// @TODO
|
|
51
|
+
// @TODO dataLoader requires validation
|
|
52
|
+
if (settings.dataLoader) {
|
|
53
|
+
settings.dataLoader(storage, matchingKey);
|
|
54
|
+
Promise.resolve(storage.splits.checkCache()).then(function (cacheReady) {
|
|
55
|
+
if (cacheReady) {
|
|
56
|
+
if (settings.sync.onlySubmitters) { // emit SDK_READY to not timeout when not synchronizing splits & segments
|
|
57
|
+
readiness.splits.emit(constants_2.SDK_SPLITS_ARRIVED);
|
|
58
|
+
readiness.segments.emit(constants_2.SDK_SEGMENTS_ARRIVED);
|
|
59
|
+
}
|
|
60
|
+
else { // emit SDK_READY_FROM_CACHE
|
|
61
|
+
readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
51
66
|
var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage });
|
|
52
67
|
// trackers
|
|
53
68
|
var observer = impressionsObserverFactory && impressionsObserverFactory();
|
|
@@ -79,6 +94,9 @@ function sdkFactory(params) {
|
|
|
79
94
|
// Logger wrapper API
|
|
80
95
|
Logger: (0, sdkLogger_1.createLoggerAPI)(settings.log),
|
|
81
96
|
settings: settings,
|
|
97
|
+
// @TODO remove
|
|
98
|
+
__storage: storage,
|
|
99
|
+
__ctx: ctx
|
|
82
100
|
}, extraProps && extraProps(ctx));
|
|
83
101
|
}
|
|
84
102
|
exports.sdkFactory = sdkFactory;
|
|
@@ -33,7 +33,7 @@ var AbstractSplitsCacheSync = /** @class */ (function () {
|
|
|
33
33
|
* It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE.
|
|
34
34
|
*/
|
|
35
35
|
AbstractSplitsCacheSync.prototype.checkCache = function () {
|
|
36
|
-
return
|
|
36
|
+
return this.getChangeNumber() > -1;
|
|
37
37
|
};
|
|
38
38
|
/**
|
|
39
39
|
* Kill `name` split and set `defaultTreatment` and `changeNumber`.
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.DataLoaderFactory = void 0;
|
|
4
4
|
var browser_1 = require("../utils/constants/browser");
|
|
5
5
|
/**
|
|
6
|
-
* Factory of
|
|
6
|
+
* Factory of storage loader
|
|
7
7
|
*
|
|
8
8
|
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
9
9
|
* and extended with a `mySegmentsData` property.
|
|
10
10
|
* @returns function to preload the storage
|
|
11
11
|
*/
|
|
12
|
-
function
|
|
12
|
+
function DataLoaderFactory(preloadedData) {
|
|
13
13
|
/**
|
|
14
14
|
* Storage-agnostic adaptation of `loadDataIntoLocalStorage` function
|
|
15
15
|
* (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
|
|
16
16
|
*
|
|
17
17
|
* @param storage object containing `splits` and `segments` cache (client-side variant)
|
|
18
|
-
* @param
|
|
18
|
+
* @param userKey user key (matching key) of the provided MySegmentsCache
|
|
19
19
|
*
|
|
20
|
-
* @TODO extend to support SegmentsCache (server-side variant) by making `userId` optional and adding the corresponding logic.
|
|
21
20
|
* @TODO extend to load data on shared mySegments storages. Be specific when emitting SDK_READY_FROM_CACHE on shared clients. Maybe the serializer should provide the `useSegments` flag.
|
|
21
|
+
* @TODO add logs, and input validation in this module, in favor of size reduction.
|
|
22
|
+
* @TODO unit tests
|
|
22
23
|
*/
|
|
23
|
-
return function loadData(storage,
|
|
24
|
+
return function loadData(storage, userKey) {
|
|
24
25
|
// Do not load data if current preloadedData is empty
|
|
25
26
|
if (Object.keys(preloadedData).length === 0)
|
|
26
27
|
return;
|
|
@@ -36,16 +37,23 @@ function dataLoaderFactory(preloadedData) {
|
|
|
36
37
|
storage.splits.setChangeNumber(since);
|
|
37
38
|
// splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
|
|
38
39
|
storage.splits.addSplits(Object.keys(splitsData).map(function (splitName) { return [splitName, splitsData[splitName]]; }));
|
|
39
|
-
// add mySegments data
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
if (userKey) { // add mySegments data (client-side)
|
|
41
|
+
var mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userKey];
|
|
42
|
+
if (!mySegmentsData) {
|
|
43
|
+
// segmentsData in an object where the property is the segment name and the pertaining value is a stringified object that contains the `added` array of userIds
|
|
44
|
+
mySegmentsData = Object.keys(segmentsData).filter(function (segmentName) {
|
|
45
|
+
var userKeys = segmentsData[segmentName];
|
|
46
|
+
return userKeys.indexOf(userKey) > -1;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
storage.segments.resetSegments(mySegmentsData);
|
|
50
|
+
}
|
|
51
|
+
else { // add segments data (server-side)
|
|
52
|
+
Object.keys(segmentsData).filter(function (segmentName) {
|
|
53
|
+
var userKeys = segmentsData[segmentName];
|
|
54
|
+
storage.segments.addToSegment(segmentName, userKeys);
|
|
46
55
|
});
|
|
47
56
|
}
|
|
48
|
-
storage.segments.resetSegments(mySegmentsData);
|
|
49
57
|
};
|
|
50
58
|
}
|
|
51
|
-
exports.
|
|
59
|
+
exports.DataLoaderFactory = DataLoaderFactory;
|
|
@@ -8,6 +8,7 @@ var EventsCacheInMemory_1 = require("./EventsCacheInMemory");
|
|
|
8
8
|
var ImpressionCountsCacheInMemory_1 = require("./ImpressionCountsCacheInMemory");
|
|
9
9
|
var constants_1 = require("../../utils/constants");
|
|
10
10
|
var TelemetryCacheInMemory_1 = require("./TelemetryCacheInMemory");
|
|
11
|
+
var sets_1 = require("../../utils/lang/sets");
|
|
11
12
|
/**
|
|
12
13
|
* InMemory storage factory for standalone server-side SplitFactory
|
|
13
14
|
*
|
|
@@ -28,7 +29,20 @@ function InMemoryStorageFactory(params) {
|
|
|
28
29
|
this.impressions.clear();
|
|
29
30
|
this.impressionCounts && this.impressionCounts.clear();
|
|
30
31
|
this.events.clear();
|
|
31
|
-
}
|
|
32
|
+
},
|
|
33
|
+
// @ts-ignore, private method, for POC
|
|
34
|
+
getSnapshot: function () {
|
|
35
|
+
var _this = this;
|
|
36
|
+
return {
|
|
37
|
+
lastUpdated: Date.now(),
|
|
38
|
+
since: this.splits.changeNumber,
|
|
39
|
+
splitsData: this.splits.splitsCache,
|
|
40
|
+
segmentsData: Object.keys(this.segments.segmentCache).reduce(function (prev, cur) {
|
|
41
|
+
prev[cur] = (0, sets_1.setToArray)(_this.segments.segmentCache[cur]);
|
|
42
|
+
return prev;
|
|
43
|
+
}, {})
|
|
44
|
+
};
|
|
45
|
+
},
|
|
32
46
|
};
|
|
33
47
|
}
|
|
34
48
|
exports.InMemoryStorageFactory = InMemoryStorageFactory;
|
|
@@ -29,6 +29,18 @@ function InMemoryStorageCSFactory(params) {
|
|
|
29
29
|
this.impressionCounts && this.impressionCounts.clear();
|
|
30
30
|
this.events.clear();
|
|
31
31
|
},
|
|
32
|
+
// @ts-ignore, private method, for POC
|
|
33
|
+
getSnapshot: function () {
|
|
34
|
+
var _a;
|
|
35
|
+
return {
|
|
36
|
+
lastUpdated: Date.now(),
|
|
37
|
+
since: this.splits.changeNumber,
|
|
38
|
+
splitsData: this.splits.splitsCache,
|
|
39
|
+
mySegmentsData: (_a = {},
|
|
40
|
+
_a[params.matchingKey] = Object.keys(this.segments.segmentCache),
|
|
41
|
+
_a)
|
|
42
|
+
};
|
|
43
|
+
},
|
|
32
44
|
// When using shared instanciation with MEMORY we reuse everything but segments (they are unique per key)
|
|
33
45
|
shared: function () {
|
|
34
46
|
return {
|
|
@@ -19,9 +19,9 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
|
|
|
19
19
|
* SyncManager factory for modular SDK
|
|
20
20
|
*/
|
|
21
21
|
return function (params) {
|
|
22
|
-
var settings = params.settings, _a = params.settings, log = _a.log, streamingEnabled = _a.streamingEnabled,
|
|
22
|
+
var settings = params.settings, _a = params.settings, log = _a.log, streamingEnabled = _a.streamingEnabled, _b = _a.sync, syncEnabled = _b.enabled, onlySubmitters = _b.onlySubmitters, telemetryTracker = params.telemetryTracker;
|
|
23
23
|
/** Polling Manager */
|
|
24
|
-
var pollingManager = pollingManagerFactory && pollingManagerFactory(params);
|
|
24
|
+
var pollingManager = onlySubmitters ? undefined : pollingManagerFactory && pollingManagerFactory(params);
|
|
25
25
|
/** Push Manager */
|
|
26
26
|
var pushManager = syncEnabled && streamingEnabled && pollingManager && pushManagerFactory ?
|
|
27
27
|
pushManagerFactory(params, pollingManager) :
|
|
@@ -5,7 +5,7 @@ var ImpressionObserver_1 = require("./ImpressionObserver");
|
|
|
5
5
|
var murmur3_1 = require("../../utils/murmur3/murmur3");
|
|
6
6
|
var buildKey_1 = require("./buildKey");
|
|
7
7
|
function hashImpression32(impression) {
|
|
8
|
-
return (0, murmur3_1.hash)((0, buildKey_1.buildKey)(impression));
|
|
8
|
+
return (0, murmur3_1.hash)((0, buildKey_1.buildKey)(impression)).toString();
|
|
9
9
|
}
|
|
10
10
|
exports.hashImpression32 = hashImpression32;
|
|
11
11
|
var LAST_SEEN_CACHE_SIZE = 500; // cache up to 500 impression hashes
|
|
@@ -127,6 +127,9 @@ function settingsValidation(config, validationParams) {
|
|
|
127
127
|
// ensure a valid SDK mode
|
|
128
128
|
// @ts-ignore, modify readonly prop
|
|
129
129
|
withDefaults.mode = (0, mode_1.mode)(withDefaults.core.authorizationKey, withDefaults.mode);
|
|
130
|
+
if (withDefaults.sync.onlySubmitters && withDefaults.mode === constants_1.STANDALONE_MODE && !withDefaults.dataLoader) {
|
|
131
|
+
throw new Error('To use `onlySubmitters` param in standalone mode, DataLoader is required to preload data into the storage');
|
|
132
|
+
}
|
|
130
133
|
// ensure a valid Storage based on mode defined.
|
|
131
134
|
// @ts-ignore, modify readonly prop
|
|
132
135
|
if (storage)
|
|
@@ -169,9 +172,13 @@ function settingsValidation(config, validationParams) {
|
|
|
169
172
|
scheduler.pushRetryBackoffBase = fromSecondsToMillis(scheduler.pushRetryBackoffBase);
|
|
170
173
|
}
|
|
171
174
|
// validate sync enabled
|
|
172
|
-
if (withDefaults.sync.enabled !== false) {
|
|
175
|
+
if (withDefaults.sync.enabled !== false) {
|
|
173
176
|
withDefaults.sync.enabled = true;
|
|
174
177
|
}
|
|
178
|
+
// validate sync onlySubmitters
|
|
179
|
+
if (withDefaults.sync.onlySubmitters !== true) {
|
|
180
|
+
withDefaults.sync.onlySubmitters = false;
|
|
181
|
+
}
|
|
175
182
|
// validate the `splitFilters` settings and parse splits query
|
|
176
183
|
var splitFiltersValidation = (0, splitFilters_1.validateSplitFilters)(log, withDefaults.sync.splitFilters, withDefaults.mode);
|
|
177
184
|
withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
|
package/esm/sdkFactory/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { validateAndTrackApiKey } from '../utils/inputValidation/apiKey';
|
|
|
8
8
|
import { createLoggerAPI } from '../logger/sdkLogger';
|
|
9
9
|
import { NEW_FACTORY, RETRIEVE_MANAGER } from '../logger/constants';
|
|
10
10
|
import { metadataBuilder } from '../storages/metadataBuilder';
|
|
11
|
-
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
11
|
+
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../readiness/constants';
|
|
12
12
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
13
13
|
/**
|
|
14
14
|
* Modular SDK factory
|
|
@@ -22,13 +22,14 @@ export function sdkFactory(params) {
|
|
|
22
22
|
validateAndTrackApiKey(log, settings.core.authorizationKey);
|
|
23
23
|
var sdkReadinessManager = sdkReadinessManagerFactory(log, platform.EventEmitter, settings.startup.readyTimeout);
|
|
24
24
|
var readiness = sdkReadinessManager.readinessManager;
|
|
25
|
+
var matchingKey = getMatching(settings.core.key);
|
|
25
26
|
// @TODO consider passing the settings object, so that each storage access only what it needs
|
|
26
27
|
var storageFactoryParams = {
|
|
27
28
|
impressionsQueueSize: settings.scheduler.impressionsQueueSize,
|
|
28
29
|
eventsQueueSize: settings.scheduler.eventsQueueSize,
|
|
29
30
|
optimize: shouldBeOptimized(settings),
|
|
30
31
|
// ATM, only used by InLocalStorage
|
|
31
|
-
matchingKey:
|
|
32
|
+
matchingKey: matchingKey,
|
|
32
33
|
splitFiltersValidation: settings.sync.__splitFiltersValidation,
|
|
33
34
|
// ATM, only used by PluggableStorage
|
|
34
35
|
mode: settings.mode,
|
|
@@ -44,7 +45,21 @@ export function sdkFactory(params) {
|
|
|
44
45
|
log: log
|
|
45
46
|
};
|
|
46
47
|
var storage = storageFactory(storageFactoryParams);
|
|
47
|
-
// @TODO
|
|
48
|
+
// @TODO dataLoader requires validation
|
|
49
|
+
if (settings.dataLoader) {
|
|
50
|
+
settings.dataLoader(storage, matchingKey);
|
|
51
|
+
Promise.resolve(storage.splits.checkCache()).then(function (cacheReady) {
|
|
52
|
+
if (cacheReady) {
|
|
53
|
+
if (settings.sync.onlySubmitters) { // emit SDK_READY to not timeout when not synchronizing splits & segments
|
|
54
|
+
readiness.splits.emit(SDK_SPLITS_ARRIVED);
|
|
55
|
+
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
56
|
+
}
|
|
57
|
+
else { // emit SDK_READY_FROM_CACHE
|
|
58
|
+
readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
48
63
|
var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage });
|
|
49
64
|
// trackers
|
|
50
65
|
var observer = impressionsObserverFactory && impressionsObserverFactory();
|
|
@@ -76,5 +91,8 @@ export function sdkFactory(params) {
|
|
|
76
91
|
// Logger wrapper API
|
|
77
92
|
Logger: createLoggerAPI(settings.log),
|
|
78
93
|
settings: settings,
|
|
94
|
+
// @TODO remove
|
|
95
|
+
__storage: storage,
|
|
96
|
+
__ctx: ctx
|
|
79
97
|
}, extraProps && extraProps(ctx));
|
|
80
98
|
}
|
|
@@ -30,7 +30,7 @@ var AbstractSplitsCacheSync = /** @class */ (function () {
|
|
|
30
30
|
* It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE.
|
|
31
31
|
*/
|
|
32
32
|
AbstractSplitsCacheSync.prototype.checkCache = function () {
|
|
33
|
-
return
|
|
33
|
+
return this.getChangeNumber() > -1;
|
|
34
34
|
};
|
|
35
35
|
/**
|
|
36
36
|
* Kill `name` split and set `defaultTreatment` and `changeNumber`.
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../utils/constants/browser';
|
|
2
2
|
/**
|
|
3
|
-
* Factory of
|
|
3
|
+
* Factory of storage loader
|
|
4
4
|
*
|
|
5
5
|
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
6
6
|
* and extended with a `mySegmentsData` property.
|
|
7
7
|
* @returns function to preload the storage
|
|
8
8
|
*/
|
|
9
|
-
export function
|
|
9
|
+
export function DataLoaderFactory(preloadedData) {
|
|
10
10
|
/**
|
|
11
11
|
* Storage-agnostic adaptation of `loadDataIntoLocalStorage` function
|
|
12
12
|
* (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
|
|
13
13
|
*
|
|
14
14
|
* @param storage object containing `splits` and `segments` cache (client-side variant)
|
|
15
|
-
* @param
|
|
15
|
+
* @param userKey user key (matching key) of the provided MySegmentsCache
|
|
16
16
|
*
|
|
17
|
-
* @TODO extend to support SegmentsCache (server-side variant) by making `userId` optional and adding the corresponding logic.
|
|
18
17
|
* @TODO extend to load data on shared mySegments storages. Be specific when emitting SDK_READY_FROM_CACHE on shared clients. Maybe the serializer should provide the `useSegments` flag.
|
|
18
|
+
* @TODO add logs, and input validation in this module, in favor of size reduction.
|
|
19
|
+
* @TODO unit tests
|
|
19
20
|
*/
|
|
20
|
-
return function loadData(storage,
|
|
21
|
+
return function loadData(storage, userKey) {
|
|
21
22
|
// Do not load data if current preloadedData is empty
|
|
22
23
|
if (Object.keys(preloadedData).length === 0)
|
|
23
24
|
return;
|
|
@@ -33,15 +34,22 @@ export function dataLoaderFactory(preloadedData) {
|
|
|
33
34
|
storage.splits.setChangeNumber(since);
|
|
34
35
|
// splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
|
|
35
36
|
storage.splits.addSplits(Object.keys(splitsData).map(function (splitName) { return [splitName, splitsData[splitName]]; }));
|
|
36
|
-
// add mySegments data
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
if (userKey) { // add mySegments data (client-side)
|
|
38
|
+
var mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userKey];
|
|
39
|
+
if (!mySegmentsData) {
|
|
40
|
+
// segmentsData in an object where the property is the segment name and the pertaining value is a stringified object that contains the `added` array of userIds
|
|
41
|
+
mySegmentsData = Object.keys(segmentsData).filter(function (segmentName) {
|
|
42
|
+
var userKeys = segmentsData[segmentName];
|
|
43
|
+
return userKeys.indexOf(userKey) > -1;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
storage.segments.resetSegments(mySegmentsData);
|
|
47
|
+
}
|
|
48
|
+
else { // add segments data (server-side)
|
|
49
|
+
Object.keys(segmentsData).filter(function (segmentName) {
|
|
50
|
+
var userKeys = segmentsData[segmentName];
|
|
51
|
+
storage.segments.addToSegment(segmentName, userKeys);
|
|
43
52
|
});
|
|
44
53
|
}
|
|
45
|
-
storage.segments.resetSegments(mySegmentsData);
|
|
46
54
|
};
|
|
47
55
|
}
|
|
@@ -5,6 +5,7 @@ import { EventsCacheInMemory } from './EventsCacheInMemory';
|
|
|
5
5
|
import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
|
|
6
6
|
import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
|
|
7
7
|
import { TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
8
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
8
9
|
/**
|
|
9
10
|
* InMemory storage factory for standalone server-side SplitFactory
|
|
10
11
|
*
|
|
@@ -25,7 +26,20 @@ export function InMemoryStorageFactory(params) {
|
|
|
25
26
|
this.impressions.clear();
|
|
26
27
|
this.impressionCounts && this.impressionCounts.clear();
|
|
27
28
|
this.events.clear();
|
|
28
|
-
}
|
|
29
|
+
},
|
|
30
|
+
// @ts-ignore, private method, for POC
|
|
31
|
+
getSnapshot: function () {
|
|
32
|
+
var _this = this;
|
|
33
|
+
return {
|
|
34
|
+
lastUpdated: Date.now(),
|
|
35
|
+
since: this.splits.changeNumber,
|
|
36
|
+
splitsData: this.splits.splitsCache,
|
|
37
|
+
segmentsData: Object.keys(this.segments.segmentCache).reduce(function (prev, cur) {
|
|
38
|
+
prev[cur] = setToArray(_this.segments.segmentCache[cur]);
|
|
39
|
+
return prev;
|
|
40
|
+
}, {})
|
|
41
|
+
};
|
|
42
|
+
},
|
|
29
43
|
};
|
|
30
44
|
}
|
|
31
45
|
InMemoryStorageFactory.type = STORAGE_MEMORY;
|
|
@@ -26,6 +26,18 @@ export function InMemoryStorageCSFactory(params) {
|
|
|
26
26
|
this.impressionCounts && this.impressionCounts.clear();
|
|
27
27
|
this.events.clear();
|
|
28
28
|
},
|
|
29
|
+
// @ts-ignore, private method, for POC
|
|
30
|
+
getSnapshot: function () {
|
|
31
|
+
var _a;
|
|
32
|
+
return {
|
|
33
|
+
lastUpdated: Date.now(),
|
|
34
|
+
since: this.splits.changeNumber,
|
|
35
|
+
splitsData: this.splits.splitsCache,
|
|
36
|
+
mySegmentsData: (_a = {},
|
|
37
|
+
_a[params.matchingKey] = Object.keys(this.segments.segmentCache),
|
|
38
|
+
_a)
|
|
39
|
+
};
|
|
40
|
+
},
|
|
29
41
|
// When using shared instanciation with MEMORY we reuse everything but segments (they are unique per key)
|
|
30
42
|
shared: function () {
|
|
31
43
|
return {
|
|
@@ -16,9 +16,9 @@ export function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFacto
|
|
|
16
16
|
* SyncManager factory for modular SDK
|
|
17
17
|
*/
|
|
18
18
|
return function (params) {
|
|
19
|
-
var settings = params.settings, _a = params.settings, log = _a.log, streamingEnabled = _a.streamingEnabled,
|
|
19
|
+
var settings = params.settings, _a = params.settings, log = _a.log, streamingEnabled = _a.streamingEnabled, _b = _a.sync, syncEnabled = _b.enabled, onlySubmitters = _b.onlySubmitters, telemetryTracker = params.telemetryTracker;
|
|
20
20
|
/** Polling Manager */
|
|
21
|
-
var pollingManager = pollingManagerFactory && pollingManagerFactory(params);
|
|
21
|
+
var pollingManager = onlySubmitters ? undefined : pollingManagerFactory && pollingManagerFactory(params);
|
|
22
22
|
/** Push Manager */
|
|
23
23
|
var pushManager = syncEnabled && streamingEnabled && pollingManager && pushManagerFactory ?
|
|
24
24
|
pushManagerFactory(params, pollingManager) :
|
|
@@ -2,7 +2,7 @@ import { ImpressionObserver } from './ImpressionObserver';
|
|
|
2
2
|
import { hash } from '../../utils/murmur3/murmur3';
|
|
3
3
|
import { buildKey } from './buildKey';
|
|
4
4
|
export function hashImpression32(impression) {
|
|
5
|
-
return hash(buildKey(impression));
|
|
5
|
+
return hash(buildKey(impression)).toString();
|
|
6
6
|
}
|
|
7
7
|
var LAST_SEEN_CACHE_SIZE = 500; // cache up to 500 impression hashes
|
|
8
8
|
export function impressionObserverCSFactory() {
|
|
@@ -124,6 +124,9 @@ export function settingsValidation(config, validationParams) {
|
|
|
124
124
|
// ensure a valid SDK mode
|
|
125
125
|
// @ts-ignore, modify readonly prop
|
|
126
126
|
withDefaults.mode = mode(withDefaults.core.authorizationKey, withDefaults.mode);
|
|
127
|
+
if (withDefaults.sync.onlySubmitters && withDefaults.mode === STANDALONE_MODE && !withDefaults.dataLoader) {
|
|
128
|
+
throw new Error('To use `onlySubmitters` param in standalone mode, DataLoader is required to preload data into the storage');
|
|
129
|
+
}
|
|
127
130
|
// ensure a valid Storage based on mode defined.
|
|
128
131
|
// @ts-ignore, modify readonly prop
|
|
129
132
|
if (storage)
|
|
@@ -166,9 +169,13 @@ export function settingsValidation(config, validationParams) {
|
|
|
166
169
|
scheduler.pushRetryBackoffBase = fromSecondsToMillis(scheduler.pushRetryBackoffBase);
|
|
167
170
|
}
|
|
168
171
|
// validate sync enabled
|
|
169
|
-
if (withDefaults.sync.enabled !== false) {
|
|
172
|
+
if (withDefaults.sync.enabled !== false) {
|
|
170
173
|
withDefaults.sync.enabled = true;
|
|
171
174
|
}
|
|
175
|
+
// validate sync onlySubmitters
|
|
176
|
+
if (withDefaults.sync.onlySubmitters !== true) {
|
|
177
|
+
withDefaults.sync.onlySubmitters = false;
|
|
178
|
+
}
|
|
172
179
|
// validate the `splitFilters` settings and parse splits query
|
|
173
180
|
var splitFiltersValidation = validateSplitFilters(log, withDefaults.sync.splitFilters, withDefaults.mode);
|
|
174
181
|
withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
|
package/package.json
CHANGED
package/src/sdkFactory/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { sdkReadinessManagerFactory } from '../readiness/sdkReadinessManager';
|
|
|
3
3
|
import { impressionsTrackerFactory } from '../trackers/impressionsTracker';
|
|
4
4
|
import { eventTrackerFactory } from '../trackers/eventTracker';
|
|
5
5
|
import { telemetryTrackerFactory } from '../trackers/telemetryTracker';
|
|
6
|
-
import { IStorageFactoryParams } from '../storages/types';
|
|
6
|
+
import { IStorageFactoryParams, IStorageSync } from '../storages/types';
|
|
7
7
|
import { SplitIO } from '../types';
|
|
8
8
|
import { getMatching } from '../utils/key';
|
|
9
9
|
import { shouldBeOptimized } from '../trackers/impressionObserver/utils';
|
|
@@ -11,7 +11,7 @@ import { validateAndTrackApiKey } from '../utils/inputValidation/apiKey';
|
|
|
11
11
|
import { createLoggerAPI } from '../logger/sdkLogger';
|
|
12
12
|
import { NEW_FACTORY, RETRIEVE_MANAGER } from '../logger/constants';
|
|
13
13
|
import { metadataBuilder } from '../storages/metadataBuilder';
|
|
14
|
-
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
14
|
+
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../readiness/constants';
|
|
15
15
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -32,6 +32,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
32
32
|
|
|
33
33
|
const sdkReadinessManager = sdkReadinessManagerFactory(log, platform.EventEmitter, settings.startup.readyTimeout);
|
|
34
34
|
const readiness = sdkReadinessManager.readinessManager;
|
|
35
|
+
const matchingKey = getMatching(settings.core.key);
|
|
35
36
|
|
|
36
37
|
// @TODO consider passing the settings object, so that each storage access only what it needs
|
|
37
38
|
const storageFactoryParams: IStorageFactoryParams = {
|
|
@@ -40,7 +41,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
40
41
|
optimize: shouldBeOptimized(settings),
|
|
41
42
|
|
|
42
43
|
// ATM, only used by InLocalStorage
|
|
43
|
-
matchingKey
|
|
44
|
+
matchingKey,
|
|
44
45
|
splitFiltersValidation: settings.sync.__splitFiltersValidation,
|
|
45
46
|
|
|
46
47
|
// ATM, only used by PluggableStorage
|
|
@@ -58,7 +59,21 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
58
59
|
};
|
|
59
60
|
|
|
60
61
|
const storage = storageFactory(storageFactoryParams);
|
|
61
|
-
|
|
62
|
+
|
|
63
|
+
// @TODO dataLoader requires validation
|
|
64
|
+
if (settings.dataLoader) {
|
|
65
|
+
settings.dataLoader(storage as IStorageSync, matchingKey);
|
|
66
|
+
Promise.resolve(storage.splits.checkCache()).then(cacheReady => {
|
|
67
|
+
if (cacheReady) {
|
|
68
|
+
if (settings.sync.onlySubmitters) { // emit SDK_READY to not timeout when not synchronizing splits & segments
|
|
69
|
+
readiness.splits.emit(SDK_SPLITS_ARRIVED);
|
|
70
|
+
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
71
|
+
} else { // emit SDK_READY_FROM_CACHE
|
|
72
|
+
readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
62
77
|
|
|
63
78
|
const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage });
|
|
64
79
|
|
|
@@ -103,5 +118,9 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
103
118
|
Logger: createLoggerAPI(settings.log),
|
|
104
119
|
|
|
105
120
|
settings,
|
|
121
|
+
|
|
122
|
+
// @TODO remove
|
|
123
|
+
__storage: storage,
|
|
124
|
+
__ctx: ctx
|
|
106
125
|
}, extraProps && extraProps(ctx));
|
|
107
126
|
}
|
|
@@ -50,7 +50,7 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
|
50
50
|
* It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE.
|
|
51
51
|
*/
|
|
52
52
|
checkCache(): boolean {
|
|
53
|
-
return
|
|
53
|
+
return this.getChangeNumber() > -1;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
@@ -3,25 +3,26 @@ import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../utils/constants/browser';
|
|
|
3
3
|
import { DataLoader, ISegmentsCacheSync, ISplitsCacheSync } from './types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Factory of
|
|
6
|
+
* Factory of storage loader
|
|
7
7
|
*
|
|
8
8
|
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
9
9
|
* and extended with a `mySegmentsData` property.
|
|
10
10
|
* @returns function to preload the storage
|
|
11
11
|
*/
|
|
12
|
-
export function
|
|
12
|
+
export function DataLoaderFactory(preloadedData: SplitIO.PreloadedData): DataLoader {
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Storage-agnostic adaptation of `loadDataIntoLocalStorage` function
|
|
16
16
|
* (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
|
|
17
17
|
*
|
|
18
18
|
* @param storage object containing `splits` and `segments` cache (client-side variant)
|
|
19
|
-
* @param
|
|
19
|
+
* @param userKey user key (matching key) of the provided MySegmentsCache
|
|
20
20
|
*
|
|
21
|
-
* @TODO extend to support SegmentsCache (server-side variant) by making `userId` optional and adding the corresponding logic.
|
|
22
21
|
* @TODO extend to load data on shared mySegments storages. Be specific when emitting SDK_READY_FROM_CACHE on shared clients. Maybe the serializer should provide the `useSegments` flag.
|
|
22
|
+
* @TODO add logs, and input validation in this module, in favor of size reduction.
|
|
23
|
+
* @TODO unit tests
|
|
23
24
|
*/
|
|
24
|
-
return function loadData(storage: { splits: ISplitsCacheSync, segments: ISegmentsCacheSync },
|
|
25
|
+
return function loadData(storage: { splits: ISplitsCacheSync, segments: ISegmentsCacheSync }, userKey?: string) {
|
|
25
26
|
// Do not load data if current preloadedData is empty
|
|
26
27
|
if (Object.keys(preloadedData).length === 0) return;
|
|
27
28
|
|
|
@@ -41,15 +42,21 @@ export function dataLoaderFactory(preloadedData: SplitIO.PreloadedData): DataLoa
|
|
|
41
42
|
// splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
|
|
42
43
|
storage.splits.addSplits(Object.keys(splitsData).map(splitName => [splitName, splitsData[splitName]]));
|
|
43
44
|
|
|
44
|
-
// add mySegments data
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
if (userKey) { // add mySegments data (client-side)
|
|
46
|
+
let mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userKey];
|
|
47
|
+
if (!mySegmentsData) {
|
|
48
|
+
// segmentsData in an object where the property is the segment name and the pertaining value is a stringified object that contains the `added` array of userIds
|
|
49
|
+
mySegmentsData = Object.keys(segmentsData).filter(segmentName => {
|
|
50
|
+
const userKeys = segmentsData[segmentName];
|
|
51
|
+
return userKeys.indexOf(userKey) > -1;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
storage.segments.resetSegments(mySegmentsData);
|
|
55
|
+
} else { // add segments data (server-side)
|
|
56
|
+
Object.keys(segmentsData).filter(segmentName => {
|
|
57
|
+
const userKeys = segmentsData[segmentName];
|
|
58
|
+
storage.segments.addToSegment(segmentName, userKeys);
|
|
51
59
|
});
|
|
52
60
|
}
|
|
53
|
-
storage.segments.resetSegments(mySegmentsData);
|
|
54
61
|
};
|
|
55
62
|
}
|
|
@@ -6,6 +6,8 @@ import { IStorageFactoryParams, IStorageSync } from '../types';
|
|
|
6
6
|
import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
|
|
7
7
|
import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
|
|
8
8
|
import { TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
9
|
+
import { SplitIO } from '../../types';
|
|
10
|
+
import { setToArray, ISet } from '../../utils/lang/sets';
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* InMemory storage factory for standalone server-side SplitFactory
|
|
@@ -29,7 +31,20 @@ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageS
|
|
|
29
31
|
this.impressions.clear();
|
|
30
32
|
this.impressionCounts && this.impressionCounts.clear();
|
|
31
33
|
this.events.clear();
|
|
32
|
-
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
// @ts-ignore, private method, for POC
|
|
37
|
+
getSnapshot(): SplitIO.PreloadedData {
|
|
38
|
+
return {
|
|
39
|
+
lastUpdated: Date.now(), // @ts-ignore accessing private prop
|
|
40
|
+
since: this.splits.changeNumber, // @ts-ignore accessing private prop
|
|
41
|
+
splitsData: this.splits.splitsCache, // @ts-ignore accessing private prop
|
|
42
|
+
segmentsData: Object.keys(this.segments.segmentCache).reduce((prev, cur) => { // @ts-ignore accessing private prop
|
|
43
|
+
prev[cur] = setToArray(this.segments.segmentCache[cur] as ISet<string>);
|
|
44
|
+
return prev;
|
|
45
|
+
}, {})
|
|
46
|
+
};
|
|
47
|
+
},
|
|
33
48
|
};
|
|
34
49
|
}
|
|
35
50
|
|
|
@@ -6,6 +6,7 @@ import { IStorageSync, IStorageFactoryParams } from '../types';
|
|
|
6
6
|
import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
|
|
7
7
|
import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
|
|
8
8
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
9
|
+
import { SplitIO } from '../../types';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* InMemory storage factory for standalone client-side SplitFactory
|
|
@@ -31,6 +32,18 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
31
32
|
this.events.clear();
|
|
32
33
|
},
|
|
33
34
|
|
|
35
|
+
// @ts-ignore, private method, for POC
|
|
36
|
+
getSnapshot(): SplitIO.PreloadedData {
|
|
37
|
+
return {
|
|
38
|
+
lastUpdated: Date.now(), // @ts-ignore accessing private prop
|
|
39
|
+
since: this.splits.changeNumber, // @ts-ignore accessing private prop
|
|
40
|
+
splitsData: this.splits.splitsCache,
|
|
41
|
+
mySegmentsData: { // @ts-ignore accessing private prop
|
|
42
|
+
[params.matchingKey as string]: Object.keys(this.segments.segmentCache)
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
|
|
34
47
|
// When using shared instanciation with MEMORY we reuse everything but segments (they are unique per key)
|
|
35
48
|
shared() {
|
|
36
49
|
return {
|
|
@@ -28,10 +28,10 @@ export function syncManagerOnlineFactory(
|
|
|
28
28
|
*/
|
|
29
29
|
return function (params: ISdkFactoryContextSync): ISyncManagerCS {
|
|
30
30
|
|
|
31
|
-
const { settings, settings: { log, streamingEnabled, sync: { enabled: syncEnabled } }, telemetryTracker } = params;
|
|
31
|
+
const { settings, settings: { log, streamingEnabled, sync: { enabled: syncEnabled, onlySubmitters } }, telemetryTracker } = params;
|
|
32
32
|
|
|
33
33
|
/** Polling Manager */
|
|
34
|
-
const pollingManager = pollingManagerFactory && pollingManagerFactory(params);
|
|
34
|
+
const pollingManager = onlySubmitters ? undefined : pollingManagerFactory && pollingManagerFactory(params);
|
|
35
35
|
|
|
36
36
|
/** Push Manager */
|
|
37
37
|
const pushManager = syncEnabled && streamingEnabled && pollingManager && pushManagerFactory ?
|
|
@@ -4,7 +4,7 @@ import { buildKey } from './buildKey';
|
|
|
4
4
|
import { ImpressionDTO } from '../../types';
|
|
5
5
|
|
|
6
6
|
export function hashImpression32(impression: ImpressionDTO) {
|
|
7
|
-
return hash(buildKey(impression));
|
|
7
|
+
return hash(buildKey(impression)).toString();
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
const LAST_SEEN_CACHE_SIZE = 500; // cache up to 500 impression hashes
|
package/src/types.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { ILogger } from './logger/types';
|
|
|
4
4
|
import { ISdkFactoryContext } from './sdkFactory/types';
|
|
5
5
|
/* eslint-disable no-use-before-define */
|
|
6
6
|
|
|
7
|
-
import { IStorageFactoryParams, IStorageSync, IStorageAsync, IStorageSyncFactory, IStorageAsyncFactory } from './storages/types';
|
|
7
|
+
import { IStorageFactoryParams, IStorageSync, IStorageAsync, IStorageSyncFactory, IStorageAsyncFactory, DataLoader } from './storages/types';
|
|
8
8
|
import { ISyncManagerCS } from './sync/types';
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -98,6 +98,7 @@ export interface ISettings {
|
|
|
98
98
|
eventsFirstPushWindow: number
|
|
99
99
|
},
|
|
100
100
|
readonly storage: IStorageSyncFactory | IStorageAsyncFactory,
|
|
101
|
+
readonly dataLoader?: DataLoader,
|
|
101
102
|
readonly integrations: Array<{
|
|
102
103
|
readonly type: string,
|
|
103
104
|
(params: IIntegrationFactoryParams): IIntegration | void
|
|
@@ -118,7 +119,8 @@ export interface ISettings {
|
|
|
118
119
|
impressionsMode: SplitIO.ImpressionsMode,
|
|
119
120
|
__splitFiltersValidation: ISplitFiltersValidation,
|
|
120
121
|
localhostMode?: SplitIO.LocalhostFactory,
|
|
121
|
-
enabled: boolean
|
|
122
|
+
enabled: boolean,
|
|
123
|
+
onlySubmitters: boolean
|
|
122
124
|
},
|
|
123
125
|
readonly runtime: {
|
|
124
126
|
ip: string | false
|
|
@@ -752,7 +754,7 @@ export namespace SplitIO {
|
|
|
752
754
|
* This property is ignored if `mySegmentsData` was provided.
|
|
753
755
|
*/
|
|
754
756
|
segmentsData?: {
|
|
755
|
-
[segmentName: string]: string
|
|
757
|
+
[segmentName: string]: string[]
|
|
756
758
|
},
|
|
757
759
|
}
|
|
758
760
|
/**
|
|
@@ -147,6 +147,9 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
|
|
|
147
147
|
// ensure a valid SDK mode
|
|
148
148
|
// @ts-ignore, modify readonly prop
|
|
149
149
|
withDefaults.mode = mode(withDefaults.core.authorizationKey, withDefaults.mode);
|
|
150
|
+
if (withDefaults.sync.onlySubmitters && withDefaults.mode === STANDALONE_MODE && !withDefaults.dataLoader) {
|
|
151
|
+
throw new Error('To use `onlySubmitters` param in standalone mode, DataLoader is required to preload data into the storage');
|
|
152
|
+
}
|
|
150
153
|
|
|
151
154
|
// ensure a valid Storage based on mode defined.
|
|
152
155
|
// @ts-ignore, modify readonly prop
|
|
@@ -193,10 +196,15 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
|
|
|
193
196
|
}
|
|
194
197
|
|
|
195
198
|
// validate sync enabled
|
|
196
|
-
if (withDefaults.sync.enabled !== false) {
|
|
199
|
+
if (withDefaults.sync.enabled !== false) {
|
|
197
200
|
withDefaults.sync.enabled = true;
|
|
198
201
|
}
|
|
199
202
|
|
|
203
|
+
// validate sync onlySubmitters
|
|
204
|
+
if (withDefaults.sync.onlySubmitters !== true) {
|
|
205
|
+
withDefaults.sync.onlySubmitters = false;
|
|
206
|
+
}
|
|
207
|
+
|
|
200
208
|
// validate the `splitFilters` settings and parse splits query
|
|
201
209
|
const splitFiltersValidation = validateSplitFilters(log, withDefaults.sync.splitFilters, withDefaults.mode);
|
|
202
210
|
withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { SplitIO } from '../types';
|
|
2
2
|
import { DataLoader } from './types';
|
|
3
3
|
/**
|
|
4
|
-
* Factory of
|
|
4
|
+
* Factory of storage loader
|
|
5
5
|
*
|
|
6
6
|
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
7
7
|
* and extended with a `mySegmentsData` property.
|
|
8
8
|
* @returns function to preload the storage
|
|
9
9
|
*/
|
|
10
|
-
export declare function
|
|
10
|
+
export declare function DataLoaderFactory(preloadedData: SplitIO.PreloadedData): DataLoader;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ImpressionObserver } from './ImpressionObserver';
|
|
2
2
|
import { ImpressionDTO } from '../../types';
|
|
3
|
-
export declare function hashImpression32(impression: ImpressionDTO):
|
|
4
|
-
export declare function impressionObserverCSFactory(): ImpressionObserver<
|
|
3
|
+
export declare function hashImpression32(impression: ImpressionDTO): string;
|
|
4
|
+
export declare function impressionObserverCSFactory(): ImpressionObserver<string>;
|
package/types/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { ISplitFiltersValidation } from './dtos/types';
|
|
|
2
2
|
import { IIntegration, IIntegrationFactoryParams } from './integrations/types';
|
|
3
3
|
import { ILogger } from './logger/types';
|
|
4
4
|
import { ISdkFactoryContext } from './sdkFactory/types';
|
|
5
|
-
import { IStorageFactoryParams, IStorageSync, IStorageAsync, IStorageSyncFactory, IStorageAsyncFactory } from './storages/types';
|
|
5
|
+
import { IStorageFactoryParams, IStorageSync, IStorageAsync, IStorageSyncFactory, IStorageAsyncFactory, DataLoader } from './storages/types';
|
|
6
6
|
import { ISyncManagerCS } from './sync/types';
|
|
7
7
|
/**
|
|
8
8
|
* Reduced version of NodeJS.EventEmitter interface with the minimal methods used by the SDK
|
|
@@ -92,6 +92,7 @@ export interface ISettings {
|
|
|
92
92
|
eventsFirstPushWindow: number;
|
|
93
93
|
};
|
|
94
94
|
readonly storage: IStorageSyncFactory | IStorageAsyncFactory;
|
|
95
|
+
readonly dataLoader?: DataLoader;
|
|
95
96
|
readonly integrations: Array<{
|
|
96
97
|
readonly type: string;
|
|
97
98
|
(params: IIntegrationFactoryParams): IIntegration | void;
|
|
@@ -113,6 +114,7 @@ export interface ISettings {
|
|
|
113
114
|
__splitFiltersValidation: ISplitFiltersValidation;
|
|
114
115
|
localhostMode?: SplitIO.LocalhostFactory;
|
|
115
116
|
enabled: boolean;
|
|
117
|
+
onlySubmitters: boolean;
|
|
116
118
|
};
|
|
117
119
|
readonly runtime: {
|
|
118
120
|
ip: string | false;
|
|
@@ -749,7 +751,7 @@ export declare namespace SplitIO {
|
|
|
749
751
|
* This property is ignored if `mySegmentsData` was provided.
|
|
750
752
|
*/
|
|
751
753
|
segmentsData?: {
|
|
752
|
-
[segmentName: string]: string;
|
|
754
|
+
[segmentName: string]: string[];
|
|
753
755
|
};
|
|
754
756
|
}
|
|
755
757
|
/**
|