@splitsoftware/splitio-commons 1.17.0 → 1.17.1-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 +8 -0
- package/cjs/evaluator/matchers/index.js +3 -1
- package/cjs/evaluator/matchers/large_segment.js +16 -0
- package/cjs/evaluator/matchers/matcherTypes.js +1 -0
- package/cjs/evaluator/matchersTransform/index.js +4 -1
- package/cjs/evaluator/matchersTransform/segment.js +3 -1
- package/cjs/logger/constants.js +2 -2
- package/cjs/logger/messages/info.js +1 -1
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/readiness/readinessManager.js +5 -6
- package/cjs/readiness/sdkReadinessManager.js +5 -6
- package/cjs/sdkClient/identity.js +7 -0
- package/cjs/sdkClient/sdkClient.js +5 -5
- package/cjs/sdkClient/sdkClientMethod.js +3 -1
- package/cjs/sdkClient/sdkClientMethodCS.js +9 -14
- package/cjs/sdkClient/sdkClientMethodCSWithTT.js +9 -14
- package/cjs/sdkFactory/index.js +6 -2
- package/cjs/services/splitApi.js +5 -5
- package/cjs/storages/AbstractSegmentsCacheSync.js +41 -12
- package/cjs/storages/AbstractSplitsCacheSync.js +2 -1
- package/cjs/storages/KeyBuilderCS.js +23 -5
- package/cjs/storages/dataLoader.js +1 -1
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +29 -52
- package/cjs/storages/inLocalStorage/index.js +6 -2
- package/cjs/storages/inMemory/InMemoryStorageCS.js +5 -0
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +9 -40
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +8 -8
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +7 -10
- package/cjs/storages/pluggable/inMemoryWrapper.js +1 -1
- package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +5 -8
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/cjs/sync/polling/pollingManagerCS.js +1 -1
- package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +15 -21
- package/cjs/sync/streaming/AuthClient/index.js +1 -1
- package/cjs/sync/streaming/SSEHandler/index.js +3 -5
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +107 -48
- package/cjs/sync/streaming/constants.js +3 -3
- package/cjs/sync/streaming/parseUtils.js +14 -9
- package/cjs/sync/streaming/pushManager.js +69 -67
- package/cjs/utils/constants/index.js +5 -4
- package/cjs/utils/settingsValidation/index.js +2 -1
- package/esm/evaluator/matchers/index.js +3 -1
- package/esm/evaluator/matchers/large_segment.js +12 -0
- package/esm/evaluator/matchers/matcherTypes.js +1 -0
- package/esm/evaluator/matchersTransform/index.js +4 -1
- package/esm/evaluator/matchersTransform/segment.js +3 -1
- package/esm/logger/constants.js +1 -1
- package/esm/logger/messages/info.js +1 -1
- package/esm/logger/messages/warn.js +1 -1
- package/esm/readiness/readinessManager.js +5 -6
- package/esm/readiness/sdkReadinessManager.js +5 -6
- package/esm/sdkClient/identity.js +3 -0
- package/esm/sdkClient/sdkClient.js +5 -5
- package/esm/sdkClient/sdkClientMethod.js +3 -1
- package/esm/sdkClient/sdkClientMethodCS.js +7 -12
- package/esm/sdkClient/sdkClientMethodCSWithTT.js +7 -12
- package/esm/sdkFactory/index.js +6 -2
- package/esm/services/splitApi.js +6 -6
- package/esm/storages/AbstractSegmentsCacheSync.js +41 -12
- package/esm/storages/AbstractSplitsCacheSync.js +3 -2
- package/esm/storages/KeyBuilderCS.js +21 -4
- package/esm/storages/dataLoader.js +1 -1
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +29 -52
- package/esm/storages/inLocalStorage/index.js +7 -3
- package/esm/storages/inMemory/InMemoryStorageCS.js +5 -0
- package/esm/storages/inMemory/MySegmentsCacheInMemory.js +9 -40
- package/esm/storages/inMemory/SplitsCacheInMemory.js +8 -8
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +7 -10
- package/esm/storages/pluggable/inMemoryWrapper.js +1 -1
- package/esm/sync/polling/fetchers/mySegmentsFetcher.js +5 -8
- package/esm/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/esm/sync/polling/pollingManagerCS.js +1 -1
- package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +15 -21
- package/esm/sync/streaming/AuthClient/index.js +1 -1
- package/esm/sync/streaming/SSEHandler/index.js +4 -6
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +108 -49
- package/esm/sync/streaming/constants.js +2 -2
- package/esm/sync/streaming/parseUtils.js +12 -8
- package/esm/sync/streaming/pushManager.js +72 -70
- package/esm/utils/constants/index.js +3 -2
- package/esm/utils/settingsValidation/index.js +2 -1
- package/package.json +1 -1
- package/src/dtos/types.ts +21 -7
- package/src/evaluator/matchers/index.ts +2 -0
- package/src/evaluator/matchers/large_segment.ts +18 -0
- package/src/evaluator/matchers/matcherTypes.ts +1 -0
- package/src/evaluator/matchersTransform/index.ts +4 -1
- package/src/evaluator/matchersTransform/segment.ts +5 -3
- package/src/logger/constants.ts +1 -1
- package/src/logger/messages/info.ts +1 -1
- package/src/logger/messages/warn.ts +1 -1
- package/src/readiness/readinessManager.ts +7 -5
- package/src/readiness/sdkReadinessManager.ts +7 -7
- package/src/readiness/types.ts +2 -2
- package/src/sdkClient/identity.ts +5 -0
- package/src/sdkClient/sdkClient.ts +5 -5
- package/src/sdkClient/sdkClientMethod.ts +4 -1
- package/src/sdkClient/sdkClientMethodCS.ts +7 -13
- package/src/sdkClient/sdkClientMethodCSWithTT.ts +7 -13
- package/src/sdkFactory/index.ts +8 -4
- package/src/sdkFactory/types.ts +2 -1
- package/src/services/splitApi.ts +7 -7
- package/src/services/splitHttpClient.ts +1 -1
- package/src/services/types.ts +2 -2
- package/src/storages/AbstractSegmentsCacheSync.ts +53 -12
- package/src/storages/AbstractSplitsCacheSync.ts +4 -3
- package/src/storages/KeyBuilderCS.ts +34 -5
- package/src/storages/dataLoader.ts +1 -1
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +29 -59
- package/src/storages/inLocalStorage/index.ts +8 -4
- package/src/storages/inMemory/InMemoryStorageCS.ts +5 -0
- package/src/storages/inMemory/MySegmentsCacheInMemory.ts +10 -44
- package/src/storages/inMemory/SplitsCacheInMemory.ts +7 -8
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +7 -11
- package/src/storages/pluggable/inMemoryWrapper.ts +1 -1
- package/src/storages/types.ts +11 -7
- package/src/sync/polling/fetchers/mySegmentsFetcher.ts +8 -10
- package/src/sync/polling/fetchers/segmentChangesFetcher.ts +1 -1
- package/src/sync/polling/fetchers/types.ts +3 -2
- package/src/sync/polling/pollingManagerCS.ts +4 -4
- package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +4 -5
- package/src/sync/polling/types.ts +7 -6
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +19 -22
- package/src/sync/streaming/AuthClient/index.ts +1 -1
- package/src/sync/streaming/SSEClient/index.ts +4 -6
- package/src/sync/streaming/SSEHandler/index.ts +5 -8
- package/src/sync/streaming/SSEHandler/types.ts +15 -15
- package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +116 -49
- package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +1 -1
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +1 -1
- package/src/sync/streaming/UpdateWorkers/types.ts +2 -2
- package/src/sync/streaming/constants.ts +2 -2
- package/src/sync/streaming/parseUtils.ts +19 -11
- package/src/sync/streaming/pushManager.ts +73 -72
- package/src/sync/streaming/types.ts +10 -10
- package/src/sync/submitters/types.ts +8 -5
- package/src/types.ts +7 -1
- package/src/utils/constants/index.ts +3 -2
- package/src/utils/settingsValidation/index.ts +3 -2
- package/src/utils/settingsValidation/types.ts +1 -1
- package/types/dtos/types.d.ts +18 -7
- package/types/evaluator/matchersTransform/segment.d.ts +2 -2
- package/types/logger/constants.d.ts +1 -1
- package/types/readiness/readinessManager.d.ts +2 -2
- package/types/readiness/sdkReadinessManager.d.ts +2 -3
- package/types/readiness/types.d.ts +2 -2
- package/types/sdkClient/identity.d.ts +0 -4
- package/types/sdkClient/sdkClientMethod.d.ts +1 -1
- package/types/sdkFactory/types.d.ts +2 -1
- package/types/services/splitApi.d.ts +1 -1
- package/types/services/splitHttpClient.d.ts +1 -1
- package/types/services/types.d.ts +2 -2
- package/types/storages/AbstractMySegmentsCacheSync.d.ts +39 -0
- package/types/storages/AbstractSegmentsCacheSync.d.ts +9 -11
- package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
- package/types/storages/KeyBuilderCS.d.ts +9 -2
- package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +4 -14
- package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +3 -9
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +1 -1
- package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +4 -6
- package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -1
- package/types/storages/types.d.ts +7 -5
- package/types/sync/polling/fetchers/mySegmentsFetcher.d.ts +2 -2
- package/types/sync/polling/fetchers/types.d.ts +2 -2
- package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +2 -2
- package/types/sync/polling/types.d.ts +7 -4
- package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +4 -3
- package/types/sync/streaming/SSEHandler/types.d.ts +16 -14
- package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +4 -2
- package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +2 -1
- package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +3 -2
- package/types/sync/streaming/UpdateWorkers/types.d.ts +2 -2
- package/types/sync/streaming/constants.d.ts +2 -2
- package/types/sync/streaming/parseUtils.d.ts +4 -5
- package/types/sync/streaming/types.d.ts +8 -8
- package/types/sync/submitters/types.d.ts +7 -4
- package/types/types.d.ts +7 -1
- package/types/utils/constants/index.d.ts +3 -2
- package/types/utils/settingsValidation/types.d.ts +1 -1
|
@@ -1,66 +1,133 @@
|
|
|
1
1
|
import { IMySegmentsSyncTask, MySegmentsData } from '../../polling/types';
|
|
2
2
|
import { Backoff } from '../../../utils/Backoff';
|
|
3
3
|
import { IUpdateWorker } from './types';
|
|
4
|
-
import { MY_SEGMENT } from '../../../utils/constants';
|
|
5
4
|
import { ITelemetryTracker } from '../../../trackers/types';
|
|
5
|
+
import { MEMBERSHIPS } from '../../../utils/constants';
|
|
6
|
+
import { ISegmentsCacheSync, IStorageSync } from '../../../storages/types';
|
|
7
|
+
import { ILogger } from '../../../logger/types';
|
|
8
|
+
import { FETCH_BACKOFF_MAX_RETRIES } from './constants';
|
|
9
|
+
import { MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../constants';
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* MySegmentsUpdateWorker factory
|
|
9
13
|
*/
|
|
10
|
-
export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker): IUpdateWorker {
|
|
11
|
-
|
|
12
|
-
let
|
|
13
|
-
let
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
isHandlingEvent
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
14
|
+
export function MySegmentsUpdateWorker(log: ILogger, storage: Pick<IStorageSync, 'segments' | 'largeSegments'>, mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker): IUpdateWorker<[mySegmentsData?: Pick<MySegmentsData, 'type' | 'cn'>, payload?: Pick<MySegmentsData, 'added' | 'removed'>, delay?: number]> {
|
|
15
|
+
|
|
16
|
+
let _delay: undefined | number;
|
|
17
|
+
let _delayTimeoutID: any;
|
|
18
|
+
|
|
19
|
+
function createUpdateWorker(mySegmentsCache: ISegmentsCacheSync) {
|
|
20
|
+
|
|
21
|
+
let maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
|
|
22
|
+
let currentChangeNumber = -1;
|
|
23
|
+
let handleNewEvent = false;
|
|
24
|
+
let isHandlingEvent: boolean;
|
|
25
|
+
let cdnBypass: boolean;
|
|
26
|
+
let _segmentsData: MySegmentsData | undefined; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber
|
|
27
|
+
const backoff = new Backoff(__handleMySegmentsUpdateCall);
|
|
28
|
+
|
|
29
|
+
function __handleMySegmentsUpdateCall() {
|
|
30
|
+
isHandlingEvent = true;
|
|
31
|
+
if (maxChangeNumber > Math.max(currentChangeNumber, mySegmentsCache.getChangeNumber())) {
|
|
32
|
+
handleNewEvent = false;
|
|
33
|
+
const currentMaxChangeNumber = maxChangeNumber;
|
|
34
|
+
|
|
35
|
+
// fetch mySegments revalidating data if cached
|
|
36
|
+
const syncTask = _delay ?
|
|
37
|
+
new Promise(res => {
|
|
38
|
+
_delayTimeoutID = setTimeout(() => {
|
|
39
|
+
_delay = undefined;
|
|
40
|
+
mySegmentsSyncTask.execute(_segmentsData, true, cdnBypass ? maxChangeNumber : undefined).then(res);
|
|
41
|
+
}, _delay);
|
|
42
|
+
}) :
|
|
43
|
+
mySegmentsSyncTask.execute(_segmentsData, true, cdnBypass ? maxChangeNumber : undefined);
|
|
44
|
+
|
|
45
|
+
syncTask.then((result) => {
|
|
46
|
+
if (!isHandlingEvent) return; // halt if `stop` has been called
|
|
47
|
+
if (result !== false) { // Unlike `Splits|SegmentsUpdateWorker`, `mySegmentsCache.getChangeNumber` can be -1, since `/memberships` change number is optional
|
|
48
|
+
const storageChangeNumber = mySegmentsCache.getChangeNumber();
|
|
49
|
+
currentChangeNumber = storageChangeNumber > -1 ?
|
|
50
|
+
storageChangeNumber :
|
|
51
|
+
Math.max(currentChangeNumber, currentMaxChangeNumber); // use `currentMaxChangeNumber`, in case that `maxChangeNumber` was updated during fetch.
|
|
52
|
+
}
|
|
53
|
+
if (handleNewEvent) {
|
|
54
|
+
__handleMySegmentsUpdateCall();
|
|
55
|
+
} else {
|
|
56
|
+
if (_segmentsData) telemetryTracker.trackUpdatesFromSSE(MEMBERSHIPS);
|
|
57
|
+
|
|
58
|
+
const attempts = backoff.attempts + 1;
|
|
59
|
+
|
|
60
|
+
if (maxChangeNumber <= currentChangeNumber) {
|
|
61
|
+
log.debug(`Refresh completed${cdnBypass ? ' bypassing the CDN' : ''} in ${attempts} attempts.`);
|
|
62
|
+
isHandlingEvent = false;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (attempts < FETCH_BACKOFF_MAX_RETRIES) {
|
|
67
|
+
backoff.scheduleCall();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (cdnBypass) {
|
|
72
|
+
log.debug(`No changes fetched after ${attempts} attempts with CDN bypassed.`);
|
|
73
|
+
isHandlingEvent = false;
|
|
74
|
+
} else {
|
|
75
|
+
backoff.reset();
|
|
76
|
+
cdnBypass = true;
|
|
77
|
+
__handleMySegmentsUpdateCall();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
} else {
|
|
82
|
+
isHandlingEvent = false;
|
|
83
|
+
}
|
|
40
84
|
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
/**
|
|
88
|
+
* Invoked by NotificationProcessor on MY_(LARGE)_SEGMENTS_UPDATE notifications
|
|
89
|
+
*
|
|
90
|
+
* @param changeNumber change number of the notification
|
|
91
|
+
* @param segmentsData data for KeyList or SegmentRemoval instant updates
|
|
92
|
+
* @param delay optional time to wait for BoundedFetchRequest or BoundedFetchRequest updates
|
|
93
|
+
*/
|
|
94
|
+
put(mySegmentsData: Pick<MySegmentsData, 'type' | 'cn'>, payload?: Pick<MySegmentsData, 'added' | 'removed'>, delay?: number) {
|
|
95
|
+
const { type, cn } = mySegmentsData;
|
|
96
|
+
// Discard event if it is outdated or there is a pending fetch request (_delay is set), but update target change number
|
|
97
|
+
if (cn <= Math.max(currentChangeNumber, mySegmentsCache.getChangeNumber()) || cn <= maxChangeNumber) return;
|
|
98
|
+
maxChangeNumber = cn;
|
|
99
|
+
if (_delay) return;
|
|
100
|
+
|
|
101
|
+
handleNewEvent = true;
|
|
102
|
+
cdnBypass = false;
|
|
103
|
+
_segmentsData = payload && { type, cn, added: payload.added, removed: payload.removed };
|
|
104
|
+
_delay = delay;
|
|
105
|
+
|
|
106
|
+
if (backoff.timeoutID || !isHandlingEvent) __handleMySegmentsUpdateCall();
|
|
107
|
+
backoff.reset();
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
stop() {
|
|
111
|
+
clearTimeout(_delayTimeoutID);
|
|
112
|
+
_delay = undefined;
|
|
113
|
+
isHandlingEvent = false;
|
|
114
|
+
backoff.reset();
|
|
115
|
+
}
|
|
116
|
+
};
|
|
41
117
|
}
|
|
42
118
|
|
|
119
|
+
const updateWorkers = {
|
|
120
|
+
[MEMBERSHIPS_MS_UPDATE]: createUpdateWorker(storage.segments),
|
|
121
|
+
[MEMBERSHIPS_LS_UPDATE]: createUpdateWorker(storage.largeSegments!),
|
|
122
|
+
};
|
|
123
|
+
|
|
43
124
|
return {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
*
|
|
47
|
-
* @param {number} changeNumber change number of the MY_SEGMENTS_UPDATE notification
|
|
48
|
-
* @param {SegmentsData | undefined} segmentsData might be undefined
|
|
49
|
-
*/
|
|
50
|
-
put(changeNumber: number, segmentsData?: MySegmentsData) {
|
|
51
|
-
if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber) return;
|
|
52
|
-
|
|
53
|
-
maxChangeNumber = changeNumber;
|
|
54
|
-
handleNewEvent = true;
|
|
55
|
-
_segmentsData = segmentsData;
|
|
56
|
-
|
|
57
|
-
if (backoff.timeoutID || !isHandlingEvent) __handleMySegmentsUpdateCall();
|
|
58
|
-
backoff.reset();
|
|
125
|
+
put(mySegmentsData: Pick<MySegmentsData, 'type' | 'cn'>, payload?: Pick<MySegmentsData, 'added' | 'removed'>, delay?: number) {
|
|
126
|
+
updateWorkers[mySegmentsData.type].put(mySegmentsData, payload, delay);
|
|
59
127
|
},
|
|
60
|
-
|
|
61
128
|
stop() {
|
|
62
|
-
|
|
63
|
-
|
|
129
|
+
updateWorkers[MEMBERSHIPS_MS_UPDATE].stop();
|
|
130
|
+
updateWorkers[MEMBERSHIPS_LS_UPDATE].stop();
|
|
64
131
|
}
|
|
65
132
|
};
|
|
66
133
|
}
|
|
@@ -9,7 +9,7 @@ import { IUpdateWorker } from './types';
|
|
|
9
9
|
/**
|
|
10
10
|
* SegmentsUpdateWorker factory
|
|
11
11
|
*/
|
|
12
|
-
export function SegmentsUpdateWorker(log: ILogger, segmentsSyncTask: ISegmentsSyncTask, segmentsCache: ISegmentsCacheSync): IUpdateWorker {
|
|
12
|
+
export function SegmentsUpdateWorker(log: ILogger, segmentsSyncTask: ISegmentsSyncTask, segmentsCache: ISegmentsCacheSync): IUpdateWorker<[ISegmentUpdateData]> {
|
|
13
13
|
|
|
14
14
|
// Handles retries with CDN bypass per segment name
|
|
15
15
|
function SegmentUpdateWorker(segment: string) {
|
|
@@ -14,7 +14,7 @@ import { IUpdateWorker } from './types';
|
|
|
14
14
|
/**
|
|
15
15
|
* SplitsUpdateWorker factory
|
|
16
16
|
*/
|
|
17
|
-
export function SplitsUpdateWorker(log: ILogger, splitsCache: ISplitsCacheSync, splitsSyncTask: ISplitsSyncTask, splitsEventEmitter: ISplitsEventEmitter, telemetryTracker: ITelemetryTracker, segmentsSyncTask?: ISegmentsSyncTask): IUpdateWorker & { killSplit(event: ISplitKillData): void } {
|
|
17
|
+
export function SplitsUpdateWorker(log: ILogger, splitsCache: ISplitsCacheSync, splitsSyncTask: ISplitsSyncTask, splitsEventEmitter: ISplitsEventEmitter, telemetryTracker: ITelemetryTracker, segmentsSyncTask?: ISegmentsSyncTask): IUpdateWorker<[updateData: ISplitUpdateData, payload?: ISplit]> & { killSplit(event: ISplitKillData): void } {
|
|
18
18
|
|
|
19
19
|
let maxChangeNumber = 0;
|
|
20
20
|
let handleNewEvent = false;
|
|
@@ -25,8 +25,8 @@ export const PUSH_SUBSYSTEM_UP = 'PUSH_SUBSYSTEM_UP';
|
|
|
25
25
|
export const PUSH_SUBSYSTEM_DOWN = 'PUSH_SUBSYSTEM_DOWN';
|
|
26
26
|
|
|
27
27
|
// Update-type push notifications, handled by NotificationProcessor
|
|
28
|
-
export const
|
|
29
|
-
export const
|
|
28
|
+
export const MEMBERSHIPS_MS_UPDATE = 'MEMBERSHIPS_MS_UPDATE';
|
|
29
|
+
export const MEMBERSHIPS_LS_UPDATE = 'MEMBERSHIPS_LS_UPDATE';
|
|
30
30
|
export const SEGMENT_UPDATE = 'SEGMENT_UPDATE';
|
|
31
31
|
export const SPLIT_KILL = 'SPLIT_KILL';
|
|
32
32
|
export const SPLIT_UPDATE = 'SPLIT_UPDATE';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { algorithms } from '../../utils/decompress';
|
|
2
2
|
import { decodeFromBase64 } from '../../utils/base64';
|
|
3
|
-
import {
|
|
3
|
+
import { hash } from '../../utils/murmur3/murmur3';
|
|
4
|
+
import { Compression, IMembershipMSUpdateData, KeyList } from './SSEHandler/types';
|
|
5
|
+
import { ISplit } from '../../dtos/types';
|
|
4
6
|
|
|
5
7
|
const GZIP = 1;
|
|
6
8
|
const ZLIB = 2;
|
|
@@ -42,7 +44,7 @@ function decompress(data: string, compression: Compression) {
|
|
|
42
44
|
* @returns {{a?: string[], r?: string[] }}
|
|
43
45
|
* @throws if data string cannot be decoded, decompressed or parsed
|
|
44
46
|
*/
|
|
45
|
-
export function parseKeyList(data: string, compression: Compression, avoidPrecisionLoss
|
|
47
|
+
export function parseKeyList(data: string, compression: Compression, avoidPrecisionLoss = true): KeyList {
|
|
46
48
|
const binKeyList = decompress(data, compression);
|
|
47
49
|
let strKeyList = Uint8ArrayToString(binKeyList);
|
|
48
50
|
// replace numbers to strings, to avoid losing precision
|
|
@@ -80,14 +82,20 @@ export function isInBitmap(bitmap: Uint8Array, hash64hex: string) {
|
|
|
80
82
|
|
|
81
83
|
/**
|
|
82
84
|
* Parse feature flags notifications for instant feature flag updates
|
|
83
|
-
*
|
|
84
|
-
* @param {ISplitUpdateData} data
|
|
85
|
-
* @returns {KeyList}
|
|
86
85
|
*/
|
|
87
|
-
export function parseFFUpdatePayload(compression: Compression, data: string):
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
export function parseFFUpdatePayload(compression: Compression, data: string): ISplit | undefined {
|
|
87
|
+
return compression > 0 ?
|
|
88
|
+
parseKeyList(data, compression, false) :
|
|
89
|
+
JSON.parse(decodeFromBase64(data));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const DEFAULT_MAX_INTERVAL = 60000;
|
|
93
|
+
|
|
94
|
+
export function getDelay(parsedData: Pick<IMembershipMSUpdateData, 'i' | 'h' | 's'>, matchingKey: string) {
|
|
95
|
+
if (parsedData.h === 0) return 0;
|
|
96
|
+
|
|
97
|
+
const interval = parsedData.i || DEFAULT_MAX_INTERVAL;
|
|
98
|
+
const seed = parsedData.s || 0;
|
|
99
|
+
|
|
100
|
+
return hash(matchingKey, seed) % interval;
|
|
93
101
|
}
|
|
@@ -11,16 +11,15 @@ import { authenticateFactory, hashUserKey } from './AuthClient';
|
|
|
11
11
|
import { forOwn } from '../../utils/lang';
|
|
12
12
|
import { SSEClient } from './SSEClient';
|
|
13
13
|
import { getMatching } from '../../utils/key';
|
|
14
|
-
import {
|
|
15
|
-
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT,
|
|
16
|
-
import { KeyList, UpdateStrategy } from './SSEHandler/types';
|
|
17
|
-
import { isInBitmap, parseBitmap, parseFFUpdatePayload, parseKeyList } from './parseUtils';
|
|
14
|
+
import { MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType } from './constants';
|
|
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
|
+
import { IMembershipMSUpdateData, IMembershipLSUpdateData, KeyList, UpdateStrategy } from './SSEHandler/types';
|
|
17
|
+
import { getDelay, isInBitmap, parseBitmap, parseFFUpdatePayload, parseKeyList } from './parseUtils';
|
|
18
18
|
import { ISet, _Set } from '../../utils/lang/sets';
|
|
19
19
|
import { Hash64, hash64 } from '../../utils/murmur3/murmur3_64';
|
|
20
20
|
import { IAuthTokenPushEnabled } from './AuthClient/types';
|
|
21
21
|
import { TOKEN_REFRESH, AUTH_REJECTION } from '../../utils/constants';
|
|
22
22
|
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
23
|
-
import { IUpdateWorker } from './UpdateWorkers/types';
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
25
|
* PushManager factory:
|
|
@@ -60,11 +59,11 @@ export function pushManagerFactory(
|
|
|
60
59
|
// For server-side we pass the segmentsSyncTask, used by SplitsUpdateWorker to fetch new segments
|
|
61
60
|
const splitsUpdateWorker = SplitsUpdateWorker(log, storage.splits, pollingManager.splitsSyncTask, readiness.splits, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask as ISegmentsSyncTask);
|
|
62
61
|
|
|
63
|
-
// [Only for client-side] map of hashes to user keys, to dispatch
|
|
62
|
+
// [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
|
|
64
63
|
const userKeyHashes: Record<string, string> = {};
|
|
65
64
|
// [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
|
|
66
|
-
// Hash64 is used to process
|
|
67
|
-
const clients: Record<string, { hash64: Hash64, worker:
|
|
65
|
+
// Hash64 is used to process membership update events and dispatch actions to the corresponding MySegmentsUpdateWorker.
|
|
66
|
+
const clients: Record<string, { hash64: Hash64, worker: ReturnType<typeof MySegmentsUpdateWorker> }> = {};
|
|
68
67
|
|
|
69
68
|
// [Only for client-side] variable to flag that a new client was added. It is needed to reconnect streaming.
|
|
70
69
|
let connectForNewClient = false;
|
|
@@ -236,76 +235,75 @@ export function pushManagerFactory(
|
|
|
236
235
|
splitsUpdateWorker.put(parsedData);
|
|
237
236
|
});
|
|
238
237
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
});
|
|
249
|
-
pushEmitter.on(MY_SEGMENTS_UPDATE_V2, function handleMySegmentsUpdate(parsedData) {
|
|
250
|
-
switch (parsedData.u) {
|
|
251
|
-
case UpdateStrategy.BoundedFetchRequest: {
|
|
252
|
-
let bitmap: Uint8Array;
|
|
253
|
-
try {
|
|
254
|
-
bitmap = parseBitmap(parsedData.d, parsedData.c);
|
|
255
|
-
} catch (e) {
|
|
256
|
-
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['BoundedFetchRequest', e]);
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
forOwn(clients, ({ hash64, worker }) => {
|
|
261
|
-
if (isInBitmap(bitmap, hash64.hex)) {
|
|
262
|
-
worker.put(parsedData.changeNumber); // fetch mySegments
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
return;
|
|
238
|
+
function handleMySegmentsUpdate(parsedData: IMembershipMSUpdateData | IMembershipLSUpdateData) {
|
|
239
|
+
switch (parsedData.u) {
|
|
240
|
+
case UpdateStrategy.BoundedFetchRequest: {
|
|
241
|
+
let bitmap: Uint8Array;
|
|
242
|
+
try {
|
|
243
|
+
bitmap = parseBitmap(parsedData.d!, parsedData.c!);
|
|
244
|
+
} catch (e) {
|
|
245
|
+
log.warn(STREAMING_PARSING_MEMBERSHIPS_UPDATE, ['BoundedFetchRequest', e]);
|
|
246
|
+
break;
|
|
266
247
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
added = new _Set(keyList.a);
|
|
272
|
-
removed = new _Set(keyList.r);
|
|
273
|
-
} catch (e) {
|
|
274
|
-
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['KeyList', e]);
|
|
275
|
-
break;
|
|
248
|
+
|
|
249
|
+
forOwn(clients, ({ hash64, worker }, matchingKey) => {
|
|
250
|
+
if (isInBitmap(bitmap, hash64.hex)) {
|
|
251
|
+
worker.put(parsedData, undefined, getDelay(parsedData, matchingKey));
|
|
276
252
|
}
|
|
253
|
+
});
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
case UpdateStrategy.KeyList: {
|
|
257
|
+
let keyList: KeyList, added: ISet<string>, removed: ISet<string>;
|
|
258
|
+
try {
|
|
259
|
+
keyList = parseKeyList(parsedData.d!, parsedData.c!);
|
|
260
|
+
added = new _Set(keyList.a);
|
|
261
|
+
removed = new _Set(keyList.r);
|
|
262
|
+
} catch (e) {
|
|
263
|
+
log.warn(STREAMING_PARSING_MEMBERSHIPS_UPDATE, ['KeyList', e]);
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
277
266
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
worker.put(parsedData.changeNumber, {
|
|
282
|
-
name: parsedData.segmentName,
|
|
283
|
-
add
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
return;
|
|
267
|
+
if (!parsedData.n || !parsedData.n.length) {
|
|
268
|
+
log.warn(STREAMING_PARSING_MEMBERSHIPS_UPDATE, ['KeyList', 'No segment name was provided']);
|
|
269
|
+
break;
|
|
288
270
|
}
|
|
289
|
-
case UpdateStrategy.SegmentRemoval:
|
|
290
|
-
if (!parsedData.segmentName) {
|
|
291
|
-
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['SegmentRemoval', 'No segment name was provided']);
|
|
292
|
-
break;
|
|
293
|
-
}
|
|
294
271
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
272
|
+
forOwn(clients, ({ hash64, worker }) => {
|
|
273
|
+
const add = added.has(hash64.dec) ? true : removed.has(hash64.dec) ? false : undefined;
|
|
274
|
+
if (add !== undefined) {
|
|
275
|
+
worker.put(parsedData, {
|
|
276
|
+
added: add ? [parsedData.n![0]] : [],
|
|
277
|
+
removed: add ? [] : [parsedData.n![0]]
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
return;
|
|
302
282
|
}
|
|
283
|
+
case UpdateStrategy.SegmentRemoval:
|
|
284
|
+
if (!parsedData.n || !parsedData.n.length) {
|
|
285
|
+
log.warn(STREAMING_PARSING_MEMBERSHIPS_UPDATE, ['SegmentRemoval', 'No segment name was provided']);
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
303
288
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
289
|
+
forOwn(clients, ({ worker }) => {
|
|
290
|
+
worker.put(parsedData, {
|
|
291
|
+
added: [],
|
|
292
|
+
removed: parsedData.n!
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// `UpdateStrategy.UnboundedFetchRequest` and fallbacks of other cases
|
|
299
|
+
forOwn(clients, ({ worker }, matchingKey) => {
|
|
300
|
+
worker.put(parsedData, undefined, getDelay(parsedData, matchingKey));
|
|
308
301
|
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (userKey) {
|
|
305
|
+
pushEmitter.on(MEMBERSHIPS_MS_UPDATE, handleMySegmentsUpdate);
|
|
306
|
+
pushEmitter.on(MEMBERSHIPS_LS_UPDATE, handleMySegmentsUpdate);
|
|
309
307
|
} else {
|
|
310
308
|
pushEmitter.on(SEGMENT_UPDATE, segmentsUpdateWorker!.put);
|
|
311
309
|
}
|
|
@@ -328,7 +326,7 @@ export function pushManagerFactory(
|
|
|
328
326
|
if (disabled || disconnected === false) return;
|
|
329
327
|
disconnected = false;
|
|
330
328
|
|
|
331
|
-
if (userKey) this.add(userKey, pollingManager.segmentsSyncTask
|
|
329
|
+
if (userKey) this.add(userKey, pollingManager.segmentsSyncTask); // client-side
|
|
332
330
|
else setTimeout(connectPush); // server-side runs in next cycle as in client-side, for consistency with client-side
|
|
333
331
|
},
|
|
334
332
|
|
|
@@ -343,7 +341,10 @@ export function pushManagerFactory(
|
|
|
343
341
|
|
|
344
342
|
if (!userKeyHashes[hash]) {
|
|
345
343
|
userKeyHashes[hash] = userKey;
|
|
346
|
-
clients[userKey] = {
|
|
344
|
+
clients[userKey] = {
|
|
345
|
+
hash64: hash64(userKey),
|
|
346
|
+
worker: MySegmentsUpdateWorker(log, storage, mySegmentsSyncTask, telemetryTracker)
|
|
347
|
+
};
|
|
347
348
|
connectForNewClient = true; // we must reconnect on start, to listen the channel for the new user key
|
|
348
349
|
|
|
349
350
|
// Reconnects in case of a new client.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IMembershipMSUpdateData, IMembershipLSUpdateData, ISegmentUpdateData, ISplitUpdateData, ISplitKillData, INotificationData } from './SSEHandler/types';
|
|
2
2
|
import { ITask } from '../types';
|
|
3
3
|
import { IMySegmentsSyncTask } from '../polling/types';
|
|
4
4
|
import { IEventEmitter } from '../../types';
|
|
@@ -11,8 +11,8 @@ export type PUSH_NONRETRYABLE_ERROR = 'PUSH_NONRETRYABLE_ERROR'
|
|
|
11
11
|
export type PUSH_RETRYABLE_ERROR = 'PUSH_RETRYABLE_ERROR'
|
|
12
12
|
|
|
13
13
|
// Update-type push notifications, handled by NotificationProcessor
|
|
14
|
-
export type
|
|
15
|
-
export type
|
|
14
|
+
export type MEMBERSHIPS_MS_UPDATE = 'MEMBERSHIPS_MS_UPDATE';
|
|
15
|
+
export type MEMBERSHIPS_LS_UPDATE = 'MEMBERSHIPS_LS_UPDATE';
|
|
16
16
|
export type SEGMENT_UPDATE = 'SEGMENT_UPDATE';
|
|
17
17
|
export type SPLIT_KILL = 'SPLIT_KILL';
|
|
18
18
|
export type SPLIT_UPDATE = 'SPLIT_UPDATE';
|
|
@@ -21,23 +21,23 @@ export type SPLIT_UPDATE = 'SPLIT_UPDATE';
|
|
|
21
21
|
export type CONTROL = 'CONTROL';
|
|
22
22
|
export type OCCUPANCY = 'OCCUPANCY';
|
|
23
23
|
|
|
24
|
-
export type IPushEvent = PUSH_SUBSYSTEM_UP | PUSH_SUBSYSTEM_DOWN | PUSH_NONRETRYABLE_ERROR | PUSH_RETRYABLE_ERROR |
|
|
24
|
+
export type IPushEvent = PUSH_SUBSYSTEM_UP | PUSH_SUBSYSTEM_DOWN | PUSH_NONRETRYABLE_ERROR | PUSH_RETRYABLE_ERROR | MEMBERSHIPS_MS_UPDATE | MEMBERSHIPS_LS_UPDATE | SEGMENT_UPDATE | SPLIT_UPDATE | SPLIT_KILL | ControlType.STREAMING_RESET
|
|
25
25
|
|
|
26
26
|
type IParsedData<T extends IPushEvent> =
|
|
27
|
-
T extends
|
|
28
|
-
T extends
|
|
27
|
+
T extends MEMBERSHIPS_MS_UPDATE ? IMembershipMSUpdateData :
|
|
28
|
+
T extends MEMBERSHIPS_LS_UPDATE ? IMembershipLSUpdateData :
|
|
29
29
|
T extends SEGMENT_UPDATE ? ISegmentUpdateData :
|
|
30
30
|
T extends SPLIT_UPDATE ? ISplitUpdateData :
|
|
31
|
-
T extends SPLIT_KILL ? ISplitKillData :
|
|
31
|
+
T extends SPLIT_KILL ? ISplitKillData : INotificationData;
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* EventEmitter used as Feedback Loop between the SyncManager and PushManager,
|
|
35
35
|
* where the latter pushes messages and the former consumes it
|
|
36
36
|
*/
|
|
37
37
|
export interface IPushEventEmitter extends IEventEmitter {
|
|
38
|
-
once<T extends IPushEvent>(event: T, listener: (parsedData: IParsedData<T
|
|
39
|
-
on<T extends IPushEvent>(event: T, listener: (parsedData: IParsedData<T
|
|
40
|
-
emit<T extends IPushEvent>(event: T, parsedData?: IParsedData<T
|
|
38
|
+
once<T extends IPushEvent>(event: T, listener: (parsedData: IParsedData<T>) => void): this;
|
|
39
|
+
on<T extends IPushEvent>(event: T, listener: (parsedData: IParsedData<T>) => void): this;
|
|
40
|
+
emit<T extends IPushEvent>(event: T, parsedData?: IParsedData<T>): boolean;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
@@ -103,7 +103,7 @@ export type DROPPED = 1;
|
|
|
103
103
|
export type DEDUPED = 2;
|
|
104
104
|
export type ImpressionDataType = QUEUED | DROPPED | DEDUPED
|
|
105
105
|
export type EventDataType = QUEUED | DROPPED;
|
|
106
|
-
export type UpdatesFromSSEEnum = SPLITS |
|
|
106
|
+
export type UpdatesFromSSEEnum = SPLITS | MEMBERSHIPS;
|
|
107
107
|
|
|
108
108
|
export type SPLITS = 'sp';
|
|
109
109
|
export type IMPRESSIONS = 'im';
|
|
@@ -112,8 +112,8 @@ export type EVENTS = 'ev';
|
|
|
112
112
|
export type TELEMETRY = 'te';
|
|
113
113
|
export type TOKEN = 'to';
|
|
114
114
|
export type SEGMENT = 'se';
|
|
115
|
-
export type
|
|
116
|
-
export type OperationType = SPLITS | IMPRESSIONS | IMPRESSIONS_COUNT | EVENTS | TELEMETRY | TOKEN | SEGMENT |
|
|
115
|
+
export type MEMBERSHIPS = 'ms';
|
|
116
|
+
export type OperationType = SPLITS | IMPRESSIONS | IMPRESSIONS_COUNT | EVENTS | TELEMETRY | TOKEN | SEGMENT | MEMBERSHIPS;
|
|
117
117
|
|
|
118
118
|
export type LastSync = Partial<Record<OperationType, number | undefined>>
|
|
119
119
|
export type HttpErrors = Partial<Record<OperationType, { [statusCode: string]: number }>>
|
|
@@ -158,8 +158,9 @@ export type TelemetryUsageStats = {
|
|
|
158
158
|
|
|
159
159
|
// amount of instant updates that we are doing by avoiding fetching to Split servers
|
|
160
160
|
export type UpdatesFromSSE = {
|
|
161
|
-
sp
|
|
161
|
+
sp?: number, // splits
|
|
162
162
|
ms?: number, // my segments
|
|
163
|
+
mls?: number // my large segments
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
// 'metrics/usage' JSON request body
|
|
@@ -175,12 +176,14 @@ export type TelemetryUsageStatsPayload = TelemetryUsageStats & {
|
|
|
175
176
|
spC?: number, // splitCount
|
|
176
177
|
seC?: number, // segmentCount
|
|
177
178
|
skC?: number, // segmentKeyCount
|
|
179
|
+
lsC?: number, // largeSegmentCount
|
|
180
|
+
lskC?: number, // largeSegmentKeyCount
|
|
178
181
|
sL?: number, // sessionLengthMs
|
|
179
182
|
eQ: number, // eventsQueued
|
|
180
183
|
eD: number, // eventsDropped
|
|
181
184
|
sE: Array<StreamingEvent>, // streamingEvents
|
|
182
185
|
t?: Array<string>, // tags
|
|
183
|
-
ufs?: UpdatesFromSSE, //
|
|
186
|
+
ufs?: UpdatesFromSSE, // instant updates
|
|
184
187
|
}
|
|
185
188
|
|
|
186
189
|
/**
|
package/src/types.ts
CHANGED
|
@@ -426,7 +426,7 @@ export interface IStatusInterface extends IEventEmitter {
|
|
|
426
426
|
* @interface IBasicClient
|
|
427
427
|
* @extends IStatusInterface
|
|
428
428
|
*/
|
|
429
|
-
interface IBasicClient extends IStatusInterface {
|
|
429
|
+
export interface IBasicClient extends IStatusInterface {
|
|
430
430
|
/**
|
|
431
431
|
* Flush data
|
|
432
432
|
* @function flush
|
|
@@ -459,6 +459,12 @@ interface IBasicSDK {
|
|
|
459
459
|
* @property Logger
|
|
460
460
|
*/
|
|
461
461
|
Logger: ILoggerAPI
|
|
462
|
+
/**
|
|
463
|
+
* Destroy all the clients created by this factory.
|
|
464
|
+
* @function destroy
|
|
465
|
+
* @returns {Promise<void>}
|
|
466
|
+
*/
|
|
467
|
+
destroy(): Promise<void>
|
|
462
468
|
}
|
|
463
469
|
/****** Exposed namespace ******/
|
|
464
470
|
/**
|
|
@@ -75,7 +75,7 @@ export const EVENTS = 'ev';
|
|
|
75
75
|
export const TELEMETRY = 'te';
|
|
76
76
|
export const TOKEN = 'to';
|
|
77
77
|
export const SEGMENT = 'se';
|
|
78
|
-
export const
|
|
78
|
+
export const MEMBERSHIPS = 'ms';
|
|
79
79
|
|
|
80
80
|
export const TREATMENT = 't';
|
|
81
81
|
export const TREATMENTS = 'ts';
|
|
@@ -105,7 +105,8 @@ export const DISABLED = 0;
|
|
|
105
105
|
export const ENABLED = 1;
|
|
106
106
|
export const PAUSED = 2;
|
|
107
107
|
|
|
108
|
-
export const FLAG_SPEC_VERSION = '1.
|
|
108
|
+
export const FLAG_SPEC_VERSION = '1.2';
|
|
109
109
|
|
|
110
110
|
// Matcher types
|
|
111
111
|
export const IN_SEGMENT = 'IN_SEGMENT';
|
|
112
|
+
export const IN_LARGE_SEGMENT = 'IN_LARGE_SEGMENT';
|
|
@@ -209,11 +209,12 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
|
|
|
209
209
|
const splitFiltersValidation = validateSplitFilters(log, sync.splitFilters, withDefaults.mode);
|
|
210
210
|
sync.splitFilters = splitFiltersValidation.validFilters;
|
|
211
211
|
sync.__splitFiltersValidation = splitFiltersValidation;
|
|
212
|
-
sync.flagSpecVersion = flagSpec ? flagSpec(withDefaults) : FLAG_SPEC_VERSION;
|
|
213
212
|
|
|
213
|
+
// ensure a valid flag spec version
|
|
214
|
+
sync.flagSpecVersion = flagSpec ? flagSpec(withDefaults) : FLAG_SPEC_VERSION;
|
|
214
215
|
// ensure a valid user consent value
|
|
215
216
|
// @ts-ignore, modify readonly prop
|
|
216
|
-
withDefaults.userConsent = consent(withDefaults);
|
|
217
|
+
withDefaults.userConsent = consent ? consent(withDefaults) : undefined;
|
|
217
218
|
|
|
218
219
|
return withDefaults;
|
|
219
220
|
}
|
|
@@ -25,7 +25,7 @@ export interface ISettingsValidationParams {
|
|
|
25
25
|
/** Localhost mode validator (`settings.sync.localhostMode`) */
|
|
26
26
|
localhost?: (settings: ISettings) => ISettings['sync']['localhostMode'],
|
|
27
27
|
/** User consent validator (`settings.userConsent`) */
|
|
28
|
-
consent
|
|
28
|
+
consent?: (settings: ISettings) => ISettings['userConsent'],
|
|
29
29
|
/** Flag spec version validation. Configurable by the JS Synchronizer but not by the SDKs */
|
|
30
30
|
flagSpec?: (settings: ISettings) => ISettings['sync']['flagSpecVersion']
|
|
31
31
|
}
|