@splitsoftware/splitio-commons 1.6.0 → 1.6.2-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +3 -0
- package/cjs/integrations/ga/GaToSplit.js +4 -2
- package/cjs/integrations/ga/GoogleAnalyticsToSplit.js +1 -0
- package/cjs/listeners/browser.js +2 -1
- package/cjs/logger/constants.js +2 -1
- package/cjs/sdkFactory/index.js +13 -5
- package/cjs/services/splitApi.js +20 -0
- package/cjs/sync/submitters/submitterManager.js +3 -0
- package/cjs/sync/submitters/uniqueKeysSubmitter.js +70 -0
- package/cjs/trackers/impressionsTracker.js +7 -28
- package/cjs/trackers/strategy/strategyDebug.js +25 -0
- package/cjs/trackers/strategy/strategyNone.js +29 -0
- package/cjs/trackers/strategy/strategyOptimized.js +34 -0
- package/cjs/trackers/uniqueKeysTracker.js +69 -0
- package/cjs/utils/constants/index.js +3 -2
- package/cjs/utils/settingsValidation/impressionsMode.js +2 -2
- package/cjs/utils/settingsValidation/index.js +3 -0
- package/esm/integrations/ga/GaToSplit.js +4 -2
- package/esm/integrations/ga/GoogleAnalyticsToSplit.js +1 -0
- package/esm/listeners/browser.js +3 -2
- package/esm/logger/constants.js +1 -0
- package/esm/sdkFactory/index.js +13 -5
- package/esm/services/splitApi.js +20 -0
- package/esm/sync/submitters/submitterManager.js +3 -0
- package/esm/sync/submitters/uniqueKeysSubmitter.js +64 -0
- package/esm/trackers/impressionsTracker.js +7 -28
- package/esm/trackers/strategy/strategyDebug.js +21 -0
- package/esm/trackers/strategy/strategyNone.js +25 -0
- package/esm/trackers/strategy/strategyOptimized.js +30 -0
- package/esm/trackers/uniqueKeysTracker.js +65 -0
- package/esm/utils/constants/index.js +1 -0
- package/esm/utils/settingsValidation/impressionsMode.js +3 -3
- package/esm/utils/settingsValidation/index.js +3 -0
- package/package.json +1 -1
- package/src/integrations/ga/GaToSplit.ts +3 -2
- package/src/integrations/ga/GoogleAnalyticsToSplit.ts +1 -1
- package/src/listeners/browser.ts +3 -2
- package/src/logger/constants.ts +1 -0
- package/src/sdkFactory/index.ts +15 -5
- package/src/sdkFactory/types.ts +7 -4
- package/src/services/splitApi.ts +22 -0
- package/src/services/types.ts +6 -0
- package/src/storages/types.ts +17 -4
- package/src/sync/submitters/submitterManager.ts +2 -0
- package/src/sync/submitters/types.ts +20 -1
- package/src/sync/submitters/uniqueKeysSubmitter.ts +79 -0
- package/src/trackers/impressionsTracker.ts +12 -34
- package/src/trackers/strategy/strategyDebug.ts +28 -0
- package/src/trackers/strategy/strategyNone.ts +34 -0
- package/src/trackers/strategy/strategyOptimized.ts +42 -0
- package/src/trackers/types.ts +30 -0
- package/src/trackers/uniqueKeysTracker.ts +80 -0
- package/src/types.ts +2 -1
- package/src/utils/constants/index.ts +1 -0
- package/src/utils/settingsValidation/impressionsMode.ts +3 -3
- package/src/utils/settingsValidation/index.ts +4 -0
- package/types/integrations/ga/GoogleAnalyticsToSplit.d.ts +1 -1
- package/types/logger/browser/{debugLogger.d.ts → DebugLogger.d.ts} +0 -0
- package/types/logger/browser/{errorLogger.d.ts → ErrorLogger.d.ts} +0 -0
- package/types/logger/browser/{infoLogger.d.ts → InfoLogger.d.ts} +0 -0
- package/types/logger/browser/{warnLogger.d.ts → WarnLogger.d.ts} +0 -0
- package/types/logger/constants.d.ts +1 -0
- package/types/sdkFactory/types.d.ts +4 -2
- package/types/services/types.d.ts +4 -0
- package/types/storages/types.d.ts +16 -3
- package/types/sync/submitters/types.d.ts +18 -1
- package/types/sync/submitters/uniqueKeysSubmitter.d.ts +19 -0
- package/types/trackers/filter/bloomFilter.d.ts +10 -0
- package/types/trackers/filter/dictionaryFilter.d.ts +8 -0
- package/types/trackers/filter/types.d.ts +5 -0
- package/types/trackers/impressionsTracker.d.ts +4 -6
- package/types/trackers/strategy/strategyDebug.d.ts +9 -0
- package/types/trackers/strategy/strategyNone.d.ts +10 -0
- package/types/trackers/strategy/strategyOptimized.d.ts +11 -0
- package/types/trackers/types.d.ts +29 -0
- package/types/trackers/uniqueKeysTracker.d.ts +13 -0
- package/types/types.d.ts +2 -1
- package/types/utils/constants/index.d.ts +1 -0
- package/types/utils/settingsValidation/index.d.ts +1 -0
- package/types/utils/timeTracker/index.d.ts +70 -1
- package/src/logger/.DS_Store +0 -0
- package/types/integrations/ga/GaToSplitPlugin.d.ts +0 -3
- package/types/integrations/ga/SplitToGaPlugin.d.ts +0 -4
- package/types/integrations/ga/autoRequire.d.ts +0 -4
- package/types/logger/codes.d.ts +0 -2
- package/types/logger/codesConstants.d.ts +0 -117
- package/types/logger/codesConstantsBrowser.d.ts +0 -2
- package/types/logger/codesConstantsNode.d.ts +0 -14
- package/types/logger/codesDebug.d.ts +0 -1
- package/types/logger/codesDebugBrowser.d.ts +0 -1
- package/types/logger/codesDebugNode.d.ts +0 -1
- package/types/logger/codesError.d.ts +0 -1
- package/types/logger/codesErrorNode.d.ts +0 -1
- package/types/logger/codesInfo.d.ts +0 -1
- package/types/logger/codesWarn.d.ts +0 -1
- package/types/logger/codesWarnNode.d.ts +0 -1
- package/types/logger/debugLogger.d.ts +0 -2
- package/types/logger/errorLogger.d.ts +0 -2
- package/types/logger/infoLogger.d.ts +0 -2
- package/types/logger/messages/debugBrowser.d.ts +0 -1
- package/types/logger/messages/debugNode.d.ts +0 -1
- package/types/logger/messages/errorNode.d.ts +0 -1
- package/types/logger/messages/warnNode.d.ts +0 -1
- package/types/logger/noopLogger.d.ts +0 -2
- package/types/logger/warnLogger.d.ts +0 -2
- package/types/sdkFactory/userConsentProps.d.ts +0 -6
- package/types/sdkManager/sdkManagerMethod.d.ts +0 -6
- package/types/storages/getRegisteredSegments.d.ts +0 -10
- package/types/storages/inMemory/index.d.ts +0 -10
- package/types/storages/parseSegments.d.ts +0 -6
- package/types/sync/polling/syncTasks/splitsSyncTask.copy.d.ts +0 -35
- package/types/sync/polling/syncTasks/splitsSyncTask.morelikeoriginal.d.ts +0 -35
- package/types/sync/streaming/AuthClient/indexV1.d.ts +0 -12
- package/types/sync/streaming/AuthClient/indexV2.d.ts +0 -8
- package/types/sync/streaming/pushManagerCS.d.ts +0 -1
- package/types/sync/streaming/pushManagerNoUsers.d.ts +0 -13
- package/types/sync/streaming/pushManagerSS.d.ts +0 -1
- package/types/sync/submitters/telemetrySyncTask.d.ts +0 -0
- package/types/sync/syncManagerFromFile.d.ts +0 -2
- package/types/sync/syncManagerFromObject.d.ts +0 -2
- package/types/sync/syncManagerOffline.d.ts +0 -9
- package/types/trackers/telemetryRecorder.d.ts +0 -0
- package/types/utils/EventEmitter.d.ts +0 -4
- package/types/utils/consent.d.ts +0 -2
- package/types/utils/lang/errors.d.ts +0 -10
- package/types/utils/murmur3/commons.d.ts +0 -12
- package/types/utils/settingsValidation/buildMetadata.d.ts +0 -3
- package/types/utils/settingsValidation/localhost/index.d.ts +0 -9
- package/types/utils/settingsValidation/logger.d.ts +0 -11
- package/types/utils/settingsValidation/runtime/browser.d.ts +0 -2
- package/types/utils/settingsValidation/runtime/node.d.ts +0 -2
- package/types/utils/settingsValidation/userConsent.d.ts +0 -5
|
@@ -4,6 +4,7 @@ import { impressionCountsSubmitterFactory } from './impressionCountsSubmitter';
|
|
|
4
4
|
import { telemetrySubmitterFactory } from './telemetrySubmitter';
|
|
5
5
|
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
6
6
|
import { ISubmitterManager } from './types';
|
|
7
|
+
import { uniqueKeysSubmitterFactory } from './uniqueKeysSubmitter';
|
|
7
8
|
|
|
8
9
|
export function submitterManagerFactory(params: ISdkFactoryContextSync): ISubmitterManager {
|
|
9
10
|
|
|
@@ -15,6 +16,7 @@ export function submitterManagerFactory(params: ISdkFactoryContextSync): ISubmit
|
|
|
15
16
|
const impressionCountsSubmitter = impressionCountsSubmitterFactory(params);
|
|
16
17
|
if (impressionCountsSubmitter) submitters.push(impressionCountsSubmitter);
|
|
17
18
|
const telemetrySubmitter = telemetrySubmitterFactory(params);
|
|
19
|
+
if (params.uniqueKeysTracker) submitters.push(uniqueKeysSubmitterFactory(params));
|
|
18
20
|
|
|
19
21
|
return {
|
|
20
22
|
// `onlyTelemetry` true if SDK is created with userConsent not GRANTED
|
|
@@ -35,6 +35,24 @@ export type ImpressionCountsPayload = {
|
|
|
35
35
|
}[]
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export type UniqueKeysPayloadSs = {
|
|
39
|
+
keys: {
|
|
40
|
+
/** Split name */
|
|
41
|
+
f: string
|
|
42
|
+
/** keyNames */
|
|
43
|
+
ks: string[]
|
|
44
|
+
}[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type UniqueKeysPayloadCs = {
|
|
48
|
+
keys: {
|
|
49
|
+
/** keyNames */
|
|
50
|
+
k: string
|
|
51
|
+
/** Split name */
|
|
52
|
+
fs: string[]
|
|
53
|
+
}[]
|
|
54
|
+
}
|
|
55
|
+
|
|
38
56
|
export type StoredImpressionWithMetadata = {
|
|
39
57
|
/** Metadata */
|
|
40
58
|
m: IMetadata,
|
|
@@ -148,7 +166,8 @@ export type OperationMode = STANDALONE_ENUM | CONSUMER_ENUM | CONSUMER_PARTIAL_E
|
|
|
148
166
|
|
|
149
167
|
export type OPTIMIZED_ENUM = 0;
|
|
150
168
|
export type DEBUG_ENUM = 1;
|
|
151
|
-
export type
|
|
169
|
+
export type NONE_ENUM = 2;
|
|
170
|
+
export type ImpressionsMode = OPTIMIZED_ENUM | DEBUG_ENUM | NONE_ENUM;
|
|
152
171
|
|
|
153
172
|
export type RefreshRates = {
|
|
154
173
|
sp: number, // splits
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
2
|
+
import { ISet, setToArray } from '../../utils/lang/sets';
|
|
3
|
+
import { submitterFactory } from './submitter';
|
|
4
|
+
import { UniqueKeysPayloadCs, UniqueKeysPayloadSs } from './types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Invert keys for feature to features for key
|
|
8
|
+
*/
|
|
9
|
+
function invertUniqueKeys(uniqueKeys: { [featureName: string]: ISet<string> }): { [key: string]: string[] } {
|
|
10
|
+
const featureNames = Object.keys(uniqueKeys);
|
|
11
|
+
const inverted: { [key: string]: string[] } = {};
|
|
12
|
+
for (let i = 0; i < featureNames.length; i++) {
|
|
13
|
+
const featureName = featureNames[i];
|
|
14
|
+
const featureKeys = setToArray(uniqueKeys[featureName]);
|
|
15
|
+
for (let j = 0; j< featureKeys.length; j++) {
|
|
16
|
+
const featureKey = featureKeys[j];
|
|
17
|
+
if (!inverted[featureKey]) inverted[featureKey] = [];
|
|
18
|
+
inverted[featureKey].push(featureName);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return inverted;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Converts `uniqueKeys` data from cache into request payload for CS.
|
|
26
|
+
*/
|
|
27
|
+
export function fromUniqueKeysCollectorCs(uniqueKeys: { [featureName: string]: ISet<string> }): UniqueKeysPayloadCs {
|
|
28
|
+
const payload = [];
|
|
29
|
+
const featuresPerKey = invertUniqueKeys(uniqueKeys);
|
|
30
|
+
const keys = Object.keys(featuresPerKey);
|
|
31
|
+
for (let k = 0; k < keys.length; k++) {
|
|
32
|
+
const key = keys[k];
|
|
33
|
+
const uniqueKeysPayload = {
|
|
34
|
+
k: key,
|
|
35
|
+
fs: featuresPerKey[key]
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
payload.push(uniqueKeysPayload);
|
|
39
|
+
}
|
|
40
|
+
return { keys: payload };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Converts `uniqueKeys` data from cache into request payload for SS.
|
|
45
|
+
*/
|
|
46
|
+
export function fromUniqueKeysCollectorSs(uniqueKeys: { [featureName: string]: ISet<string> }): UniqueKeysPayloadSs {
|
|
47
|
+
const payload = [];
|
|
48
|
+
const featureNames = Object.keys(uniqueKeys);
|
|
49
|
+
for (let i = 0; i < featureNames.length; i++) {
|
|
50
|
+
const featureName = featureNames[i];
|
|
51
|
+
const featureKeys = setToArray(uniqueKeys[featureName]);
|
|
52
|
+
const uniqueKeysPayload = {
|
|
53
|
+
f: featureName,
|
|
54
|
+
ks: featureKeys
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
payload.push(uniqueKeysPayload);
|
|
58
|
+
}
|
|
59
|
+
return { keys: payload };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Submitter that periodically posts impression counts
|
|
64
|
+
*/
|
|
65
|
+
export function uniqueKeysSubmitterFactory(params: ISdkFactoryContextSync) {
|
|
66
|
+
|
|
67
|
+
const {
|
|
68
|
+
settings: { log, scheduler: { uniqueKeysRefreshRate }, core: {key}},
|
|
69
|
+
splitApi: { postUniqueKeysBulkCs, postUniqueKeysBulkSs },
|
|
70
|
+
storage: { uniqueKeys }
|
|
71
|
+
} = params;
|
|
72
|
+
|
|
73
|
+
const isClientSide = key !== undefined;
|
|
74
|
+
const postUniqueKeysBulk = isClientSide ? postUniqueKeysBulkCs : postUniqueKeysBulkSs;
|
|
75
|
+
const fromUniqueKeysCollector = isClientSide ? fromUniqueKeysCollectorCs : fromUniqueKeysCollectorSs;
|
|
76
|
+
|
|
77
|
+
return submitterFactory(log, postUniqueKeysBulk, uniqueKeys!, uniqueKeysRefreshRate, 'unique keys', fromUniqueKeysCollector);
|
|
78
|
+
}
|
|
79
|
+
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
2
2
|
import { thenable } from '../utils/promise/thenable';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { IImpressionsHandler, IImpressionsTracker } from './types';
|
|
3
|
+
import { IImpressionsCacheBase, ITelemetryCacheSync, ITelemetryCacheAsync } from '../storages/types';
|
|
4
|
+
import { IImpressionsHandler, IImpressionsTracker, IStrategy } from './types';
|
|
6
5
|
import { SplitIO, ImpressionDTO, ISettings } from '../types';
|
|
7
|
-
import { IImpressionObserver } from './impressionObserver/types';
|
|
8
6
|
import { IMPRESSIONS_TRACKER_SUCCESS, ERROR_IMPRESSIONS_TRACKER, ERROR_IMPRESSIONS_LISTENER } from '../logger/constants';
|
|
9
7
|
import { CONSENT_DECLINED, DEDUPED, QUEUED } from '../utils/constants';
|
|
10
8
|
|
|
@@ -15,18 +13,14 @@ import { CONSENT_DECLINED, DEDUPED, QUEUED } from '../utils/constants';
|
|
|
15
13
|
* @param metadata runtime metadata (ip, hostname and version)
|
|
16
14
|
* @param impressionListener optional impression listener
|
|
17
15
|
* @param integrationsManager optional integrations manager
|
|
18
|
-
* @param
|
|
19
|
-
* @param countsCache optional cache to save impressions count. If provided, impressions will be deduped (OPTIMIZED mode)
|
|
16
|
+
* @param strategy strategy for impressions tracking.
|
|
20
17
|
*/
|
|
21
18
|
export function impressionsTrackerFactory(
|
|
22
19
|
settings: ISettings,
|
|
23
20
|
impressionsCache: IImpressionsCacheBase,
|
|
21
|
+
strategy: IStrategy,
|
|
24
22
|
integrationsManager?: IImpressionsHandler,
|
|
25
|
-
|
|
26
|
-
observer?: IImpressionObserver,
|
|
27
|
-
// if countsCache is provided, it implies `isOptimized` flag (i.e., if impressions should be deduped or not)
|
|
28
|
-
countsCache?: IImpressionCountsCacheSync,
|
|
29
|
-
telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync
|
|
23
|
+
telemetryCache?: ITelemetryCacheSync | ITelemetryCacheAsync,
|
|
30
24
|
): IImpressionsTracker {
|
|
31
25
|
|
|
32
26
|
const { log, impressionListener, runtime: { ip, hostname }, version } = settings;
|
|
@@ -37,26 +31,10 @@ export function impressionsTrackerFactory(
|
|
|
37
31
|
|
|
38
32
|
const impressionsCount = impressions.length;
|
|
39
33
|
|
|
40
|
-
const impressionsToStore
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Adds previous time if it is enabled
|
|
45
|
-
impression.pt = observer.testAndSet(impression);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const now = Date.now();
|
|
49
|
-
if (countsCache) {
|
|
50
|
-
// Increments impression counter per featureName
|
|
51
|
-
countsCache.track(impression.feature, now, 1);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Checks if the impression should be added in queue to be sent
|
|
55
|
-
if (!countsCache || !impression.pt || impression.pt < truncateTimeFrame(now)) {
|
|
56
|
-
impressionsToStore.push(impression);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
34
|
+
const { impressionsToStore, impressionsToListener, deduped } = strategy.process(impressions);
|
|
35
|
+
|
|
36
|
+
const impressionsToListenerCount = impressionsToListener.length;
|
|
37
|
+
|
|
60
38
|
const res = impressionsCache.track(impressionsToStore);
|
|
61
39
|
|
|
62
40
|
// If we're on an async storage, handle error and log it.
|
|
@@ -71,16 +49,16 @@ export function impressionsTrackerFactory(
|
|
|
71
49
|
// @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
|
|
72
50
|
if (telemetryCache) {
|
|
73
51
|
(telemetryCache as ITelemetryCacheSync).recordImpressionStats(QUEUED, impressionsToStore.length);
|
|
74
|
-
(telemetryCache as ITelemetryCacheSync).recordImpressionStats(DEDUPED,
|
|
52
|
+
(telemetryCache as ITelemetryCacheSync).recordImpressionStats(DEDUPED, deduped);
|
|
75
53
|
}
|
|
76
54
|
}
|
|
77
55
|
|
|
78
56
|
// @TODO next block might be handled by the integration manager. In that case, the metadata object doesn't need to be passed in the constructor
|
|
79
57
|
if (impressionListener || integrationsManager) {
|
|
80
|
-
for (let i = 0; i <
|
|
58
|
+
for (let i = 0; i < impressionsToListenerCount; i++) {
|
|
81
59
|
const impressionData: SplitIO.ImpressionData = {
|
|
82
60
|
// copy of impression, to avoid unexpected behaviour if modified by integrations or impressionListener
|
|
83
|
-
impression: objectAssign({},
|
|
61
|
+
impression: objectAssign({}, impressionsToListener[i]),
|
|
84
62
|
attributes,
|
|
85
63
|
ip,
|
|
86
64
|
hostname,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ImpressionDTO } from '../../types';
|
|
2
|
+
import { IImpressionObserver } from '../impressionObserver/types';
|
|
3
|
+
import { IStrategy } from '../types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Debug strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
|
|
7
|
+
*
|
|
8
|
+
* @param impressionsObserver impression observer. Previous time (pt property) is included in impression instances
|
|
9
|
+
* @returns IStrategyResult
|
|
10
|
+
*/
|
|
11
|
+
export function strategyDebugFactory(
|
|
12
|
+
impressionsObserver: IImpressionObserver
|
|
13
|
+
): IStrategy {
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
process(impressions: ImpressionDTO[]) {
|
|
17
|
+
impressions.forEach((impression) => {
|
|
18
|
+
// Adds previous time if it is enabled
|
|
19
|
+
impression.pt = impressionsObserver.testAndSet(impression);
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
impressionsToStore: impressions,
|
|
23
|
+
impressionsToListener: impressions,
|
|
24
|
+
deduped: 0
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { IImpressionCountsCacheSync } from '../../storages/types';
|
|
2
|
+
import { ImpressionDTO } from '../../types';
|
|
3
|
+
import { IStrategy, IUniqueKeysTracker } from '../types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* None strategy for impressions tracker.
|
|
7
|
+
*
|
|
8
|
+
* @param impressionsCounter cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
|
|
9
|
+
* @param uniqueKeysTracker unique keys tracker in charge of tracking the unique keys per split.
|
|
10
|
+
* @returns IStrategyResult
|
|
11
|
+
*/
|
|
12
|
+
export function strategyNoneFactory(
|
|
13
|
+
impressionsCounter: IImpressionCountsCacheSync,
|
|
14
|
+
uniqueKeysTracker: IUniqueKeysTracker
|
|
15
|
+
): IStrategy {
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
process(impressions: ImpressionDTO[]) {
|
|
19
|
+
impressions.forEach((impression) => {
|
|
20
|
+
const now = Date.now();
|
|
21
|
+
// Increments impression counter per featureName
|
|
22
|
+
impressionsCounter.track(impression.feature, now, 1);
|
|
23
|
+
// Keep track by unique key
|
|
24
|
+
uniqueKeysTracker.track(impression.feature, impression.keyName);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
impressionsToStore: [],
|
|
29
|
+
impressionsToListener: impressions,
|
|
30
|
+
deduped: 0
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IImpressionCountsCacheSync } from '../../storages/types';
|
|
2
|
+
import { ImpressionDTO } from '../../types';
|
|
3
|
+
import { truncateTimeFrame } from '../../utils/time';
|
|
4
|
+
import { IImpressionObserver } from '../impressionObserver/types';
|
|
5
|
+
import { IStrategy } from '../types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Optimized strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
|
|
9
|
+
*
|
|
10
|
+
* @param impressionsObserver impression observer. previous time (pt property) is included in impression instances
|
|
11
|
+
* @param impressionsCounter cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
|
|
12
|
+
* @returns IStrategyResult
|
|
13
|
+
*/
|
|
14
|
+
export function strategyOptimizedFactory(
|
|
15
|
+
impressionsObserver: IImpressionObserver,
|
|
16
|
+
impressionsCounter: IImpressionCountsCacheSync,
|
|
17
|
+
): IStrategy {
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
process(impressions: ImpressionDTO[]) {
|
|
21
|
+
const impressionsToStore: ImpressionDTO[] = [];
|
|
22
|
+
impressions.forEach((impression) => {
|
|
23
|
+
impression.pt = impressionsObserver.testAndSet(impression);
|
|
24
|
+
|
|
25
|
+
const now = Date.now();
|
|
26
|
+
|
|
27
|
+
// Increments impression counter per featureName
|
|
28
|
+
impressionsCounter.track(impression.feature, now, 1);
|
|
29
|
+
|
|
30
|
+
// Checks if the impression should be added in queue to be sent
|
|
31
|
+
if (!impression.pt || impression.pt < truncateTimeFrame(now)) {
|
|
32
|
+
impressionsToStore.push(impression);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
impressionsToStore: impressionsToStore,
|
|
37
|
+
impressionsToListener: impressions,
|
|
38
|
+
deduped: impressions.length - impressionsToStore.length
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
package/src/trackers/types.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { SplitIO, ImpressionDTO } from '../types';
|
|
|
2
2
|
import { StreamingEventType, Method, OperationType } from '../sync/submitters/types';
|
|
3
3
|
import { IEventsCacheBase } from '../storages/types';
|
|
4
4
|
import { NetworkError } from '../services/types';
|
|
5
|
+
import { ISet } from '../utils/lang/sets';
|
|
5
6
|
|
|
6
7
|
/** Events tracker */
|
|
7
8
|
|
|
@@ -42,3 +43,32 @@ export interface ITelemetryTracker {
|
|
|
42
43
|
*/
|
|
43
44
|
streamingEvent(e: StreamingEventType | AUTH_REJECTION, d?: number): void
|
|
44
45
|
}
|
|
46
|
+
|
|
47
|
+
export interface IFilterAdapter {
|
|
48
|
+
add(featureName: string, key: string): boolean;
|
|
49
|
+
contains(featureName: string, key: string): boolean;
|
|
50
|
+
clear(): void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface IImpressionSenderAdapter {
|
|
54
|
+
recordUniqueKeys(data: Object): void;
|
|
55
|
+
recordImpressionCounts(data: Object): void
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Unique keys tracker */
|
|
59
|
+
export interface IUniqueKeysTracker {
|
|
60
|
+
track(featureName: string, key: string): void;
|
|
61
|
+
pop(toMerge?: { [featureName: string]: ISet<string> }): { [featureName: string]: ISet<string>; };
|
|
62
|
+
clear(): void;
|
|
63
|
+
isEmpty(): boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface IStrategyResult {
|
|
67
|
+
impressionsToStore: ImpressionDTO[],
|
|
68
|
+
impressionsToListener: ImpressionDTO[],
|
|
69
|
+
deduped: number
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface IStrategy {
|
|
73
|
+
process(impressions: ImpressionDTO[]): IStrategyResult
|
|
74
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { LOG_PREFIX_UNIQUE_KEYS_TRACKER } from '../logger/constants';
|
|
2
|
+
import { ILogger } from '../logger/types';
|
|
3
|
+
import { ISet, _Set } from '../utils/lang/sets';
|
|
4
|
+
import { IFilterAdapter, IUniqueKeysTracker } from './types';
|
|
5
|
+
|
|
6
|
+
const noopFilterAdapter = {
|
|
7
|
+
add() {return true;},
|
|
8
|
+
contains() {return true;},
|
|
9
|
+
clear() {}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const DEFAULT_CACHE_SIZE = 30000;
|
|
13
|
+
/**
|
|
14
|
+
* Trackes uniques keys
|
|
15
|
+
* Unique Keys Tracker will be in charge of checking if the MTK was already sent to the BE in the last period
|
|
16
|
+
* or schedule to be sent; if not it will be added in an internal cache and sent in the next post.
|
|
17
|
+
*
|
|
18
|
+
* @param log Logger instance
|
|
19
|
+
* @param filterAdapter filter adapter
|
|
20
|
+
* @param cacheSize optional internal cache size
|
|
21
|
+
* @param maxBulkSize optional max MTKs bulk size
|
|
22
|
+
*/
|
|
23
|
+
export function uniqueKeysTrackerFactory(
|
|
24
|
+
log: ILogger,
|
|
25
|
+
filterAdapter: IFilterAdapter = noopFilterAdapter,
|
|
26
|
+
cacheSize = DEFAULT_CACHE_SIZE,
|
|
27
|
+
// @TODO
|
|
28
|
+
// maxBulkSize: number = 5000,
|
|
29
|
+
): IUniqueKeysTracker {
|
|
30
|
+
|
|
31
|
+
let uniqueKeysTracker: { [featureName: string]: ISet<string> } = {};
|
|
32
|
+
let uniqueTrackerSize = 0;
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
track(featureName: string, key: string): void {
|
|
36
|
+
if (!filterAdapter.add(featureName, key)) {
|
|
37
|
+
log.debug(`${LOG_PREFIX_UNIQUE_KEYS_TRACKER}The feature ${featureName} and key ${key} exist in the filter`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!uniqueKeysTracker[featureName]) uniqueKeysTracker[featureName] = new _Set();
|
|
41
|
+
const tracker = uniqueKeysTracker[featureName];
|
|
42
|
+
if (!tracker.has(key)) {
|
|
43
|
+
tracker.add(key);
|
|
44
|
+
log.debug(`${LOG_PREFIX_UNIQUE_KEYS_TRACKER}Key ${key} added to feature ${featureName}`);
|
|
45
|
+
uniqueTrackerSize++;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (uniqueTrackerSize >= cacheSize) {
|
|
49
|
+
log.warn(`${LOG_PREFIX_UNIQUE_KEYS_TRACKER}The UniqueKeysTracker size reached the maximum limit`);
|
|
50
|
+
// @TODO trigger event to submitter to send mtk
|
|
51
|
+
uniqueTrackerSize = 0;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Pop the collected data, used as payload for posting.
|
|
57
|
+
*/
|
|
58
|
+
pop() {
|
|
59
|
+
const data = uniqueKeysTracker;
|
|
60
|
+
uniqueKeysTracker = {};
|
|
61
|
+
return data;
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Clear the data stored on the cache.
|
|
66
|
+
*/
|
|
67
|
+
clear() {
|
|
68
|
+
uniqueKeysTracker = {};
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Check if the cache is empty.
|
|
73
|
+
*/
|
|
74
|
+
isEmpty() {
|
|
75
|
+
return Object.keys(uniqueKeysTracker).length === 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -80,6 +80,7 @@ export interface ISettings {
|
|
|
80
80
|
featuresRefreshRate: number,
|
|
81
81
|
impressionsRefreshRate: number,
|
|
82
82
|
impressionsQueueSize: number,
|
|
83
|
+
uniqueKeysRefreshRate: number,
|
|
83
84
|
/**
|
|
84
85
|
* @deprecated
|
|
85
86
|
*/
|
|
@@ -718,7 +719,7 @@ export namespace SplitIO {
|
|
|
718
719
|
* ImpressionsMode type
|
|
719
720
|
* @typedef {string} ImpressionsMode
|
|
720
721
|
*/
|
|
721
|
-
export type ImpressionsMode = 'OPTIMIZED' | 'DEBUG'
|
|
722
|
+
export type ImpressionsMode = 'OPTIMIZED' | 'DEBUG' | 'NONE'
|
|
722
723
|
/**
|
|
723
724
|
* Defines the format of Split data to preload on the factory storage (cache).
|
|
724
725
|
*/
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { ERROR_INVALID_CONFIG_PARAM } from '../../logger/constants';
|
|
2
2
|
import { ILogger } from '../../logger/types';
|
|
3
3
|
import { SplitIO } from '../../types';
|
|
4
|
-
import { DEBUG, OPTIMIZED } from '../constants';
|
|
4
|
+
import { DEBUG, OPTIMIZED, NONE } from '../constants';
|
|
5
5
|
import { stringToUpperCase } from '../lang';
|
|
6
6
|
|
|
7
7
|
export function validImpressionsMode(log: ILogger, impressionsMode: any): SplitIO.ImpressionsMode {
|
|
8
8
|
impressionsMode = stringToUpperCase(impressionsMode);
|
|
9
9
|
|
|
10
|
-
if ([DEBUG, OPTIMIZED].indexOf(impressionsMode) > -1) return impressionsMode;
|
|
10
|
+
if ([DEBUG, OPTIMIZED, NONE].indexOf(impressionsMode) > -1) return impressionsMode;
|
|
11
11
|
|
|
12
|
-
log.error(ERROR_INVALID_CONFIG_PARAM, ['impressionsMode', [DEBUG, OPTIMIZED], OPTIMIZED]);
|
|
12
|
+
log.error(ERROR_INVALID_CONFIG_PARAM, ['impressionsMode', [DEBUG, OPTIMIZED, NONE], OPTIMIZED]);
|
|
13
13
|
return OPTIMIZED;
|
|
14
14
|
}
|
|
@@ -36,6 +36,8 @@ export const base = {
|
|
|
36
36
|
telemetryRefreshRate: 3600,
|
|
37
37
|
// publish evaluations each 300 sec (default value for OPTIMIZED impressions mode)
|
|
38
38
|
impressionsRefreshRate: 300,
|
|
39
|
+
// publish unique Keys each 900 sec (15 min)
|
|
40
|
+
uniqueKeysRefreshRate: 900,
|
|
39
41
|
// fetch offline changes each 15 sec
|
|
40
42
|
offlineRefreshRate: 15,
|
|
41
43
|
// publish events every 60 seconds after the first flush
|
|
@@ -130,11 +132,13 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
|
|
|
130
132
|
scheduler.segmentsRefreshRate = fromSecondsToMillis(scheduler.segmentsRefreshRate);
|
|
131
133
|
scheduler.offlineRefreshRate = fromSecondsToMillis(scheduler.offlineRefreshRate);
|
|
132
134
|
scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate);
|
|
135
|
+
scheduler.uniqueKeysRefreshRate = fromSecondsToMillis(scheduler.uniqueKeysRefreshRate);
|
|
133
136
|
scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
|
|
134
137
|
|
|
135
138
|
// Default impressionsRefreshRate for DEBUG mode is 60 secs
|
|
136
139
|
if (get(config, 'scheduler.impressionsRefreshRate') === undefined && withDefaults.sync.impressionsMode === DEBUG) scheduler.impressionsRefreshRate = 60;
|
|
137
140
|
scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
|
|
141
|
+
|
|
138
142
|
|
|
139
143
|
// Log deprecation for old telemetry param
|
|
140
144
|
if (scheduler.metricsRefreshRate) log.warn('`metricsRefreshRate` will be deprecated soon. For configuring telemetry rates, update `telemetryRefreshRate` value in configs');
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { IntegrationFactory } from '../types';
|
|
2
2
|
import { GoogleAnalyticsToSplitOptions } from './types';
|
|
3
|
-
export declare function GoogleAnalyticsToSplit(options
|
|
3
|
+
export declare function GoogleAnalyticsToSplit(options?: GoogleAnalyticsToSplitOptions): IntegrationFactory;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -138,4 +138,5 @@ export declare const LOG_PREFIX_SYNC_POLLING: string;
|
|
|
138
138
|
export declare const LOG_PREFIX_SYNC_SUBMITTERS: string;
|
|
139
139
|
export declare const LOG_PREFIX_IMPRESSIONS_TRACKER = "impressions-tracker: ";
|
|
140
140
|
export declare const LOG_PREFIX_EVENTS_TRACKER = "events-tracker: ";
|
|
141
|
+
export declare const LOG_PREFIX_UNIQUE_KEYS_TRACKER = "unique-keys-tracker: ";
|
|
141
142
|
export declare const LOG_PREFIX_CLEANUP = "cleanup: ";
|
|
@@ -6,7 +6,7 @@ import { IFetch, ISplitApi, IEventSourceConstructor } from '../services/types';
|
|
|
6
6
|
import { IStorageAsync, IStorageSync, ISplitsCacheSync, ISplitsCacheAsync, IStorageFactoryParams } from '../storages/types';
|
|
7
7
|
import { ISyncManager } from '../sync/types';
|
|
8
8
|
import { IImpressionObserver } from '../trackers/impressionObserver/types';
|
|
9
|
-
import { IImpressionsTracker, IEventTracker, ITelemetryTracker } from '../trackers/types';
|
|
9
|
+
import { IImpressionsTracker, IEventTracker, ITelemetryTracker, IFilterAdapter, IUniqueKeysTracker } from '../trackers/types';
|
|
10
10
|
import { SplitIO, ISettings, IEventEmitter } from '../types';
|
|
11
11
|
/**
|
|
12
12
|
* Environment related dependencies.
|
|
@@ -42,6 +42,7 @@ export interface ISdkFactoryContext {
|
|
|
42
42
|
eventTracker: IEventTracker;
|
|
43
43
|
telemetryTracker: ITelemetryTracker;
|
|
44
44
|
storage: IStorageSync | IStorageAsync;
|
|
45
|
+
uniqueKeysTracker?: IUniqueKeysTracker;
|
|
45
46
|
signalListener?: ISignalListener;
|
|
46
47
|
splitApi?: ISplitApi;
|
|
47
48
|
syncManager?: ISyncManager;
|
|
@@ -70,11 +71,12 @@ export interface ISdkFactoryParams {
|
|
|
70
71
|
(): SplitIO.ICsClient;
|
|
71
72
|
(key: SplitIO.SplitKey, trafficType?: string | undefined): SplitIO.ICsClient;
|
|
72
73
|
} | (() => SplitIO.IClient) | (() => SplitIO.IAsyncClient));
|
|
74
|
+
impressionsObserverFactory: () => IImpressionObserver;
|
|
75
|
+
filterAdapterFactory?: () => IFilterAdapter;
|
|
73
76
|
SignalListener?: new (syncManager: ISyncManager | undefined, // Used by NodeSignalListener to flush data, and by BrowserSignalListener to close streaming connection.
|
|
74
77
|
settings: ISettings, // Used by BrowserSignalListener
|
|
75
78
|
storage: IStorageSync | IStorageAsync, // Used by BrowserSignalListener
|
|
76
79
|
serviceApi: ISplitApi | undefined) => ISignalListener;
|
|
77
80
|
integrationsManagerFactory?: (params: IIntegrationFactoryParams) => IIntegrationManager | undefined;
|
|
78
|
-
impressionsObserverFactory?: () => IImpressionObserver;
|
|
79
81
|
extraProps?: (params: ISdkFactoryContext) => object;
|
|
80
82
|
}
|
|
@@ -20,6 +20,8 @@ export declare type IFetchSplitChanges = (since: number, noCache?: boolean, till
|
|
|
20
20
|
export declare type IFetchSegmentChanges = (since: number, segmentName: string, noCache?: boolean, till?: number) => Promise<IResponse>;
|
|
21
21
|
export declare type IFetchMySegments = (userMatchingKey: string, noCache?: boolean) => Promise<IResponse>;
|
|
22
22
|
export declare type IPostEventsBulk = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
|
|
23
|
+
export declare type IPostUniqueKeysBulkCs = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
|
|
24
|
+
export declare type IPostUniqueKeysBulkSs = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
|
|
23
25
|
export declare type IPostTestImpressionsBulk = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
|
|
24
26
|
export declare type IPostTestImpressionsCount = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
|
|
25
27
|
export declare type IPostMetricsConfig = (body: string) => Promise<IResponse>;
|
|
@@ -32,6 +34,8 @@ export interface ISplitApi {
|
|
|
32
34
|
fetchSegmentChanges: IFetchSegmentChanges;
|
|
33
35
|
fetchMySegments: IFetchMySegments;
|
|
34
36
|
postEventsBulk: IPostEventsBulk;
|
|
37
|
+
postUniqueKeysBulkCs: IPostUniqueKeysBulkCs;
|
|
38
|
+
postUniqueKeysBulkSs: IPostUniqueKeysBulkSs;
|
|
35
39
|
postTestImpressionsBulk: IPostTestImpressionsBulk;
|
|
36
40
|
postTestImpressionsCount: IPostTestImpressionsCount;
|
|
37
41
|
postMetricsConfig: IPostMetricsConfig;
|
|
@@ -2,6 +2,7 @@ import { MaybeThenable, IMetadata, ISplitFiltersValidation } from '../dtos/types
|
|
|
2
2
|
import { ILogger } from '../logger/types';
|
|
3
3
|
import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent } from '../sync/submitters/types';
|
|
4
4
|
import { SplitIO, ImpressionDTO, SDKMode } from '../types';
|
|
5
|
+
import { ISet } from '../utils/lang/sets';
|
|
5
6
|
/**
|
|
6
7
|
* Interface of a pluggable storage wrapper.
|
|
7
8
|
*/
|
|
@@ -297,6 +298,17 @@ export interface IImpressionCountsCacheSync extends IRecorderCacheProducerSync<R
|
|
|
297
298
|
isEmpty(): boolean;
|
|
298
299
|
pop(toMerge?: Record<string, number>): Record<string, number>;
|
|
299
300
|
}
|
|
301
|
+
export interface IUniqueKeysCacheBase extends IRecorderCacheProducerSync<{
|
|
302
|
+
[featureName: string]: ISet<string>;
|
|
303
|
+
}> {
|
|
304
|
+
track(featureName: string, timeFrame: number, amount: number): void;
|
|
305
|
+
isEmpty(): boolean;
|
|
306
|
+
pop(toMerge?: {
|
|
307
|
+
[featureName: string]: ISet<string>;
|
|
308
|
+
}): {
|
|
309
|
+
[featureName: string]: ISet<string>;
|
|
310
|
+
};
|
|
311
|
+
}
|
|
300
312
|
/**
|
|
301
313
|
* Telemetry storage interface for standalone and partial consumer modes.
|
|
302
314
|
* Methods are sync because data is stored in memory.
|
|
@@ -366,19 +378,20 @@ export interface ITelemetryCacheAsync extends ITelemetryEvaluationProducerAsync
|
|
|
366
378
|
/**
|
|
367
379
|
* Storages
|
|
368
380
|
*/
|
|
369
|
-
export interface IStorageBase<TSplitsCache extends ISplitsCacheBase, TSegmentsCache extends ISegmentsCacheBase, TImpressionsCache extends IImpressionsCacheBase, TEventsCache extends IEventsCacheBase, TTelemetryCache extends ITelemetryCacheSync | ITelemetryCacheAsync> {
|
|
381
|
+
export interface IStorageBase<TSplitsCache extends ISplitsCacheBase, TSegmentsCache extends ISegmentsCacheBase, TImpressionsCache extends IImpressionsCacheBase, TEventsCache extends IEventsCacheBase, TTelemetryCache extends ITelemetryCacheSync | ITelemetryCacheAsync, TUniqueKeysCache extends IUniqueKeysCacheBase> {
|
|
370
382
|
splits: TSplitsCache;
|
|
371
383
|
segments: TSegmentsCache;
|
|
372
384
|
impressions: TImpressionsCache;
|
|
373
385
|
impressionCounts?: IImpressionCountsCacheSync;
|
|
374
386
|
events: TEventsCache;
|
|
375
387
|
telemetry?: TTelemetryCache;
|
|
388
|
+
uniqueKeys?: TUniqueKeysCache;
|
|
376
389
|
destroy(): void | Promise<void>;
|
|
377
390
|
shared?: (matchingKey: string, onReadyCb: (error?: any) => void) => this;
|
|
378
391
|
}
|
|
379
|
-
export interface IStorageSync extends IStorageBase<ISplitsCacheSync, ISegmentsCacheSync, IImpressionsCacheSync, IEventsCacheSync, ITelemetryCacheSync> {
|
|
392
|
+
export interface IStorageSync extends IStorageBase<ISplitsCacheSync, ISegmentsCacheSync, IImpressionsCacheSync, IEventsCacheSync, ITelemetryCacheSync, IUniqueKeysCacheBase> {
|
|
380
393
|
}
|
|
381
|
-
export interface IStorageAsync extends IStorageBase<ISplitsCacheAsync, ISegmentsCacheAsync, IImpressionsCacheAsync | IImpressionsCacheSync, IEventsCacheAsync | IEventsCacheSync, ITelemetryCacheAsync> {
|
|
394
|
+
export interface IStorageAsync extends IStorageBase<ISplitsCacheAsync, ISegmentsCacheAsync, IImpressionsCacheAsync | IImpressionsCacheSync, IEventsCacheAsync | IEventsCacheSync, ITelemetryCacheAsync, IUniqueKeysCacheBase> {
|
|
382
395
|
}
|
|
383
396
|
/** StorageFactory */
|
|
384
397
|
export declare type DataLoader = (storage: IStorageSync, matchingKey: string) => void;
|