@splitsoftware/splitio-commons 1.17.1-rc.4 → 1.17.1-rc.5

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 (261) hide show
  1. package/CHANGES.txt +28 -29
  2. package/LICENSE +1 -1
  3. package/README.md +4 -3
  4. package/cjs/consent/sdkUserConsent.js +4 -2
  5. package/cjs/evaluator/matchers/index.js +1 -3
  6. package/cjs/evaluator/matchers/matcherTypes.js +0 -1
  7. package/cjs/evaluator/matchers/segment.js +0 -6
  8. package/cjs/evaluator/matchersTransform/index.js +1 -4
  9. package/cjs/evaluator/matchersTransform/segment.js +1 -3
  10. package/cjs/logger/constants.js +2 -2
  11. package/cjs/logger/messages/info.js +1 -1
  12. package/cjs/logger/messages/warn.js +1 -1
  13. package/cjs/readiness/readinessManager.js +8 -18
  14. package/cjs/readiness/sdkReadinessManager.js +6 -5
  15. package/cjs/sdkClient/sdkClient.js +5 -5
  16. package/cjs/sdkClient/sdkClientMethod.js +1 -3
  17. package/cjs/sdkClient/sdkClientMethodCS.js +15 -9
  18. package/cjs/sdkClient/sdkClientMethodCSWithTT.js +15 -9
  19. package/cjs/sdkFactory/index.js +10 -32
  20. package/cjs/services/decorateHeaders.js +6 -1
  21. package/cjs/services/splitApi.js +5 -5
  22. package/cjs/services/splitHttpClient.js +5 -2
  23. package/cjs/storages/AbstractSegmentsCacheSync.js +33 -0
  24. package/cjs/storages/AbstractSplitsCacheSync.js +1 -2
  25. package/cjs/storages/KeyBuilderCS.js +5 -23
  26. package/cjs/storages/dataLoader.js +1 -1
  27. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +56 -33
  28. package/cjs/storages/inLocalStorage/index.js +2 -6
  29. package/cjs/storages/inMemory/InMemoryStorageCS.js +1 -6
  30. package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +44 -13
  31. package/cjs/storages/inMemory/SegmentsCacheInMemory.js +28 -14
  32. package/cjs/storages/inMemory/SplitsCacheInMemory.js +9 -8
  33. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +10 -7
  34. package/cjs/storages/inRedis/SegmentsCacheInRedis.js +21 -15
  35. package/cjs/storages/inRedis/index.js +11 -5
  36. package/cjs/storages/pluggable/SegmentsCachePluggable.js +34 -13
  37. package/cjs/storages/pluggable/inMemoryWrapper.js +1 -1
  38. package/cjs/sync/offline/syncManagerOffline.js +11 -18
  39. package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +8 -5
  40. package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
  41. package/cjs/sync/polling/pollingManagerCS.js +1 -1
  42. package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  43. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +21 -15
  44. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +28 -12
  45. package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -1
  46. package/cjs/sync/streaming/AuthClient/index.js +1 -1
  47. package/cjs/sync/streaming/SSEHandler/index.js +5 -3
  48. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +48 -107
  49. package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
  50. package/cjs/sync/streaming/constants.js +3 -3
  51. package/cjs/sync/streaming/parseUtils.js +9 -14
  52. package/cjs/sync/streaming/pushManager.js +67 -69
  53. package/cjs/sync/syncManagerOnline.js +21 -20
  54. package/cjs/sync/syncTask.js +2 -2
  55. package/cjs/trackers/eventTracker.js +10 -12
  56. package/cjs/trackers/impressionsTracker.js +14 -16
  57. package/cjs/trackers/uniqueKeysTracker.js +3 -5
  58. package/cjs/utils/constants/index.js +4 -5
  59. package/cjs/utils/settingsValidation/index.js +1 -2
  60. package/esm/consent/sdkUserConsent.js +4 -2
  61. package/esm/evaluator/matchers/index.js +1 -3
  62. package/esm/evaluator/matchers/matcherTypes.js +0 -1
  63. package/esm/evaluator/matchers/segment.js +0 -6
  64. package/esm/evaluator/matchersTransform/index.js +1 -4
  65. package/esm/evaluator/matchersTransform/segment.js +1 -3
  66. package/esm/logger/constants.js +1 -1
  67. package/esm/logger/messages/info.js +1 -1
  68. package/esm/logger/messages/warn.js +1 -1
  69. package/esm/readiness/readinessManager.js +8 -18
  70. package/esm/readiness/sdkReadinessManager.js +6 -5
  71. package/esm/sdkClient/sdkClient.js +5 -5
  72. package/esm/sdkClient/sdkClientMethod.js +1 -3
  73. package/esm/sdkClient/sdkClientMethodCS.js +13 -7
  74. package/esm/sdkClient/sdkClientMethodCSWithTT.js +13 -7
  75. package/esm/sdkFactory/index.js +10 -32
  76. package/esm/services/decorateHeaders.js +4 -0
  77. package/esm/services/splitApi.js +6 -6
  78. package/esm/services/splitHttpClient.js +6 -3
  79. package/esm/storages/AbstractSegmentsCacheSync.js +30 -0
  80. package/esm/storages/AbstractSplitsCacheSync.js +2 -3
  81. package/esm/storages/KeyBuilderCS.js +4 -21
  82. package/esm/storages/dataLoader.js +1 -1
  83. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +56 -33
  84. package/esm/storages/inLocalStorage/index.js +3 -7
  85. package/esm/storages/inMemory/InMemoryStorageCS.js +1 -6
  86. package/esm/storages/inMemory/MySegmentsCacheInMemory.js +44 -13
  87. package/esm/storages/inMemory/SegmentsCacheInMemory.js +28 -14
  88. package/esm/storages/inMemory/SplitsCacheInMemory.js +9 -8
  89. package/esm/storages/inMemory/TelemetryCacheInMemory.js +10 -7
  90. package/esm/storages/inRedis/SegmentsCacheInRedis.js +21 -15
  91. package/esm/storages/inRedis/index.js +11 -5
  92. package/esm/storages/pluggable/SegmentsCachePluggable.js +34 -13
  93. package/esm/storages/pluggable/inMemoryWrapper.js +1 -1
  94. package/esm/sync/offline/syncManagerOffline.js +11 -18
  95. package/esm/sync/polling/fetchers/mySegmentsFetcher.js +8 -5
  96. package/esm/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
  97. package/esm/sync/polling/pollingManagerCS.js +1 -1
  98. package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  99. package/esm/sync/polling/updaters/mySegmentsUpdater.js +21 -15
  100. package/esm/sync/polling/updaters/segmentChangesUpdater.js +28 -12
  101. package/esm/sync/polling/updaters/splitChangesUpdater.js +1 -1
  102. package/esm/sync/streaming/AuthClient/index.js +1 -1
  103. package/esm/sync/streaming/SSEHandler/index.js +6 -4
  104. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +49 -108
  105. package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
  106. package/esm/sync/streaming/constants.js +2 -2
  107. package/esm/sync/streaming/parseUtils.js +8 -12
  108. package/esm/sync/streaming/pushManager.js +70 -72
  109. package/esm/sync/syncManagerOnline.js +21 -20
  110. package/esm/sync/syncTask.js +2 -2
  111. package/esm/trackers/eventTracker.js +10 -12
  112. package/esm/trackers/impressionsTracker.js +14 -16
  113. package/esm/trackers/uniqueKeysTracker.js +3 -5
  114. package/esm/utils/constants/index.js +2 -3
  115. package/esm/utils/settingsValidation/index.js +1 -2
  116. package/package.json +1 -1
  117. package/src/consent/sdkUserConsent.ts +3 -2
  118. package/src/dtos/types.ts +7 -21
  119. package/src/evaluator/matchers/index.ts +0 -2
  120. package/src/evaluator/matchers/matcherTypes.ts +0 -1
  121. package/src/evaluator/matchers/segment.ts +0 -7
  122. package/src/evaluator/matchersTransform/index.ts +1 -4
  123. package/src/evaluator/matchersTransform/segment.ts +3 -5
  124. package/src/logger/constants.ts +1 -1
  125. package/src/logger/messages/info.ts +1 -1
  126. package/src/logger/messages/warn.ts +1 -1
  127. package/src/readiness/readinessManager.ts +8 -19
  128. package/src/readiness/sdkReadinessManager.ts +7 -7
  129. package/src/readiness/types.ts +2 -5
  130. package/src/sdkClient/sdkClient.ts +5 -5
  131. package/src/sdkClient/sdkClientMethod.ts +1 -4
  132. package/src/sdkClient/sdkClientMethodCS.ts +15 -7
  133. package/src/sdkClient/sdkClientMethodCSWithTT.ts +15 -7
  134. package/src/sdkFactory/index.ts +12 -35
  135. package/src/sdkFactory/types.ts +1 -4
  136. package/src/services/decorateHeaders.ts +5 -0
  137. package/src/services/splitApi.ts +7 -7
  138. package/src/services/splitHttpClient.ts +7 -4
  139. package/src/services/types.ts +2 -2
  140. package/src/storages/AbstractSegmentsCacheSync.ts +68 -0
  141. package/src/storages/AbstractSplitsCacheSync.ts +3 -4
  142. package/src/storages/KeyBuilderCS.ts +5 -34
  143. package/src/storages/dataLoader.ts +1 -1
  144. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +63 -33
  145. package/src/storages/inLocalStorage/index.ts +4 -8
  146. package/src/storages/inMemory/InMemoryStorageCS.ts +1 -6
  147. package/src/storages/inMemory/MySegmentsCacheInMemory.ts +47 -13
  148. package/src/storages/inMemory/SegmentsCacheInMemory.ts +27 -13
  149. package/src/storages/inMemory/SplitsCacheInMemory.ts +9 -7
  150. package/src/storages/inMemory/TelemetryCacheInMemory.ts +11 -7
  151. package/src/storages/inRedis/SegmentsCacheInRedis.ts +24 -15
  152. package/src/storages/inRedis/index.ts +12 -6
  153. package/src/storages/pluggable/SegmentsCachePluggable.ts +37 -13
  154. package/src/storages/pluggable/inMemoryWrapper.ts +1 -1
  155. package/src/storages/types.ts +17 -15
  156. package/src/sync/offline/syncManagerOffline.ts +13 -21
  157. package/src/sync/polling/fetchers/mySegmentsFetcher.ts +10 -8
  158. package/src/sync/polling/fetchers/segmentChangesFetcher.ts +1 -1
  159. package/src/sync/polling/fetchers/types.ts +2 -3
  160. package/src/sync/polling/pollingManagerCS.ts +4 -4
  161. package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +5 -4
  162. package/src/sync/polling/types.ts +6 -7
  163. package/src/sync/polling/updaters/mySegmentsUpdater.ts +22 -19
  164. package/src/sync/polling/updaters/segmentChangesUpdater.ts +29 -13
  165. package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -1
  166. package/src/sync/streaming/AuthClient/index.ts +1 -1
  167. package/src/sync/streaming/SSEClient/index.ts +6 -4
  168. package/src/sync/streaming/SSEHandler/index.ts +8 -5
  169. package/src/sync/streaming/SSEHandler/types.ts +15 -15
  170. package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +49 -116
  171. package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +4 -4
  172. package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +1 -1
  173. package/src/sync/streaming/UpdateWorkers/types.ts +2 -2
  174. package/src/sync/streaming/constants.ts +2 -2
  175. package/src/sync/streaming/parseUtils.ts +11 -19
  176. package/src/sync/streaming/pushManager.ts +72 -73
  177. package/src/sync/streaming/types.ts +10 -10
  178. package/src/sync/submitters/types.ts +5 -8
  179. package/src/sync/syncManagerOnline.ts +17 -17
  180. package/src/sync/syncTask.ts +2 -2
  181. package/src/sync/types.ts +1 -1
  182. package/src/trackers/eventTracker.ts +8 -11
  183. package/src/trackers/impressionsTracker.ts +10 -13
  184. package/src/trackers/types.ts +0 -1
  185. package/src/trackers/uniqueKeysTracker.ts +4 -6
  186. package/src/types.ts +1 -7
  187. package/src/utils/constants/index.ts +2 -3
  188. package/src/utils/settingsValidation/index.ts +2 -3
  189. package/src/utils/settingsValidation/types.ts +1 -1
  190. package/types/dtos/types.d.ts +7 -18
  191. package/types/evaluator/matchersTransform/segment.d.ts +2 -2
  192. package/types/logger/constants.d.ts +1 -1
  193. package/types/readiness/readinessManager.d.ts +2 -2
  194. package/types/readiness/sdkReadinessManager.d.ts +3 -2
  195. package/types/readiness/types.d.ts +2 -5
  196. package/types/sdkClient/sdkClientMethod.d.ts +1 -1
  197. package/types/sdkFactory/types.d.ts +1 -3
  198. package/types/services/decorateHeaders.d.ts +1 -0
  199. package/types/services/splitApi.d.ts +1 -1
  200. package/types/services/splitHttpClient.d.ts +1 -1
  201. package/types/services/types.d.ts +2 -2
  202. package/types/storages/AbstractSegmentsCacheSync.d.ts +11 -9
  203. package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
  204. package/types/storages/KeyBuilderCS.d.ts +2 -9
  205. package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +18 -8
  206. package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +13 -7
  207. package/types/storages/inMemory/SegmentsCacheInMemory.d.ts +8 -6
  208. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +2 -1
  209. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -4
  210. package/types/storages/inRedis/SegmentsCacheInRedis.d.ts +4 -7
  211. package/types/storages/inRedis/index.d.ts +1 -1
  212. package/types/storages/pluggable/SegmentsCachePluggable.d.ts +17 -5
  213. package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -1
  214. package/types/storages/types.d.ts +15 -11
  215. package/types/sync/polling/fetchers/mySegmentsFetcher.d.ts +2 -2
  216. package/types/sync/polling/fetchers/types.d.ts +2 -2
  217. package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +2 -2
  218. package/types/sync/polling/types.d.ts +4 -7
  219. package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +3 -4
  220. package/types/sync/streaming/SSEHandler/types.d.ts +14 -16
  221. package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -4
  222. package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +1 -2
  223. package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +2 -3
  224. package/types/sync/streaming/UpdateWorkers/types.d.ts +2 -2
  225. package/types/sync/streaming/constants.d.ts +2 -2
  226. package/types/sync/streaming/parseUtils.d.ts +5 -4
  227. package/types/sync/streaming/types.d.ts +8 -8
  228. package/types/sync/submitters/types.d.ts +4 -7
  229. package/types/sync/types.d.ts +1 -1
  230. package/types/trackers/eventTracker.d.ts +1 -1
  231. package/types/trackers/impressionsTracker.d.ts +1 -1
  232. package/types/trackers/types.d.ts +0 -1
  233. package/types/types.d.ts +1 -7
  234. package/types/utils/constants/index.d.ts +2 -3
  235. package/types/utils/settingsValidation/types.d.ts +1 -1
  236. package/cjs/evaluator/matchers/large_segment.js +0 -16
  237. package/cjs/sdkClient/identity.js +0 -7
  238. package/cjs/storages/AbstractMySegmentsCacheSync.js +0 -60
  239. package/esm/evaluator/matchers/large_segment.js +0 -12
  240. package/esm/sdkClient/identity.js +0 -3
  241. package/esm/storages/AbstractMySegmentsCacheSync.js +0 -57
  242. package/src/evaluator/matchers/large_segment.ts +0 -18
  243. package/src/sdkClient/identity.ts +0 -5
  244. package/src/storages/AbstractMySegmentsCacheSync.ts +0 -94
  245. package/types/evaluator/matchers/large_segment.d.ts +0 -5
  246. package/types/evaluator/matchers/sember_inlist.d.ts +0 -3
  247. package/types/evaluator/matchersTransform/set.d.ts +0 -5
  248. package/types/evaluator/matchersTransform/string.d.ts +0 -7
  249. package/types/sdkClient/identity.d.ts +0 -2
  250. package/types/storages/AbstractMySegmentsCacheSync.d.ts +0 -39
  251. package/types/storages/AbstractSplitsCache.d.ts +0 -46
  252. package/types/sync/streaming/mySegmentsV2utils.d.ts +0 -27
  253. package/types/sync/streaming/pushManagerCS_Spec1_3.d.ts +0 -9
  254. package/types/sync/streaming/pushManager_Spec1_3.d.ts +0 -9
  255. package/types/trackers/impressionObserver/utils.d.ts +0 -5
  256. package/types/utils/inputValidation/sdkKey.d.ts +0 -7
  257. package/types/utils/inputValidation/splitExistance.d.ts +0 -7
  258. package/types/utils/inputValidation/trafficTypeExistance.d.ts +0 -9
  259. package/types/utils/redis/RedisMock.d.ts +0 -4
  260. package/types/utils/settingsValidation/logger/globalLogLevel.d.ts +0 -8
  261. /package/types/utils/{semVer.d.ts → Semver.d.ts} +0 -0
@@ -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, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE } from '../constants';
3
+ import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE } from '../constants';
4
4
  import { IPushEventEmitter } from '../types';
5
5
  import { ISseEventHandler } from '../SSEClient/types';
6
6
  import { INotificationError, INotificationMessage } from './types';
@@ -74,18 +74,21 @@ 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) return;
77
+ // we only handle update events if streaming is up.
78
+ if (!notificationKeeper.isStreamingUp() && [OCCUPANCY, CONTROL].indexOf(parsedData.type) === -1)
79
+ return;
79
80
 
80
81
  switch (parsedData.type) {
81
82
  /* update events */
82
83
  case SPLIT_UPDATE:
83
84
  case SEGMENT_UPDATE:
84
- case MEMBERSHIPS_MS_UPDATE:
85
- case MEMBERSHIPS_LS_UPDATE:
85
+ case MY_SEGMENTS_UPDATE_V2:
86
86
  case SPLIT_KILL:
87
87
  pushEmitter.emit(parsedData.type, parsedData);
88
88
  break;
89
+ case MY_SEGMENTS_UPDATE:
90
+ pushEmitter.emit(parsedData.type, parsedData, channel);
91
+ break;
89
92
 
90
93
  /* occupancy & control events, handled by NotificationManagerKeeper */
91
94
  case OCCUPANCY:
@@ -1,5 +1,12 @@
1
1
  import { ControlType } from '../constants';
2
- import { SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../types';
2
+ import { MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY } from '../types';
3
+
4
+ export interface IMySegmentsUpdateData {
5
+ type: MY_SEGMENTS_UPDATE,
6
+ changeNumber: number,
7
+ includesPayload: boolean,
8
+ segmentList?: string[]
9
+ }
3
10
 
4
11
  export enum Compression {
5
12
  None = 0,
@@ -19,22 +26,15 @@ export interface KeyList {
19
26
  r?: string[], // decimal hash64 of user keys
20
27
  }
21
28
 
22
- interface IMembershipUpdateData<T extends string> {
23
- type: T,
24
- cn: number,
25
- n?: string[],
26
- c?: Compression,
27
- d?: string,
29
+ export interface IMySegmentsUpdateV2Data {
30
+ type: MY_SEGMENTS_UPDATE_V2,
31
+ changeNumber: number,
32
+ segmentName: string,
33
+ c: Compression,
34
+ d: string,
28
35
  u: UpdateStrategy,
29
- i?: number, // time interval in millis
30
- h?: number, // hash function
31
- s?: number, // seed for hash function
32
36
  }
33
37
 
34
- export interface IMembershipMSUpdateData extends IMembershipUpdateData<MEMBERSHIPS_MS_UPDATE> { }
35
-
36
- export interface IMembershipLSUpdateData extends IMembershipUpdateData<MEMBERSHIPS_LS_UPDATE> { }
37
-
38
38
  export interface ISegmentUpdateData {
39
39
  type: SEGMENT_UPDATE,
40
40
  changeNumber: number,
@@ -68,6 +68,6 @@ export interface IOccupancyData {
68
68
  }
69
69
  }
70
70
 
71
- export type INotificationData = IMembershipMSUpdateData | IMembershipLSUpdateData | ISegmentUpdateData | ISplitUpdateData | ISplitKillData | IControlData | IOccupancyData
71
+ export type INotificationData = IMySegmentsUpdateData | IMySegmentsUpdateV2Data | ISegmentUpdateData | ISplitUpdateData | ISplitKillData | IControlData | IOccupancyData
72
72
  export type INotificationMessage = { parsedData: INotificationData, channel: string, timestamp: number, data: string }
73
73
  export type INotificationError = Event & { parsedData?: any, message?: string }
@@ -1,133 +1,66 @@
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';
4
5
  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';
10
6
 
11
7
  /**
12
8
  * MySegmentsUpdateWorker factory
13
9
  */
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
- }
10
+ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker): IUpdateWorker {
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
+ const backoff = new Backoff(__handleMySegmentsUpdateCall);
18
+
19
+ function __handleMySegmentsUpdateCall() {
20
+ isHandlingEvent = true;
21
+ if (maxChangeNumber > currentChangeNumber) {
22
+ handleNewEvent = false;
23
+ const currentMaxChangeNumber = maxChangeNumber;
24
+
25
+ // fetch mySegments revalidating data if cached
26
+ mySegmentsSyncTask.execute(_segmentsData, true).then((result) => {
27
+ if (!isHandlingEvent) return; // halt if `stop` has been called
28
+ if (result !== false) {// Unlike `Splits|SegmentsUpdateWorker`, we cannot use `mySegmentsCache.getChangeNumber` since `/mySegments` endpoint doesn't provide this value.
29
+ if (_segmentsData) telemetryTracker.trackUpdatesFromSSE(MY_SEGMENT);
30
+ currentChangeNumber = Math.max(currentChangeNumber, currentMaxChangeNumber); // use `currentMaxChangeNumber`, in case that `maxChangeNumber` was updated during fetch.
31
+ }
32
+ if (handleNewEvent) {
33
+ __handleMySegmentsUpdateCall();
34
+ } else {
35
+ backoff.scheduleCall();
36
+ }
37
+ });
38
+ } else {
39
+ isHandlingEvent = false;
84
40
  }
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
- };
117
41
  }
118
42
 
119
- const updateWorkers = {
120
- [MEMBERSHIPS_MS_UPDATE]: createUpdateWorker(storage.segments),
121
- [MEMBERSHIPS_LS_UPDATE]: createUpdateWorker(storage.largeSegments!),
122
- };
123
-
124
43
  return {
125
- put(mySegmentsData: Pick<MySegmentsData, 'type' | 'cn'>, payload?: Pick<MySegmentsData, 'added' | 'removed'>, delay?: number) {
126
- updateWorkers[mySegmentsData.type].put(mySegmentsData, payload, delay);
44
+ /**
45
+ * Invoked by NotificationProcessor on MY_SEGMENTS_UPDATE event
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();
127
59
  },
60
+
128
61
  stop() {
129
- updateWorkers[MEMBERSHIPS_MS_UPDATE].stop();
130
- updateWorkers[MEMBERSHIPS_LS_UPDATE].stop();
62
+ isHandlingEvent = false;
63
+ backoff.reset();
131
64
  }
132
65
  };
133
66
  }
@@ -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<[ISegmentUpdateData]> {
12
+ export function SegmentsUpdateWorker(log: ILogger, segmentsSyncTask: ISegmentsSyncTask, segmentsCache: ISegmentsCacheSync): IUpdateWorker {
13
13
 
14
14
  // Handles retries with CDN bypass per segment name
15
15
  function SegmentUpdateWorker(segment: string) {
@@ -21,7 +21,7 @@ export function SegmentsUpdateWorker(log: ILogger, segmentsSyncTask: ISegmentsSy
21
21
 
22
22
  function __handleSegmentUpdateCall() {
23
23
  isHandlingEvent = true;
24
- if (maxChangeNumber > segmentsCache.getChangeNumber(segment)) {
24
+ if (maxChangeNumber > (segmentsCache.getChangeNumber(segment) || -1)) {
25
25
  handleNewEvent = false;
26
26
 
27
27
  // fetch segments revalidating data if cached
@@ -32,7 +32,7 @@ export function SegmentsUpdateWorker(log: ILogger, segmentsSyncTask: ISegmentsSy
32
32
  } else {
33
33
  const attempts = backoff.attempts + 1;
34
34
 
35
- if (maxChangeNumber <= segmentsCache.getChangeNumber(segment)) {
35
+ if (maxChangeNumber <= (segmentsCache.getChangeNumber(segment) || -1)) {
36
36
  log.debug(`Refresh completed${cdnBypass ? ' bypassing the CDN' : ''} in ${attempts} attempts.`);
37
37
  isHandlingEvent = false;
38
38
  return;
@@ -60,7 +60,7 @@ export function SegmentsUpdateWorker(log: ILogger, segmentsSyncTask: ISegmentsSy
60
60
 
61
61
  return {
62
62
  put(changeNumber: number) {
63
- const currentChangeNumber = segmentsCache.getChangeNumber(segment);
63
+ const currentChangeNumber = segmentsCache.getChangeNumber(segment) || -1;
64
64
 
65
65
  if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber) return;
66
66
 
@@ -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<[updateData: ISplitUpdateData, payload?: ISplit]> & { killSplit(event: ISplitKillData): void } {
17
+ export function SplitsUpdateWorker(log: ILogger, splitsCache: ISplitsCacheSync, splitsSyncTask: ISplitsSyncTask, splitsEventEmitter: ISplitsEventEmitter, telemetryTracker: ITelemetryTracker, segmentsSyncTask?: ISegmentsSyncTask): IUpdateWorker & { killSplit(event: ISplitKillData): void } {
18
18
 
19
19
  let maxChangeNumber = 0;
20
20
  let handleNewEvent = false;
@@ -1,4 +1,4 @@
1
- export interface IUpdateWorker<T extends any[]> {
1
+ export interface IUpdateWorker {
2
2
  stop(): void // clear scheduled tasks (backoff)
3
- put(...args: T): void // handle new update event
3
+ put(...args: any[]): void // handle new update event
4
4
  }
@@ -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 MEMBERSHIPS_MS_UPDATE = 'MEMBERSHIPS_MS_UPDATE';
29
- export const MEMBERSHIPS_LS_UPDATE = 'MEMBERSHIPS_LS_UPDATE';
28
+ export const MY_SEGMENTS_UPDATE = 'MY_SEGMENTS_UPDATE';
29
+ export const MY_SEGMENTS_UPDATE_V2 = 'MY_SEGMENTS_UPDATE_V2';
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,8 +1,6 @@
1
1
  import { algorithms } from '../../utils/decompress';
2
2
  import { decodeFromBase64 } from '../../utils/base64';
3
- import { hash } from '../../utils/murmur3/murmur3';
4
- import { Compression, IMembershipMSUpdateData, KeyList } from './SSEHandler/types';
5
- import { ISplit } from '../../dtos/types';
3
+ import { Compression, KeyList } from './SSEHandler/types';
6
4
 
7
5
  const GZIP = 1;
8
6
  const ZLIB = 2;
@@ -44,7 +42,7 @@ function decompress(data: string, compression: Compression) {
44
42
  * @returns {{a?: string[], r?: string[] }}
45
43
  * @throws if data string cannot be decoded, decompressed or parsed
46
44
  */
47
- export function parseKeyList(data: string, compression: Compression, avoidPrecisionLoss = true): KeyList {
45
+ export function parseKeyList(data: string, compression: Compression, avoidPrecisionLoss: boolean = true): KeyList {
48
46
  const binKeyList = decompress(data, compression);
49
47
  let strKeyList = Uint8ArrayToString(binKeyList);
50
48
  // replace numbers to strings, to avoid losing precision
@@ -82,20 +80,14 @@ export function isInBitmap(bitmap: Uint8Array, hash64hex: string) {
82
80
 
83
81
  /**
84
82
  * Parse feature flags notifications for instant feature flag updates
83
+ *
84
+ * @param {ISplitUpdateData} data
85
+ * @returns {KeyList}
85
86
  */
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;
87
+ export function parseFFUpdatePayload(compression: Compression, data: string): KeyList | undefined {
88
+ const avoidPrecisionLoss = false;
89
+ if (compression > 0)
90
+ return parseKeyList(data, compression, avoidPrecisionLoss);
91
+ else
92
+ return JSON.parse(decodeFromBase64(data));
101
93
  }
@@ -11,15 +11,16 @@ 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 { 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';
14
+ import { MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, 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_MY_SEGMENTS_UPDATE_V2, STREAMING_PARSING_SPLIT_UPDATE } from '../../logger/constants';
16
+ import { KeyList, UpdateStrategy } from './SSEHandler/types';
17
+ import { 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';
23
24
 
24
25
  /**
25
26
  * PushManager factory:
@@ -59,11 +60,11 @@ export function pushManagerFactory(
59
60
  // For server-side we pass the segmentsSyncTask, used by SplitsUpdateWorker to fetch new segments
60
61
  const splitsUpdateWorker = SplitsUpdateWorker(log, storage.splits, pollingManager.splitsSyncTask, readiness.splits, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask as ISegmentsSyncTask);
61
62
 
62
- // [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
63
+ // [Only for client-side] map of hashes to user keys, to dispatch MY_SEGMENTS_UPDATE events to the corresponding MySegmentsUpdateWorker
63
64
  const userKeyHashes: Record<string, string> = {};
64
65
  // [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
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> }> = {};
66
+ // Hash64 is used to process MY_SEGMENTS_UPDATE_V2 events and dispatch actions to the corresponding MySegmentsUpdateWorker.
67
+ const clients: Record<string, { hash64: Hash64, worker: IUpdateWorker }> = {};
67
68
 
68
69
  // [Only for client-side] variable to flag that a new client was added. It is needed to reconnect streaming.
69
70
  let connectForNewClient = false;
@@ -235,75 +236,76 @@ export function pushManagerFactory(
235
236
  splitsUpdateWorker.put(parsedData);
236
237
  });
237
238
 
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;
247
- }
248
-
249
- forOwn(clients, ({ hash64, worker }, matchingKey) => {
250
- if (isInBitmap(bitmap, hash64.hex)) {
251
- worker.put(parsedData, undefined, getDelay(parsedData, matchingKey));
252
- }
253
- });
254
- return;
239
+ if (userKey) {
240
+ pushEmitter.on(MY_SEGMENTS_UPDATE, function handleMySegmentsUpdate(parsedData, channel) {
241
+ const userKeyHash = channel.split('_')[2];
242
+ const userKey = userKeyHashes[userKeyHash];
243
+ if (userKey && clients[userKey]) { // check existence since it can be undefined if client has been destroyed
244
+ clients[userKey].worker.put(
245
+ parsedData.changeNumber,
246
+ parsedData.includesPayload ? parsedData.segmentList ? parsedData.segmentList : [] : undefined);
255
247
  }
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
- }
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
+ }
266
259
 
267
- if (!parsedData.n || !parsedData.n.length) {
268
- log.warn(STREAMING_PARSING_MEMBERSHIPS_UPDATE, ['KeyList', 'No segment name was provided']);
269
- break;
260
+ forOwn(clients, ({ hash64, worker }) => {
261
+ if (isInBitmap(bitmap, hash64.hex)) {
262
+ worker.put(parsedData.changeNumber); // fetch mySegments
263
+ }
264
+ });
265
+ return;
270
266
  }
271
-
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
- });
267
+ case UpdateStrategy.KeyList: {
268
+ let keyList: KeyList, added: ISet<string>, removed: ISet<string>;
269
+ try {
270
+ keyList = parseKeyList(parsedData.d, parsedData.c);
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;
279
276
  }
280
- });
281
- return;
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
- }
288
277
 
289
- forOwn(clients, ({ worker }) => {
290
- worker.put(parsedData, {
291
- added: [],
292
- removed: parsedData.n!
278
+ forOwn(clients, ({ hash64, worker }) => {
279
+ const add = added.has(hash64.dec) ? true : removed.has(hash64.dec) ? false : undefined;
280
+ if (add !== undefined) {
281
+ worker.put(parsedData.changeNumber, {
282
+ name: parsedData.segmentName,
283
+ add
284
+ });
285
+ }
293
286
  });
294
- });
295
- return;
296
- }
287
+ return;
288
+ }
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
+ }
297
294
 
298
- // `UpdateStrategy.UnboundedFetchRequest` and fallbacks of other cases
299
- forOwn(clients, ({ worker }, matchingKey) => {
300
- worker.put(parsedData, undefined, getDelay(parsedData, matchingKey));
301
- });
302
- }
295
+ forOwn(clients, ({ worker }) =>
296
+ worker.put(parsedData.changeNumber, {
297
+ name: parsedData.segmentName,
298
+ add: false
299
+ })
300
+ );
301
+ return;
302
+ }
303
303
 
304
- if (userKey) {
305
- pushEmitter.on(MEMBERSHIPS_MS_UPDATE, handleMySegmentsUpdate);
306
- pushEmitter.on(MEMBERSHIPS_LS_UPDATE, handleMySegmentsUpdate);
304
+ // `UpdateStrategy.UnboundedFetchRequest` and fallbacks of other cases
305
+ forOwn(clients, ({ worker }) => {
306
+ worker.put(parsedData.changeNumber);
307
+ });
308
+ });
307
309
  } else {
308
310
  pushEmitter.on(SEGMENT_UPDATE, segmentsUpdateWorker!.put);
309
311
  }
@@ -326,7 +328,7 @@ export function pushManagerFactory(
326
328
  if (disabled || disconnected === false) return;
327
329
  disconnected = false;
328
330
 
329
- if (userKey) this.add(userKey, pollingManager.segmentsSyncTask); // client-side
331
+ if (userKey) this.add(userKey, pollingManager.segmentsSyncTask as IMySegmentsSyncTask); // client-side
330
332
  else setTimeout(connectPush); // server-side runs in next cycle as in client-side, for consistency with client-side
331
333
  },
332
334
 
@@ -341,10 +343,7 @@ export function pushManagerFactory(
341
343
 
342
344
  if (!userKeyHashes[hash]) {
343
345
  userKeyHashes[hash] = userKey;
344
- clients[userKey] = {
345
- hash64: hash64(userKey),
346
- worker: MySegmentsUpdateWorker(log, storage, mySegmentsSyncTask, telemetryTracker)
347
- };
346
+ clients[userKey] = { hash64: hash64(userKey), worker: MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker) };
348
347
  connectForNewClient = true; // we must reconnect on start, to listen the channel for the new user key
349
348
 
350
349
  // Reconnects in case of a new client.
@@ -1,4 +1,4 @@
1
- import { IMembershipMSUpdateData, IMembershipLSUpdateData, ISegmentUpdateData, ISplitUpdateData, ISplitKillData, INotificationData } from './SSEHandler/types';
1
+ import { IMySegmentsUpdateData, IMySegmentsUpdateV2Data, ISegmentUpdateData, ISplitUpdateData, ISplitKillData } 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 MEMBERSHIPS_MS_UPDATE = 'MEMBERSHIPS_MS_UPDATE';
15
- export type MEMBERSHIPS_LS_UPDATE = 'MEMBERSHIPS_LS_UPDATE';
14
+ export type MY_SEGMENTS_UPDATE = 'MY_SEGMENTS_UPDATE';
15
+ export type MY_SEGMENTS_UPDATE_V2 = 'MY_SEGMENTS_UPDATE_V2';
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 | MEMBERSHIPS_MS_UPDATE | MEMBERSHIPS_LS_UPDATE | SEGMENT_UPDATE | SPLIT_UPDATE | SPLIT_KILL | ControlType.STREAMING_RESET
24
+ export type IPushEvent = PUSH_SUBSYSTEM_UP | PUSH_SUBSYSTEM_DOWN | PUSH_NONRETRYABLE_ERROR | PUSH_RETRYABLE_ERROR | MY_SEGMENTS_UPDATE | MY_SEGMENTS_UPDATE_V2 | SEGMENT_UPDATE | SPLIT_UPDATE | SPLIT_KILL | ControlType.STREAMING_RESET
25
25
 
26
26
  type IParsedData<T extends IPushEvent> =
27
- T extends MEMBERSHIPS_MS_UPDATE ? IMembershipMSUpdateData :
28
- T extends MEMBERSHIPS_LS_UPDATE ? IMembershipLSUpdateData :
27
+ T extends MY_SEGMENTS_UPDATE ? IMySegmentsUpdateData :
28
+ T extends MY_SEGMENTS_UPDATE_V2 ? IMySegmentsUpdateV2Data :
29
29
  T extends SEGMENT_UPDATE ? ISegmentUpdateData :
30
30
  T extends SPLIT_UPDATE ? ISplitUpdateData :
31
- T extends SPLIT_KILL ? ISplitKillData : INotificationData;
31
+ T extends SPLIT_KILL ? ISplitKillData : undefined;
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>) => 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;
38
+ once<T extends IPushEvent>(event: T, listener: (parsedData: IParsedData<T>, channel: T extends MY_SEGMENTS_UPDATE ? string : undefined) => void): this;
39
+ on<T extends IPushEvent>(event: T, listener: (parsedData: IParsedData<T>, channel: T extends MY_SEGMENTS_UPDATE ? string : undefined) => void): this;
40
+ emit<T extends IPushEvent>(event: T, parsedData?: IParsedData<T>, channel?: T extends MY_SEGMENTS_UPDATE ? string : undefined): boolean;
41
41
  }
42
42
 
43
43
  /**