@splitsoftware/splitio-commons 1.9.2-rc.1 → 1.9.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 -0
- package/cjs/evaluator/index.js +1 -18
- package/cjs/logger/constants.js +2 -7
- package/cjs/logger/messages/error.js +0 -2
- package/cjs/logger/messages/info.js +1 -1
- package/cjs/logger/messages/warn.js +1 -4
- package/cjs/sdkClient/client.js +0 -33
- package/cjs/sdkClient/clientAttributesDecoration.js +0 -20
- package/cjs/sdkClient/clientCS.js +4 -5
- package/cjs/sdkClient/clientInputValidation.js +3 -52
- package/cjs/sdkClient/sdkClientMethodCS.js +2 -2
- package/cjs/sdkClient/sdkClientMethodCSWithTT.js +1 -1
- package/cjs/sdkManager/index.js +1 -2
- package/cjs/services/splitApi.js +1 -7
- package/cjs/storages/KeyBuilder.js +0 -3
- package/cjs/storages/KeyBuilderSS.js +0 -4
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +27 -63
- package/cjs/storages/inLocalStorage/index.js +2 -2
- package/cjs/storages/inMemory/InMemoryStorage.js +2 -2
- package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -3
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +2 -47
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +0 -11
- package/cjs/storages/pluggable/SplitsCachePluggable.js +0 -11
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +4 -24
- package/cjs/sync/submitters/telemetrySubmitter.js +1 -15
- package/cjs/utils/constants/index.js +2 -6
- package/cjs/utils/lang/sets.js +1 -9
- package/cjs/utils/settingsValidation/index.js +1 -1
- package/cjs/utils/settingsValidation/splitFilters.js +2 -72
- package/esm/evaluator/index.js +0 -16
- package/esm/logger/constants.js +0 -5
- package/esm/logger/messages/error.js +0 -2
- package/esm/logger/messages/info.js +1 -1
- package/esm/logger/messages/warn.js +1 -4
- package/esm/sdkClient/client.js +2 -35
- package/esm/sdkClient/clientAttributesDecoration.js +0 -20
- package/esm/sdkClient/clientCS.js +4 -5
- package/esm/sdkClient/clientInputValidation.js +3 -52
- package/esm/sdkClient/sdkClientMethodCS.js +2 -2
- package/esm/sdkClient/sdkClientMethodCSWithTT.js +1 -1
- package/esm/sdkManager/index.js +1 -2
- package/esm/services/splitApi.js +1 -7
- package/esm/storages/KeyBuilder.js +0 -3
- package/esm/storages/KeyBuilderSS.js +0 -4
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +27 -63
- package/esm/storages/inLocalStorage/index.js +2 -2
- package/esm/storages/inMemory/InMemoryStorage.js +2 -2
- package/esm/storages/inMemory/InMemoryStorageCS.js +3 -3
- package/esm/storages/inMemory/SplitsCacheInMemory.js +2 -47
- package/esm/storages/inRedis/SplitsCacheInRedis.js +0 -11
- package/esm/storages/pluggable/SplitsCachePluggable.js +0 -11
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/esm/sync/polling/updaters/splitChangesUpdater.js +4 -24
- package/esm/sync/submitters/telemetrySubmitter.js +1 -15
- package/esm/utils/constants/index.js +0 -4
- package/esm/utils/lang/sets.js +0 -7
- package/esm/utils/settingsValidation/index.js +1 -1
- package/esm/utils/settingsValidation/splitFilters.js +2 -71
- package/package.json +1 -1
- package/src/dtos/types.ts +2 -3
- package/src/evaluator/index.ts +0 -24
- package/src/logger/constants.ts +0 -5
- package/src/logger/messages/error.ts +0 -2
- package/src/logger/messages/info.ts +1 -1
- package/src/logger/messages/warn.ts +1 -4
- package/src/sdkClient/client.ts +2 -42
- package/src/sdkClient/clientAttributesDecoration.ts +0 -24
- package/src/sdkClient/clientCS.ts +4 -5
- package/src/sdkClient/clientInputValidation.ts +4 -56
- package/src/sdkClient/sdkClientMethodCS.ts +2 -2
- package/src/sdkClient/sdkClientMethodCSWithTT.ts +1 -1
- package/src/sdkManager/index.ts +1 -2
- package/src/services/splitApi.ts +1 -6
- package/src/storages/AbstractSegmentsCacheSync.ts +1 -0
- package/src/storages/AbstractSplitsCacheAsync.ts +0 -2
- package/src/storages/AbstractSplitsCacheSync.ts +0 -3
- package/src/storages/KeyBuilder.ts +0 -4
- package/src/storages/KeyBuilderSS.ts +0 -4
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +28 -74
- package/src/storages/inLocalStorage/index.ts +2 -2
- package/src/storages/inMemory/InMemoryStorage.ts +2 -2
- package/src/storages/inMemory/InMemoryStorageCS.ts +3 -3
- package/src/storages/inMemory/SplitsCacheInMemory.ts +1 -50
- package/src/storages/inRedis/SplitsCacheInRedis.ts +0 -12
- package/src/storages/pluggable/SplitsCachePluggable.ts +0 -12
- package/src/storages/types.ts +3 -7
- package/src/sync/polling/syncTasks/splitsSyncTask.ts +0 -1
- package/src/sync/polling/updaters/splitChangesUpdater.ts +4 -27
- package/src/sync/submitters/telemetrySubmitter.ts +2 -19
- package/src/sync/submitters/types.ts +1 -7
- package/src/types.ts +1 -118
- package/src/utils/constants/index.ts +0 -4
- package/src/utils/lang/sets.ts +0 -8
- package/src/utils/settingsValidation/index.ts +1 -1
- package/src/utils/settingsValidation/splitFilters.ts +2 -77
- package/types/dtos/types.d.ts +0 -1
- package/types/evaluator/index.d.ts +0 -1
- package/types/logger/constants.d.ts +0 -5
- package/types/sdkClient/clientAttributesDecoration.d.ts +0 -4
- package/types/sdkClient/identity.d.ts +6 -0
- package/types/sdkClient/sdkClientMethodCS.d.ts +2 -2
- package/types/sdkClient/sdkClientMethodCSWithTT.d.ts +1 -1
- package/types/storages/AbstractSegmentsCacheSync.d.ts +1 -0
- package/types/storages/AbstractSplitsCacheAsync.d.ts +0 -2
- package/types/storages/AbstractSplitsCacheSync.d.ts +0 -2
- package/types/storages/KeyBuilder.d.ts +0 -1
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +1 -6
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +1 -9
- package/types/storages/inRedis/SplitsCacheInRedis.d.ts +0 -8
- package/types/storages/pluggable/SplitsCachePluggable.d.ts +0 -8
- package/types/storages/types.d.ts +0 -4
- package/types/sync/polling/updaters/splitChangesUpdater.d.ts +3 -3
- package/types/sync/submitters/types.d.ts +1 -7
- package/types/types.d.ts +1 -118
- package/types/utils/constants/index.d.ts +0 -4
- package/types/utils/inputValidation/sdkKey.d.ts +7 -0
- package/types/utils/lang/sets.d.ts +0 -1
- package/types/utils/settingsValidation/splitFilters.d.ts +0 -1
- package/types/myLogger.d.ts +0 -5
- package/types/sdkClient/types.d.ts +0 -18
- package/types/storages/inMemory/CountsCacheInMemory.d.ts +0 -20
- package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +0 -20
- package/types/storages/inRedis/CountsCacheInRedis.d.ts +0 -9
- package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +0 -9
- package/types/storages/metadataBuilder.d.ts +0 -3
- package/types/sync/offline/LocalhostFromFile.d.ts +0 -2
- package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +0 -2
- package/types/sync/offline/updaters/splitChangesUpdater.d.ts +0 -0
- package/types/sync/submitters/eventsSyncTask.d.ts +0 -8
- package/types/sync/submitters/impressionCountsSubmitterInRedis.d.ts +0 -5
- package/types/sync/submitters/impressionCountsSyncTask.d.ts +0 -13
- package/types/sync/submitters/impressionsSyncTask.d.ts +0 -14
- package/types/sync/submitters/metricsSyncTask.d.ts +0 -12
- package/types/sync/submitters/submitterSyncTask.d.ts +0 -10
- package/types/sync/submitters/uniqueKeysSubmitterInRedis.d.ts +0 -5
- package/types/sync/syncTaskComposite.d.ts +0 -5
- package/types/trackers/filter/bloomFilter.d.ts +0 -10
- package/types/trackers/filter/dictionaryFilter.d.ts +0 -8
- package/types/trackers/filter/types.d.ts +0 -5
- package/types/utils/timeTracker/index.d.ts +0 -70
- /package/types/storages/inMemory/{uniqueKeysCacheInMemory.d.ts → UniqueKeysCacheInMemory.d.ts} +0 -0
- /package/types/storages/inMemory/{uniqueKeysCacheInMemoryCS.d.ts → UniqueKeysCacheInMemoryCS.d.ts} +0 -0
- /package/types/storages/inRedis/{uniqueKeysCacheInRedis.d.ts → UniqueKeysCacheInRedis.d.ts} +0 -0
|
@@ -4,7 +4,6 @@ import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
|
|
|
4
4
|
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
5
5
|
import { ILogger } from '../../logger/types';
|
|
6
6
|
import { LOG_PREFIX } from './constants';
|
|
7
|
-
import { ISet, _Set, returnSetsUnion, setToArray } from '../../utils/lang/sets';
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
|
|
@@ -13,8 +12,8 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
13
12
|
|
|
14
13
|
private readonly keys: KeyBuilderCS;
|
|
15
14
|
private readonly splitFiltersValidation: ISplitFiltersValidation;
|
|
16
|
-
private readonly flagSetsFilter: string[];
|
|
17
15
|
private hasSync?: boolean;
|
|
16
|
+
private cacheReadyButNeedsToFlush: boolean = false;
|
|
18
17
|
private updateNewFilter?: boolean;
|
|
19
18
|
|
|
20
19
|
/**
|
|
@@ -22,11 +21,10 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
22
21
|
* @param {number | undefined} expirationTimestamp
|
|
23
22
|
* @param {ISplitFiltersValidation} splitFiltersValidation
|
|
24
23
|
*/
|
|
25
|
-
constructor(private readonly log: ILogger, keys: KeyBuilderCS, expirationTimestamp?: number, splitFiltersValidation: ISplitFiltersValidation = { queryString: null, groupedFilters: {
|
|
24
|
+
constructor(private readonly log: ILogger, keys: KeyBuilderCS, expirationTimestamp?: number, splitFiltersValidation: ISplitFiltersValidation = { queryString: null, groupedFilters: { byName: [], byPrefix: [] }, validFilters: [] }) {
|
|
26
25
|
super();
|
|
27
26
|
this.keys = keys;
|
|
28
27
|
this.splitFiltersValidation = splitFiltersValidation;
|
|
29
|
-
this.flagSetsFilter = this.splitFiltersValidation.groupedFilters.bySet;
|
|
30
28
|
|
|
31
29
|
this._checkExpiration(expirationTimestamp);
|
|
32
30
|
|
|
@@ -108,9 +106,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
108
106
|
this._incrementCounts(split);
|
|
109
107
|
this._decrementCounts(previousSplit);
|
|
110
108
|
|
|
111
|
-
if (previousSplit) this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
112
|
-
this.addToFlagSets(split);
|
|
113
|
-
|
|
114
109
|
return true;
|
|
115
110
|
} catch (e) {
|
|
116
111
|
this.log.error(LOG_PREFIX + e);
|
|
@@ -124,7 +119,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
124
119
|
localStorage.removeItem(this.keys.buildSplitKey(name));
|
|
125
120
|
|
|
126
121
|
this._decrementCounts(split);
|
|
127
|
-
if (split) this.removeFromFlagSets(split.name, split.sets);
|
|
128
122
|
|
|
129
123
|
return true;
|
|
130
124
|
} catch (e) {
|
|
@@ -139,6 +133,11 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
139
133
|
}
|
|
140
134
|
|
|
141
135
|
setChangeNumber(changeNumber: number): boolean {
|
|
136
|
+
// when cache is ready but using a new split query, we must clear all split data
|
|
137
|
+
if (this.cacheReadyButNeedsToFlush) {
|
|
138
|
+
this.clear();
|
|
139
|
+
this.cacheReadyButNeedsToFlush = false;
|
|
140
|
+
}
|
|
142
141
|
|
|
143
142
|
// when using a new split query, we must update it at the store
|
|
144
143
|
if (this.updateNewFilter) {
|
|
@@ -221,7 +220,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
221
220
|
* @override
|
|
222
221
|
*/
|
|
223
222
|
checkCache(): boolean {
|
|
224
|
-
return this.getChangeNumber() > -1;
|
|
223
|
+
return this.getChangeNumber() > -1 || this.cacheReadyButNeedsToFlush;
|
|
225
224
|
}
|
|
226
225
|
|
|
227
226
|
/**
|
|
@@ -238,7 +237,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
238
237
|
}
|
|
239
238
|
|
|
240
239
|
private _checkFilterQuery() {
|
|
241
|
-
const { queryString } = this.splitFiltersValidation;
|
|
240
|
+
const { queryString, groupedFilters } = this.splitFiltersValidation;
|
|
242
241
|
const queryKey = this.keys.buildSplitsFilterQueryKey();
|
|
243
242
|
const currentQueryString = localStorage.getItem(queryKey);
|
|
244
243
|
|
|
@@ -247,74 +246,29 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
247
246
|
// mark cache to update the new query filter on first successful splits fetch
|
|
248
247
|
this.updateNewFilter = true;
|
|
249
248
|
|
|
250
|
-
// if
|
|
251
|
-
if (this.checkCache())
|
|
252
|
-
|
|
249
|
+
// if cache is ready:
|
|
250
|
+
if (this.checkCache()) {
|
|
251
|
+
// * set change number to -1, to fetch splits with -1 `since` value.
|
|
252
|
+
localStorage.setItem(this.keys.buildSplitsTillKey(), '-1');
|
|
253
|
+
|
|
254
|
+
// * remove from cache splits that doesn't match with the new filters
|
|
255
|
+
this.getSplitNames().forEach((splitName) => {
|
|
256
|
+
if (queryString && (
|
|
257
|
+
// @TODO consider redefining `groupedFilters` to expose a method like `groupedFilters::filter(splitName): boolean`
|
|
258
|
+
groupedFilters.byName.indexOf(splitName) > -1 ||
|
|
259
|
+
groupedFilters.byPrefix.some((prefix: string) => splitName.startsWith(prefix + '__'))
|
|
260
|
+
)) {
|
|
261
|
+
// * set `cacheReadyButNeedsToFlush` so that `checkCache` returns true (the storage is ready to be used) and the data is cleared before updating on first successful splits fetch
|
|
262
|
+
this.cacheReadyButNeedsToFlush = true;
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
this.removeSplit(splitName);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
253
268
|
} catch (e) {
|
|
254
269
|
this.log.error(LOG_PREFIX + e);
|
|
255
270
|
}
|
|
256
271
|
}
|
|
257
272
|
// if the filter didn't change, nothing is done
|
|
258
273
|
}
|
|
259
|
-
|
|
260
|
-
getNamesByFlagSets(flagSets: string[]): ISet<string>{
|
|
261
|
-
let toReturn: ISet<string> = new _Set([]);
|
|
262
|
-
flagSets.forEach(flagSet => {
|
|
263
|
-
const flagSetKey = this.keys.buildFlagSetKey(flagSet);
|
|
264
|
-
let flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
265
|
-
|
|
266
|
-
if (flagSetFromLocalStorage) {
|
|
267
|
-
const flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
|
|
268
|
-
toReturn = returnSetsUnion(toReturn, flagSetCache);
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
return toReturn;
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
private addToFlagSets(featureFlag: ISplit) {
|
|
276
|
-
if (!featureFlag.sets) return;
|
|
277
|
-
|
|
278
|
-
featureFlag.sets.forEach(featureFlagSet => {
|
|
279
|
-
|
|
280
|
-
if (this.flagSetsFilter.length > 0 && !this.flagSetsFilter.some(filterFlagSet => filterFlagSet === featureFlagSet)) return;
|
|
281
|
-
|
|
282
|
-
const flagSetKey = this.keys.buildFlagSetKey(featureFlagSet);
|
|
283
|
-
|
|
284
|
-
let flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
285
|
-
if (!flagSetFromLocalStorage) flagSetFromLocalStorage = '[]';
|
|
286
|
-
|
|
287
|
-
const flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
|
|
288
|
-
flagSetCache.add(featureFlag.name);
|
|
289
|
-
|
|
290
|
-
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
private removeFromFlagSets(featureFlagName: string, flagSets?: string[]) {
|
|
295
|
-
if (!flagSets) return;
|
|
296
|
-
|
|
297
|
-
flagSets.forEach(flagSet => {
|
|
298
|
-
this.removeNames(flagSet, featureFlagName);
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
private removeNames(flagSetName: string, featureFlagName: string) {
|
|
303
|
-
const flagSetKey = this.keys.buildFlagSetKey(flagSetName);
|
|
304
|
-
|
|
305
|
-
let flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
306
|
-
|
|
307
|
-
if (!flagSetFromLocalStorage) return;
|
|
308
|
-
|
|
309
|
-
const flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
|
|
310
|
-
flagSetCache.delete(featureFlagName);
|
|
311
|
-
|
|
312
|
-
if (flagSetCache.size === 0) {
|
|
313
|
-
localStorage.removeItem(flagSetKey);
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
|
|
318
|
-
}
|
|
319
|
-
|
|
320
274
|
}
|
|
@@ -54,7 +54,7 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
54
54
|
uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
|
|
55
55
|
|
|
56
56
|
destroy() {
|
|
57
|
-
this.splits = new SplitsCacheInMemory(
|
|
57
|
+
this.splits = new SplitsCacheInMemory();
|
|
58
58
|
this.segments = new MySegmentsCacheInMemory();
|
|
59
59
|
this.impressions.clear();
|
|
60
60
|
this.impressionCounts && this.impressionCounts.clear();
|
|
@@ -75,7 +75,7 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
75
75
|
telemetry: this.telemetry,
|
|
76
76
|
|
|
77
77
|
destroy() {
|
|
78
|
-
this.splits = new SplitsCacheInMemory(
|
|
78
|
+
this.splits = new SplitsCacheInMemory();
|
|
79
79
|
this.segments = new MySegmentsCacheInMemory();
|
|
80
80
|
}
|
|
81
81
|
};
|
|
@@ -14,9 +14,9 @@ import { UniqueKeysCacheInMemory } from './UniqueKeysCacheInMemory';
|
|
|
14
14
|
* @param params parameters required by EventsCacheSync
|
|
15
15
|
*/
|
|
16
16
|
export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageSync {
|
|
17
|
-
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode
|
|
17
|
+
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode } } } = params;
|
|
18
18
|
|
|
19
|
-
const splits = new SplitsCacheInMemory(
|
|
19
|
+
const splits = new SplitsCacheInMemory();
|
|
20
20
|
const segments = new SegmentsCacheInMemory();
|
|
21
21
|
|
|
22
22
|
const storage = {
|
|
@@ -14,9 +14,9 @@ import { UniqueKeysCacheInMemoryCS } from './UniqueKeysCacheInMemoryCS';
|
|
|
14
14
|
* @param params parameters required by EventsCacheSync
|
|
15
15
|
*/
|
|
16
16
|
export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorageSync {
|
|
17
|
-
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode
|
|
17
|
+
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode } } } = params;
|
|
18
18
|
|
|
19
|
-
const splits = new SplitsCacheInMemory(
|
|
19
|
+
const splits = new SplitsCacheInMemory();
|
|
20
20
|
const segments = new MySegmentsCacheInMemory();
|
|
21
21
|
|
|
22
22
|
const storage = {
|
|
@@ -50,7 +50,7 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
50
50
|
|
|
51
51
|
// Set a new splits cache to clean it for the client without affecting other clients
|
|
52
52
|
destroy() {
|
|
53
|
-
this.splits = new SplitsCacheInMemory(
|
|
53
|
+
this.splits = new SplitsCacheInMemory();
|
|
54
54
|
this.segments.clear();
|
|
55
55
|
}
|
|
56
56
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { ISplit
|
|
1
|
+
import { ISplit } from '../../dtos/types';
|
|
2
2
|
import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
|
|
3
3
|
import { isFiniteNumber } from '../../utils/lang';
|
|
4
|
-
import { ISet, _Set, returnSetsUnion } from '../../utils/lang/sets';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Default ISplitsCacheSync implementation that stores split definitions in memory.
|
|
@@ -9,17 +8,10 @@ import { ISet, _Set, returnSetsUnion } from '../../utils/lang/sets';
|
|
|
9
8
|
*/
|
|
10
9
|
export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
11
10
|
|
|
12
|
-
private flagSetsFilter: string[];
|
|
13
11
|
private splitsCache: Record<string, ISplit> = {};
|
|
14
12
|
private ttCache: Record<string, number> = {};
|
|
15
13
|
private changeNumber: number = -1;
|
|
16
14
|
private splitsWithSegmentsCount: number = 0;
|
|
17
|
-
private flagSetsCache: Record<string, ISet<string>> = {};
|
|
18
|
-
|
|
19
|
-
constructor(splitFiltersValidation: ISplitFiltersValidation = { queryString: null, groupedFilters: { bySet: [], byName: [], byPrefix: [] }, validFilters: [] }) {
|
|
20
|
-
super();
|
|
21
|
-
this.flagSetsFilter = splitFiltersValidation.groupedFilters.bySet;
|
|
22
|
-
}
|
|
23
15
|
|
|
24
16
|
clear() {
|
|
25
17
|
this.splitsCache = {};
|
|
@@ -36,8 +28,6 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
36
28
|
this.ttCache[previousTtName]--;
|
|
37
29
|
if (!this.ttCache[previousTtName]) delete this.ttCache[previousTtName];
|
|
38
30
|
|
|
39
|
-
this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
40
|
-
|
|
41
31
|
if (usesSegments(previousSplit)) { // Substract from segments count for the previous version of this Split.
|
|
42
32
|
this.splitsWithSegmentsCount--;
|
|
43
33
|
}
|
|
@@ -49,7 +39,6 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
49
39
|
// Update TT cache
|
|
50
40
|
const ttName = split.trafficTypeName;
|
|
51
41
|
this.ttCache[ttName] = (this.ttCache[ttName] || 0) + 1;
|
|
52
|
-
this.addToFlagSets(split);
|
|
53
42
|
|
|
54
43
|
// Add to segments count for the new version of the Split
|
|
55
44
|
if (usesSegments(split)) this.splitsWithSegmentsCount++;
|
|
@@ -69,7 +58,6 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
69
58
|
const ttName = split.trafficTypeName;
|
|
70
59
|
this.ttCache[ttName]--; // Update tt cache
|
|
71
60
|
if (!this.ttCache[ttName]) delete this.ttCache[ttName];
|
|
72
|
-
this.removeFromFlagSets(split.name, split.sets);
|
|
73
61
|
|
|
74
62
|
// Update the segments count.
|
|
75
63
|
if (usesSegments(split)) this.splitsWithSegmentsCount--;
|
|
@@ -105,41 +93,4 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
105
93
|
return this.getChangeNumber() === -1 || this.splitsWithSegmentsCount > 0;
|
|
106
94
|
}
|
|
107
95
|
|
|
108
|
-
getNamesByFlagSets(flagSets: string[]): ISet<string>{
|
|
109
|
-
let toReturn: ISet<string> = new _Set([]);
|
|
110
|
-
flagSets.forEach(flagSet => {
|
|
111
|
-
const featureFlagNames = this.flagSetsCache[flagSet];
|
|
112
|
-
if (featureFlagNames) {
|
|
113
|
-
toReturn = returnSetsUnion(toReturn, featureFlagNames);
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
return toReturn;
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
private addToFlagSets(featureFlag: ISplit) {
|
|
121
|
-
if (!featureFlag.sets) return;
|
|
122
|
-
featureFlag.sets.forEach(featureFlagSet => {
|
|
123
|
-
|
|
124
|
-
if (this.flagSetsFilter.length > 0 && !this.flagSetsFilter.some(filterFlagSet => filterFlagSet === featureFlagSet)) return;
|
|
125
|
-
|
|
126
|
-
if (!this.flagSetsCache[featureFlagSet]) this.flagSetsCache[featureFlagSet] = new _Set([]);
|
|
127
|
-
|
|
128
|
-
this.flagSetsCache[featureFlagSet].add(featureFlag.name);
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
private removeFromFlagSets(featureFlagName :string, flagSets: string[] | undefined) {
|
|
133
|
-
if (!flagSets) return;
|
|
134
|
-
flagSets.forEach(flagSet => {
|
|
135
|
-
this.removeNames(flagSet, featureFlagName);
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
private removeNames(flagSetName: string, featureFlagName: string) {
|
|
140
|
-
if (!this.flagSetsCache[flagSetName]) return;
|
|
141
|
-
this.flagSetsCache[flagSetName].delete(featureFlagName);
|
|
142
|
-
if (this.flagSetsCache[flagSetName].size === 0) delete this.flagSetsCache[flagSetName];
|
|
143
|
-
}
|
|
144
|
-
|
|
145
96
|
}
|
|
@@ -5,7 +5,6 @@ import { ILogger } from '../../logger/types';
|
|
|
5
5
|
import { LOG_PREFIX } from './constants';
|
|
6
6
|
import { ISplit } from '../../dtos/types';
|
|
7
7
|
import { AbstractSplitsCacheAsync } from '../AbstractSplitsCacheAsync';
|
|
8
|
-
import { ISet, _Set } from '../../utils/lang/sets';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Discard errors for an answer of multiple operations.
|
|
@@ -189,17 +188,6 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
189
188
|
);
|
|
190
189
|
}
|
|
191
190
|
|
|
192
|
-
/**
|
|
193
|
-
* Get list of split names related to a given flag set names list.
|
|
194
|
-
* The returned promise is resolved with the list of split names,
|
|
195
|
-
* or rejected if wrapper operation fails.
|
|
196
|
-
* @todo this is a no-op method to be implemented
|
|
197
|
-
*/
|
|
198
|
-
getNamesByFlagSets(): Promise<ISet<string>> {
|
|
199
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
200
|
-
return new Promise(flagSets => new _Set([]));
|
|
201
|
-
}
|
|
202
|
-
|
|
203
191
|
/**
|
|
204
192
|
* Check traffic type existence.
|
|
205
193
|
* The returned promise is resolved with a boolean indicating whether the TT exist or not.
|
|
@@ -5,7 +5,6 @@ import { ILogger } from '../../logger/types';
|
|
|
5
5
|
import { ISplit } from '../../dtos/types';
|
|
6
6
|
import { LOG_PREFIX } from './constants';
|
|
7
7
|
import { AbstractSplitsCacheAsync } from '../AbstractSplitsCacheAsync';
|
|
8
|
-
import { ISet, _Set } from '../../utils/lang/sets';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* ISplitsCacheAsync implementation for pluggable storages.
|
|
@@ -155,17 +154,6 @@ export class SplitsCachePluggable extends AbstractSplitsCacheAsync {
|
|
|
155
154
|
);
|
|
156
155
|
}
|
|
157
156
|
|
|
158
|
-
/**
|
|
159
|
-
* Get list of split names related to a given flag set names list.
|
|
160
|
-
* The returned promise is resolved with the list of split names,
|
|
161
|
-
* or rejected if wrapper operation fails.
|
|
162
|
-
* @todo this is a no-op method to be implemented
|
|
163
|
-
*/
|
|
164
|
-
getNamesByFlagSets(): Promise<ISet<string>> {
|
|
165
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
166
|
-
return new Promise(flagSets => new _Set([]));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
157
|
/**
|
|
170
158
|
* Check traffic type existence.
|
|
171
159
|
* The returned promise is resolved with a boolean indicating whether the TT exist or not.
|
package/src/storages/types.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { MaybeThenable, ISplit } from '../dtos/types';
|
|
2
2
|
import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, MultiMethodExceptions, MultiMethodLatencies, MultiConfigs, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent, UniqueKeysPayloadCs, UniqueKeysPayloadSs, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../sync/submitters/types';
|
|
3
3
|
import { SplitIO, ImpressionDTO, ISettings } from '../types';
|
|
4
|
-
import { ISet } from '../utils/lang/sets';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Interface of a pluggable storage wrapper.
|
|
@@ -209,8 +208,7 @@ export interface ISplitsCacheBase {
|
|
|
209
208
|
clear(): MaybeThenable<boolean | void>,
|
|
210
209
|
// should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE.
|
|
211
210
|
checkCache(): MaybeThenable<boolean>,
|
|
212
|
-
killLocally(name: string, defaultTreatment: string, changeNumber: number): MaybeThenable<boolean
|
|
213
|
-
getNamesByFlagSets(flagSets: string[]): MaybeThenable<ISet<string>>
|
|
211
|
+
killLocally(name: string, defaultTreatment: string, changeNumber: number): MaybeThenable<boolean>
|
|
214
212
|
}
|
|
215
213
|
|
|
216
214
|
export interface ISplitsCacheSync extends ISplitsCacheBase {
|
|
@@ -226,8 +224,7 @@ export interface ISplitsCacheSync extends ISplitsCacheBase {
|
|
|
226
224
|
usesSegments(): boolean,
|
|
227
225
|
clear(): void,
|
|
228
226
|
checkCache(): boolean,
|
|
229
|
-
killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean
|
|
230
|
-
getNamesByFlagSets(flagSets: string[]): ISet<string>
|
|
227
|
+
killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean
|
|
231
228
|
}
|
|
232
229
|
|
|
233
230
|
export interface ISplitsCacheAsync extends ISplitsCacheBase {
|
|
@@ -243,8 +240,7 @@ export interface ISplitsCacheAsync extends ISplitsCacheBase {
|
|
|
243
240
|
usesSegments(): Promise<boolean>,
|
|
244
241
|
clear(): Promise<boolean | void>,
|
|
245
242
|
checkCache(): Promise<boolean>,
|
|
246
|
-
killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise<boolean
|
|
247
|
-
getNamesByFlagSets(flagSets: string[]): Promise<ISet<string>>
|
|
243
|
+
killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise<boolean>
|
|
248
244
|
}
|
|
249
245
|
|
|
250
246
|
/** Segments cache */
|
|
@@ -24,7 +24,6 @@ export function splitsSyncTaskFactory(
|
|
|
24
24
|
splitChangesFetcherFactory(fetchSplitChanges),
|
|
25
25
|
storage.splits,
|
|
26
26
|
storage.segments,
|
|
27
|
-
settings.sync.__splitFiltersValidation,
|
|
28
27
|
readiness.splits,
|
|
29
28
|
settings.startup.requestTimeoutBeforeReady,
|
|
30
29
|
settings.startup.retriesOnFailureBeforeReady,
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { _Set, setToArray, ISet } from '../../../utils/lang/sets';
|
|
2
2
|
import { ISegmentsCacheBase, ISplitsCacheBase } from '../../../storages/types';
|
|
3
3
|
import { ISplitChangesFetcher } from '../fetchers/types';
|
|
4
|
-
import { ISplit, ISplitChangesResponse
|
|
4
|
+
import { ISplit, ISplitChangesResponse } from '../../../dtos/types';
|
|
5
5
|
import { ISplitsEventEmitter } from '../../../readiness/types';
|
|
6
6
|
import { timeout } from '../../../utils/promise/timeout';
|
|
7
7
|
import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
|
|
8
8
|
import { ILogger } from '../../../logger/types';
|
|
9
9
|
import { SYNC_SPLITS_FETCH, SYNC_SPLITS_NEW, SYNC_SPLITS_REMOVED, SYNC_SPLITS_SEGMENTS, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
|
|
10
|
-
import { startsWith } from '../../../utils/lang';
|
|
11
10
|
|
|
12
11
|
type ISplitChangesUpdater = (noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }) => Promise<boolean>
|
|
13
12
|
|
|
@@ -46,36 +45,15 @@ interface ISplitMutations {
|
|
|
46
45
|
segments: string[]
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
/**
|
|
50
|
-
* If there are defined filters and one feature flag doesn't match with them, its status is changed to 'ARCHIVE' to avoid storing it
|
|
51
|
-
* If there are set filter defined, names filter is ignored
|
|
52
|
-
*
|
|
53
|
-
* @param featureFlag feature flag to be evaluated
|
|
54
|
-
* @param filters splitFiltersValidation bySet | byName
|
|
55
|
-
*/
|
|
56
|
-
function matchFilters(featureFlag: ISplit, filters: ISplitFiltersValidation) {
|
|
57
|
-
const { bySet: setsFilter, byName: namesFilter, byPrefix: prefixFilter} = filters.groupedFilters;
|
|
58
|
-
if (setsFilter.length > 0) return featureFlag.sets && featureFlag.sets.some((featureFlagSet: string) => setsFilter.indexOf(featureFlagSet) > -1);
|
|
59
|
-
|
|
60
|
-
const namesFilterConfigured = namesFilter.length > 0;
|
|
61
|
-
const prefixFilterConfigured = prefixFilter.length > 0;
|
|
62
|
-
|
|
63
|
-
if (!namesFilterConfigured && !prefixFilterConfigured) return true;
|
|
64
|
-
|
|
65
|
-
const matchNames = namesFilterConfigured && namesFilter.indexOf(featureFlag.name) > -1;
|
|
66
|
-
const matchPrefix = prefixFilterConfigured && prefixFilter.some(prefix => startsWith(featureFlag.name, prefix));
|
|
67
|
-
return matchNames || matchPrefix;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
48
|
/**
|
|
71
49
|
* Given the list of splits from /splitChanges endpoint, it returns the mutations,
|
|
72
50
|
* i.e., an object with added splits, removed splits and used segments.
|
|
73
51
|
* Exported for testing purposes.
|
|
74
52
|
*/
|
|
75
|
-
export function computeSplitsMutation(entries: ISplit[]
|
|
53
|
+
export function computeSplitsMutation(entries: ISplit[]): ISplitMutations {
|
|
76
54
|
const segments = new _Set<string>();
|
|
77
55
|
const computed = entries.reduce((accum, split) => {
|
|
78
|
-
if (split.status === 'ACTIVE'
|
|
56
|
+
if (split.status === 'ACTIVE') {
|
|
79
57
|
accum.added.push([split.name, split]);
|
|
80
58
|
|
|
81
59
|
parseSegments(split).forEach((segmentName: string) => {
|
|
@@ -112,7 +90,6 @@ export function splitChangesUpdaterFactory(
|
|
|
112
90
|
splitChangesFetcher: ISplitChangesFetcher,
|
|
113
91
|
splits: ISplitsCacheBase,
|
|
114
92
|
segments: ISegmentsCacheBase,
|
|
115
|
-
splitFiltersValidation: ISplitFiltersValidation,
|
|
116
93
|
splitsEventEmitter?: ISplitsEventEmitter,
|
|
117
94
|
requestTimeoutBeforeReady: number = 0,
|
|
118
95
|
retriesOnFailureBeforeReady: number = 0,
|
|
@@ -149,7 +126,7 @@ export function splitChangesUpdaterFactory(
|
|
|
149
126
|
.then((splitChanges: ISplitChangesResponse) => {
|
|
150
127
|
startingUp = false;
|
|
151
128
|
|
|
152
|
-
const mutation = computeSplitsMutation(splitChanges.splits
|
|
129
|
+
const mutation = computeSplitsMutation(splitChanges.splits);
|
|
153
130
|
|
|
154
131
|
log.debug(SYNC_SPLITS_NEW, [mutation.added.length]);
|
|
155
132
|
log.debug(SYNC_SPLITS_REMOVED, [mutation.removed.length]);
|
|
@@ -3,13 +3,12 @@ import { submitterFactory, firstPushWindowDecorator } from './submitter';
|
|
|
3
3
|
import { TelemetryConfigStatsPayload, TelemetryConfigStats } from './types';
|
|
4
4
|
import { CONSUMER_MODE, CONSUMER_ENUM, STANDALONE_MODE, CONSUMER_PARTIAL_MODE, STANDALONE_ENUM, CONSUMER_PARTIAL_ENUM, OPTIMIZED, DEBUG, NONE, DEBUG_ENUM, OPTIMIZED_ENUM, NONE_ENUM, CONSENT_GRANTED, CONSENT_DECLINED, CONSENT_UNKNOWN } from '../../utils/constants';
|
|
5
5
|
import { SDK_READY, SDK_READY_FROM_CACHE } from '../../readiness/constants';
|
|
6
|
-
import { ConsentStatus, ISettings, SDKMode
|
|
6
|
+
import { ConsentStatus, ISettings, SDKMode } from '../../types';
|
|
7
7
|
import { base } from '../../utils/settingsValidation';
|
|
8
8
|
import { usedKeysMap } from '../../utils/inputValidation/apiKey';
|
|
9
9
|
import { timer } from '../../utils/timeTracker/timer';
|
|
10
10
|
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
11
11
|
import { objectAssign } from '../../utils/lang/objectAssign';
|
|
12
|
-
import { ISplitFiltersValidation } from '../../dtos/types';
|
|
13
12
|
|
|
14
13
|
const OPERATION_MODE_MAP = {
|
|
15
14
|
[STANDALONE_MODE]: STANDALONE_ENUM,
|
|
@@ -39,18 +38,6 @@ function getRedundantActiveFactories() {
|
|
|
39
38
|
}, 0);
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
function getTelemetryFlagSetsStats(splitFiltersValidation: ISplitFiltersValidation) {
|
|
43
|
-
// Group every configured flag set in an unique array called originalSets
|
|
44
|
-
let flagSetsTotal = 0;
|
|
45
|
-
splitFiltersValidation.validFilters.forEach((filter: SplitIO.SplitFilter) => {
|
|
46
|
-
if (filter.type === 'bySet') flagSetsTotal += filter.values.length;
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
const flagSetsValid = splitFiltersValidation.groupedFilters.bySet.length;
|
|
50
|
-
const flagSetsIgnored = flagSetsTotal - flagSetsValid;
|
|
51
|
-
return { flagSetsTotal, flagSetsIgnored };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
41
|
export function getTelemetryConfigStats(mode: SDKMode, storageType: string): TelemetryConfigStats {
|
|
55
42
|
return {
|
|
56
43
|
oM: OPERATION_MODE_MAP[mode], // @ts-ignore lower case of storage type
|
|
@@ -72,8 +59,6 @@ export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, sett
|
|
|
72
59
|
const { urls, scheduler } = settings;
|
|
73
60
|
const isClientSide = settings.core.key !== undefined;
|
|
74
61
|
|
|
75
|
-
const { flagSetsTotal, flagSetsIgnored } = getTelemetryFlagSetsStats(settings.sync.__splitFiltersValidation);
|
|
76
|
-
|
|
77
62
|
return objectAssign(getTelemetryConfigStats(settings.mode, settings.storage.type), {
|
|
78
63
|
sE: settings.streamingEnabled,
|
|
79
64
|
rR: {
|
|
@@ -101,9 +86,7 @@ export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, sett
|
|
|
101
86
|
nR: telemetry.getNonReadyUsage(),
|
|
102
87
|
t: telemetry.popTags(),
|
|
103
88
|
i: settings.integrations && settings.integrations.map(int => int.type),
|
|
104
|
-
uC: settings.userConsent ? USER_CONSENT_MAP[settings.userConsent] : 0
|
|
105
|
-
fsT: flagSetsTotal,
|
|
106
|
-
fsI: flagSetsIgnored
|
|
89
|
+
uC: settings.userConsent ? USER_CONSENT_MAP[settings.userConsent] : 0
|
|
107
90
|
});
|
|
108
91
|
}
|
|
109
92
|
};
|
|
@@ -124,11 +124,7 @@ export type TREATMENTS = 'ts';
|
|
|
124
124
|
export type TREATMENT_WITH_CONFIG = 'tc';
|
|
125
125
|
export type TREATMENTS_WITH_CONFIG = 'tcs';
|
|
126
126
|
export type TRACK = 'tr';
|
|
127
|
-
export type
|
|
128
|
-
export type TREATMENTS_BY_FLAGSETS = 'tfs'
|
|
129
|
-
export type TREATMENTS_WITH_CONFIG_BY_FLAGSET = 'tcf'
|
|
130
|
-
export type TREATMENTS_WITH_CONFIG_BY_FLAGSETS = 'tcfs'
|
|
131
|
-
export type Method = TREATMENT | TREATMENTS | TREATMENT_WITH_CONFIG | TREATMENTS_WITH_CONFIG | TRACK | TREATMENTS_BY_FLAGSET | TREATMENTS_BY_FLAGSETS | TREATMENTS_WITH_CONFIG_BY_FLAGSET | TREATMENTS_WITH_CONFIG_BY_FLAGSETS;
|
|
127
|
+
export type Method = TREATMENT | TREATMENTS | TREATMENT_WITH_CONFIG | TREATMENTS_WITH_CONFIG | TRACK;
|
|
132
128
|
|
|
133
129
|
export type MethodLatencies = Partial<Record<Method, Array<number>>>;
|
|
134
130
|
|
|
@@ -238,8 +234,6 @@ export type TelemetryConfigStatsPayload = TelemetryConfigStats & {
|
|
|
238
234
|
nR: number, // SDKNotReadyUsage
|
|
239
235
|
i?: Array<string>, // integrations
|
|
240
236
|
uC: number, // userConsent
|
|
241
|
-
fsT: number, // flagSetsTotal
|
|
242
|
-
fsI: number, // flagSetsInvalid
|
|
243
237
|
}
|
|
244
238
|
|
|
245
239
|
export interface ISubmitterManager extends ISyncTask {
|