@splitsoftware/splitio-commons 1.16.1-rc.1 → 1.16.1-rc.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +4 -0
- package/cjs/logger/constants.js +5 -4
- package/cjs/logger/messages/info.js +2 -1
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/readiness/readinessManager.js +7 -12
- package/cjs/services/splitApi.js +5 -9
- package/cjs/storages/AbstractSegmentsCacheSync.js +41 -12
- package/cjs/storages/AbstractSplitsCacheAsync.js +2 -2
- package/cjs/storages/AbstractSplitsCacheSync.js +7 -5
- package/cjs/storages/KeyBuilder.js +0 -3
- package/cjs/storages/KeyBuilderCS.js +6 -0
- package/cjs/storages/dataLoader.js +1 -1
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +29 -52
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +4 -16
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +9 -40
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +6 -15
- package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +4 -11
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/cjs/sync/polling/pollingManagerCS.js +33 -51
- package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +14 -20
- package/cjs/sync/streaming/AuthClient/index.js +1 -1
- package/cjs/sync/streaming/SSEHandler/index.js +3 -6
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +15 -9
- package/cjs/sync/streaming/constants.js +3 -4
- package/cjs/sync/streaming/parseUtils.js +14 -9
- package/cjs/sync/streaming/pushManager.js +29 -55
- package/cjs/sync/submitters/telemetrySubmitter.js +0 -2
- package/cjs/sync/syncManagerOnline.js +14 -24
- package/cjs/utils/constants/index.js +4 -5
- package/cjs/utils/settingsValidation/index.js +1 -5
- package/esm/logger/constants.js +2 -1
- package/esm/logger/messages/info.js +2 -1
- package/esm/logger/messages/warn.js +1 -1
- package/esm/readiness/readinessManager.js +7 -12
- package/esm/services/splitApi.js +6 -10
- package/esm/storages/AbstractSegmentsCacheSync.js +41 -12
- package/esm/storages/AbstractSplitsCacheAsync.js +2 -2
- package/esm/storages/AbstractSplitsCacheSync.js +5 -3
- package/esm/storages/KeyBuilder.js +0 -3
- package/esm/storages/KeyBuilderCS.js +6 -0
- package/esm/storages/dataLoader.js +1 -1
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +29 -52
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +5 -17
- package/esm/storages/inMemory/MySegmentsCacheInMemory.js +9 -40
- package/esm/storages/inMemory/SplitsCacheInMemory.js +7 -16
- package/esm/sync/polling/fetchers/mySegmentsFetcher.js +4 -11
- package/esm/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/esm/sync/polling/pollingManagerCS.js +34 -52
- package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +12 -18
- package/esm/sync/streaming/AuthClient/index.js +1 -1
- package/esm/sync/streaming/SSEHandler/index.js +4 -7
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +15 -9
- package/esm/sync/streaming/constants.js +2 -3
- package/esm/sync/streaming/parseUtils.js +12 -8
- package/esm/sync/streaming/pushManager.js +32 -57
- package/esm/sync/submitters/telemetrySubmitter.js +0 -2
- package/esm/sync/syncManagerOnline.js +15 -25
- package/esm/utils/constants/index.js +2 -3
- package/esm/utils/settingsValidation/index.js +1 -5
- package/package.json +1 -1
- package/src/dtos/types.ts +7 -8
- package/src/logger/constants.ts +2 -1
- package/src/logger/messages/info.ts +2 -1
- package/src/logger/messages/warn.ts +1 -1
- package/src/readiness/readinessManager.ts +7 -9
- package/src/readiness/types.ts +0 -1
- package/src/services/splitApi.ts +7 -12
- package/src/services/splitHttpClient.ts +1 -1
- package/src/services/types.ts +2 -3
- package/src/storages/AbstractSegmentsCacheSync.ts +53 -12
- package/src/storages/AbstractSplitsCacheAsync.ts +2 -2
- package/src/storages/AbstractSplitsCacheSync.ts +7 -5
- package/src/storages/KeyBuilder.ts +0 -3
- package/src/storages/KeyBuilderCS.ts +9 -0
- package/src/storages/dataLoader.ts +1 -1
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +26 -56
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +5 -20
- package/src/storages/inMemory/MySegmentsCacheInMemory.ts +10 -44
- package/src/storages/inMemory/SplitsCacheInMemory.ts +7 -13
- package/src/storages/types.ts +10 -8
- package/src/sync/polling/fetchers/mySegmentsFetcher.ts +7 -14
- package/src/sync/polling/fetchers/segmentChangesFetcher.ts +1 -1
- package/src/sync/polling/fetchers/types.ts +2 -2
- package/src/sync/polling/pollingManagerCS.ts +29 -61
- package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +12 -13
- package/src/sync/polling/types.ts +8 -8
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +17 -18
- 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 -9
- package/src/sync/streaming/SSEHandler/types.ts +13 -25
- package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +17 -12
- 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 -3
- package/src/sync/streaming/parseUtils.ts +19 -11
- package/src/sync/streaming/pushManager.ts +38 -68
- package/src/sync/streaming/types.ts +11 -13
- package/src/sync/submitters/telemetrySubmitter.ts +0 -2
- package/src/sync/submitters/types.ts +3 -6
- package/src/sync/syncManagerOnline.ts +11 -19
- package/src/types.ts +1 -26
- package/src/utils/constants/index.ts +2 -3
- package/src/utils/settingsValidation/index.ts +1 -5
- package/types/dtos/types.d.ts +7 -8
- package/types/logger/constants.d.ts +2 -1
- package/types/readiness/types.d.ts +0 -1
- package/types/services/decorateHeaders.d.ts +2 -0
- package/types/services/splitApi.d.ts +1 -1
- package/types/services/splitHttpClient.d.ts +1 -1
- package/types/services/types.d.ts +2 -3
- package/types/storages/AbstractSegmentsCacheSync.d.ts +9 -11
- package/types/storages/AbstractSplitsCacheAsync.d.ts +1 -1
- package/types/storages/AbstractSplitsCacheSync.d.ts +4 -4
- package/types/storages/KeyBuilder.d.ts +0 -1
- package/types/storages/KeyBuilderCS.d.ts +2 -0
- package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +2 -12
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +1 -1
- package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +3 -9
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +1 -2
- package/types/storages/types.d.ts +8 -7
- 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 +4 -3
- package/types/sync/polling/types.d.ts +8 -12
- package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +3 -2
- package/types/sync/streaming/SSEHandler/types.d.ts +13 -22
- package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -3
- 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 -3
- package/types/sync/streaming/parseUtils.d.ts +4 -5
- package/types/sync/streaming/pushManager.d.ts +0 -2
- package/types/sync/streaming/pushManagerCS_Spec1_3.d.ts +9 -0
- package/types/sync/streaming/pushManager_Spec1_3.d.ts +9 -0
- package/types/sync/streaming/types.d.ts +9 -10
- package/types/sync/submitters/types.d.ts +3 -6
- package/types/types.d.ts +0 -25
- package/types/utils/constants/index.d.ts +2 -3
- package/types/utils/settingsValidation/index.d.ts +0 -2
|
@@ -1,31 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { IFetchMemberships, IResponse } from '../../../services/types';
|
|
2
|
+
import { IMembershipsResponse } from '../../../dtos/types';
|
|
3
3
|
import { IMySegmentsFetcher } from './types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Factory of MySegments fetcher.
|
|
7
7
|
* MySegments fetcher is a wrapper around `mySegments` API service that parses the response and handle errors.
|
|
8
8
|
*/
|
|
9
|
-
export function mySegmentsFetcherFactory(
|
|
9
|
+
export function mySegmentsFetcherFactory(fetchMemberships: IFetchMemberships): IMySegmentsFetcher {
|
|
10
10
|
|
|
11
11
|
return function mySegmentsFetcher(
|
|
12
12
|
userMatchingKey: string,
|
|
13
13
|
noCache?: boolean,
|
|
14
|
-
// Optional decorator for `
|
|
14
|
+
// Optional decorator for `fetchMemberships` promise, such as timeout or time tracker
|
|
15
15
|
decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
|
|
16
|
-
): Promise<
|
|
16
|
+
): Promise<IMembershipsResponse> {
|
|
17
17
|
|
|
18
|
-
let mySegmentsPromise =
|
|
18
|
+
let mySegmentsPromise = fetchMemberships(userMatchingKey, noCache);
|
|
19
19
|
if (decorator) mySegmentsPromise = decorator(mySegmentsPromise);
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
return mySegmentsPromise
|
|
23
|
-
.then(resp => resp.json())
|
|
24
|
-
.then((json: IMySegmentsResponse | IMyLargeSegmentsResponse) => {
|
|
25
|
-
return (json as IMySegmentsResponse).mySegments ?
|
|
26
|
-
(json as IMySegmentsResponse).mySegments.map((segment) => segment.name) :
|
|
27
|
-
(json as IMyLargeSegmentsResponse).myLargeSegments;
|
|
28
|
-
});
|
|
21
|
+
return mySegmentsPromise.then(resp => resp.json());
|
|
29
22
|
};
|
|
30
23
|
|
|
31
24
|
}
|
|
@@ -28,7 +28,7 @@ export function segmentChangesFetcherFactory(fetchSegmentChanges: IFetchSegmentC
|
|
|
28
28
|
segmentName: string,
|
|
29
29
|
noCache?: boolean,
|
|
30
30
|
till?: number,
|
|
31
|
-
// Optional decorator for `
|
|
31
|
+
// Optional decorator for `fetchSegmentChanges` promise, such as timeout or time tracker
|
|
32
32
|
decorator?: (promise: Promise<ISegmentChangesResponse[]>) => Promise<ISegmentChangesResponse[]>
|
|
33
33
|
): Promise<ISegmentChangesResponse[]> {
|
|
34
34
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ISplitChangesResponse, ISegmentChangesResponse } from '../../../dtos/types';
|
|
1
|
+
import { ISplitChangesResponse, ISegmentChangesResponse, IMembershipsResponse } from '../../../dtos/types';
|
|
2
2
|
import { IResponse } from '../../../services/types';
|
|
3
3
|
|
|
4
4
|
export type ISplitChangesFetcher = (
|
|
@@ -20,4 +20,4 @@ export type IMySegmentsFetcher = (
|
|
|
20
20
|
userMatchingKey: string,
|
|
21
21
|
noCache?: boolean,
|
|
22
22
|
decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
|
|
23
|
-
) => Promise<
|
|
23
|
+
) => Promise<IMembershipsResponse>
|
|
@@ -6,9 +6,8 @@ import { mySegmentsSyncTaskFactory } from './syncTasks/mySegmentsSyncTask';
|
|
|
6
6
|
import { splitsSyncTaskFactory } from './syncTasks/splitsSyncTask';
|
|
7
7
|
import { getMatching } from '../../utils/key';
|
|
8
8
|
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../../readiness/constants';
|
|
9
|
-
import { POLLING_START, POLLING_STOP } from '../../logger/constants';
|
|
9
|
+
import { POLLING_SMART_PAUSING, POLLING_START, POLLING_STOP } from '../../logger/constants';
|
|
10
10
|
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
11
|
-
import { IN_LARGE_SEGMENT, IN_SEGMENT } from '../../utils/constants';
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* Expose start / stop mechanism for polling data from services.
|
|
@@ -23,92 +22,62 @@ export function pollingManagerCSFactory(
|
|
|
23
22
|
|
|
24
23
|
const splitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings, true);
|
|
25
24
|
|
|
26
|
-
// Map of matching keys to their corresponding MySegmentsSyncTask
|
|
27
|
-
const mySegmentsSyncTasks: Record<string,
|
|
25
|
+
// Map of matching keys to their corresponding MySegmentsSyncTask.
|
|
26
|
+
const mySegmentsSyncTasks: Record<string, IMySegmentsSyncTask> = {};
|
|
28
27
|
|
|
29
28
|
const matchingKey = getMatching(settings.core.key);
|
|
30
|
-
const
|
|
29
|
+
const mySegmentsSyncTask = add(matchingKey, readiness, storage);
|
|
31
30
|
|
|
32
31
|
function startMySegmentsSyncTasks() {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
forOwn(mySegmentsSyncTasks, ({ msSyncTask, mlsSyncTask }) => {
|
|
37
|
-
if (splitsHaveSegments) msSyncTask.start();
|
|
38
|
-
else msSyncTask.stop(); // smart pausing
|
|
39
|
-
|
|
40
|
-
if (mlsSyncTask) {
|
|
41
|
-
if (splitsHaveLargeSegments) mlsSyncTask.start();
|
|
42
|
-
else mlsSyncTask.stop(); // smart pausing
|
|
43
|
-
}
|
|
32
|
+
forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask) => {
|
|
33
|
+
mySegmentsSyncTask.start();
|
|
44
34
|
});
|
|
45
35
|
}
|
|
46
36
|
|
|
47
37
|
function stopMySegmentsSyncTasks() {
|
|
48
|
-
forOwn(mySegmentsSyncTasks, (
|
|
49
|
-
|
|
50
|
-
mlsSyncTask && mlsSyncTask.stop();
|
|
38
|
+
forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask) => {
|
|
39
|
+
if (mySegmentsSyncTask.isRunning()) mySegmentsSyncTask.stop();
|
|
51
40
|
});
|
|
52
41
|
}
|
|
53
42
|
|
|
43
|
+
// smart pausing
|
|
54
44
|
readiness.splits.on(SDK_SPLITS_ARRIVED, () => {
|
|
55
|
-
if (splitsSyncTask.isRunning())
|
|
45
|
+
if (!splitsSyncTask.isRunning()) return; // noop if not doing polling
|
|
46
|
+
const splitsHaveSegments = storage.splits.usesSegments();
|
|
47
|
+
if (splitsHaveSegments !== mySegmentsSyncTask.isRunning()) {
|
|
48
|
+
log.info(POLLING_SMART_PAUSING, [splitsHaveSegments ? 'ON' : 'OFF']);
|
|
49
|
+
if (splitsHaveSegments) {
|
|
50
|
+
startMySegmentsSyncTasks();
|
|
51
|
+
} else {
|
|
52
|
+
stopMySegmentsSyncTasks();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
56
55
|
});
|
|
57
56
|
|
|
58
57
|
function add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync) {
|
|
59
|
-
const
|
|
60
|
-
splitApi.fetchMySegments,
|
|
61
|
-
storage.segments,
|
|
62
|
-
() => { if (storage.splits.usesMatcher(IN_SEGMENT)) readiness.segments.emit(SDK_SEGMENTS_ARRIVED); },
|
|
63
|
-
settings,
|
|
64
|
-
matchingKey,
|
|
65
|
-
settings.scheduler.segmentsRefreshRate,
|
|
66
|
-
'mySegmentsUpdater'
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
let mlsSyncTask;
|
|
70
|
-
if (settings.sync.largeSegmentsEnabled) {
|
|
71
|
-
mlsSyncTask = mySegmentsSyncTaskFactory(
|
|
72
|
-
splitApi.fetchMyLargeSegments,
|
|
73
|
-
storage.largeSegments!,
|
|
74
|
-
() => { if (readiness.largeSegments && storage.splits.usesMatcher(IN_LARGE_SEGMENT)) readiness.largeSegments.emit(SDK_SEGMENTS_ARRIVED); },
|
|
75
|
-
settings,
|
|
76
|
-
matchingKey,
|
|
77
|
-
settings.scheduler.largeSegmentsRefreshRate,
|
|
78
|
-
'myLargeSegmentsUpdater'
|
|
79
|
-
);
|
|
80
|
-
}
|
|
58
|
+
const mySegmentsSyncTask = mySegmentsSyncTaskFactory(splitApi.fetchMemberships, storage, readiness, settings, matchingKey);
|
|
81
59
|
|
|
82
60
|
// smart ready
|
|
83
61
|
function smartReady() {
|
|
84
|
-
if (!readiness.isReady())
|
|
85
|
-
if (readiness.largeSegments && !storage.splits.usesMatcher(IN_LARGE_SEGMENT)) readiness.largeSegments.emit(SDK_SEGMENTS_ARRIVED);
|
|
86
|
-
if (!storage.splits.usesMatcher(IN_SEGMENT)) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
87
|
-
}
|
|
62
|
+
if (!readiness.isReady() && !storage.splits.usesSegments()) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
88
63
|
}
|
|
64
|
+
if (!storage.splits.usesSegments()) setTimeout(smartReady, 0);
|
|
65
|
+
else readiness.splits.once(SDK_SPLITS_ARRIVED, smartReady);
|
|
89
66
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
mySegmentsSyncTasks[matchingKey] = { msSyncTask: msSyncTask, mlsSyncTask: mlsSyncTask };
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
msSyncTask,
|
|
97
|
-
mlsSyncTask
|
|
98
|
-
};
|
|
67
|
+
mySegmentsSyncTasks[matchingKey] = mySegmentsSyncTask;
|
|
68
|
+
return mySegmentsSyncTask;
|
|
99
69
|
}
|
|
100
70
|
|
|
101
71
|
return {
|
|
102
72
|
splitsSyncTask,
|
|
103
|
-
segmentsSyncTask:
|
|
104
|
-
largeSegmentsSyncTask: mlsSyncTask,
|
|
73
|
+
segmentsSyncTask: mySegmentsSyncTask,
|
|
105
74
|
|
|
106
75
|
// Start periodic fetching (polling)
|
|
107
76
|
start() {
|
|
108
77
|
log.info(POLLING_START);
|
|
109
78
|
|
|
110
79
|
splitsSyncTask.start();
|
|
111
|
-
startMySegmentsSyncTasks();
|
|
80
|
+
if (storage.splits.usesSegments()) startMySegmentsSyncTasks();
|
|
112
81
|
},
|
|
113
82
|
|
|
114
83
|
// Stop periodic fetching (polling)
|
|
@@ -125,9 +94,8 @@ export function pollingManagerCSFactory(
|
|
|
125
94
|
// fetch splits and segments
|
|
126
95
|
syncAll() {
|
|
127
96
|
const promises = [splitsSyncTask.execute()];
|
|
128
|
-
forOwn(mySegmentsSyncTasks,
|
|
129
|
-
promises.push(
|
|
130
|
-
mlsSyncTask && promises.push(mlsSyncTask.execute());
|
|
97
|
+
forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask) => {
|
|
98
|
+
promises.push(mySegmentsSyncTask.execute());
|
|
131
99
|
});
|
|
132
100
|
return Promise.all(promises);
|
|
133
101
|
},
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IStorageSync } from '../../../storages/types';
|
|
2
|
+
import { IReadinessManager } from '../../../readiness/types';
|
|
2
3
|
import { syncTaskFactory } from '../../syncTask';
|
|
3
4
|
import { IMySegmentsSyncTask } from '../types';
|
|
4
|
-
import {
|
|
5
|
+
import { IFetchMemberships } from '../../../services/types';
|
|
5
6
|
import { mySegmentsFetcherFactory } from '../fetchers/mySegmentsFetcher';
|
|
6
7
|
import { ISettings } from '../../../types';
|
|
7
8
|
import { mySegmentsUpdaterFactory } from '../updaters/mySegmentsUpdater';
|
|
@@ -10,26 +11,24 @@ import { mySegmentsUpdaterFactory } from '../updaters/mySegmentsUpdater';
|
|
|
10
11
|
* Creates a sync task that periodically executes a `mySegmentsUpdater` task
|
|
11
12
|
*/
|
|
12
13
|
export function mySegmentsSyncTaskFactory(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
fetchMemberships: IFetchMemberships,
|
|
15
|
+
storage: IStorageSync,
|
|
16
|
+
readiness: IReadinessManager,
|
|
16
17
|
settings: ISettings,
|
|
17
|
-
matchingKey: string
|
|
18
|
-
segmentsRefreshRate: number,
|
|
19
|
-
NAME: string
|
|
18
|
+
matchingKey: string
|
|
20
19
|
): IMySegmentsSyncTask {
|
|
21
20
|
return syncTaskFactory(
|
|
22
21
|
settings.log,
|
|
23
22
|
mySegmentsUpdaterFactory(
|
|
24
23
|
settings.log,
|
|
25
|
-
mySegmentsFetcherFactory(
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
mySegmentsFetcherFactory(fetchMemberships),
|
|
25
|
+
storage,
|
|
26
|
+
readiness.segments,
|
|
28
27
|
settings.startup.requestTimeoutBeforeReady,
|
|
29
28
|
settings.startup.retriesOnFailureBeforeReady,
|
|
30
29
|
matchingKey
|
|
31
30
|
),
|
|
32
|
-
segmentsRefreshRate,
|
|
33
|
-
|
|
31
|
+
settings.scheduler.segmentsRefreshRate,
|
|
32
|
+
'mySegmentsUpdater',
|
|
34
33
|
);
|
|
35
34
|
}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { ISplit } from '../../dtos/types';
|
|
2
2
|
import { IReadinessManager } from '../../readiness/types';
|
|
3
3
|
import { IStorageSync } from '../../storages/types';
|
|
4
|
+
import { MEMBERSHIP_LS_UPDATE, MEMBERSHIP_MS_UPDATE } from '../streaming/types';
|
|
4
5
|
import { ITask, ISyncTask } from '../types';
|
|
5
6
|
|
|
6
7
|
export interface ISplitsSyncTask extends ISyncTask<[noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }], boolean> { }
|
|
7
8
|
|
|
8
9
|
export interface ISegmentsSyncTask extends ISyncTask<[fetchOnlyNew?: boolean, segmentName?: string, noCache?: boolean, till?: number], boolean> { }
|
|
9
10
|
|
|
10
|
-
export type MySegmentsData =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
export type MySegmentsData = {
|
|
12
|
+
type: MEMBERSHIP_MS_UPDATE | MEMBERSHIP_LS_UPDATE
|
|
13
|
+
cn: number
|
|
14
|
+
added: string[]
|
|
15
|
+
removed: string[]
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export interface IMySegmentsSyncTask extends ISyncTask<[segmentsData?: MySegmentsData, noCache?: boolean], boolean> { }
|
|
@@ -20,14 +21,13 @@ export interface IPollingManager extends ITask {
|
|
|
20
21
|
syncAll(): Promise<any>
|
|
21
22
|
splitsSyncTask: ISplitsSyncTask
|
|
22
23
|
segmentsSyncTask: ISyncTask
|
|
23
|
-
largeSegmentsSyncTask?: ISyncTask
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* PollingManager for client-side with support for multiple clients
|
|
28
28
|
*/
|
|
29
29
|
export interface IPollingManagerCS extends IPollingManager {
|
|
30
|
-
add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync):
|
|
30
|
+
add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync): IMySegmentsSyncTask
|
|
31
31
|
remove(matchingKey: string): void;
|
|
32
|
-
get(matchingKey: string):
|
|
32
|
+
get(matchingKey: string): IMySegmentsSyncTask | undefined
|
|
33
33
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { IMySegmentsFetcher } from '../fetchers/types';
|
|
2
|
-
import {
|
|
2
|
+
import { IStorageSync } from '../../../storages/types';
|
|
3
|
+
import { ISegmentsEventEmitter } from '../../../readiness/types';
|
|
3
4
|
import { timeout } from '../../../utils/promise/timeout';
|
|
5
|
+
import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
|
|
4
6
|
import { ILogger } from '../../../logger/types';
|
|
5
7
|
import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants';
|
|
6
8
|
import { MySegmentsData } from '../types';
|
|
9
|
+
import { IMembershipsResponse } from '../../../dtos/types';
|
|
10
|
+
import { MEMBERSHIP_LS_UPDATE } from '../../streaming/constants';
|
|
7
11
|
|
|
8
12
|
type IMySegmentsUpdater = (segmentList?: MySegmentsData, noCache?: boolean) => Promise<boolean>
|
|
9
13
|
|
|
@@ -16,13 +20,14 @@ type IMySegmentsUpdater = (segmentList?: MySegmentsData, noCache?: boolean) => P
|
|
|
16
20
|
export function mySegmentsUpdaterFactory(
|
|
17
21
|
log: ILogger,
|
|
18
22
|
mySegmentsFetcher: IMySegmentsFetcher,
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
storage: IStorageSync,
|
|
24
|
+
segmentsEventEmitter: ISegmentsEventEmitter,
|
|
21
25
|
requestTimeoutBeforeReady: number,
|
|
22
26
|
retriesOnFailureBeforeReady: number,
|
|
23
27
|
matchingKey: string
|
|
24
28
|
): IMySegmentsUpdater {
|
|
25
29
|
|
|
30
|
+
const { splits, segments, largeSegments } = storage;
|
|
26
31
|
let readyOnAlreadyExistentState = true;
|
|
27
32
|
let startingUp = true;
|
|
28
33
|
|
|
@@ -33,28 +38,22 @@ export function mySegmentsUpdaterFactory(
|
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
// @TODO if allowing pluggable storages, handle async execution
|
|
36
|
-
function updateSegments(segmentsData: MySegmentsData) {
|
|
41
|
+
function updateSegments(segmentsData: IMembershipsResponse | MySegmentsData) {
|
|
37
42
|
|
|
38
43
|
let shouldNotifyUpdate;
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
if ((segmentsData as MySegmentsData).type !== undefined) {
|
|
45
|
+
shouldNotifyUpdate = (segmentsData as MySegmentsData).type === MEMBERSHIP_LS_UPDATE ?
|
|
46
|
+
largeSegments!.resetSegments(segmentsData as MySegmentsData) :
|
|
47
|
+
segments.resetSegments(segmentsData as MySegmentsData);
|
|
42
48
|
} else {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (mySegmentsCache.isInSegment(name) !== add) {
|
|
46
|
-
shouldNotifyUpdate = true;
|
|
47
|
-
if (add) mySegmentsCache.addToSegment(name);
|
|
48
|
-
else mySegmentsCache.removeFromSegment(name);
|
|
49
|
-
} else {
|
|
50
|
-
shouldNotifyUpdate = false;
|
|
51
|
-
}
|
|
49
|
+
shouldNotifyUpdate = segments.resetSegments((segmentsData as IMembershipsResponse).ms || {});
|
|
50
|
+
shouldNotifyUpdate = largeSegments!.resetSegments((segmentsData as IMembershipsResponse).ls || {}) || shouldNotifyUpdate;
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
// Notify update if required
|
|
55
|
-
if (shouldNotifyUpdate || readyOnAlreadyExistentState) {
|
|
54
|
+
if (splits.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
|
|
56
55
|
readyOnAlreadyExistentState = false;
|
|
57
|
-
|
|
56
|
+
segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
|
|
@@ -14,7 +14,7 @@ export function authenticateFactory(fetchAuth: IFetchAuth): IAuthenticate {
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Run authentication requests to Auth Server, and returns a promise that resolves with the decoded JTW token.
|
|
17
|
-
* @param {string[] | undefined} userKeys set of user Keys to track
|
|
17
|
+
* @param {string[] | undefined} userKeys set of user Keys to track membership updates. It is undefined for server-side API.
|
|
18
18
|
*/
|
|
19
19
|
return function authenticate(userKeys?: string[]): Promise<IAuthToken> {
|
|
20
20
|
return fetchAuth(userKeys)
|
|
@@ -76,12 +76,10 @@ export class SSEClient implements ISSEClient {
|
|
|
76
76
|
open(authToken: IAuthTokenPushEnabled) {
|
|
77
77
|
this.close(); // it closes connection if previously opened
|
|
78
78
|
|
|
79
|
-
const channelsQueryParam = Object.keys(authToken.channels).map(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
).join(',');
|
|
79
|
+
const channelsQueryParam = Object.keys(authToken.channels).map((channel) => {
|
|
80
|
+
const params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
|
|
81
|
+
return encodeURIComponent(params + channel);
|
|
82
|
+
}).join(',');
|
|
85
83
|
const url = `${this.streamingUrl}?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${ABLY_API_VERSION}&heartbeats=true`; // same results using `&heartbeats=false`
|
|
86
84
|
|
|
87
85
|
this.connection = new this.eventSource!(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { errorParser, messageParser } from './NotificationParser';
|
|
2
2
|
import { notificationKeeperFactory } from './NotificationKeeper';
|
|
3
|
-
import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL,
|
|
3
|
+
import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MEMBERSHIP_MS_UPDATE, MEMBERSHIP_LS_UPDATE } from '../constants';
|
|
4
4
|
import { IPushEventEmitter } from '../types';
|
|
5
5
|
import { ISseEventHandler } from '../SSEClient/types';
|
|
6
6
|
import { INotificationError, INotificationMessage } from './types';
|
|
@@ -74,22 +74,18 @@ export function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventEmitter,
|
|
|
74
74
|
const { parsedData, data, channel, timestamp } = messageWithParsedData;
|
|
75
75
|
log.debug(STREAMING_NEW_MESSAGE, [data]);
|
|
76
76
|
|
|
77
|
-
// we only handle update events if streaming is up
|
|
78
|
-
if (!notificationKeeper.isStreamingUp() && [OCCUPANCY, CONTROL].indexOf(parsedData.type) === -1)
|
|
79
|
-
return;
|
|
77
|
+
// we only handle update events if streaming is up
|
|
78
|
+
if (!notificationKeeper.isStreamingUp() && [OCCUPANCY, CONTROL].indexOf(parsedData.type) === -1) return;
|
|
80
79
|
|
|
81
80
|
switch (parsedData.type) {
|
|
82
81
|
/* update events */
|
|
83
82
|
case SPLIT_UPDATE:
|
|
84
83
|
case SEGMENT_UPDATE:
|
|
85
|
-
case
|
|
86
|
-
case
|
|
84
|
+
case MEMBERSHIP_MS_UPDATE:
|
|
85
|
+
case MEMBERSHIP_LS_UPDATE:
|
|
87
86
|
case SPLIT_KILL:
|
|
88
87
|
pushEmitter.emit(parsedData.type, parsedData);
|
|
89
88
|
break;
|
|
90
|
-
case MY_SEGMENTS_UPDATE:
|
|
91
|
-
pushEmitter.emit(parsedData.type, parsedData, channel);
|
|
92
|
-
break;
|
|
93
89
|
|
|
94
90
|
/* occupancy & control events, handled by NotificationManagerKeeper */
|
|
95
91
|
case OCCUPANCY:
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { ControlType } from '../constants';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export interface IMySegmentsUpdateData {
|
|
5
|
-
type: MY_SEGMENTS_UPDATE,
|
|
6
|
-
changeNumber: number,
|
|
7
|
-
includesPayload: boolean,
|
|
8
|
-
segmentList?: string[]
|
|
9
|
-
}
|
|
2
|
+
import { SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MEMBERSHIP_LS_UPDATE, MEMBERSHIP_MS_UPDATE } from '../types';
|
|
10
3
|
|
|
11
4
|
export enum Compression {
|
|
12
5
|
None = 0,
|
|
@@ -26,27 +19,22 @@ export interface KeyList {
|
|
|
26
19
|
r?: string[], // decimal hash64 of user keys
|
|
27
20
|
}
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
type:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
c
|
|
34
|
-
d
|
|
35
|
-
u: UpdateStrategy,
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface IMyLargeSegmentsUpdateData {
|
|
39
|
-
type: MY_LARGE_SEGMENTS_UPDATE,
|
|
40
|
-
changeNumber: number,
|
|
41
|
-
largeSegments: string[],
|
|
42
|
-
c: Compression,
|
|
43
|
-
d: string,
|
|
22
|
+
interface IMembershipUpdateData<T extends string> {
|
|
23
|
+
type: T,
|
|
24
|
+
cn: number,
|
|
25
|
+
n?: string[],
|
|
26
|
+
c?: Compression,
|
|
27
|
+
d?: string,
|
|
44
28
|
u: UpdateStrategy,
|
|
45
29
|
i?: number, // time interval in millis
|
|
46
|
-
h?: number, // hash function
|
|
30
|
+
h?: number, // hash function
|
|
47
31
|
s?: number, // seed for hash function
|
|
48
32
|
}
|
|
49
33
|
|
|
34
|
+
export interface IMembershipMSUpdateData extends IMembershipUpdateData<MEMBERSHIP_MS_UPDATE> { }
|
|
35
|
+
|
|
36
|
+
export interface IMembershipLSUpdateData extends IMembershipUpdateData<MEMBERSHIP_LS_UPDATE> { }
|
|
37
|
+
|
|
50
38
|
export interface ISegmentUpdateData {
|
|
51
39
|
type: SEGMENT_UPDATE,
|
|
52
40
|
changeNumber: number,
|
|
@@ -80,6 +68,6 @@ export interface IOccupancyData {
|
|
|
80
68
|
}
|
|
81
69
|
}
|
|
82
70
|
|
|
83
|
-
export type INotificationData =
|
|
71
|
+
export type INotificationData = IMembershipMSUpdateData | IMembershipLSUpdateData | ISegmentUpdateData | ISplitUpdateData | ISplitKillData | IControlData | IOccupancyData
|
|
84
72
|
export type INotificationMessage = { parsedData: INotificationData, channel: string, timestamp: number, data: string }
|
|
85
73
|
export type INotificationError = Event & { parsedData?: any, message?: string }
|
|
@@ -2,12 +2,12 @@ import { IMySegmentsSyncTask, MySegmentsData } from '../../polling/types';
|
|
|
2
2
|
import { Backoff } from '../../../utils/Backoff';
|
|
3
3
|
import { IUpdateWorker } from './types';
|
|
4
4
|
import { ITelemetryTracker } from '../../../trackers/types';
|
|
5
|
-
import {
|
|
5
|
+
import { MEMBERSHIPS } from '../../../utils/constants';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* MySegmentsUpdateWorker factory
|
|
9
9
|
*/
|
|
10
|
-
export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker
|
|
10
|
+
export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker): IUpdateWorker<[mySegmentsData?: Pick<MySegmentsData, 'type' | 'cn'>, payload?: Pick<MySegmentsData, 'added' | 'removed'>, delay?: number]> {
|
|
11
11
|
|
|
12
12
|
let maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
|
|
13
13
|
let currentChangeNumber = -1;
|
|
@@ -15,7 +15,7 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
15
15
|
let isHandlingEvent: boolean;
|
|
16
16
|
let _segmentsData: MySegmentsData | undefined; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber
|
|
17
17
|
let _delay: undefined | number;
|
|
18
|
-
let _delayTimeoutID:
|
|
18
|
+
let _delayTimeoutID: any;
|
|
19
19
|
const backoff = new Backoff(__handleMySegmentsUpdateCall);
|
|
20
20
|
|
|
21
21
|
function __handleMySegmentsUpdateCall() {
|
|
@@ -28,6 +28,7 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
28
28
|
const syncTask = _delay ?
|
|
29
29
|
new Promise(res => {
|
|
30
30
|
_delayTimeoutID = setTimeout(() => {
|
|
31
|
+
_delay = undefined;
|
|
31
32
|
mySegmentsSyncTask.execute(_segmentsData, true).then(res);
|
|
32
33
|
}, _delay);
|
|
33
34
|
}) :
|
|
@@ -35,8 +36,8 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
35
36
|
|
|
36
37
|
syncTask.then((result) => {
|
|
37
38
|
if (!isHandlingEvent) return; // halt if `stop` has been called
|
|
38
|
-
if (result !== false) {// Unlike `Splits|SegmentsUpdateWorker`, we cannot use `mySegmentsCache.getChangeNumber` since `/mySegments` endpoint doesn't provide this value.
|
|
39
|
-
if (_segmentsData) telemetryTracker.trackUpdatesFromSSE(
|
|
39
|
+
if (result !== false) { // Unlike `Splits|SegmentsUpdateWorker`, we cannot use `mySegmentsCache.getChangeNumber` since `/mySegments` endpoint doesn't provide this value.
|
|
40
|
+
if (_segmentsData) telemetryTracker.trackUpdatesFromSSE(MEMBERSHIPS);
|
|
40
41
|
currentChangeNumber = Math.max(currentChangeNumber, currentMaxChangeNumber); // use `currentMaxChangeNumber`, in case that `maxChangeNumber` was updated during fetch.
|
|
41
42
|
}
|
|
42
43
|
if (handleNewEvent) {
|
|
@@ -52,17 +53,20 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
52
53
|
|
|
53
54
|
return {
|
|
54
55
|
/**
|
|
55
|
-
* Invoked by NotificationProcessor on
|
|
56
|
+
* Invoked by NotificationProcessor on MY_(LARGE)_SEGMENTS_UPDATE notifications
|
|
56
57
|
*
|
|
57
|
-
* @param
|
|
58
|
-
* @param
|
|
58
|
+
* @param changeNumber change number of the notification
|
|
59
|
+
* @param segmentsData data for KeyList or SegmentRemoval instant updates
|
|
60
|
+
* @param delay optional time to wait for BoundedFetchRequest or BoundedFetchRequest updates
|
|
59
61
|
*/
|
|
60
|
-
put(
|
|
61
|
-
|
|
62
|
+
put(mySegmentsData: Pick<MySegmentsData, 'type' | 'cn'>, payload?: Pick<MySegmentsData, 'added' | 'removed'>, delay?: number) {
|
|
63
|
+
const { type, cn } = mySegmentsData;
|
|
64
|
+
// Ignore event if it is outdated or if there is a pending fetch request (_delay is set)
|
|
65
|
+
if (cn <= currentChangeNumber || cn <= maxChangeNumber || _delay) return;
|
|
62
66
|
|
|
63
|
-
maxChangeNumber =
|
|
67
|
+
maxChangeNumber = cn;
|
|
64
68
|
handleNewEvent = true;
|
|
65
|
-
_segmentsData =
|
|
69
|
+
_segmentsData = payload && { type, cn, added: payload.added, removed: payload.removed };
|
|
66
70
|
_delay = delay;
|
|
67
71
|
|
|
68
72
|
if (backoff.timeoutID || !isHandlingEvent) __handleMySegmentsUpdateCall();
|
|
@@ -71,6 +75,7 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
71
75
|
|
|
72
76
|
stop() {
|
|
73
77
|
clearTimeout(_delayTimeoutID);
|
|
78
|
+
_delay = undefined;
|
|
74
79
|
isHandlingEvent = false;
|
|
75
80
|
backoff.reset();
|
|
76
81
|
}
|
|
@@ -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,12 +25,11 @@ 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 MEMBERSHIP_MS_UPDATE = 'MEMBERSHIP_MS_UPDATE';
|
|
29
|
+
export const MEMBERSHIP_LS_UPDATE = 'MEMBERSHIP_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';
|
|
33
|
-
export const MY_LARGE_SEGMENTS_UPDATE = 'MY_LARGE_SEGMENTS_UPDATE';
|
|
34
33
|
|
|
35
34
|
// Control-type push notifications, handled by NotificationKeeper
|
|
36
35
|
export const CONTROL = 'CONTROL';
|