@splitsoftware/splitio-commons 1.17.1-rc.3 → 2.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +7 -3
- package/cjs/evaluator/index.js +2 -2
- package/cjs/evaluator/matchers/semver_inlist.js +1 -2
- package/cjs/evaluator/matchers/whitelist.js +1 -2
- package/cjs/listeners/browser.js +1 -2
- package/cjs/logger/browser/DebugLogger.js +1 -2
- package/cjs/logger/browser/ErrorLogger.js +1 -2
- package/cjs/logger/browser/InfoLogger.js +1 -2
- package/cjs/logger/browser/WarnLogger.js +1 -2
- package/cjs/logger/index.js +1 -2
- package/cjs/readiness/readinessManager.js +5 -7
- package/cjs/sdkClient/clientCS.js +5 -8
- package/cjs/sdkClient/sdkClientMethodCS.js +5 -8
- package/cjs/sdkFactory/index.js +10 -33
- package/cjs/services/decorateHeaders.js +1 -2
- package/cjs/storages/AbstractSplitsCacheAsync.js +7 -0
- package/cjs/storages/AbstractSplitsCacheSync.js +7 -0
- package/cjs/storages/KeyBuilderCS.js +0 -9
- package/cjs/storages/dataLoader.js +32 -64
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -21
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +14 -7
- package/cjs/storages/inLocalStorage/index.js +1 -6
- package/cjs/storages/inMemory/InMemoryStorageCS.js +4 -16
- package/cjs/storages/inMemory/SegmentsCacheInMemory.js +3 -4
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +2 -3
- package/cjs/storages/inMemory/UniqueKeysCacheInMemory.js +2 -3
- package/cjs/storages/inMemory/UniqueKeysCacheInMemoryCS.js +2 -3
- package/cjs/storages/inRedis/RedisAdapter.js +3 -4
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/TelemetryCacheInRedis.js +3 -4
- package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +1 -2
- package/cjs/storages/pluggable/SplitsCachePluggable.js +1 -1
- package/cjs/storages/pluggable/TelemetryCachePluggable.js +6 -7
- package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +1 -2
- package/cjs/storages/pluggable/inMemoryWrapper.js +7 -8
- package/cjs/storages/pluggable/index.js +32 -37
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +7 -2
- package/cjs/sync/polling/pollingManagerSS.js +3 -3
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +13 -5
- package/cjs/sync/streaming/parseUtils.js +0 -1
- package/cjs/sync/streaming/pushManager.js +2 -3
- package/cjs/trackers/eventTracker.js +9 -11
- package/cjs/trackers/impressionsTracker.js +13 -15
- package/cjs/trackers/uniqueKeysTracker.js +3 -5
- package/cjs/utils/LRUCache/index.js +1 -2
- package/cjs/utils/constants/browser.js +1 -4
- package/cjs/utils/lang/index.js +6 -9
- package/cjs/utils/lang/objectAssign.js +12 -77
- package/cjs/utils/lang/sets.js +3 -110
- package/cjs/utils/settingsValidation/index.js +0 -9
- package/cjs/utils/settingsValidation/logger/builtinLogger.js +1 -2
- package/cjs/utils/settingsValidation/storage/storageCS.js +12 -1
- package/esm/evaluator/index.js +3 -3
- package/esm/evaluator/matchers/semver_inlist.js +1 -2
- package/esm/evaluator/matchers/whitelist.js +1 -2
- package/esm/listeners/browser.js +1 -2
- package/esm/logger/browser/DebugLogger.js +1 -2
- package/esm/logger/browser/ErrorLogger.js +1 -2
- package/esm/logger/browser/InfoLogger.js +1 -2
- package/esm/logger/browser/WarnLogger.js +1 -2
- package/esm/logger/index.js +1 -2
- package/esm/readiness/readinessManager.js +5 -7
- package/esm/sdkClient/clientCS.js +5 -8
- package/esm/sdkClient/sdkClientMethodCS.js +5 -8
- package/esm/sdkFactory/index.js +11 -34
- package/esm/services/decorateHeaders.js +1 -2
- package/esm/storages/AbstractSplitsCacheAsync.js +7 -0
- package/esm/storages/AbstractSplitsCacheSync.js +7 -0
- package/esm/storages/KeyBuilderCS.js +0 -9
- package/esm/storages/dataLoader.js +30 -61
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -21
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +14 -7
- package/esm/storages/inLocalStorage/index.js +2 -7
- package/esm/storages/inMemory/InMemoryStorageCS.js +4 -16
- package/esm/storages/inMemory/SegmentsCacheInMemory.js +3 -4
- package/esm/storages/inMemory/SplitsCacheInMemory.js +2 -3
- package/esm/storages/inMemory/UniqueKeysCacheInMemory.js +2 -3
- package/esm/storages/inMemory/UniqueKeysCacheInMemoryCS.js +2 -3
- package/esm/storages/inRedis/RedisAdapter.js +3 -4
- package/esm/storages/inRedis/SplitsCacheInRedis.js +2 -2
- package/esm/storages/inRedis/TelemetryCacheInRedis.js +3 -4
- package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +1 -2
- package/esm/storages/pluggable/SplitsCachePluggable.js +2 -2
- package/esm/storages/pluggable/TelemetryCachePluggable.js +6 -7
- package/esm/storages/pluggable/UniqueKeysCachePluggable.js +1 -2
- package/esm/storages/pluggable/inMemoryWrapper.js +7 -8
- package/esm/storages/pluggable/index.js +32 -37
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +8 -3
- package/esm/sync/polling/pollingManagerSS.js +3 -3
- package/esm/sync/polling/updaters/splitChangesUpdater.js +14 -6
- package/esm/sync/streaming/parseUtils.js +0 -1
- package/esm/sync/streaming/pushManager.js +2 -3
- package/esm/trackers/eventTracker.js +9 -11
- package/esm/trackers/impressionsTracker.js +13 -15
- package/esm/trackers/uniqueKeysTracker.js +3 -5
- package/esm/utils/LRUCache/index.js +1 -2
- package/esm/utils/constants/browser.js +0 -3
- package/esm/utils/lang/index.js +6 -9
- package/esm/utils/lang/objectAssign.js +12 -77
- package/esm/utils/lang/sets.js +2 -107
- package/esm/utils/settingsValidation/index.js +0 -9
- package/esm/utils/settingsValidation/logger/builtinLogger.js +1 -2
- package/esm/utils/settingsValidation/storage/storageCS.js +10 -0
- package/package.json +2 -2
- package/src/evaluator/index.ts +5 -5
- package/src/evaluator/matchers/semver_inlist.ts +1 -2
- package/src/evaluator/matchers/whitelist.ts +1 -3
- package/src/listeners/browser.ts +1 -2
- package/src/logger/browser/DebugLogger.ts +1 -2
- package/src/logger/browser/ErrorLogger.ts +1 -2
- package/src/logger/browser/InfoLogger.ts +1 -2
- package/src/logger/browser/WarnLogger.ts +1 -2
- package/src/logger/index.ts +3 -4
- package/src/readiness/readinessManager.ts +7 -9
- package/src/readiness/types.ts +0 -1
- package/src/sdkClient/clientCS.ts +5 -8
- package/src/sdkClient/sdkClientMethodCS.ts +3 -6
- package/src/sdkFactory/index.ts +12 -37
- package/src/sdkFactory/types.ts +1 -4
- package/src/services/decorateHeaders.ts +1 -2
- package/src/storages/AbstractSplitsCacheAsync.ts +9 -2
- package/src/storages/AbstractSplitsCacheSync.ts +9 -2
- package/src/storages/KeyBuilderCS.ts +0 -13
- package/src/storages/dataLoader.ts +32 -62
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +1 -21
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +16 -8
- package/src/storages/inLocalStorage/index.ts +2 -8
- package/src/storages/inMemory/InMemoryStorageCS.ts +4 -19
- package/src/storages/inMemory/SegmentsCacheInMemory.ts +4 -5
- package/src/storages/inMemory/SplitsCacheInMemory.ts +4 -5
- package/src/storages/inMemory/UniqueKeysCacheInMemory.ts +4 -5
- package/src/storages/inMemory/UniqueKeysCacheInMemoryCS.ts +4 -5
- package/src/storages/inRedis/RedisAdapter.ts +4 -5
- package/src/storages/inRedis/SplitsCacheInRedis.ts +3 -3
- package/src/storages/inRedis/TelemetryCacheInRedis.ts +3 -4
- package/src/storages/inRedis/UniqueKeysCacheInRedis.ts +1 -2
- package/src/storages/pluggable/SegmentsCachePluggable.ts +0 -1
- package/src/storages/pluggable/SplitsCachePluggable.ts +3 -3
- package/src/storages/pluggable/TelemetryCachePluggable.ts +6 -7
- package/src/storages/pluggable/UniqueKeysCachePluggable.ts +1 -2
- package/src/storages/pluggable/inMemoryWrapper.ts +8 -9
- package/src/storages/pluggable/index.ts +33 -38
- package/src/storages/types.ts +9 -6
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +7 -3
- package/src/sync/polling/pollingManagerSS.ts +2 -3
- package/src/sync/polling/updaters/splitChangesUpdater.ts +15 -8
- package/src/sync/streaming/parseUtils.ts +0 -1
- package/src/sync/streaming/pushManager.ts +3 -4
- package/src/sync/submitters/types.ts +3 -4
- package/src/trackers/eventTracker.ts +7 -10
- package/src/trackers/impressionsTracker.ts +9 -12
- package/src/trackers/types.ts +0 -1
- package/src/trackers/uniqueKeysTracker.ts +4 -6
- package/src/types.ts +9 -18
- package/src/utils/LRUCache/index.ts +2 -3
- package/src/utils/constants/browser.ts +0 -4
- package/src/utils/lang/index.ts +6 -7
- package/src/utils/lang/objectAssign.ts +13 -92
- package/src/utils/lang/sets.ts +3 -125
- package/src/utils/settingsValidation/index.ts +0 -10
- package/src/utils/settingsValidation/logger/builtinLogger.ts +1 -2
- package/src/utils/settingsValidation/storage/storageCS.ts +13 -0
- package/src/utils/settingsValidation/types.ts +0 -2
- package/types/logger/index.d.ts +1 -2
- package/types/readiness/types.d.ts +0 -1
- package/types/sdkClient/clientCS.d.ts +2 -3
- package/types/sdkFactory/types.d.ts +1 -3
- package/types/storages/AbstractSplitsCacheAsync.d.ts +6 -2
- package/types/storages/AbstractSplitsCacheSync.d.ts +6 -2
- package/types/storages/KeyBuilderCS.d.ts +0 -2
- package/types/storages/dataLoader.d.ts +6 -17
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +7 -2
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +1 -2
- package/types/storages/inMemory/UniqueKeysCacheInMemory.d.ts +2 -3
- package/types/storages/inRedis/SplitsCacheInRedis.d.ts +1 -2
- package/types/storages/pluggable/SplitsCachePluggable.d.ts +1 -2
- package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -2
- package/types/storages/types.d.ts +7 -6
- package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -2
- package/types/sync/submitters/types.d.ts +3 -4
- package/types/trackers/eventTracker.d.ts +1 -1
- package/types/trackers/impressionsTracker.d.ts +1 -1
- package/types/trackers/types.d.ts +0 -1
- package/types/types.d.ts +9 -17
- package/types/utils/LRUCache/index.d.ts +1 -2
- package/types/utils/constants/browser.d.ts +0 -2
- package/types/utils/lang/objectAssign.d.ts +3 -0
- package/types/utils/lang/sets.d.ts +1 -61
- package/types/utils/settingsValidation/index.d.ts +0 -1
- package/types/utils/settingsValidation/storage/storageCS.d.ts +5 -0
- package/types/utils/settingsValidation/types.d.ts +0 -2
- package/cjs/integrations/browser.js +0 -31
- package/cjs/integrations/ga/GaToSplit.js +0 -257
- package/cjs/integrations/ga/GoogleAnalyticsToSplit.js +0 -14
- package/cjs/integrations/ga/SplitToGa.js +0 -123
- package/cjs/integrations/ga/SplitToGoogleAnalytics.js +0 -14
- package/cjs/integrations/ga/types.js +0 -2
- package/cjs/sdkClient/sdkClientMethodCSWithTT.js +0 -79
- package/cjs/utils/lang/maps.js +0 -96
- package/esm/integrations/browser.js +0 -27
- package/esm/integrations/ga/GaToSplit.js +0 -250
- package/esm/integrations/ga/GoogleAnalyticsToSplit.js +0 -10
- package/esm/integrations/ga/SplitToGa.js +0 -120
- package/esm/integrations/ga/SplitToGoogleAnalytics.js +0 -10
- package/esm/integrations/ga/types.js +0 -1
- package/esm/sdkClient/sdkClientMethodCSWithTT.js +0 -75
- package/esm/utils/lang/maps.js +0 -92
- package/src/integrations/browser.ts +0 -35
- package/src/integrations/ga/GaToSplit.ts +0 -299
- package/src/integrations/ga/GoogleAnalyticsToSplit.ts +0 -14
- package/src/integrations/ga/SplitToGa.ts +0 -135
- package/src/integrations/ga/SplitToGoogleAnalytics.ts +0 -14
- package/src/integrations/ga/autoRequire.js +0 -33
- package/src/integrations/ga/types.ts +0 -153
- package/src/sdkClient/sdkClientMethodCSWithTT.ts +0 -101
- package/src/utils/lang/maps.ts +0 -108
|
@@ -4,7 +4,7 @@ import { ILogger } from '../../logger/types';
|
|
|
4
4
|
import { LOG_PREFIX } from './constants';
|
|
5
5
|
import { ISplit, ISplitFiltersValidation } from '../../dtos/types';
|
|
6
6
|
import { AbstractSplitsCacheAsync } from '../AbstractSplitsCacheAsync';
|
|
7
|
-
import {
|
|
7
|
+
import { returnDifference } from '../../utils/lang/sets';
|
|
8
8
|
import type { RedisAdapter } from './RedisAdapter';
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -215,14 +215,14 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
215
215
|
* The returned promise is resolved with the list of feature flag names per flag set,
|
|
216
216
|
* or rejected if the pipelined redis operation fails (e.g., timeout).
|
|
217
217
|
*/
|
|
218
|
-
getNamesByFlagSets(flagSets: string[]): Promise<
|
|
218
|
+
getNamesByFlagSets(flagSets: string[]): Promise<Set<string>[]> {
|
|
219
219
|
return this.redis.pipeline(flagSets.map(flagSet => ['smembers', this.keys.buildFlagSetKey(flagSet)])).exec()
|
|
220
220
|
.then((results) => results.map(([e, value], index) => {
|
|
221
221
|
if (e === null) return value;
|
|
222
222
|
|
|
223
223
|
this.log.error(LOG_PREFIX + `Could not read result from get members of flag set ${flagSets[index]} due to an error: ${e}`);
|
|
224
224
|
}))
|
|
225
|
-
.then(namesByFlagSets => namesByFlagSets.map(namesByFlagSet => new
|
|
225
|
+
.then(namesByFlagSets => namesByFlagSets.map(namesByFlagSet => new Set(namesByFlagSet)));
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
/**
|
|
@@ -6,7 +6,6 @@ import { findLatencyIndex } from '../findLatencyIndex';
|
|
|
6
6
|
import { getTelemetryConfigStats } from '../../sync/submitters/telemetrySubmitter';
|
|
7
7
|
import { CONSUMER_MODE, STORAGE_REDIS } from '../../utils/constants';
|
|
8
8
|
import { isNaNNumber, isString } from '../../utils/lang';
|
|
9
|
-
import { _Map } from '../../utils/lang/maps';
|
|
10
9
|
import { MAX_LATENCY_BUCKET_COUNT, newBuckets } from '../inMemory/TelemetryCacheInMemory';
|
|
11
10
|
import { parseLatencyField, parseExceptionField, parseMetadata } from '../utils';
|
|
12
11
|
import type { RedisAdapter } from './RedisAdapter';
|
|
@@ -46,7 +45,7 @@ export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
|
46
45
|
popLatencies(): Promise<MultiMethodLatencies> {
|
|
47
46
|
return this.redis.hgetall(this.keys.latencyPrefix).then(latencies => {
|
|
48
47
|
|
|
49
|
-
const result: MultiMethodLatencies = new
|
|
48
|
+
const result: MultiMethodLatencies = new Map();
|
|
50
49
|
|
|
51
50
|
Object.keys(latencies).forEach(field => {
|
|
52
51
|
|
|
@@ -86,7 +85,7 @@ export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
|
86
85
|
popExceptions(): Promise<MultiMethodExceptions> {
|
|
87
86
|
return this.redis.hgetall(this.keys.exceptionPrefix).then(exceptions => {
|
|
88
87
|
|
|
89
|
-
const result: MultiMethodExceptions = new
|
|
88
|
+
const result: MultiMethodExceptions = new Map();
|
|
90
89
|
|
|
91
90
|
Object.keys(exceptions).forEach(field => {
|
|
92
91
|
|
|
@@ -119,7 +118,7 @@ export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
|
119
118
|
popConfigs(): Promise<MultiConfigs> {
|
|
120
119
|
return this.redis.hgetall(this.keys.initPrefix).then(configs => {
|
|
121
120
|
|
|
122
|
-
const result: MultiConfigs = new
|
|
121
|
+
const result: MultiConfigs = new Map();
|
|
123
122
|
|
|
124
123
|
Object.keys(configs).forEach(field => {
|
|
125
124
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { IUniqueKeysCacheBase } from '../types';
|
|
2
2
|
import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
|
|
3
|
-
import { setToArray } from '../../utils/lang/sets';
|
|
4
3
|
import { DEFAULT_CACHE_SIZE, REFRESH_RATE, TTL_REFRESH } from './constants';
|
|
5
4
|
import { LOG_PREFIX } from './constants';
|
|
6
5
|
import { ILogger } from '../../logger/types';
|
|
@@ -29,7 +28,7 @@ export class UniqueKeysCacheInRedis extends UniqueKeysCacheInMemory implements I
|
|
|
29
28
|
if (!featureNames.length) return Promise.resolve(false);
|
|
30
29
|
|
|
31
30
|
const uniqueKeysArray = featureNames.map((featureName) => {
|
|
32
|
-
const featureKeys =
|
|
31
|
+
const featureKeys = Array.from(this.uniqueKeysTracker[featureName]);
|
|
33
32
|
const uniqueKeysPayload = {
|
|
34
33
|
f: featureName,
|
|
35
34
|
ks: featureKeys
|
|
@@ -5,7 +5,6 @@ import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
|
5
5
|
import { IPluggableStorageWrapper, ISegmentsCacheAsync } from '../types';
|
|
6
6
|
import { ILogger } from '../../logger/types';
|
|
7
7
|
import { LOG_PREFIX } from './constants';
|
|
8
|
-
import { _Set } from '../../utils/lang/sets';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* ISegmentsCacheAsync implementation for pluggable storages.
|
|
@@ -5,7 +5,7 @@ import { ILogger } from '../../logger/types';
|
|
|
5
5
|
import { ISplit, ISplitFiltersValidation } from '../../dtos/types';
|
|
6
6
|
import { LOG_PREFIX } from './constants';
|
|
7
7
|
import { AbstractSplitsCacheAsync } from '../AbstractSplitsCacheAsync';
|
|
8
|
-
import {
|
|
8
|
+
import { returnDifference } from '../../utils/lang/sets';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* ISplitsCacheAsync implementation for pluggable storages.
|
|
@@ -181,11 +181,11 @@ export class SplitsCachePluggable extends AbstractSplitsCacheAsync {
|
|
|
181
181
|
* The returned promise is resolved with the list of feature flag names per flag set.
|
|
182
182
|
* It never rejects (If there is a wrapper error for some flag set, an empty set is returned for it).
|
|
183
183
|
*/
|
|
184
|
-
getNamesByFlagSets(flagSets: string[]): Promise<
|
|
184
|
+
getNamesByFlagSets(flagSets: string[]): Promise<Set<string>[]> {
|
|
185
185
|
return Promise.all(flagSets.map(flagSet => {
|
|
186
186
|
const flagSetKey = this.keys.buildFlagSetKey(flagSet);
|
|
187
187
|
return this.wrapper.getItems(flagSetKey).catch(() => []);
|
|
188
|
-
})).then(namesByFlagSets => namesByFlagSets.map(namesByFlagSet => new
|
|
188
|
+
})).then(namesByFlagSets => namesByFlagSets.map(namesByFlagSet => new Set(namesByFlagSet)));
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
/**
|
|
@@ -6,7 +6,6 @@ import { findLatencyIndex } from '../findLatencyIndex';
|
|
|
6
6
|
import { getTelemetryConfigStats } from '../../sync/submitters/telemetrySubmitter';
|
|
7
7
|
import { CONSUMER_MODE, STORAGE_PLUGGABLE } from '../../utils/constants';
|
|
8
8
|
import { isString, isNaNNumber } from '../../utils/lang';
|
|
9
|
-
import { _Map } from '../../utils/lang/maps';
|
|
10
9
|
import { MAX_LATENCY_BUCKET_COUNT, newBuckets } from '../inMemory/TelemetryCacheInMemory';
|
|
11
10
|
import { parseLatencyField, parseExceptionField, parseMetadata } from '../utils';
|
|
12
11
|
|
|
@@ -43,7 +42,7 @@ export class TelemetryCachePluggable implements ITelemetryCacheAsync {
|
|
|
43
42
|
return latencyKeys.length ?
|
|
44
43
|
this.wrapper.getMany(latencyKeys).then(latencies => {
|
|
45
44
|
|
|
46
|
-
const result: MultiMethodLatencies = new
|
|
45
|
+
const result: MultiMethodLatencies = new Map();
|
|
47
46
|
|
|
48
47
|
for (let i = 0; i < latencyKeys.length; i++) {
|
|
49
48
|
const field = latencyKeys[i].split('::')[1];
|
|
@@ -77,7 +76,7 @@ export class TelemetryCachePluggable implements ITelemetryCacheAsync {
|
|
|
77
76
|
return Promise.all(latencyKeys.map((latencyKey) => this.wrapper.del(latencyKey))).then(() => result);
|
|
78
77
|
}) :
|
|
79
78
|
// If latencyKeys is empty, return an empty map.
|
|
80
|
-
new
|
|
79
|
+
new Map();
|
|
81
80
|
});
|
|
82
81
|
}
|
|
83
82
|
|
|
@@ -90,7 +89,7 @@ export class TelemetryCachePluggable implements ITelemetryCacheAsync {
|
|
|
90
89
|
return exceptionKeys.length ?
|
|
91
90
|
this.wrapper.getMany(exceptionKeys).then(exceptions => {
|
|
92
91
|
|
|
93
|
-
const result: MultiMethodExceptions = new
|
|
92
|
+
const result: MultiMethodExceptions = new Map();
|
|
94
93
|
|
|
95
94
|
for (let i = 0; i < exceptionKeys.length; i++) {
|
|
96
95
|
const field = exceptionKeys[i].split('::')[1];
|
|
@@ -117,7 +116,7 @@ export class TelemetryCachePluggable implements ITelemetryCacheAsync {
|
|
|
117
116
|
return Promise.all(exceptionKeys.map((exceptionKey) => this.wrapper.del(exceptionKey))).then(() => result);
|
|
118
117
|
}) :
|
|
119
118
|
// If exceptionKeys is empty, return an empty map.
|
|
120
|
-
new
|
|
119
|
+
new Map();
|
|
121
120
|
});
|
|
122
121
|
}
|
|
123
122
|
|
|
@@ -130,7 +129,7 @@ export class TelemetryCachePluggable implements ITelemetryCacheAsync {
|
|
|
130
129
|
return configKeys.length ?
|
|
131
130
|
this.wrapper.getMany(configKeys).then(configs => {
|
|
132
131
|
|
|
133
|
-
const result: MultiConfigs = new
|
|
132
|
+
const result: MultiConfigs = new Map();
|
|
134
133
|
|
|
135
134
|
for (let i = 0; i < configKeys.length; i++) {
|
|
136
135
|
const field = configKeys[i].split('::')[1];
|
|
@@ -154,7 +153,7 @@ export class TelemetryCachePluggable implements ITelemetryCacheAsync {
|
|
|
154
153
|
return Promise.all(configKeys.map((configKey) => this.wrapper.del(configKey))).then(() => result);
|
|
155
154
|
}) :
|
|
156
155
|
// If configKeys is empty, return an empty map.
|
|
157
|
-
new
|
|
156
|
+
new Map();
|
|
158
157
|
});
|
|
159
158
|
}
|
|
160
159
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { IPluggableStorageWrapper, IUniqueKeysCacheBase } from '../types';
|
|
2
2
|
import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
|
|
3
|
-
import { setToArray } from '../../utils/lang/sets';
|
|
4
3
|
import { DEFAULT_CACHE_SIZE, REFRESH_RATE } from '../inRedis/constants';
|
|
5
4
|
import { LOG_PREFIX } from './constants';
|
|
6
5
|
import { ILogger } from '../../logger/types';
|
|
@@ -28,7 +27,7 @@ export class UniqueKeysCachePluggable extends UniqueKeysCacheInMemory implements
|
|
|
28
27
|
if (!featureNames.length) return Promise.resolve(false);
|
|
29
28
|
|
|
30
29
|
const uniqueKeysArray = featureNames.map((featureName) => {
|
|
31
|
-
const featureKeys =
|
|
30
|
+
const featureKeys = Array.from(this.uniqueKeysTracker[featureName]);
|
|
32
31
|
const uniqueKeysPayload = {
|
|
33
32
|
f: featureName,
|
|
34
33
|
ks: featureKeys
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { IPluggableStorageWrapper } from '../types';
|
|
2
2
|
import { startsWith, toNumber } from '../../utils/lang';
|
|
3
|
-
import { ISet, setToArray, _Set } from '../../utils/lang/sets';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Creates a IPluggableStorageWrapper implementation that stores items in memory.
|
|
@@ -9,9 +8,9 @@ import { ISet, setToArray, _Set } from '../../utils/lang/sets';
|
|
|
9
8
|
*
|
|
10
9
|
* @param connDelay delay in millis for `connect` resolve. If not provided, `connect` resolves immediately.
|
|
11
10
|
*/
|
|
12
|
-
export function inMemoryWrapperFactory(connDelay?: number): IPluggableStorageWrapper & { _cache: Record<string, string | string[] |
|
|
11
|
+
export function inMemoryWrapperFactory(connDelay?: number): IPluggableStorageWrapper & { _cache: Record<string, string | string[] | Set<string>>, _setConnDelay(connDelay: number): void } {
|
|
13
12
|
|
|
14
|
-
let _cache: Record<string, string | string[] |
|
|
13
|
+
let _cache: Record<string, string | string[] | Set<string>> = {};
|
|
15
14
|
let _connDelay = connDelay;
|
|
16
15
|
|
|
17
16
|
return {
|
|
@@ -84,22 +83,22 @@ export function inMemoryWrapperFactory(connDelay?: number): IPluggableStorageWra
|
|
|
84
83
|
itemContains(key: string, item: string) {
|
|
85
84
|
const set = _cache[key];
|
|
86
85
|
if (!set) return Promise.resolve(false);
|
|
87
|
-
if (set instanceof
|
|
86
|
+
if (set instanceof Set) return Promise.resolve(set.has(item));
|
|
88
87
|
return Promise.reject('key is not a set');
|
|
89
88
|
},
|
|
90
89
|
addItems(key: string, items: string[]) {
|
|
91
|
-
if (!(key in _cache)) _cache[key] = new
|
|
90
|
+
if (!(key in _cache)) _cache[key] = new Set();
|
|
92
91
|
const set = _cache[key];
|
|
93
|
-
if (set instanceof
|
|
92
|
+
if (set instanceof Set) {
|
|
94
93
|
items.forEach(item => set.add(item));
|
|
95
94
|
return Promise.resolve();
|
|
96
95
|
}
|
|
97
96
|
return Promise.reject('key is not a set');
|
|
98
97
|
},
|
|
99
98
|
removeItems(key: string, items: string[]) {
|
|
100
|
-
if (!(key in _cache)) _cache[key] = new
|
|
99
|
+
if (!(key in _cache)) _cache[key] = new Set();
|
|
101
100
|
const set = _cache[key];
|
|
102
|
-
if (set instanceof
|
|
101
|
+
if (set instanceof Set) {
|
|
103
102
|
items.forEach(item => set.delete(item));
|
|
104
103
|
return Promise.resolve();
|
|
105
104
|
}
|
|
@@ -108,7 +107,7 @@ export function inMemoryWrapperFactory(connDelay?: number): IPluggableStorageWra
|
|
|
108
107
|
getItems(key: string) {
|
|
109
108
|
const set = _cache[key];
|
|
110
109
|
if (!set) return Promise.resolve([]);
|
|
111
|
-
if (set instanceof
|
|
110
|
+
if (set instanceof Set) return Promise.resolve(Array.from(set));
|
|
112
111
|
return Promise.reject('key is not a set');
|
|
113
112
|
},
|
|
114
113
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IPluggableStorageWrapper, IStorageAsyncFactory, IStorageFactoryParams, ITelemetryCacheAsync } from '../types';
|
|
1
|
+
import { IPluggableStorageWrapper, IStorageAsync, IStorageAsyncFactory, IStorageFactoryParams, ITelemetryCacheAsync } from '../types';
|
|
2
2
|
|
|
3
3
|
import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
4
4
|
import { SplitsCachePluggable } from './SplitsCachePluggable';
|
|
@@ -62,12 +62,11 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
62
62
|
|
|
63
63
|
const prefix = validatePrefix(options.prefix);
|
|
64
64
|
|
|
65
|
-
function PluggableStorageFactory(params: IStorageFactoryParams) {
|
|
65
|
+
function PluggableStorageFactory(params: IStorageFactoryParams): IStorageAsync {
|
|
66
66
|
const { onReadyCb, settings, settings: { log, mode, sync: { impressionsMode }, scheduler: { impressionsQueueSize, eventsQueueSize } } } = params;
|
|
67
67
|
const metadata = metadataBuilder(settings);
|
|
68
68
|
const keys = new KeyBuilderSS(prefix, metadata);
|
|
69
69
|
const wrapper = wrapperAdapter(log, options.wrapper);
|
|
70
|
-
let connectPromise: Promise<void>;
|
|
71
70
|
|
|
72
71
|
const isSyncronizer = mode === undefined; // If mode is not defined, the synchronizer is running
|
|
73
72
|
const isPartialConsumer = mode === CONSUMER_PARTIAL_MODE;
|
|
@@ -90,6 +89,35 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
90
89
|
new UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper) :
|
|
91
90
|
undefined;
|
|
92
91
|
|
|
92
|
+
// Connects to wrapper and emits SDK_READY event on main client
|
|
93
|
+
const connectPromise = wrapper.connect().then(() => {
|
|
94
|
+
if (isSyncronizer) {
|
|
95
|
+
// In standalone or producer mode, clear storage if SDK key or feature flag filter has changed
|
|
96
|
+
return wrapper.get(keys.buildHashKey()).then((hash) => {
|
|
97
|
+
const currentHash = getStorageHash(settings);
|
|
98
|
+
if (hash !== currentHash) {
|
|
99
|
+
log.info(LOG_PREFIX + 'Storage HASH has changed (SDK key, flags filter criteria or flags spec version was modified). Clearing cache');
|
|
100
|
+
return wrapper.getKeysByPrefix(`${keys.prefix}.`).then(storageKeys => {
|
|
101
|
+
return Promise.all(storageKeys.map(storageKey => wrapper.del(storageKey)));
|
|
102
|
+
}).then(() => wrapper.set(keys.buildHashKey(), currentHash));
|
|
103
|
+
}
|
|
104
|
+
}).then(() => {
|
|
105
|
+
onReadyCb();
|
|
106
|
+
});
|
|
107
|
+
} else {
|
|
108
|
+
// Start periodic flush of async storages if not running synchronizer (producer mode)
|
|
109
|
+
if (impressionCountsCache && (impressionCountsCache as ImpressionCountsCachePluggable).start) (impressionCountsCache as ImpressionCountsCachePluggable).start();
|
|
110
|
+
if (uniqueKeysCache && (uniqueKeysCache as UniqueKeysCachePluggable).start) (uniqueKeysCache as UniqueKeysCachePluggable).start();
|
|
111
|
+
if (telemetry && (telemetry as ITelemetryCacheAsync).recordConfig) (telemetry as ITelemetryCacheAsync).recordConfig();
|
|
112
|
+
|
|
113
|
+
onReadyCb();
|
|
114
|
+
}
|
|
115
|
+
}).catch((e) => {
|
|
116
|
+
e = e || new Error('Error connecting wrapper');
|
|
117
|
+
onReadyCb(e);
|
|
118
|
+
return e; // Propagate error for shared clients
|
|
119
|
+
});
|
|
120
|
+
|
|
93
121
|
return {
|
|
94
122
|
splits: new SplitsCachePluggable(log, keys, wrapper, settings.sync.__splitFiltersValidation),
|
|
95
123
|
segments: new SegmentsCachePluggable(log, keys, wrapper),
|
|
@@ -99,39 +127,6 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
99
127
|
telemetry,
|
|
100
128
|
uniqueKeys: uniqueKeysCache,
|
|
101
129
|
|
|
102
|
-
init() {
|
|
103
|
-
if (connectPromise) return connectPromise;
|
|
104
|
-
|
|
105
|
-
// Connects to wrapper and emits SDK_READY event on main client
|
|
106
|
-
return connectPromise = wrapper.connect().then(() => {
|
|
107
|
-
if (isSyncronizer) {
|
|
108
|
-
// In standalone or producer mode, clear storage if SDK key or feature flag filter has changed
|
|
109
|
-
return wrapper.get(keys.buildHashKey()).then((hash) => {
|
|
110
|
-
const currentHash = getStorageHash(settings);
|
|
111
|
-
if (hash !== currentHash) {
|
|
112
|
-
log.info(LOG_PREFIX + 'Storage HASH has changed (SDK key, flags filter criteria or flags spec version was modified). Clearing cache');
|
|
113
|
-
return wrapper.getKeysByPrefix(`${keys.prefix}.`).then(storageKeys => {
|
|
114
|
-
return Promise.all(storageKeys.map(storageKey => wrapper.del(storageKey)));
|
|
115
|
-
}).then(() => wrapper.set(keys.buildHashKey(), currentHash));
|
|
116
|
-
}
|
|
117
|
-
}).then(() => {
|
|
118
|
-
onReadyCb();
|
|
119
|
-
});
|
|
120
|
-
} else {
|
|
121
|
-
// Start periodic flush of async storages if not running synchronizer (producer mode)
|
|
122
|
-
if (impressionCountsCache && (impressionCountsCache as ImpressionCountsCachePluggable).start) (impressionCountsCache as ImpressionCountsCachePluggable).start();
|
|
123
|
-
if (uniqueKeysCache && (uniqueKeysCache as UniqueKeysCachePluggable).start) (uniqueKeysCache as UniqueKeysCachePluggable).start();
|
|
124
|
-
if (telemetry && (telemetry as ITelemetryCacheAsync).recordConfig) (telemetry as ITelemetryCacheAsync).recordConfig();
|
|
125
|
-
|
|
126
|
-
onReadyCb();
|
|
127
|
-
}
|
|
128
|
-
}).catch((e) => {
|
|
129
|
-
e = e || new Error('Error connecting wrapper');
|
|
130
|
-
onReadyCb(e);
|
|
131
|
-
return e; // Propagate error for shared clients
|
|
132
|
-
});
|
|
133
|
-
},
|
|
134
|
-
|
|
135
130
|
// Stop periodic flush and disconnect the underlying storage
|
|
136
131
|
destroy() {
|
|
137
132
|
return Promise.all(isSyncronizer ? [] : [
|
|
@@ -141,8 +136,8 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
141
136
|
},
|
|
142
137
|
|
|
143
138
|
// emits SDK_READY event on shared clients and returns a reference to the storage
|
|
144
|
-
shared(_
|
|
145
|
-
|
|
139
|
+
shared(_, onReadyCb) {
|
|
140
|
+
connectPromise.then(onReadyCb);
|
|
146
141
|
|
|
147
142
|
return {
|
|
148
143
|
...this,
|
package/src/storages/types.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { MaybeThenable, ISplit, IMySegmentsResponse } from '../dtos/types';
|
|
|
2
2
|
import { MySegmentsData } from '../sync/polling/types';
|
|
3
3
|
import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, MultiMethodExceptions, MultiMethodLatencies, MultiConfigs, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent, UniqueKeysPayloadCs, UniqueKeysPayloadSs, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../sync/submitters/types';
|
|
4
4
|
import { SplitIO, ImpressionDTO, ISettings } from '../types';
|
|
5
|
-
import { ISet } from '../utils/lang/sets';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Interface of a pluggable storage wrapper.
|
|
@@ -208,8 +207,10 @@ export interface ISplitsCacheBase {
|
|
|
208
207
|
// only for Client-Side. Returns true if the storage is not synchronized yet (getChangeNumber() === -1) or contains a FF using segments or large segments
|
|
209
208
|
usesSegments(): MaybeThenable<boolean>,
|
|
210
209
|
clear(): MaybeThenable<boolean | void>,
|
|
210
|
+
// should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE.
|
|
211
|
+
checkCache(): MaybeThenable<boolean>,
|
|
211
212
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): MaybeThenable<boolean>,
|
|
212
|
-
getNamesByFlagSets(flagSets: string[]): MaybeThenable<
|
|
213
|
+
getNamesByFlagSets(flagSets: string[]): MaybeThenable<Set<string>[]>
|
|
213
214
|
}
|
|
214
215
|
|
|
215
216
|
export interface ISplitsCacheSync extends ISplitsCacheBase {
|
|
@@ -224,8 +225,9 @@ export interface ISplitsCacheSync extends ISplitsCacheBase {
|
|
|
224
225
|
trafficTypeExists(trafficType: string): boolean,
|
|
225
226
|
usesSegments(): boolean,
|
|
226
227
|
clear(): void,
|
|
228
|
+
checkCache(): boolean,
|
|
227
229
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean,
|
|
228
|
-
getNamesByFlagSets(flagSets: string[]):
|
|
230
|
+
getNamesByFlagSets(flagSets: string[]): Set<string>[]
|
|
229
231
|
}
|
|
230
232
|
|
|
231
233
|
export interface ISplitsCacheAsync extends ISplitsCacheBase {
|
|
@@ -240,8 +242,9 @@ export interface ISplitsCacheAsync extends ISplitsCacheBase {
|
|
|
240
242
|
trafficTypeExists(trafficType: string): Promise<boolean>,
|
|
241
243
|
usesSegments(): Promise<boolean>,
|
|
242
244
|
clear(): Promise<boolean | void>,
|
|
245
|
+
checkCache(): Promise<boolean>,
|
|
243
246
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise<boolean>,
|
|
244
|
-
getNamesByFlagSets(flagSets: string[]): Promise<
|
|
247
|
+
getNamesByFlagSets(flagSets: string[]): Promise<Set<string>[]>
|
|
245
248
|
}
|
|
246
249
|
|
|
247
250
|
/** Segments cache */
|
|
@@ -462,7 +465,6 @@ export interface IStorageBase<
|
|
|
462
465
|
events: TEventsCache,
|
|
463
466
|
telemetry?: TTelemetryCache,
|
|
464
467
|
uniqueKeys?: TUniqueKeysCache,
|
|
465
|
-
init?: () => void | Promise<void>,
|
|
466
468
|
destroy(): void | Promise<void>,
|
|
467
469
|
shared?: (matchingKey: string, onReadyCb: (error?: any) => void) => this
|
|
468
470
|
}
|
|
@@ -492,6 +494,8 @@ export interface IStorageAsync extends IStorageBase<
|
|
|
492
494
|
|
|
493
495
|
/** StorageFactory */
|
|
494
496
|
|
|
497
|
+
export type DataLoader = (storage: IStorageSync, matchingKey: string) => void
|
|
498
|
+
|
|
495
499
|
export interface IStorageFactoryParams {
|
|
496
500
|
settings: ISettings,
|
|
497
501
|
/**
|
|
@@ -499,7 +503,6 @@ export interface IStorageFactoryParams {
|
|
|
499
503
|
* It is meant for emitting SDK_READY event in consumer mode, and waiting before using the storage in the synchronizer.
|
|
500
504
|
*/
|
|
501
505
|
onReadyCb: (error?: any) => void,
|
|
502
|
-
onReadyFromCacheCb: (error?: any) => void,
|
|
503
506
|
}
|
|
504
507
|
|
|
505
508
|
export type StorageType = 'MEMORY' | 'LOCALSTORAGE' | 'REDIS' | 'PLUGGABLE';
|
|
@@ -7,7 +7,7 @@ import { syncTaskFactory } from '../../syncTask';
|
|
|
7
7
|
import { ISyncTask } from '../../types';
|
|
8
8
|
import { ISettings } from '../../../types';
|
|
9
9
|
import { CONTROL } from '../../../utils/constants';
|
|
10
|
-
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
|
|
10
|
+
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
|
|
11
11
|
import { SYNC_OFFLINE_DATA, ERROR_SYNC_OFFLINE_LOADING } from '../../../logger/constants';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -60,8 +60,12 @@ export function fromObjectUpdaterFactory(
|
|
|
60
60
|
|
|
61
61
|
if (startingUp) {
|
|
62
62
|
startingUp = false;
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
Promise.resolve(splitsCache.checkCache()).then(cacheReady => {
|
|
64
|
+
// Emits SDK_READY_FROM_CACHE
|
|
65
|
+
if (cacheReady) readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
|
|
66
|
+
// Emits SDK_READY
|
|
67
|
+
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
68
|
+
});
|
|
65
69
|
}
|
|
66
70
|
return true;
|
|
67
71
|
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { splitsSyncTaskFactory } from './syncTasks/splitsSyncTask';
|
|
2
2
|
import { segmentsSyncTaskFactory } from './syncTasks/segmentsSyncTask';
|
|
3
3
|
import { IPollingManager, ISegmentsSyncTask, ISplitsSyncTask } from './types';
|
|
4
|
-
import { thenable } from '../../utils/promise/thenable';
|
|
5
4
|
import { POLLING_START, POLLING_STOP, LOG_PREFIX_SYNC_POLLING } from '../../logger/constants';
|
|
6
5
|
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
7
6
|
|
|
@@ -29,9 +28,9 @@ export function pollingManagerSSFactory(
|
|
|
29
28
|
log.debug(LOG_PREFIX_SYNC_POLLING + `Segments will be refreshed each ${settings.scheduler.segmentsRefreshRate} millis`);
|
|
30
29
|
|
|
31
30
|
const startingUp = splitsSyncTask.start();
|
|
32
|
-
if (
|
|
31
|
+
if (startingUp) {
|
|
33
32
|
startingUp.then(() => {
|
|
34
|
-
segmentsSyncTask.start();
|
|
33
|
+
if (splitsSyncTask.isRunning()) segmentsSyncTask.start();
|
|
35
34
|
});
|
|
36
35
|
}
|
|
37
36
|
},
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { _Set, setToArray, ISet } from '../../../utils/lang/sets';
|
|
2
1
|
import { ISegmentsCacheBase, ISplitsCacheBase } from '../../../storages/types';
|
|
3
2
|
import { ISplitChangesFetcher } from '../fetchers/types';
|
|
4
3
|
import { ISplit, ISplitChangesResponse, ISplitFiltersValidation } from '../../../dtos/types';
|
|
5
4
|
import { ISplitsEventEmitter } from '../../../readiness/types';
|
|
6
5
|
import { timeout } from '../../../utils/promise/timeout';
|
|
7
|
-
import { SDK_SPLITS_ARRIVED } from '../../../readiness/constants';
|
|
6
|
+
import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
|
|
8
7
|
import { ILogger } from '../../../logger/types';
|
|
9
8
|
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
9
|
import { startsWith } from '../../../utils/lang';
|
|
@@ -27,8 +26,8 @@ function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
|
|
|
27
26
|
* Collect segments from a raw split definition.
|
|
28
27
|
* Exported for testing purposes.
|
|
29
28
|
*/
|
|
30
|
-
export function parseSegments({ conditions }: ISplit):
|
|
31
|
-
let segments = new
|
|
29
|
+
export function parseSegments({ conditions }: ISplit): Set<string> {
|
|
30
|
+
let segments = new Set<string>();
|
|
32
31
|
|
|
33
32
|
for (let i = 0; i < conditions.length; i++) {
|
|
34
33
|
const matchers = conditions[i].matcherGroup.matchers;
|
|
@@ -74,7 +73,7 @@ function matchFilters(featureFlag: ISplit, filters: ISplitFiltersValidation) {
|
|
|
74
73
|
* Exported for testing purposes.
|
|
75
74
|
*/
|
|
76
75
|
export function computeSplitsMutation(entries: ISplit[], filters: ISplitFiltersValidation): ISplitMutations {
|
|
77
|
-
const segments = new
|
|
76
|
+
const segments = new Set<string>();
|
|
78
77
|
const computed = entries.reduce((accum, split) => {
|
|
79
78
|
if (split.status === 'ACTIVE' && matchFilters(split, filters)) {
|
|
80
79
|
accum.added.push([split.name, split]);
|
|
@@ -89,7 +88,7 @@ export function computeSplitsMutation(entries: ISplit[], filters: ISplitFiltersV
|
|
|
89
88
|
return accum;
|
|
90
89
|
}, { added: [], removed: [], segments: [] } as ISplitMutations);
|
|
91
90
|
|
|
92
|
-
computed.segments =
|
|
91
|
+
computed.segments = Array.from(segments);
|
|
93
92
|
|
|
94
93
|
return computed;
|
|
95
94
|
}
|
|
@@ -153,8 +152,7 @@ export function splitChangesUpdaterFactory(
|
|
|
153
152
|
*/
|
|
154
153
|
function _splitChangesUpdater(since: number, retry = 0): Promise<boolean> {
|
|
155
154
|
log.debug(SYNC_SPLITS_FETCH, [since]);
|
|
156
|
-
|
|
157
|
-
return Promise.resolve(splitUpdateNotification ?
|
|
155
|
+
const fetcherPromise = Promise.resolve(splitUpdateNotification ?
|
|
158
156
|
{ splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
|
|
159
157
|
splitChangesFetcher(since, noCache, till, _promiseDecorator)
|
|
160
158
|
)
|
|
@@ -201,6 +199,15 @@ export function splitChangesUpdaterFactory(
|
|
|
201
199
|
}
|
|
202
200
|
return false;
|
|
203
201
|
});
|
|
202
|
+
|
|
203
|
+
// After triggering the requests, if we have cached splits information let's notify that to emit SDK_READY_FROM_CACHE.
|
|
204
|
+
// Wrapping in a promise since checkCache can be async.
|
|
205
|
+
if (splitsEventEmitter && startingUp) {
|
|
206
|
+
Promise.resolve(splits.checkCache()).then(isCacheReady => {
|
|
207
|
+
if (isCacheReady) splitsEventEmitter.emit(SDK_SPLITS_CACHE_LOADED);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
return fetcherPromise;
|
|
204
211
|
}
|
|
205
212
|
|
|
206
213
|
let sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error
|
|
@@ -13,7 +13,6 @@ function Uint8ArrayToString(myUint8Arr: Uint8Array) { // @ts-ignore
|
|
|
13
13
|
|
|
14
14
|
function StringToUint8Array(myString: string) {
|
|
15
15
|
const charCodes = myString.split('').map((e) => e.charCodeAt(0));
|
|
16
|
-
// eslint-disable-next-line compat/compat
|
|
17
16
|
return new Uint8Array(charCodes);
|
|
18
17
|
}
|
|
19
18
|
|
|
@@ -15,7 +15,6 @@ import { MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE, PUSH_NONRETRYABLE_ERROR,
|
|
|
15
15
|
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MEMBERSHIPS_UPDATE, STREAMING_PARSING_SPLIT_UPDATE } from '../../logger/constants';
|
|
16
16
|
import { IMembershipMSUpdateData, IMembershipLSUpdateData, KeyList, UpdateStrategy } from './SSEHandler/types';
|
|
17
17
|
import { getDelay, isInBitmap, parseBitmap, parseFFUpdatePayload, parseKeyList } from './parseUtils';
|
|
18
|
-
import { ISet, _Set } from '../../utils/lang/sets';
|
|
19
18
|
import { Hash64, hash64 } from '../../utils/murmur3/murmur3_64';
|
|
20
19
|
import { IAuthTokenPushEnabled } from './AuthClient/types';
|
|
21
20
|
import { TOKEN_REFRESH, AUTH_REJECTION } from '../../utils/constants';
|
|
@@ -254,11 +253,11 @@ export function pushManagerFactory(
|
|
|
254
253
|
return;
|
|
255
254
|
}
|
|
256
255
|
case UpdateStrategy.KeyList: {
|
|
257
|
-
let keyList: KeyList, added:
|
|
256
|
+
let keyList: KeyList, added: Set<string>, removed: Set<string>;
|
|
258
257
|
try {
|
|
259
258
|
keyList = parseKeyList(parsedData.d!, parsedData.c!);
|
|
260
|
-
added = new
|
|
261
|
-
removed = new
|
|
259
|
+
added = new Set(keyList.a);
|
|
260
|
+
removed = new Set(keyList.r);
|
|
262
261
|
} catch (e) {
|
|
263
262
|
log.warn(STREAMING_PARSING_MEMBERSHIPS_UPDATE, ['KeyList', e]);
|
|
264
263
|
break;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-use-before-define */
|
|
2
2
|
import { IMetadata } from '../../dtos/types';
|
|
3
3
|
import { SplitIO } from '../../types';
|
|
4
|
-
import { IMap } from '../../utils/lang/maps';
|
|
5
4
|
import { ISyncTask } from '../types';
|
|
6
5
|
|
|
7
6
|
export type ImpressionsPayload = {
|
|
@@ -88,11 +87,11 @@ export type StoredEventWithMetadata = {
|
|
|
88
87
|
e: SplitIO.EventData
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
export type MultiMethodLatencies =
|
|
90
|
+
export type MultiMethodLatencies = Map<string, MethodLatencies>
|
|
92
91
|
|
|
93
|
-
export type MultiMethodExceptions =
|
|
92
|
+
export type MultiMethodExceptions = Map<string, MethodExceptions>
|
|
94
93
|
|
|
95
|
-
export type MultiConfigs =
|
|
94
|
+
export type MultiConfigs = Map<string, TelemetryConfigStats>
|
|
96
95
|
|
|
97
96
|
/**
|
|
98
97
|
* Telemetry usage stats
|
|
@@ -16,7 +16,6 @@ import { isConsumerMode } from '../utils/settingsValidation/mode';
|
|
|
16
16
|
export function eventTrackerFactory(
|
|
17
17
|
settings: ISettings,
|
|
18
18
|
eventsCache: IEventsCacheBase,
|
|
19
|
-
whenInit: (cb: () => void) => void,
|
|
20
19
|
integrationsManager?: IEventsHandler,
|
|
21
20
|
telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync
|
|
22
21
|
): IEventTracker {
|
|
@@ -33,15 +32,13 @@ export function eventTrackerFactory(
|
|
|
33
32
|
log.info(EVENTS_TRACKER_SUCCESS, [msg]);
|
|
34
33
|
if (integrationsManager) {
|
|
35
34
|
// Wrap in a timeout because we don't want it to be blocking.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
44
|
-
});
|
|
35
|
+
setTimeout(function () {
|
|
36
|
+
// copy of event, to avoid unexpected behaviour if modified by integrations
|
|
37
|
+
const eventDataCopy = objectAssign({}, eventData);
|
|
38
|
+
if (properties) eventDataCopy.properties = objectAssign({}, properties);
|
|
39
|
+
// integrationsManager does not throw errors (they are internally handled by each integration module)
|
|
40
|
+
integrationsManager.handleEvent(eventDataCopy);
|
|
41
|
+
}, 0);
|
|
45
42
|
}
|
|
46
43
|
} else {
|
|
47
44
|
log.error(ERROR_EVENTS_TRACKER, [msg]);
|