@splitsoftware/splitio-commons 1.16.1-rc.10 → 1.16.1-rc.12

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.
Files changed (77) hide show
  1. package/cjs/logger/constants.js +2 -2
  2. package/cjs/logger/messages/warn.js +1 -1
  3. package/cjs/services/splitApi.js +3 -3
  4. package/cjs/storages/AbstractSegmentsCacheSync.js +41 -7
  5. package/cjs/storages/dataLoader.js +1 -1
  6. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +19 -63
  7. package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +5 -40
  8. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +1 -1
  9. package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +2 -2
  10. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +12 -21
  11. package/cjs/sync/streaming/AuthClient/index.js +1 -1
  12. package/cjs/sync/streaming/SSEHandler/index.js +5 -7
  13. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +106 -63
  14. package/cjs/sync/streaming/constants.js +3 -3
  15. package/cjs/sync/streaming/pushManager.js +25 -31
  16. package/cjs/utils/constants/index.js +3 -4
  17. package/esm/logger/constants.js +1 -1
  18. package/esm/logger/messages/warn.js +1 -1
  19. package/esm/services/splitApi.js +4 -4
  20. package/esm/storages/AbstractSegmentsCacheSync.js +41 -7
  21. package/esm/storages/dataLoader.js +1 -1
  22. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +19 -63
  23. package/esm/storages/inMemory/MySegmentsCacheInMemory.js +5 -40
  24. package/esm/storages/inMemory/TelemetryCacheInMemory.js +1 -1
  25. package/esm/sync/polling/fetchers/mySegmentsFetcher.js +2 -2
  26. package/esm/sync/polling/updaters/mySegmentsUpdater.js +12 -21
  27. package/esm/sync/streaming/AuthClient/index.js +1 -1
  28. package/esm/sync/streaming/SSEHandler/index.js +6 -8
  29. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +106 -63
  30. package/esm/sync/streaming/constants.js +2 -2
  31. package/esm/sync/streaming/pushManager.js +28 -34
  32. package/esm/utils/constants/index.js +1 -2
  33. package/package.json +1 -1
  34. package/src/dtos/types.ts +9 -12
  35. package/src/logger/constants.ts +1 -1
  36. package/src/logger/messages/warn.ts +1 -1
  37. package/src/services/splitApi.ts +4 -4
  38. package/src/services/types.ts +1 -1
  39. package/src/storages/AbstractSegmentsCacheSync.ts +52 -7
  40. package/src/storages/AbstractSplitsCacheSync.ts +1 -1
  41. package/src/storages/dataLoader.ts +1 -1
  42. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +15 -69
  43. package/src/storages/inMemory/MySegmentsCacheInMemory.ts +6 -46
  44. package/src/storages/inMemory/TelemetryCacheInMemory.ts +1 -1
  45. package/src/storages/types.ts +6 -5
  46. package/src/sync/polling/fetchers/mySegmentsFetcher.ts +2 -1
  47. package/src/sync/polling/fetchers/types.ts +1 -0
  48. package/src/sync/polling/types.ts +9 -10
  49. package/src/sync/polling/updaters/mySegmentsUpdater.ts +15 -19
  50. package/src/sync/streaming/AuthClient/index.ts +1 -1
  51. package/src/sync/streaming/SSEHandler/index.ts +9 -11
  52. package/src/sync/streaming/SSEHandler/types.ts +6 -6
  53. package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +114 -65
  54. package/src/sync/streaming/constants.ts +2 -2
  55. package/src/sync/streaming/parseUtils.ts +2 -2
  56. package/src/sync/streaming/pushManager.ts +30 -39
  57. package/src/sync/streaming/types.ts +6 -6
  58. package/src/sync/submitters/types.ts +4 -5
  59. package/src/utils/constants/index.ts +1 -2
  60. package/types/dtos/types.d.ts +8 -12
  61. package/types/logger/constants.d.ts +1 -1
  62. package/types/services/types.d.ts +1 -1
  63. package/types/storages/AbstractSegmentsCacheSync.d.ts +8 -6
  64. package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
  65. package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +1 -12
  66. package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +1 -9
  67. package/types/storages/types.d.ts +6 -5
  68. package/types/sync/polling/fetchers/types.d.ts +1 -1
  69. package/types/sync/polling/types.d.ts +9 -7
  70. package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +1 -1
  71. package/types/sync/streaming/SSEHandler/types.d.ts +6 -6
  72. package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +3 -2
  73. package/types/sync/streaming/constants.d.ts +2 -2
  74. package/types/sync/streaming/parseUtils.d.ts +2 -2
  75. package/types/sync/streaming/types.d.ts +5 -5
  76. package/types/sync/submitters/types.d.ts +4 -5
  77. package/types/utils/constants/index.d.ts +1 -2
@@ -2,81 +2,130 @@ 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 { UpdatesFromSSEEnum } from '../../submitters/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, updateType: UpdatesFromSSEEnum): IUpdateWorker<[changeNumber: number, segmentsData?: MySegmentsData, delay?: number]> {
11
-
12
- let maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
13
- let currentChangeNumber = -1;
14
- let handleNewEvent = false;
15
- let isHandlingEvent: boolean;
16
- let _segmentsData: MySegmentsData | undefined; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber
17
- let _delay: undefined | number;
18
- let _delayTimeoutID: any;
19
- const backoff = new Backoff(__handleMySegmentsUpdateCall);
20
-
21
- function __handleMySegmentsUpdateCall() {
22
- isHandlingEvent = true;
23
- if (maxChangeNumber > currentChangeNumber) {
24
- handleNewEvent = false;
25
- const currentMaxChangeNumber = maxChangeNumber;
26
-
27
- // fetch mySegments revalidating data if cached
28
- const syncTask = _delay ?
29
- new Promise(res => {
30
- _delayTimeoutID = setTimeout(() => {
31
- _delay = undefined;
32
- mySegmentsSyncTask.execute(_segmentsData, true).then(res);
33
- }, _delay);
34
- }) :
35
- mySegmentsSyncTask.execute(_segmentsData, true);
36
-
37
- syncTask.then((result) => {
38
- if (!isHandlingEvent) return; // halt if `stop` has been called
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(updateType);
41
- currentChangeNumber = Math.max(currentChangeNumber, currentMaxChangeNumber); // use `currentMaxChangeNumber`, in case that `maxChangeNumber` was updated during fetch.
42
- }
43
- if (handleNewEvent) {
44
- __handleMySegmentsUpdateCall();
45
- } else {
46
- backoff.scheduleCall();
47
- }
48
- });
49
- } else {
50
- isHandlingEvent = false;
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
+ function createUpdateWorker(mySegmentsCache: ISegmentsCacheSync) {
17
+
18
+ let maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
19
+ let currentChangeNumber = -1;
20
+ let handleNewEvent = false;
21
+ let isHandlingEvent: boolean;
22
+ let cdnBypass: boolean;
23
+ let _segmentsData: MySegmentsData | undefined; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber
24
+ let _delay: undefined | number;
25
+ let _delayTimeoutID: any;
26
+ const backoff = new Backoff(__handleMySegmentsUpdateCall);
27
+
28
+ function __handleMySegmentsUpdateCall() {
29
+ isHandlingEvent = true;
30
+ if (maxChangeNumber > Math.max(currentChangeNumber, mySegmentsCache.getChangeNumber())) {
31
+ handleNewEvent = false;
32
+ const currentMaxChangeNumber = maxChangeNumber;
33
+
34
+ // fetch mySegments revalidating data if cached
35
+ const syncTask = _delay ?
36
+ new Promise(res => {
37
+ _delayTimeoutID = setTimeout(() => {
38
+ _delay = undefined;
39
+ mySegmentsSyncTask.execute(_segmentsData, true, cdnBypass ? maxChangeNumber : undefined).then(res);
40
+ }, _delay);
41
+ }) :
42
+ mySegmentsSyncTask.execute(_segmentsData, true, cdnBypass ? maxChangeNumber : undefined);
43
+
44
+ syncTask.then((result) => {
45
+ if (!isHandlingEvent) return; // halt if `stop` has been called
46
+ if (result !== false) { // Unlike `Splits|SegmentsUpdateWorker`, `mySegmentsCache.getChangeNumber` can be -1, since `/memberships` change number is optional
47
+ const storageChangeNumber = mySegmentsCache.getChangeNumber();
48
+ currentChangeNumber = storageChangeNumber > -1 ?
49
+ storageChangeNumber :
50
+ Math.max(currentChangeNumber, currentMaxChangeNumber); // use `currentMaxChangeNumber`, in case that `maxChangeNumber` was updated during fetch.
51
+ }
52
+ if (handleNewEvent) {
53
+ __handleMySegmentsUpdateCall();
54
+ } else {
55
+ if (_segmentsData) telemetryTracker.trackUpdatesFromSSE(MEMBERSHIPS);
56
+
57
+ const attempts = backoff.attempts + 1;
58
+
59
+ if (maxChangeNumber <= currentChangeNumber) {
60
+ log.debug(`Refresh completed${cdnBypass ? ' bypassing the CDN' : ''} in ${attempts} attempts.`);
61
+ isHandlingEvent = false;
62
+ return;
63
+ }
64
+
65
+ if (attempts < FETCH_BACKOFF_MAX_RETRIES) {
66
+ backoff.scheduleCall();
67
+ return;
68
+ }
69
+
70
+ if (cdnBypass) {
71
+ log.debug(`No changes fetched after ${attempts} attempts with CDN bypassed.`);
72
+ isHandlingEvent = false;
73
+ } else {
74
+ backoff.reset();
75
+ cdnBypass = true;
76
+ __handleMySegmentsUpdateCall();
77
+ }
78
+ }
79
+ });
80
+ } else {
81
+ isHandlingEvent = false;
82
+ }
51
83
  }
84
+
85
+ return {
86
+ /**
87
+ * Invoked by NotificationProcessor on MY_(LARGE)_SEGMENTS_UPDATE notifications
88
+ *
89
+ * @param changeNumber change number of the notification
90
+ * @param segmentsData data for KeyList or SegmentRemoval instant updates
91
+ * @param delay optional time to wait for BoundedFetchRequest or BoundedFetchRequest updates
92
+ */
93
+ put(mySegmentsData: Pick<MySegmentsData, 'type' | 'cn'>, payload?: Pick<MySegmentsData, 'added' | 'removed'>, delay?: number) {
94
+ const { type, cn } = mySegmentsData;
95
+ // Ignore event if it is outdated or if there is a pending fetch request (_delay is set)
96
+ if (cn <= Math.max(currentChangeNumber, mySegmentsCache.getChangeNumber()) || cn <= maxChangeNumber || _delay) return;
97
+
98
+ maxChangeNumber = cn;
99
+ handleNewEvent = true;
100
+ cdnBypass = false;
101
+ _segmentsData = payload && { type, cn, added: payload.added, removed: payload.removed };
102
+ _delay = delay;
103
+
104
+ if (backoff.timeoutID || !isHandlingEvent) __handleMySegmentsUpdateCall();
105
+ backoff.reset();
106
+ },
107
+
108
+ stop() {
109
+ clearTimeout(_delayTimeoutID);
110
+ _delay = undefined;
111
+ isHandlingEvent = false;
112
+ backoff.reset();
113
+ }
114
+ };
52
115
  }
53
116
 
117
+ const updateWorkers = {
118
+ [MEMBERSHIPS_MS_UPDATE]: createUpdateWorker(storage.segments),
119
+ [MEMBERSHIPS_LS_UPDATE]: createUpdateWorker(storage.largeSegments!),
120
+ };
121
+
54
122
  return {
55
- /**
56
- * Invoked by NotificationProcessor on MY_(LARGE)_SEGMENTS_UPDATE notifications
57
- *
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
61
- */
62
- put(changeNumber: number, segmentsData?: MySegmentsData, delay?: number) {
63
- // Ignore event if it is outdated or if there is a pending fetch request (_delay is set)
64
- if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber || _delay) return;
65
-
66
- maxChangeNumber = changeNumber;
67
- handleNewEvent = true;
68
- _segmentsData = segmentsData;
69
- _delay = delay;
70
-
71
- if (backoff.timeoutID || !isHandlingEvent) __handleMySegmentsUpdateCall();
72
- backoff.reset();
123
+ put(mySegmentsData: Pick<MySegmentsData, 'type' | 'cn'>, payload?: Pick<MySegmentsData, 'added' | 'removed'>, delay?: number) {
124
+ updateWorkers[mySegmentsData.type].put(mySegmentsData, payload, delay);
73
125
  },
74
-
75
126
  stop() {
76
- clearTimeout(_delayTimeoutID);
77
- _delay = undefined;
78
- isHandlingEvent = false;
79
- backoff.reset();
127
+ updateWorkers[MEMBERSHIPS_MS_UPDATE].stop();
128
+ updateWorkers[MEMBERSHIPS_LS_UPDATE].stop();
80
129
  }
81
130
  };
82
131
  }
@@ -25,11 +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 MY_SEGMENTS_UPDATE_V3 = 'MY_SEGMENTS_UPDATE_V3';
28
+ export const MEMBERSHIPS_MS_UPDATE = 'MEMBERSHIPS_MS_UPDATE';
29
+ export const MEMBERSHIPS_LS_UPDATE = 'MEMBERSHIPS_LS_UPDATE';
29
30
  export const SEGMENT_UPDATE = 'SEGMENT_UPDATE';
30
31
  export const SPLIT_KILL = 'SPLIT_KILL';
31
32
  export const SPLIT_UPDATE = 'SPLIT_UPDATE';
32
- export const MY_LARGE_SEGMENTS_UPDATE = 'MY_LARGE_SEGMENTS_UPDATE';
33
33
 
34
34
  // Control-type push notifications, handled by NotificationKeeper
35
35
  export const CONTROL = 'CONTROL';
@@ -1,7 +1,7 @@
1
1
  import { algorithms } from '../../utils/decompress';
2
2
  import { decodeFromBase64 } from '../../utils/base64';
3
3
  import { hash } from '../../utils/murmur3/murmur3';
4
- import { Compression, IMyLargeSegmentsUpdateData, KeyList } from './SSEHandler/types';
4
+ import { Compression, IMembershipMSUpdateData, KeyList } from './SSEHandler/types';
5
5
  import { ISplit } from '../../dtos/types';
6
6
 
7
7
  const GZIP = 1;
@@ -91,7 +91,7 @@ export function parseFFUpdatePayload(compression: Compression, data: string): IS
91
91
 
92
92
  const DEFAULT_MAX_INTERVAL = 60000;
93
93
 
94
- export function getDelay(parsedData: Pick<IMyLargeSegmentsUpdateData, 'i' | 'h' | 's'>, matchingKey: string) {
94
+ export function getDelay(parsedData: Pick<IMembershipMSUpdateData, 'i' | 'h' | 's'>, matchingKey: string) {
95
95
  if (parsedData.h === 0) return 0;
96
96
 
97
97
  const interval = parsedData.i || DEFAULT_MAX_INTERVAL;
@@ -11,14 +11,14 @@ 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 { MY_SEGMENTS_UPDATE_V3, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType, MY_LARGE_SEGMENTS_UPDATE } from './constants';
15
- import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MY_SEGMENTS_UPDATE, STREAMING_PARSING_SPLIT_UPDATE } from '../../logger/constants';
16
- import { IMyLargeSegmentsUpdateData, IMySegmentsUpdateV3Data, KeyList, UpdateStrategy } from './SSEHandler/types';
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
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
- import { TOKEN_REFRESH, AUTH_REJECTION, MY_LARGE_SEGMENT, MY_SEGMENT } from '../../utils/constants';
21
+ import { TOKEN_REFRESH, AUTH_REJECTION } from '../../utils/constants';
22
22
  import { ISdkFactoryContextSync } from '../../sdkFactory/types';
23
23
 
24
24
  /**
@@ -59,11 +59,11 @@ export function pushManagerFactory(
59
59
  // For server-side we pass the segmentsSyncTask, used by SplitsUpdateWorker to fetch new segments
60
60
  const splitsUpdateWorker = SplitsUpdateWorker(log, storage.splits, pollingManager.splitsSyncTask, readiness.splits, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask as ISegmentsSyncTask);
61
61
 
62
- // [Only for client-side] map of hashes to user keys, to dispatch MY_SEGMENTS_UPDATE events to the corresponding MySegmentsUpdateWorker
62
+ // [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
63
63
  const userKeyHashes: Record<string, string> = {};
64
64
  // [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
65
- // Hash64 is used to process MY_SEGMENTS_UPDATE events and dispatch actions to the corresponding MySegmentsUpdateWorker.
66
- const clients: Record<string, { hash64: Hash64, worker: ReturnType<typeof MySegmentsUpdateWorker>, workerLarge: ReturnType<typeof MySegmentsUpdateWorker> }> = {};
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> }> = {};
67
67
 
68
68
  // [Only for client-side] variable to flag that a new client was added. It is needed to reconnect streaming.
69
69
  let connectForNewClient = false;
@@ -170,10 +170,7 @@ export function pushManagerFactory(
170
170
  // cancel scheduled fetch retries of Splits, Segments, and MySegments Update Workers
171
171
  function stopWorkers() {
172
172
  splitsUpdateWorker.stop();
173
- if (userKey) forOwn(clients, ({ worker, workerLarge }) => {
174
- worker.stop();
175
- workerLarge.stop();
176
- });
173
+ if (userKey) forOwn(clients, ({ worker }) => worker.stop());
177
174
  else segmentsUpdateWorker!.stop();
178
175
  }
179
176
 
@@ -238,22 +235,20 @@ export function pushManagerFactory(
238
235
  splitsUpdateWorker.put(parsedData);
239
236
  });
240
237
 
241
- function handleMySegmentsUpdate(parsedData: IMySegmentsUpdateV3Data | IMyLargeSegmentsUpdateData) {
242
- const isLS = parsedData.t === MY_LARGE_SEGMENTS_UPDATE;
243
-
238
+ function handleMySegmentsUpdate(parsedData: IMembershipMSUpdateData | IMembershipLSUpdateData) {
244
239
  switch (parsedData.u) {
245
240
  case UpdateStrategy.BoundedFetchRequest: {
246
241
  let bitmap: Uint8Array;
247
242
  try {
248
243
  bitmap = parseBitmap(parsedData.d!, parsedData.c!);
249
244
  } catch (e) {
250
- log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['BoundedFetchRequest', e]);
245
+ log.warn(STREAMING_PARSING_MEMBERSHIPS_UPDATE, ['BoundedFetchRequest', e]);
251
246
  break;
252
247
  }
253
248
 
254
- forOwn(clients, ({ hash64, worker, workerLarge }, matchingKey) => {
249
+ forOwn(clients, ({ hash64, worker }, matchingKey) => {
255
250
  if (isInBitmap(bitmap, hash64.hex)) {
256
- (isLS ? workerLarge : worker).put(parsedData.cn, undefined, getDelay(parsedData, matchingKey));
251
+ worker.put(parsedData, undefined, getDelay(parsedData, matchingKey));
257
252
  }
258
253
  });
259
254
  return;
@@ -265,53 +260,50 @@ export function pushManagerFactory(
265
260
  added = new _Set(keyList.a);
266
261
  removed = new _Set(keyList.r);
267
262
  } catch (e) {
268
- log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['KeyList', e]);
263
+ log.warn(STREAMING_PARSING_MEMBERSHIPS_UPDATE, ['KeyList', e]);
269
264
  break;
270
265
  }
271
266
 
272
267
  if (!parsedData.n || !parsedData.n.length) {
273
- log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['KeyList', 'No segment name was provided']);
268
+ log.warn(STREAMING_PARSING_MEMBERSHIPS_UPDATE, ['KeyList', 'No segment name was provided']);
274
269
  break;
275
270
  }
276
271
 
277
- forOwn(clients, ({ hash64, worker, workerLarge }) => {
272
+ forOwn(clients, ({ hash64, worker }) => {
278
273
  const add = added.has(hash64.dec) ? true : removed.has(hash64.dec) ? false : undefined;
279
274
  if (add !== undefined) {
280
- (isLS ? workerLarge : worker).put(parsedData.cn, [{
281
- isLS,
282
- name: parsedData.n![0],
283
- add,
284
- }]);
275
+ worker.put(parsedData, {
276
+ added: add ? [parsedData.n![0]] : [],
277
+ removed: add ? [] : [parsedData.n![0]]
278
+ });
285
279
  }
286
280
  });
287
281
  return;
288
282
  }
289
283
  case UpdateStrategy.SegmentRemoval:
290
284
  if (!parsedData.n || !parsedData.n.length) {
291
- log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['SegmentRemoval', 'No segment name was provided']);
285
+ log.warn(STREAMING_PARSING_MEMBERSHIPS_UPDATE, ['SegmentRemoval', 'No segment name was provided']);
292
286
  break;
293
287
  }
294
288
 
295
- forOwn(clients, ({ worker, workerLarge }) => {
296
- (isLS ? workerLarge : worker).put(parsedData.cn, parsedData.n!.map(largeSegment => ({
297
- isLS,
298
- name: largeSegment,
299
- add: false,
300
- cn: parsedData.cn
301
- })));
289
+ forOwn(clients, ({ worker }) => {
290
+ worker.put(parsedData, {
291
+ added: [],
292
+ removed: parsedData.n!
293
+ });
302
294
  });
303
295
  return;
304
296
  }
305
297
 
306
298
  // `UpdateStrategy.UnboundedFetchRequest` and fallbacks of other cases
307
- forOwn(clients, ({ worker, workerLarge }, matchingKey) => {
308
- (isLS ? workerLarge : worker).put(parsedData.cn, undefined, getDelay(parsedData, matchingKey));
299
+ forOwn(clients, ({ worker }, matchingKey) => {
300
+ worker.put(parsedData, undefined, getDelay(parsedData, matchingKey));
309
301
  });
310
302
  }
311
303
 
312
304
  if (userKey) {
313
- pushEmitter.on(MY_SEGMENTS_UPDATE_V3, handleMySegmentsUpdate);
314
- pushEmitter.on(MY_LARGE_SEGMENTS_UPDATE, handleMySegmentsUpdate);
305
+ pushEmitter.on(MEMBERSHIPS_MS_UPDATE, handleMySegmentsUpdate);
306
+ pushEmitter.on(MEMBERSHIPS_LS_UPDATE, handleMySegmentsUpdate);
315
307
  } else {
316
308
  pushEmitter.on(SEGMENT_UPDATE, segmentsUpdateWorker!.put);
317
309
  }
@@ -351,8 +343,7 @@ export function pushManagerFactory(
351
343
  userKeyHashes[hash] = userKey;
352
344
  clients[userKey] = {
353
345
  hash64: hash64(userKey),
354
- worker: MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker, MY_SEGMENT),
355
- workerLarge: MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker, MY_LARGE_SEGMENT)
346
+ worker: MySegmentsUpdateWorker(log, storage, mySegmentsSyncTask, telemetryTracker)
356
347
  };
357
348
  connectForNewClient = true; // we must reconnect on start, to listen the channel for the new user key
358
349
 
@@ -1,4 +1,4 @@
1
- import { IMySegmentsUpdateV3Data, ISegmentUpdateData, ISplitUpdateData, ISplitKillData, IMyLargeSegmentsUpdateData, INotificationData } from './SSEHandler/types';
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,21 +11,21 @@ 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 MY_SEGMENTS_UPDATE_V3 = 'MY_SEGMENTS_UPDATE_V3';
14
+ export type MEMBERSHIPS_MS_UPDATE = 'MEMBERSHIPS_MS_UPDATE';
15
+ export type MEMBERSHIPS_LS_UPDATE = 'MEMBERSHIPS_LS_UPDATE';
15
16
  export type SEGMENT_UPDATE = 'SEGMENT_UPDATE';
16
17
  export type SPLIT_KILL = 'SPLIT_KILL';
17
18
  export type SPLIT_UPDATE = 'SPLIT_UPDATE';
18
- export type MY_LARGE_SEGMENTS_UPDATE = 'MY_LARGE_SEGMENTS_UPDATE';
19
19
 
20
20
  // Control-type push notifications, handled by NotificationKeeper
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 | MY_SEGMENTS_UPDATE_V3 | SEGMENT_UPDATE | SPLIT_UPDATE | SPLIT_KILL | MY_LARGE_SEGMENTS_UPDATE | ControlType.STREAMING_RESET
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 MY_SEGMENTS_UPDATE_V3 ? IMySegmentsUpdateV3Data :
28
- T extends MY_LARGE_SEGMENTS_UPDATE ? IMyLargeSegmentsUpdateData :
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
31
  T extends SPLIT_KILL ? ISplitKillData : INotificationData;
@@ -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 | MY_SEGMENT | MY_LARGE_SEGMENT;
106
+ export type UpdatesFromSSEEnum = SPLITS | MEMBERSHIPS;
107
107
 
108
108
  export type SPLITS = 'sp';
109
109
  export type IMPRESSIONS = 'im';
@@ -112,9 +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 MY_SEGMENT = 'ms';
116
- export type MY_LARGE_SEGMENT = 'mls';
117
- export type OperationType = SPLITS | IMPRESSIONS | IMPRESSIONS_COUNT | EVENTS | TELEMETRY | TOKEN | SEGMENT | MY_SEGMENT;
115
+ export type MEMBERSHIPS = 'ms';
116
+ export type OperationType = SPLITS | IMPRESSIONS | IMPRESSIONS_COUNT | EVENTS | TELEMETRY | TOKEN | SEGMENT | MEMBERSHIPS;
118
117
 
119
118
  export type LastSync = Partial<Record<OperationType, number | undefined>>
120
119
  export type HttpErrors = Partial<Record<OperationType, { [statusCode: string]: number }>>
@@ -177,7 +176,7 @@ export type TelemetryUsageStatsPayload = TelemetryUsageStats & {
177
176
  spC?: number, // splitCount
178
177
  seC?: number, // segmentCount
179
178
  skC?: number, // segmentKeyCount
180
- lseC?: number, // largeSegmentCount
179
+ lsC?: number, // largeSegmentCount
181
180
  lskC?: number, // largeSegmentKeyCount
182
181
  sL?: number, // sessionLengthMs
183
182
  eQ: number, // eventsQueued
@@ -75,8 +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 MY_SEGMENT = 'ms';
79
- export const MY_LARGE_SEGMENT = 'mls';
78
+ export const MEMBERSHIPS = 'ms';
80
79
 
81
80
  export const TREATMENT = 't';
82
81
  export const TREATMENTS = 'ts';
@@ -177,20 +177,16 @@ export interface ISegmentChangesResponse {
177
177
  since: number;
178
178
  till: number;
179
179
  }
180
+ export interface IMySegmentsResponse {
181
+ cn?: number;
182
+ k?: {
183
+ n: string;
184
+ }[];
185
+ }
180
186
  /** Interface of the parsed JSON response of `/memberships/{userKey}` */
181
187
  export interface IMembershipsResponse {
182
- ms?: {
183
- cn?: number;
184
- k?: Array<{
185
- n: string;
186
- }>;
187
- };
188
- ls?: {
189
- cn?: number;
190
- k?: Array<{
191
- n: string;
192
- }>;
193
- };
188
+ ms?: IMySegmentsResponse;
189
+ ls?: IMySegmentsResponse;
194
190
  }
195
191
  /** Metadata internal type for storages */
196
192
  export interface IMetadata {
@@ -77,7 +77,7 @@ export declare const WARN_SPLITS_FILTER_IGNORED = 219;
77
77
  export declare const WARN_SPLITS_FILTER_INVALID = 220;
78
78
  export declare const WARN_SPLITS_FILTER_EMPTY = 221;
79
79
  export declare const WARN_SDK_KEY = 222;
80
- export declare const STREAMING_PARSING_MY_SEGMENTS_UPDATE = 223;
80
+ export declare const STREAMING_PARSING_MEMBERSHIPS_UPDATE = 223;
81
81
  export declare const STREAMING_PARSING_SPLIT_UPDATE = 224;
82
82
  export declare const WARN_INVALID_FLAGSET = 225;
83
83
  export declare const WARN_LOWERCASE_FLAGSET = 226;
@@ -18,7 +18,7 @@ export declare type ISplitHttpClient = (url: string, options?: IRequestOptions,
18
18
  export declare type IFetchAuth = (userKeys?: string[]) => Promise<IResponse>;
19
19
  export declare type IFetchSplitChanges = (since: number, noCache?: boolean, till?: number) => Promise<IResponse>;
20
20
  export declare type IFetchSegmentChanges = (since: number, segmentName: string, noCache?: boolean, till?: number) => Promise<IResponse>;
21
- export declare type IFetchMemberships = (userMatchingKey: string, noCache?: boolean) => Promise<IResponse>;
21
+ export declare type IFetchMemberships = (userMatchingKey: string, noCache?: boolean, till?: number) => Promise<IResponse>;
22
22
  export declare type IPostEventsBulk = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
23
23
  export declare type IPostUniqueKeysBulkCs = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
24
24
  export declare type IPostUniqueKeysBulkSs = (body: string, headers?: Record<string, string>) => Promise<IResponse>;
@@ -1,3 +1,5 @@
1
+ import { IMySegmentsResponse } from '../dtos/types';
2
+ import { MySegmentsData } from '../sync/polling/types';
1
3
  import { ISegmentsCacheSync } from './types';
2
4
  /**
3
5
  * This class provides a skeletal implementation of the ISegmentsCacheSync interface
@@ -22,7 +24,7 @@ export declare abstract class AbstractSegmentsCacheSync implements ISegmentsCach
22
24
  /**
23
25
  * clear the cache.
24
26
  */
25
- abstract clear(): void;
27
+ clear(): void;
26
28
  /**
27
29
  * For server-side synchronizer: add the given list of segments to the cache, with an empty list of keys. The segments that already exist are not modified.
28
30
  * For client-side synchronizer: the method is not used.
@@ -39,14 +41,14 @@ export declare abstract class AbstractSegmentsCacheSync implements ISegmentsCach
39
41
  */
40
42
  abstract getKeysCount(): number;
41
43
  /**
42
- * For server-side synchronizer: set the change number of `name` segment.
43
- * For client-side synchronizer: the method is not used.
44
+ * For server-side synchronizer: change number of `name` segment.
45
+ * For client-side synchronizer: change number of mySegments.
44
46
  */
45
- setChangeNumber(name: string, changeNumber: number): boolean;
47
+ abstract setChangeNumber(name?: string, changeNumber?: number): boolean | void;
46
48
  abstract getChangeNumber(name: string): number;
47
49
  /**
48
50
  * For server-side synchronizer: the method is not used.
49
- * For client-side synchronizer: reset the cache with the given list of segments.
51
+ * For client-side synchronizer: it resets or updates the cache.
50
52
  */
51
- resetSegments(names: string[], changeNumber?: number): boolean;
53
+ resetSegments(segmentsData: MySegmentsData | IMySegmentsResponse): boolean;
52
54
  }
@@ -12,7 +12,7 @@ export declare abstract class AbstractSplitsCacheSync implements ISplitsCacheSyn
12
12
  removeSplits(names: string[]): boolean[];
13
13
  abstract getSplit(name: string): ISplit | null;
14
14
  getSplits(names: string[]): Record<string, ISplit | null>;
15
- abstract setChangeNumber(changeNumber: number): boolean;
15
+ abstract setChangeNumber(changeNumber: number): boolean | void;
16
16
  abstract getChangeNumber(): number;
17
17
  getAll(): ISplit[];
18
18
  abstract getSplitNames(): string[];
@@ -5,22 +5,11 @@ export declare class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync {
5
5
  private readonly keys;
6
6
  private readonly log;
7
7
  constructor(log: ILogger, keys: MySegmentsKeyBuilder);
8
- /**
9
- * Removes list of segments from localStorage
10
- * @NOTE this method is not being used at the moment.
11
- */
12
- clear(): void;
13
8
  addToSegment(name: string): boolean;
14
9
  removeFromSegment(name: string): boolean;
15
10
  isInSegment(name: string): boolean;
16
- /**
17
- * Reset (update) the cached list of segments with the given list, removing and adding segments if necessary.
18
- *
19
- * @param {string[]} names list of segment names
20
- * @returns boolean indicating if the cache was updated (i.e., given list was different from the cached one)
21
- */
22
- resetSegments(names: string[], changeNumber?: number): boolean;
23
11
  getRegisteredSegments(): string[];
24
12
  getKeysCount(): number;
13
+ setChangeNumber(name?: string, changeNumber?: number): void;
25
14
  getChangeNumber(): number;
26
15
  }
@@ -6,18 +6,10 @@ import { AbstractSegmentsCacheSync } from '../AbstractSegmentsCacheSync';
6
6
  export declare class MySegmentsCacheInMemory extends AbstractSegmentsCacheSync {
7
7
  private segmentCache;
8
8
  private cn?;
9
- clear(): void;
10
9
  addToSegment(name: string): boolean;
11
10
  removeFromSegment(name: string): boolean;
12
11
  isInSegment(name: string): boolean;
13
- /**
14
- * Reset (update) the cached list of segments with the given list, removing and adding segments if necessary.
15
- * @NOTE based on the way we use segments in the browser, this way is the best option
16
- *
17
- * @param {string[]} names list of segment names
18
- * @returns boolean indicating if the cache was updated (i.e., given list was different from the cached one)
19
- */
20
- resetSegments(names: string[], changeNumber?: number): boolean;
12
+ setChangeNumber(name?: string, changeNumber?: number): void;
21
13
  getChangeNumber(): number;
22
14
  getRegisteredSegments(): string[];
23
15
  getKeysCount(): number;
@@ -1,4 +1,5 @@
1
- import { MaybeThenable, ISplit } from '../dtos/types';
1
+ import { MaybeThenable, ISplit, IMySegmentsResponse } from '../dtos/types';
2
+ import { MySegmentsData } from '../sync/polling/types';
2
3
  import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, MultiMethodExceptions, MultiMethodLatencies, MultiConfigs, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent, UniqueKeysPayloadCs, UniqueKeysPayloadSs, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../sync/submitters/types';
3
4
  import { SplitIO, ImpressionDTO, ISettings } from '../types';
4
5
  import { ISet } from '../utils/lang/sets';
@@ -200,7 +201,7 @@ export interface ISplitsCacheSync extends ISplitsCacheBase {
200
201
  removeSplits(names: string[]): boolean[];
201
202
  getSplit(name: string): ISplit | null;
202
203
  getSplits(names: string[]): Record<string, ISplit | null>;
203
- setChangeNumber(changeNumber: number): boolean;
204
+ setChangeNumber(changeNumber: number): boolean | void;
204
205
  getChangeNumber(): number;
205
206
  getAll(): ISplit[];
206
207
  getSplitNames(): string[];
@@ -245,9 +246,9 @@ export interface ISegmentsCacheSync extends ISegmentsCacheBase {
245
246
  registerSegments(names: string[]): boolean;
246
247
  getRegisteredSegments(): string[];
247
248
  getKeysCount(): number;
248
- setChangeNumber(name: string, changeNumber: number): boolean;
249
- getChangeNumber(name: string): number;
250
- resetSegments(names: string[], changeNumber?: number): boolean;
249
+ setChangeNumber(name: string, changeNumber: number): boolean | void;
250
+ getChangeNumber(name?: string): number;
251
+ resetSegments(segmentsData: MySegmentsData | IMySegmentsResponse): boolean;
251
252
  clear(): void;
252
253
  }
253
254
  export interface ISegmentsCacheAsync extends ISegmentsCacheBase {
@@ -2,4 +2,4 @@ import { ISplitChangesResponse, ISegmentChangesResponse, IMembershipsResponse }
2
2
  import { IResponse } from '../../../services/types';
3
3
  export declare type ISplitChangesFetcher = (since: number, noCache?: boolean, till?: number, decorator?: (promise: Promise<IResponse>) => Promise<IResponse>) => Promise<ISplitChangesResponse>;
4
4
  export declare type ISegmentChangesFetcher = (since: number, segmentName: string, noCache?: boolean, till?: number, decorator?: (promise: Promise<ISegmentChangesResponse[]>) => Promise<ISegmentChangesResponse[]>) => Promise<ISegmentChangesResponse[]>;
5
- export declare type IMySegmentsFetcher = (userMatchingKey: string, noCache?: boolean, decorator?: (promise: Promise<IResponse>) => Promise<IResponse>) => Promise<IMembershipsResponse>;
5
+ export declare type IMySegmentsFetcher = (userMatchingKey: string, noCache?: boolean, till?: number, decorator?: (promise: Promise<IResponse>) => Promise<IResponse>) => Promise<IMembershipsResponse>;