@splitsoftware/splitio-commons 2.1.0-rc.0 → 2.1.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +11 -0
- package/LICENSE +1 -1
- package/cjs/evaluator/index.js +2 -0
- package/cjs/evaluator/matchers/large_segment.js +0 -6
- package/cjs/evaluator/matchers/segment.js +0 -6
- package/cjs/listeners/browser.js +4 -6
- package/cjs/readiness/readinessManager.js +6 -0
- package/cjs/sdkClient/client.js +14 -11
- package/cjs/sdkClient/sdkClient.js +1 -1
- package/cjs/sdkFactory/index.js +9 -14
- package/cjs/sdkManager/index.js +2 -1
- package/cjs/storages/inLocalStorage/index.js +4 -3
- package/cjs/storages/inLocalStorage/validateCache.js +1 -2
- package/cjs/storages/inMemory/InMemoryStorage.js +5 -7
- package/cjs/storages/inMemory/InMemoryStorageCS.js +6 -7
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/index.js +9 -13
- package/cjs/storages/pluggable/index.js +15 -19
- package/cjs/sync/submitters/impressionCountsSubmitter.js +2 -4
- package/cjs/sync/submitters/submitterManager.js +3 -6
- package/cjs/trackers/impressionsTracker.js +17 -18
- package/cjs/trackers/strategy/strategyDebug.js +4 -11
- package/cjs/trackers/strategy/strategyNone.js +11 -16
- package/cjs/trackers/strategy/strategyOptimized.js +11 -21
- package/esm/evaluator/index.js +2 -0
- package/esm/evaluator/matchers/large_segment.js +0 -6
- package/esm/evaluator/matchers/segment.js +0 -6
- package/esm/listeners/browser.js +1 -3
- package/esm/readiness/readinessManager.js +6 -0
- package/esm/sdkClient/client.js +14 -11
- package/esm/sdkClient/sdkClient.js +1 -1
- package/esm/sdkFactory/index.js +10 -15
- package/esm/sdkManager/index.js +2 -1
- package/esm/storages/inLocalStorage/index.js +5 -4
- package/esm/storages/inLocalStorage/validateCache.js +1 -2
- package/esm/storages/inMemory/InMemoryStorage.js +6 -8
- package/esm/storages/inMemory/InMemoryStorageCS.js +7 -8
- package/esm/storages/inRedis/SplitsCacheInRedis.js +1 -1
- package/esm/storages/inRedis/index.js +10 -14
- package/esm/storages/pluggable/index.js +16 -20
- package/esm/sync/submitters/impressionCountsSubmitter.js +2 -4
- package/esm/sync/submitters/submitterManager.js +3 -6
- package/esm/trackers/impressionsTracker.js +17 -18
- package/esm/trackers/strategy/strategyDebug.js +4 -11
- package/esm/trackers/strategy/strategyNone.js +11 -16
- package/esm/trackers/strategy/strategyOptimized.js +11 -21
- package/package.json +1 -1
- package/src/dtos/types.ts +2 -1
- package/src/evaluator/index.ts +2 -0
- package/src/evaluator/matchers/large_segment.ts +0 -7
- package/src/evaluator/matchers/segment.ts +0 -7
- package/src/evaluator/types.ts +1 -1
- package/src/listeners/browser.ts +1 -3
- package/src/readiness/readinessManager.ts +5 -0
- package/src/sdkClient/client.ts +19 -15
- package/src/sdkClient/sdkClient.ts +1 -1
- package/src/sdkFactory/index.ts +11 -16
- package/src/sdkFactory/types.ts +1 -1
- package/src/sdkManager/index.ts +2 -1
- package/src/storages/inLocalStorage/index.ts +5 -4
- package/src/storages/inLocalStorage/validateCache.ts +1 -2
- package/src/storages/inMemory/InMemoryStorage.ts +6 -6
- package/src/storages/inMemory/InMemoryStorageCS.ts +7 -6
- package/src/storages/inRedis/SplitsCacheInRedis.ts +1 -1
- package/src/storages/inRedis/index.ts +10 -10
- package/src/storages/pluggable/index.ts +16 -20
- package/src/storages/types.ts +2 -2
- package/src/sync/submitters/impressionCountsSubmitter.ts +2 -4
- package/src/sync/submitters/submitterManager.ts +3 -4
- package/src/sync/submitters/uniqueKeysSubmitter.ts +2 -3
- package/src/trackers/impressionsTracker.ts +18 -19
- package/src/trackers/strategy/strategyDebug.ts +4 -11
- package/src/trackers/strategy/strategyNone.ts +11 -17
- package/src/trackers/strategy/strategyOptimized.ts +10 -20
- package/src/trackers/types.ts +13 -8
- package/types/splitio.d.ts +4 -0
|
@@ -6,14 +6,11 @@ import { uniqueKeysSubmitterFactory } from './uniqueKeysSubmitter';
|
|
|
6
6
|
export function submitterManagerFactory(params) {
|
|
7
7
|
var submitters = [
|
|
8
8
|
impressionsSubmitterFactory(params),
|
|
9
|
-
eventsSubmitterFactory(params)
|
|
9
|
+
eventsSubmitterFactory(params),
|
|
10
|
+
impressionCountsSubmitterFactory(params),
|
|
11
|
+
uniqueKeysSubmitterFactory(params)
|
|
10
12
|
];
|
|
11
|
-
var impressionCountsSubmitter = impressionCountsSubmitterFactory(params);
|
|
12
|
-
if (impressionCountsSubmitter)
|
|
13
|
-
submitters.push(impressionCountsSubmitter);
|
|
14
13
|
var telemetrySubmitter = telemetrySubmitterFactory(params);
|
|
15
|
-
if (params.storage.uniqueKeys)
|
|
16
|
-
submitters.push(uniqueKeysSubmitterFactory(params));
|
|
17
14
|
return {
|
|
18
15
|
// `onlyTelemetry` true if SDK is created with userConsent not GRANTED
|
|
19
16
|
start: function (onlyTelemetry) {
|
|
@@ -4,38 +4,37 @@ import { IMPRESSIONS_TRACKER_SUCCESS, ERROR_IMPRESSIONS_TRACKER, ERROR_IMPRESSIO
|
|
|
4
4
|
import { CONSENT_DECLINED, DEDUPED, QUEUED } from '../utils/constants';
|
|
5
5
|
/**
|
|
6
6
|
* Impressions tracker stores impressions in cache and pass them to the listener and integrations manager if provided.
|
|
7
|
-
*
|
|
8
|
-
* @param impressionsCache - cache to save impressions
|
|
9
|
-
* @param metadata - runtime metadata (ip, hostname and version)
|
|
10
|
-
* @param impressionListener - optional impression listener
|
|
11
|
-
* @param integrationsManager - optional integrations manager
|
|
12
|
-
* @param strategy - strategy for impressions tracking.
|
|
13
7
|
*/
|
|
14
|
-
export function impressionsTrackerFactory(settings, impressionsCache, strategy, whenInit, integrationsManager, telemetryCache) {
|
|
8
|
+
export function impressionsTrackerFactory(settings, impressionsCache, noneStrategy, strategy, whenInit, integrationsManager, telemetryCache) {
|
|
15
9
|
var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version;
|
|
16
10
|
return {
|
|
17
11
|
track: function (impressions, attributes) {
|
|
18
12
|
if (settings.userConsent === CONSENT_DECLINED)
|
|
19
13
|
return;
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
var impressionsToStore = impressions.filter(function (_a) {
|
|
15
|
+
var imp = _a.imp, disabled = _a.disabled;
|
|
16
|
+
return disabled ?
|
|
17
|
+
noneStrategy.process(imp) :
|
|
18
|
+
strategy.process(imp);
|
|
19
|
+
});
|
|
20
|
+
var impressionsLength = impressions.length;
|
|
21
|
+
var impressionsToStoreLength = impressionsToStore.length;
|
|
22
|
+
if (impressionsToStoreLength) {
|
|
23
|
+
var res = impressionsCache.track(impressionsToStore.map(function (item) { return item.imp; }));
|
|
25
24
|
// If we're on an async storage, handle error and log it.
|
|
26
25
|
if (thenable(res)) {
|
|
27
26
|
res.then(function () {
|
|
28
|
-
log.info(IMPRESSIONS_TRACKER_SUCCESS, [
|
|
27
|
+
log.info(IMPRESSIONS_TRACKER_SUCCESS, [impressionsLength]);
|
|
29
28
|
}).catch(function (err) {
|
|
30
|
-
log.error(ERROR_IMPRESSIONS_TRACKER, [
|
|
29
|
+
log.error(ERROR_IMPRESSIONS_TRACKER, [impressionsLength, err]);
|
|
31
30
|
});
|
|
32
31
|
}
|
|
33
32
|
else {
|
|
34
33
|
// Record when impressionsCache is sync only (standalone mode)
|
|
35
34
|
// @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
|
|
36
35
|
if (telemetryCache) {
|
|
37
|
-
telemetryCache.recordImpressionStats(QUEUED,
|
|
38
|
-
telemetryCache.recordImpressionStats(DEDUPED,
|
|
36
|
+
telemetryCache.recordImpressionStats(QUEUED, impressionsToStoreLength);
|
|
37
|
+
telemetryCache.recordImpressionStats(DEDUPED, impressionsLength - impressionsToStoreLength);
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
}
|
|
@@ -44,7 +43,7 @@ export function impressionsTrackerFactory(settings, impressionsCache, strategy,
|
|
|
44
43
|
var _loop_1 = function (i) {
|
|
45
44
|
var impressionData = {
|
|
46
45
|
// copy of impression, to avoid unexpected behavior if modified by integrations or impressionListener
|
|
47
|
-
impression: objectAssign({},
|
|
46
|
+
impression: objectAssign({}, impressions[i].imp),
|
|
48
47
|
attributes: attributes,
|
|
49
48
|
ip: ip,
|
|
50
49
|
hostname: hostname,
|
|
@@ -66,7 +65,7 @@ export function impressionsTrackerFactory(settings, impressionsCache, strategy,
|
|
|
66
65
|
});
|
|
67
66
|
});
|
|
68
67
|
};
|
|
69
|
-
for (var i = 0; i <
|
|
68
|
+
for (var i = 0; i < impressionsLength; i++) {
|
|
70
69
|
_loop_1(i);
|
|
71
70
|
}
|
|
72
71
|
}
|
|
@@ -2,20 +2,13 @@
|
|
|
2
2
|
* Debug strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
|
|
3
3
|
*
|
|
4
4
|
* @param impressionsObserver - impression observer. Previous time (pt property) is included in impression instances
|
|
5
|
-
* @returns
|
|
5
|
+
* @returns Debug strategy
|
|
6
6
|
*/
|
|
7
7
|
export function strategyDebugFactory(impressionsObserver) {
|
|
8
8
|
return {
|
|
9
|
-
process: function (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
impression.pt = impressionsObserver.testAndSet(impression);
|
|
13
|
-
});
|
|
14
|
-
return {
|
|
15
|
-
impressionsToStore: impressions,
|
|
16
|
-
impressionsToListener: impressions,
|
|
17
|
-
deduped: 0
|
|
18
|
-
};
|
|
9
|
+
process: function (impression) {
|
|
10
|
+
impression.pt = impressionsObserver.testAndSet(impression);
|
|
11
|
+
return true;
|
|
19
12
|
}
|
|
20
13
|
};
|
|
21
14
|
}
|
|
@@ -1,25 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* None strategy for impressions tracker.
|
|
3
3
|
*
|
|
4
|
-
* @param
|
|
4
|
+
* @param impressionCounts - cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
|
|
5
5
|
* @param uniqueKeysTracker - unique keys tracker in charge of tracking the unique keys per split.
|
|
6
|
-
* @returns
|
|
6
|
+
* @returns None strategy
|
|
7
7
|
*/
|
|
8
|
-
export function strategyNoneFactory(
|
|
8
|
+
export function strategyNoneFactory(impressionCounts, uniqueKeysTracker) {
|
|
9
9
|
return {
|
|
10
|
-
process: function (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
impressionsToStore: [],
|
|
20
|
-
impressionsToListener: impressions,
|
|
21
|
-
deduped: 0
|
|
22
|
-
};
|
|
10
|
+
process: function (impression) {
|
|
11
|
+
var now = Date.now();
|
|
12
|
+
// Increments impression counter per featureName
|
|
13
|
+
impressionCounts.track(impression.feature, now, 1);
|
|
14
|
+
// Keep track by unique key
|
|
15
|
+
uniqueKeysTracker.track(impression.keyName, impression.feature);
|
|
16
|
+
// Do not store impressions
|
|
17
|
+
return false;
|
|
23
18
|
}
|
|
24
19
|
};
|
|
25
20
|
}
|
|
@@ -3,29 +3,19 @@ import { truncateTimeFrame } from '../../utils/time';
|
|
|
3
3
|
* Optimized strategy for impressions tracker. Wraps impressions to store and adds previousTime if it corresponds
|
|
4
4
|
*
|
|
5
5
|
* @param impressionsObserver - impression observer. previous time (pt property) is included in impression instances
|
|
6
|
-
* @param
|
|
7
|
-
* @returns
|
|
6
|
+
* @param impressionCounts - cache to save impressions count. impressions will be deduped (OPTIMIZED mode)
|
|
7
|
+
* @returns Optimized strategy
|
|
8
8
|
*/
|
|
9
|
-
export function strategyOptimizedFactory(impressionsObserver,
|
|
9
|
+
export function strategyOptimizedFactory(impressionsObserver, impressionCounts) {
|
|
10
10
|
return {
|
|
11
|
-
process: function (
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// Checks if the impression should be added in queue to be sent
|
|
20
|
-
if (!impression.pt || impression.pt < truncateTimeFrame(now)) {
|
|
21
|
-
impressionsToStore.push(impression);
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
return {
|
|
25
|
-
impressionsToStore: impressionsToStore,
|
|
26
|
-
impressionsToListener: impressions,
|
|
27
|
-
deduped: impressions.length - impressionsToStore.length
|
|
28
|
-
};
|
|
11
|
+
process: function (impression) {
|
|
12
|
+
impression.pt = impressionsObserver.testAndSet(impression);
|
|
13
|
+
var now = Date.now();
|
|
14
|
+
// Increments impression counter per featureName
|
|
15
|
+
if (impression.pt)
|
|
16
|
+
impressionCounts.track(impression.feature, now, 1);
|
|
17
|
+
// Checks if the impression should be added in queue to be sent
|
|
18
|
+
return (!impression.pt || impression.pt < truncateTimeFrame(now)) ? true : false;
|
|
29
19
|
}
|
|
30
20
|
};
|
|
31
21
|
}
|
package/package.json
CHANGED
package/src/dtos/types.ts
CHANGED
package/src/evaluator/index.ts
CHANGED
|
@@ -156,12 +156,14 @@ function getEvaluation(
|
|
|
156
156
|
return evaluation.then(result => {
|
|
157
157
|
result.changeNumber = split.getChangeNumber();
|
|
158
158
|
result.config = splitJSON.configurations && splitJSON.configurations[result.treatment] || null;
|
|
159
|
+
result.impressionsDisabled = splitJSON.impressionsDisabled;
|
|
159
160
|
|
|
160
161
|
return result;
|
|
161
162
|
});
|
|
162
163
|
} else {
|
|
163
164
|
evaluation.changeNumber = split.getChangeNumber(); // Always sync and optional
|
|
164
165
|
evaluation.config = splitJSON.configurations && splitJSON.configurations[evaluation.treatment] || null;
|
|
166
|
+
evaluation.impressionsDisabled = splitJSON.impressionsDisabled;
|
|
165
167
|
}
|
|
166
168
|
}
|
|
167
169
|
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import { MaybeThenable } from '../../dtos/types';
|
|
2
2
|
import { ISegmentsCacheBase } from '../../storages/types';
|
|
3
|
-
import { thenable } from '../../utils/promise/thenable';
|
|
4
3
|
|
|
5
4
|
export function largeSegmentMatcherContext(largeSegmentName: string, storage: { largeSegments?: ISegmentsCacheBase }) {
|
|
6
5
|
|
|
7
6
|
return function largeSegmentMatcher(key: string): MaybeThenable<boolean> {
|
|
8
7
|
const isInLargeSegment = storage.largeSegments ? storage.largeSegments.isInSegment(largeSegmentName, key) : false;
|
|
9
8
|
|
|
10
|
-
if (thenable(isInLargeSegment)) {
|
|
11
|
-
isInLargeSegment.then(result => {
|
|
12
|
-
return result;
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
|
|
16
9
|
return isInLargeSegment;
|
|
17
10
|
};
|
|
18
11
|
}
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import { MaybeThenable } from '../../dtos/types';
|
|
2
2
|
import { ISegmentsCacheBase } from '../../storages/types';
|
|
3
|
-
import { thenable } from '../../utils/promise/thenable';
|
|
4
3
|
|
|
5
4
|
export function segmentMatcherContext(segmentName: string, storage: { segments: ISegmentsCacheBase }) {
|
|
6
5
|
|
|
7
6
|
return function segmentMatcher(key: string): MaybeThenable<boolean> {
|
|
8
7
|
const isInSegment = storage.segments.isInSegment(segmentName, key);
|
|
9
8
|
|
|
10
|
-
if (thenable(isInSegment)) {
|
|
11
|
-
isInSegment.then(result => {
|
|
12
|
-
return result;
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
|
|
16
9
|
return isInSegment;
|
|
17
10
|
};
|
|
18
11
|
}
|
package/src/evaluator/types.ts
CHANGED
|
@@ -25,7 +25,7 @@ export interface IEvaluation {
|
|
|
25
25
|
config?: string | null
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export type IEvaluationResult = IEvaluation & { treatment: string }
|
|
28
|
+
export type IEvaluationResult = IEvaluation & { treatment: string; impressionsDisabled?: boolean }
|
|
29
29
|
|
|
30
30
|
export type ISplitEvaluator = (log: ILogger, key: SplitIO.SplitKey, splitName: string, attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync) => MaybeThenable<IEvaluation>
|
|
31
31
|
|
package/src/listeners/browser.ts
CHANGED
|
@@ -8,7 +8,6 @@ import { IResponse, ISplitApi } from '../services/types';
|
|
|
8
8
|
import { ISettings } from '../types';
|
|
9
9
|
import SplitIO from '../../types/splitio';
|
|
10
10
|
import { ImpressionsPayload } from '../sync/submitters/types';
|
|
11
|
-
import { OPTIMIZED, DEBUG, NONE } from '../utils/constants';
|
|
12
11
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
13
12
|
import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
|
|
14
13
|
import { ISyncManager } from '../sync/types';
|
|
@@ -78,10 +77,9 @@ export class BrowserSignalListener implements ISignalListener {
|
|
|
78
77
|
|
|
79
78
|
// Flush impressions & events data if there is user consent
|
|
80
79
|
if (isConsentGranted(this.settings)) {
|
|
81
|
-
const sim = this.settings.sync.impressionsMode;
|
|
82
80
|
const extraMetadata = {
|
|
83
81
|
// sim stands for Sync/Split Impressions Mode
|
|
84
|
-
sim:
|
|
82
|
+
sim: this.settings.sync.impressionsMode
|
|
85
83
|
};
|
|
86
84
|
|
|
87
85
|
this._flushData(events + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata);
|
|
@@ -3,6 +3,7 @@ import { ISettings } from '../types';
|
|
|
3
3
|
import SplitIO from '../../types/splitio';
|
|
4
4
|
import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED, SDK_SEGMENTS_ARRIVED, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE, SDK_READY } from './constants';
|
|
5
5
|
import { IReadinessEventEmitter, IReadinessManager, ISegmentsEventEmitter, ISplitsEventEmitter } from './types';
|
|
6
|
+
import { STORAGE_LOCALSTORAGE } from '../utils/constants';
|
|
6
7
|
|
|
7
8
|
function splitsEventEmitterFactory(EventEmitter: new () => SplitIO.IEventEmitter): ISplitsEventEmitter {
|
|
8
9
|
const splitsEventEmitter = objectAssign(new EventEmitter(), {
|
|
@@ -114,6 +115,10 @@ export function readinessManagerFactory(
|
|
|
114
115
|
isReady = true;
|
|
115
116
|
try {
|
|
116
117
|
syncLastUpdate();
|
|
118
|
+
if (!isReadyFromCache && settings.storage?.type === STORAGE_LOCALSTORAGE) {
|
|
119
|
+
isReadyFromCache = true;
|
|
120
|
+
gate.emit(SDK_READY_FROM_CACHE);
|
|
121
|
+
}
|
|
117
122
|
gate.emit(SDK_READY);
|
|
118
123
|
} catch (e) {
|
|
119
124
|
// throws user callback exceptions in next tick
|
package/src/sdkClient/client.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { IMPRESSION, IMPRESSION_QUEUEING } from '../logger/constants';
|
|
|
11
11
|
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
12
12
|
import { isConsumerMode } from '../utils/settingsValidation/mode';
|
|
13
13
|
import { Method } from '../sync/submitters/types';
|
|
14
|
+
import { ImpressionDecorated } from '../trackers/types';
|
|
14
15
|
|
|
15
16
|
const treatmentNotReady = { treatment: CONTROL, label: SDK_NOT_READY };
|
|
16
17
|
|
|
@@ -34,11 +35,11 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
34
35
|
const stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENT_WITH_CONFIG : TREATMENT);
|
|
35
36
|
|
|
36
37
|
const wrapUp = (evaluationResult: IEvaluationResult) => {
|
|
37
|
-
const queue:
|
|
38
|
+
const queue: ImpressionDecorated[] = [];
|
|
38
39
|
const treatment = processEvaluation(evaluationResult, featureFlagName, key, attributes, withConfig, methodName, queue);
|
|
39
40
|
impressionsTracker.track(queue, attributes);
|
|
40
41
|
|
|
41
|
-
stopTelemetryTracker(queue[0] && queue[0].label);
|
|
42
|
+
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
42
43
|
return treatment;
|
|
43
44
|
};
|
|
44
45
|
|
|
@@ -59,14 +60,14 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
59
60
|
const stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENTS_WITH_CONFIG : TREATMENTS);
|
|
60
61
|
|
|
61
62
|
const wrapUp = (evaluationResults: Record<string, IEvaluationResult>) => {
|
|
62
|
-
const queue:
|
|
63
|
+
const queue: ImpressionDecorated[] = [];
|
|
63
64
|
const treatments: Record<string, SplitIO.Treatment | SplitIO.TreatmentWithConfig> = {};
|
|
64
65
|
Object.keys(evaluationResults).forEach(featureFlagName => {
|
|
65
66
|
treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, attributes, withConfig, methodName, queue);
|
|
66
67
|
});
|
|
67
68
|
impressionsTracker.track(queue, attributes);
|
|
68
69
|
|
|
69
|
-
stopTelemetryTracker(queue[0] && queue[0].label);
|
|
70
|
+
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
70
71
|
return treatments;
|
|
71
72
|
};
|
|
72
73
|
|
|
@@ -87,7 +88,7 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
87
88
|
const stopTelemetryTracker = telemetryTracker.trackEval(method);
|
|
88
89
|
|
|
89
90
|
const wrapUp = (evaluationResults: Record<string, IEvaluationResult>) => {
|
|
90
|
-
const queue:
|
|
91
|
+
const queue: ImpressionDecorated[] = [];
|
|
91
92
|
const treatments: Record<string, SplitIO.Treatment | SplitIO.TreatmentWithConfig> = {};
|
|
92
93
|
const evaluations = evaluationResults;
|
|
93
94
|
Object.keys(evaluations).forEach(featureFlagName => {
|
|
@@ -95,7 +96,7 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
95
96
|
});
|
|
96
97
|
impressionsTracker.track(queue, attributes);
|
|
97
98
|
|
|
98
|
-
stopTelemetryTracker(queue[0] && queue[0].label);
|
|
99
|
+
stopTelemetryTracker(queue[0] && queue[0].imp.label);
|
|
99
100
|
return treatments;
|
|
100
101
|
};
|
|
101
102
|
|
|
@@ -128,24 +129,27 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
|
|
|
128
129
|
attributes: SplitIO.Attributes | undefined,
|
|
129
130
|
withConfig: boolean,
|
|
130
131
|
invokingMethodName: string,
|
|
131
|
-
queue:
|
|
132
|
+
queue: ImpressionDecorated[]
|
|
132
133
|
): SplitIO.Treatment | SplitIO.TreatmentWithConfig {
|
|
133
134
|
const matchingKey = getMatching(key);
|
|
134
135
|
const bucketingKey = getBucketing(key);
|
|
135
136
|
|
|
136
|
-
const { treatment, label, changeNumber, config = null } = evaluation;
|
|
137
|
+
const { treatment, label, changeNumber, config = null, impressionsDisabled } = evaluation;
|
|
137
138
|
log.info(IMPRESSION, [featureFlagName, matchingKey, treatment, label]);
|
|
138
139
|
|
|
139
140
|
if (validateSplitExistence(log, readinessManager, featureFlagName, label, invokingMethodName)) {
|
|
140
141
|
log.info(IMPRESSION_QUEUEING);
|
|
141
142
|
queue.push({
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
imp: {
|
|
144
|
+
feature: featureFlagName,
|
|
145
|
+
keyName: matchingKey,
|
|
146
|
+
treatment,
|
|
147
|
+
time: Date.now(),
|
|
148
|
+
bucketingKey,
|
|
149
|
+
label,
|
|
150
|
+
changeNumber: changeNumber as number,
|
|
151
|
+
},
|
|
152
|
+
disabled: impressionsDisabled
|
|
149
153
|
});
|
|
150
154
|
}
|
|
151
155
|
|
|
@@ -61,7 +61,7 @@ export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: bo
|
|
|
61
61
|
releaseApiKey(settings.core.authorizationKey);
|
|
62
62
|
telemetryTracker.sessionLength();
|
|
63
63
|
signalListener && signalListener.stop();
|
|
64
|
-
uniqueKeysTracker
|
|
64
|
+
uniqueKeysTracker.stop();
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
// Stop background jobs
|
package/src/sdkFactory/index.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { strategyDebugFactory } from '../trackers/strategy/strategyDebug';
|
|
|
13
13
|
import { strategyOptimizedFactory } from '../trackers/strategy/strategyOptimized';
|
|
14
14
|
import { strategyNoneFactory } from '../trackers/strategy/strategyNone';
|
|
15
15
|
import { uniqueKeysTrackerFactory } from '../trackers/uniqueKeysTracker';
|
|
16
|
-
import {
|
|
16
|
+
import { DEBUG, OPTIMIZED } from '../utils/constants';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Modular SDK factory
|
|
@@ -59,21 +59,16 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IA
|
|
|
59
59
|
const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage, telemetryTracker });
|
|
60
60
|
|
|
61
61
|
const observer = impressionsObserverFactory();
|
|
62
|
-
const uniqueKeysTracker =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
strategy = strategyNoneFactory(storage.impressionCounts!, uniqueKeysTracker!);
|
|
71
|
-
break;
|
|
72
|
-
default:
|
|
73
|
-
strategy = strategyDebugFactory(observer);
|
|
74
|
-
}
|
|
62
|
+
const uniqueKeysTracker = uniqueKeysTrackerFactory(log, storage.uniqueKeys, filterAdapterFactory && filterAdapterFactory());
|
|
63
|
+
|
|
64
|
+
const noneStrategy = strategyNoneFactory(storage.impressionCounts, uniqueKeysTracker);
|
|
65
|
+
const strategy = impressionsMode === OPTIMIZED ?
|
|
66
|
+
strategyOptimizedFactory(observer, storage.impressionCounts) :
|
|
67
|
+
impressionsMode === DEBUG ?
|
|
68
|
+
strategyDebugFactory(observer) :
|
|
69
|
+
noneStrategy;
|
|
75
70
|
|
|
76
|
-
const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, strategy, whenInit, integrationsManager, storage.telemetry);
|
|
71
|
+
const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, noneStrategy, strategy, whenInit, integrationsManager, storage.telemetry);
|
|
77
72
|
const eventTracker = eventTrackerFactory(settings, storage.events, whenInit, integrationsManager, storage.telemetry);
|
|
78
73
|
|
|
79
74
|
// splitApi is used by SyncManager and Browser signal listener
|
|
@@ -99,7 +94,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IA
|
|
|
99
94
|
// We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle.
|
|
100
95
|
validateAndTrackApiKey(log, settings.core.authorizationKey);
|
|
101
96
|
readiness.init();
|
|
102
|
-
uniqueKeysTracker
|
|
97
|
+
uniqueKeysTracker.start();
|
|
103
98
|
syncManager && syncManager.start();
|
|
104
99
|
signalListener && signalListener.start();
|
|
105
100
|
|
package/src/sdkFactory/types.ts
CHANGED
|
@@ -46,7 +46,7 @@ export interface ISdkFactoryContext {
|
|
|
46
46
|
eventTracker: IEventTracker,
|
|
47
47
|
telemetryTracker: ITelemetryTracker,
|
|
48
48
|
storage: IStorageSync | IStorageAsync,
|
|
49
|
-
uniqueKeysTracker
|
|
49
|
+
uniqueKeysTracker: IUniqueKeysTracker,
|
|
50
50
|
signalListener?: ISignalListener
|
|
51
51
|
splitApi?: ISplitApi
|
|
52
52
|
syncManager?: ISyncManager,
|
package/src/sdkManager/index.ts
CHANGED
|
@@ -31,7 +31,8 @@ function objectToView(splitObject: ISplit | null): SplitIO.SplitView | null {
|
|
|
31
31
|
treatments: collectTreatments(splitObject),
|
|
32
32
|
configs: splitObject.configurations || {},
|
|
33
33
|
sets: splitObject.sets || [],
|
|
34
|
-
defaultTreatment: splitObject.defaultTreatment
|
|
34
|
+
defaultTreatment: splitObject.defaultTreatment,
|
|
35
|
+
impressionsDisabled: splitObject.impressionsDisabled === true
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
38
|
|
|
@@ -9,7 +9,7 @@ import { SplitsCacheInLocal } from './SplitsCacheInLocal';
|
|
|
9
9
|
import { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
|
|
10
10
|
import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS';
|
|
11
11
|
import { LOG_PREFIX } from './constants';
|
|
12
|
-
import {
|
|
12
|
+
import { STORAGE_LOCALSTORAGE } from '../../utils/constants';
|
|
13
13
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
|
|
14
14
|
import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
|
|
15
15
|
import { getMatching } from '../../utils/key';
|
|
@@ -31,7 +31,7 @@ export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): ISt
|
|
|
31
31
|
return InMemoryStorageCSFactory(params);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize
|
|
34
|
+
const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize } } } = params;
|
|
35
35
|
const matchingKey = getMatching(settings.core.key);
|
|
36
36
|
const keys = new KeyBuilderCS(prefix, matchingKey);
|
|
37
37
|
|
|
@@ -44,10 +44,10 @@ export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): ISt
|
|
|
44
44
|
segments,
|
|
45
45
|
largeSegments,
|
|
46
46
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
47
|
-
impressionCounts:
|
|
47
|
+
impressionCounts: new ImpressionCountsCacheInMemory(),
|
|
48
48
|
events: new EventsCacheInMemory(eventsQueueSize),
|
|
49
49
|
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
|
|
50
|
-
uniqueKeys:
|
|
50
|
+
uniqueKeys: new UniqueKeysCacheInMemoryCS(),
|
|
51
51
|
|
|
52
52
|
validateCache() {
|
|
53
53
|
return validateCache(options, settings, keys, splits, segments, largeSegments);
|
|
@@ -66,6 +66,7 @@ export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): ISt
|
|
|
66
66
|
impressionCounts: this.impressionCounts,
|
|
67
67
|
events: this.events,
|
|
68
68
|
telemetry: this.telemetry,
|
|
69
|
+
uniqueKeys: this.uniqueKeys,
|
|
69
70
|
|
|
70
71
|
destroy() { }
|
|
71
72
|
};
|
|
@@ -7,7 +7,6 @@ import type { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
|
|
|
7
7
|
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
8
8
|
import SplitIO from '../../../types/splitio';
|
|
9
9
|
|
|
10
|
-
// milliseconds in a day
|
|
11
10
|
const DEFAULT_CACHE_EXPIRATION_IN_DAYS = 10;
|
|
12
11
|
const MILLIS_IN_A_DAY = 86400000;
|
|
13
12
|
|
|
@@ -42,7 +41,7 @@ function validateExpiration(options: SplitIO.InLocalStorageOptions, settings: IS
|
|
|
42
41
|
log.error(LOG_PREFIX + e);
|
|
43
42
|
}
|
|
44
43
|
if (isThereCache) {
|
|
45
|
-
log.info(LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version has changed. Cleaning up cache');
|
|
44
|
+
log.info(LOG_PREFIX + 'SDK key, flags filter criteria, or flags spec version has changed. Cleaning up cache');
|
|
46
45
|
return true;
|
|
47
46
|
}
|
|
48
47
|
return false; // No cache to clear
|
|
@@ -4,7 +4,7 @@ import { ImpressionsCacheInMemory } from './ImpressionsCacheInMemory';
|
|
|
4
4
|
import { EventsCacheInMemory } from './EventsCacheInMemory';
|
|
5
5
|
import { IStorageFactoryParams, IStorageSync } from '../types';
|
|
6
6
|
import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
|
|
7
|
-
import {
|
|
7
|
+
import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
|
|
8
8
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
9
9
|
import { UniqueKeysCacheInMemory } from './UniqueKeysCacheInMemory';
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ 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: {
|
|
17
|
+
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { __splitFiltersValidation } } } = params;
|
|
18
18
|
|
|
19
19
|
const splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
20
20
|
const segments = new SegmentsCacheInMemory();
|
|
@@ -23,10 +23,10 @@ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageS
|
|
|
23
23
|
splits,
|
|
24
24
|
segments,
|
|
25
25
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
26
|
-
impressionCounts:
|
|
26
|
+
impressionCounts: new ImpressionCountsCacheInMemory(),
|
|
27
27
|
events: new EventsCacheInMemory(eventsQueueSize),
|
|
28
28
|
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
|
|
29
|
-
uniqueKeys:
|
|
29
|
+
uniqueKeys: new UniqueKeysCacheInMemory(),
|
|
30
30
|
|
|
31
31
|
destroy() { }
|
|
32
32
|
};
|
|
@@ -37,8 +37,8 @@ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageS
|
|
|
37
37
|
const noopTrack = () => true;
|
|
38
38
|
storage.impressions.track = noopTrack;
|
|
39
39
|
storage.events.track = noopTrack;
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
storage.impressionCounts.track = noopTrack;
|
|
41
|
+
storage.uniqueKeys.track = noopTrack;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
return storage;
|