@splitsoftware/splitio-commons 1.16.1-rc.7 → 1.17.0-rc.0

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 (165) hide show
  1. package/CHANGES.txt +2 -1
  2. package/cjs/evaluator/matchers/index.js +1 -3
  3. package/cjs/evaluator/matchers/matcherTypes.js +0 -1
  4. package/cjs/evaluator/matchersTransform/index.js +1 -1
  5. package/cjs/logger/constants.js +4 -3
  6. package/cjs/logger/messages/info.js +2 -1
  7. package/cjs/readiness/readinessManager.js +10 -14
  8. package/cjs/readiness/sdkReadinessManager.js +6 -5
  9. package/cjs/sdkClient/sdkClientMethodCS.js +2 -2
  10. package/cjs/sdkClient/sdkClientMethodCSWithTT.js +2 -2
  11. package/cjs/sdkFactory/index.js +1 -1
  12. package/cjs/services/decorateHeaders.js +42 -0
  13. package/cjs/services/splitApi.js +0 -4
  14. package/cjs/services/splitHttpClient.js +5 -4
  15. package/cjs/storages/AbstractSplitsCacheAsync.js +2 -2
  16. package/cjs/storages/AbstractSplitsCacheSync.js +6 -5
  17. package/cjs/storages/KeyBuilder.js +0 -3
  18. package/cjs/storages/KeyBuilderCS.js +5 -17
  19. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +4 -16
  20. package/cjs/storages/inLocalStorage/index.js +2 -6
  21. package/cjs/storages/inMemory/InMemoryStorageCS.js +0 -5
  22. package/cjs/storages/inMemory/SplitsCacheInMemory.js +11 -20
  23. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +10 -7
  24. package/cjs/storages/pluggable/inMemoryWrapper.js +1 -1
  25. package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +1 -5
  26. package/cjs/sync/polling/pollingManagerCS.js +33 -51
  27. package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  28. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +21 -20
  29. package/cjs/sync/streaming/SSEClient/index.js +0 -4
  30. package/cjs/sync/streaming/SSEHandler/index.js +0 -1
  31. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +9 -23
  32. package/cjs/sync/streaming/constants.js +1 -2
  33. package/cjs/sync/streaming/parseUtils.js +8 -3
  34. package/cjs/sync/streaming/pushManager.js +68 -97
  35. package/cjs/sync/submitters/telemetrySubmitter.js +0 -4
  36. package/cjs/sync/syncManagerOnline.js +14 -24
  37. package/cjs/utils/constants/index.js +2 -4
  38. package/cjs/utils/settingsValidation/index.js +2 -7
  39. package/esm/evaluator/matchers/index.js +1 -3
  40. package/esm/evaluator/matchers/matcherTypes.js +0 -1
  41. package/esm/evaluator/matchersTransform/index.js +1 -1
  42. package/esm/logger/constants.js +1 -0
  43. package/esm/logger/messages/info.js +2 -1
  44. package/esm/readiness/readinessManager.js +10 -14
  45. package/esm/readiness/sdkReadinessManager.js +6 -5
  46. package/esm/sdkClient/sdkClientMethodCS.js +2 -2
  47. package/esm/sdkClient/sdkClientMethodCSWithTT.js +2 -2
  48. package/esm/sdkFactory/index.js +1 -1
  49. package/esm/services/decorateHeaders.js +38 -0
  50. package/esm/services/splitApi.js +1 -5
  51. package/esm/services/splitHttpClient.js +5 -4
  52. package/esm/storages/AbstractSplitsCacheAsync.js +2 -2
  53. package/esm/storages/AbstractSplitsCacheSync.js +4 -3
  54. package/esm/storages/KeyBuilder.js +0 -3
  55. package/esm/storages/KeyBuilderCS.js +4 -15
  56. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +5 -17
  57. package/esm/storages/inLocalStorage/index.js +3 -7
  58. package/esm/storages/inMemory/InMemoryStorageCS.js +0 -5
  59. package/esm/storages/inMemory/SplitsCacheInMemory.js +12 -21
  60. package/esm/storages/inMemory/TelemetryCacheInMemory.js +10 -7
  61. package/esm/storages/pluggable/inMemoryWrapper.js +1 -1
  62. package/esm/sync/polling/fetchers/mySegmentsFetcher.js +1 -5
  63. package/esm/sync/polling/pollingManagerCS.js +34 -52
  64. package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  65. package/esm/sync/polling/updaters/mySegmentsUpdater.js +19 -18
  66. package/esm/sync/streaming/SSEClient/index.js +1 -5
  67. package/esm/sync/streaming/SSEHandler/index.js +1 -2
  68. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +9 -23
  69. package/esm/sync/streaming/constants.js +0 -1
  70. package/esm/sync/streaming/parseUtils.js +8 -3
  71. package/esm/sync/streaming/pushManager.js +69 -97
  72. package/esm/sync/submitters/telemetrySubmitter.js +0 -4
  73. package/esm/sync/syncManagerOnline.js +15 -25
  74. package/esm/utils/constants/index.js +1 -3
  75. package/esm/utils/settingsValidation/index.js +2 -7
  76. package/package.json +1 -1
  77. package/src/dtos/types.ts +7 -17
  78. package/src/evaluator/matchers/index.ts +0 -2
  79. package/src/evaluator/matchers/matcherTypes.ts +0 -1
  80. package/src/evaluator/matchersTransform/index.ts +1 -1
  81. package/src/logger/constants.ts +1 -0
  82. package/src/logger/messages/info.ts +2 -1
  83. package/src/readiness/readinessManager.ts +9 -13
  84. package/src/readiness/sdkReadinessManager.ts +7 -7
  85. package/src/readiness/types.ts +2 -3
  86. package/src/sdkClient/sdkClientMethodCS.ts +2 -2
  87. package/src/sdkClient/sdkClientMethodCSWithTT.ts +2 -2
  88. package/src/sdkFactory/index.ts +1 -1
  89. package/src/services/decorateHeaders.ts +40 -0
  90. package/src/services/splitApi.ts +1 -6
  91. package/src/services/splitHttpClient.ts +5 -4
  92. package/src/services/types.ts +0 -1
  93. package/src/storages/AbstractSplitsCacheAsync.ts +2 -2
  94. package/src/storages/AbstractSplitsCacheSync.ts +5 -4
  95. package/src/storages/KeyBuilder.ts +0 -3
  96. package/src/storages/KeyBuilderCS.ts +5 -25
  97. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +3 -3
  98. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +5 -20
  99. package/src/storages/inLocalStorage/index.ts +4 -8
  100. package/src/storages/inMemory/InMemoryStorageCS.ts +0 -5
  101. package/src/storages/inMemory/SplitsCacheInMemory.ts +10 -15
  102. package/src/storages/inMemory/TelemetryCacheInMemory.ts +11 -7
  103. package/src/storages/pluggable/inMemoryWrapper.ts +1 -1
  104. package/src/storages/types.ts +5 -7
  105. package/src/sync/polling/fetchers/mySegmentsFetcher.ts +2 -6
  106. package/src/sync/polling/pollingManagerCS.ts +29 -61
  107. package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +10 -10
  108. package/src/sync/polling/types.ts +3 -4
  109. package/src/sync/polling/updaters/mySegmentsUpdater.ts +20 -17
  110. package/src/sync/streaming/SSEClient/index.ts +7 -10
  111. package/src/sync/streaming/SSEHandler/index.ts +1 -2
  112. package/src/sync/streaming/SSEHandler/types.ts +2 -14
  113. package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +9 -25
  114. package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +1 -1
  115. package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +1 -1
  116. package/src/sync/streaming/UpdateWorkers/types.ts +2 -2
  117. package/src/sync/streaming/constants.ts +0 -1
  118. package/src/sync/streaming/parseUtils.ts +10 -6
  119. package/src/sync/streaming/pushManager.ts +67 -101
  120. package/src/sync/streaming/types.ts +3 -5
  121. package/src/sync/submitters/telemetrySubmitter.ts +0 -4
  122. package/src/sync/submitters/types.ts +4 -11
  123. package/src/sync/syncManagerOnline.ts +11 -19
  124. package/src/types.ts +9 -28
  125. package/src/utils/constants/index.ts +1 -3
  126. package/src/utils/settingsValidation/index.ts +3 -8
  127. package/src/utils/settingsValidation/types.ts +1 -1
  128. package/types/dtos/types.d.ts +6 -14
  129. package/types/logger/constants.d.ts +1 -0
  130. package/types/readiness/readinessManager.d.ts +2 -2
  131. package/types/readiness/sdkReadinessManager.d.ts +3 -2
  132. package/types/readiness/types.d.ts +2 -3
  133. package/types/services/decorateHeaders.d.ts +2 -0
  134. package/types/services/types.d.ts +0 -1
  135. package/types/storages/AbstractSplitsCacheAsync.d.ts +1 -1
  136. package/types/storages/AbstractSplitsCacheSync.d.ts +3 -3
  137. package/types/storages/KeyBuilder.d.ts +0 -1
  138. package/types/storages/KeyBuilderCS.d.ts +2 -7
  139. package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +2 -2
  140. package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +1 -1
  141. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +2 -3
  142. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -4
  143. package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -1
  144. package/types/storages/types.d.ts +3 -4
  145. package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +3 -2
  146. package/types/sync/polling/types.d.ts +3 -10
  147. package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +4 -4
  148. package/types/sync/streaming/SSEClient/index.d.ts +0 -1
  149. package/types/sync/streaming/SSEHandler/types.d.ts +2 -13
  150. package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -3
  151. package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +1 -2
  152. package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +2 -3
  153. package/types/sync/streaming/UpdateWorkers/types.d.ts +2 -2
  154. package/types/sync/streaming/constants.d.ts +0 -1
  155. package/types/sync/streaming/parseUtils.d.ts +4 -2
  156. package/types/sync/streaming/pushManager.d.ts +0 -2
  157. package/types/sync/streaming/types.d.ts +4 -5
  158. package/types/sync/submitters/types.d.ts +3 -10
  159. package/types/types.d.ts +11 -26
  160. package/types/utils/constants/index.d.ts +1 -3
  161. package/types/utils/settingsValidation/index.d.ts +0 -2
  162. package/types/utils/settingsValidation/types.d.ts +1 -1
  163. package/cjs/evaluator/matchers/large_segment.js +0 -16
  164. package/esm/evaluator/matchers/large_segment.js +0 -12
  165. package/src/evaluator/matchers/large_segment.ts +0 -18
@@ -1,4 +1,4 @@
1
- import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies, TelemetryUsageStatsPayload, UpdatesFromSSEEnum, UpdatesFromSSE } from '../../sync/submitters/types';
1
+ import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../../sync/submitters/types';
2
2
  import { DEDUPED, DROPPED, LOCALHOST_MODE, QUEUED } from '../../utils/constants';
3
3
  import { findLatencyIndex } from '../findLatencyIndex';
4
4
  import { ISegmentsCacheSync, ISplitsCacheSync, IStorageFactoryParams, ITelemetryCacheSync } from '../types';
@@ -25,7 +25,7 @@ export function shouldRecordTelemetry({ settings }: IStorageFactoryParams) {
25
25
 
26
26
  export class TelemetryCacheInMemory implements ITelemetryCacheSync {
27
27
 
28
- constructor(private splits?: ISplitsCacheSync, private segments?: ISegmentsCacheSync, private largeSegments?: ISegmentsCacheSync) { }
28
+ constructor(private splits?: ISplitsCacheSync, private segments?: ISegmentsCacheSync) { }
29
29
 
30
30
  // isEmpty flag
31
31
  private e = true;
@@ -51,8 +51,6 @@ export class TelemetryCacheInMemory implements ITelemetryCacheSync {
51
51
  spC: this.splits && this.splits.getSplitNames().length,
52
52
  seC: this.segments && this.segments.getRegisteredSegments().length,
53
53
  skC: this.segments && this.segments.getKeysCount(),
54
- lseC: this.largeSegments && this.largeSegments.getRegisteredSegments().length,
55
- lskC: this.largeSegments && this.largeSegments.getKeysCount(),
56
54
  sL: this.getSessionLength(),
57
55
  eQ: this.getEventStats(QUEUED),
58
56
  eD: this.getEventStats(DROPPED),
@@ -247,16 +245,22 @@ export class TelemetryCacheInMemory implements ITelemetryCacheSync {
247
245
  this.e = false;
248
246
  }
249
247
 
250
- private updatesFromSSE: UpdatesFromSSE = {};
248
+ private updatesFromSSE = {
249
+ sp: 0,
250
+ ms: 0
251
+ };
251
252
 
252
253
  popUpdatesFromSSE() {
253
254
  const result = this.updatesFromSSE;
254
- this.updatesFromSSE = {};
255
+ this.updatesFromSSE = {
256
+ sp: 0,
257
+ ms: 0,
258
+ };
255
259
  return result;
256
260
  }
257
261
 
258
262
  recordUpdatesFromSSE(type: UpdatesFromSSEEnum) {
259
- this.updatesFromSSE[type] = (this.updatesFromSSE[type] || 0) + 1;
263
+ this.updatesFromSSE[type]++;
260
264
  this.e = false;
261
265
  }
262
266
 
@@ -7,7 +7,7 @@ import { ISet, setToArray, _Set } from '../../utils/lang/sets';
7
7
  * The `_cache` property is the object were items are stored.
8
8
  * Intended for testing purposes.
9
9
  *
10
- * @param connDelay delay in millis for `connect` resolve. If not provided, `connect` resolves immediately.
10
+ * @param connDelay delay in millis for `connect` resolve. If not provided, `connect` resolves inmediatelly.
11
11
  */
12
12
  export function inMemoryWrapperFactory(connDelay?: number): IPluggableStorageWrapper & { _cache: Record<string, string | string[] | ISet<string>>, _setConnDelay(connDelay: number): void } {
13
13
 
@@ -204,8 +204,8 @@ export interface ISplitsCacheBase {
204
204
  getSplitNames(): MaybeThenable<string[]>,
205
205
  // should never reject or throw an exception. Instead return true by default, asssuming the TT might exist.
206
206
  trafficTypeExists(trafficType: string): MaybeThenable<boolean>,
207
- // only for Client-Side. Returns true if the storage is not synchronized yet (getChangeNumber() === 1) or contains a FF using the given matcher
208
- usesMatcher(matcherType: string): MaybeThenable<boolean>,
207
+ // only for Client-Side
208
+ usesSegments(): MaybeThenable<boolean>,
209
209
  clear(): MaybeThenable<boolean | void>,
210
210
  // should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE.
211
211
  checkCache(): MaybeThenable<boolean>,
@@ -223,7 +223,7 @@ export interface ISplitsCacheSync extends ISplitsCacheBase {
223
223
  getAll(): ISplit[],
224
224
  getSplitNames(): string[],
225
225
  trafficTypeExists(trafficType: string): boolean,
226
- usesMatcher(matcherType: string): boolean,
226
+ usesSegments(): boolean,
227
227
  clear(): void,
228
228
  checkCache(): boolean,
229
229
  killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean,
@@ -240,7 +240,7 @@ export interface ISplitsCacheAsync extends ISplitsCacheBase {
240
240
  getAll(): Promise<ISplit[]>,
241
241
  getSplitNames(): Promise<string[]>,
242
242
  trafficTypeExists(trafficType: string): Promise<boolean>,
243
- usesMatcher(matcherType: string): Promise<boolean>,
243
+ usesSegments(): Promise<boolean>,
244
244
  clear(): Promise<boolean | void>,
245
245
  checkCache(): Promise<boolean>,
246
246
  killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise<boolean>,
@@ -477,9 +477,7 @@ export interface IStorageSync extends IStorageBase<
477
477
  IEventsCacheSync,
478
478
  ITelemetryCacheSync,
479
479
  IUniqueKeysCacheSync
480
- > {
481
- largeSegments?: ISegmentsCacheSync,
482
- }
480
+ > { }
483
481
 
484
482
  export interface IStorageAsync extends IStorageBase<
485
483
  ISplitsCacheAsync,
@@ -1,5 +1,5 @@
1
1
  import { IFetchMySegments, IResponse } from '../../../services/types';
2
- import { IMySegmentsResponse, IMyLargeSegmentsResponse } from '../../../dtos/types';
2
+ import { IMySegmentsResponseItem } from '../../../dtos/types';
3
3
  import { IMySegmentsFetcher } from './types';
4
4
 
5
5
  /**
@@ -21,11 +21,7 @@ export function mySegmentsFetcherFactory(fetchMySegments: IFetchMySegments): IMy
21
21
  // Extract segment names
22
22
  return mySegmentsPromise
23
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
- });
24
+ .then(json => json.mySegments.map((segment: IMySegmentsResponseItem) => segment.name));
29
25
  };
30
26
 
31
27
  }
@@ -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 for segments and large segments.
27
- const mySegmentsSyncTasks: Record<string, { msSyncTask: IMySegmentsSyncTask, mlsSyncTask?: IMySegmentsSyncTask }> = {};
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 { msSyncTask, mlsSyncTask } = add(matchingKey, readiness, storage);
29
+ const mySegmentsSyncTask = add(matchingKey, readiness, storage);
31
30
 
32
31
  function startMySegmentsSyncTasks() {
33
- const splitsHaveSegments = storage.splits.usesMatcher(IN_SEGMENT);
34
- const splitsHaveLargeSegments = storage.splits.usesMatcher(IN_LARGE_SEGMENT);
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, function (mySegmentsSyncTask) {
33
+ mySegmentsSyncTask.start();
44
34
  });
45
35
  }
46
36
 
47
37
  function stopMySegmentsSyncTasks() {
48
- forOwn(mySegmentsSyncTasks, ({ msSyncTask, mlsSyncTask }) => {
49
- msSyncTask.stop();
50
- mlsSyncTask && mlsSyncTask.stop();
38
+ forOwn(mySegmentsSyncTasks, function (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()) startMySegmentsSyncTasks();
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 msSyncTask = mySegmentsSyncTaskFactory(
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.fetchMySegments, 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
- if (storage.splits.usesMatcher(IN_SEGMENT) && storage.splits.usesMatcher(IN_LARGE_SEGMENT)) readiness.splits.once(SDK_SPLITS_ARRIVED, smartReady);
91
- else setTimeout(smartReady, 0);
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: msSyncTask,
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, function ({ msSyncTask, mlsSyncTask }) {
129
- promises.push(msSyncTask.execute());
130
- mlsSyncTask && promises.push(mlsSyncTask.execute());
97
+ forOwn(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
98
+ promises.push(mySegmentsSyncTask.execute());
131
99
  });
132
100
  return Promise.all(promises);
133
101
  },
@@ -1,4 +1,5 @@
1
- import { ISegmentsCacheSync } from '../../../storages/types';
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
5
  import { IFetchMySegments } from '../../../services/types';
@@ -11,25 +12,24 @@ import { mySegmentsUpdaterFactory } from '../updaters/mySegmentsUpdater';
11
12
  */
12
13
  export function mySegmentsSyncTaskFactory(
13
14
  fetchMySegments: IFetchMySegments,
14
- mySegmentsCache: ISegmentsCacheSync,
15
- notifyUpdate: () => void,
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
24
  mySegmentsFetcherFactory(fetchMySegments),
26
- mySegmentsCache,
27
- notifyUpdate,
25
+ storage.splits,
26
+ storage.segments,
27
+ readiness.segments,
28
28
  settings.startup.requestTimeoutBeforeReady,
29
29
  settings.startup.retriesOnFailureBeforeReady,
30
30
  matchingKey
31
31
  ),
32
- segmentsRefreshRate,
33
- NAME,
32
+ settings.scheduler.segmentsRefreshRate,
33
+ 'mySegmentsUpdater',
34
34
  );
35
35
  }
@@ -12,7 +12,7 @@ export type MySegmentsData = string[] | {
12
12
  name: string,
13
13
  /* action: `true` for add, and `false` for delete */
14
14
  add: boolean
15
- }[]
15
+ }
16
16
 
17
17
  export interface IMySegmentsSyncTask extends ISyncTask<[segmentsData?: MySegmentsData, noCache?: boolean], boolean> { }
18
18
 
@@ -20,14 +20,13 @@ export interface IPollingManager extends ITask {
20
20
  syncAll(): Promise<any>
21
21
  splitsSyncTask: ISplitsSyncTask
22
22
  segmentsSyncTask: ISyncTask
23
- largeSegmentsSyncTask?: ISyncTask
24
23
  }
25
24
 
26
25
  /**
27
26
  * PollingManager for client-side with support for multiple clients
28
27
  */
29
28
  export interface IPollingManagerCS extends IPollingManager {
30
- add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync): { msSyncTask: IMySegmentsSyncTask, mlsSyncTask?: IMySegmentsSyncTask }
29
+ add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync): IMySegmentsSyncTask
31
30
  remove(matchingKey: string): void;
32
- get(matchingKey: string): { msSyncTask: IMySegmentsSyncTask, mlsSyncTask?: IMySegmentsSyncTask } | undefined
31
+ get(matchingKey: string): IMySegmentsSyncTask | undefined
33
32
  }
@@ -1,12 +1,13 @@
1
1
  import { IMySegmentsFetcher } from '../fetchers/types';
2
- import { ISegmentsCacheSync } from '../../../storages/types';
2
+ import { ISegmentsCacheSync, ISplitsCacheSync } 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';
7
- import { isObject } from '../../../utils/lang';
8
9
 
9
- type IMySegmentsUpdater = (segmentList?: MySegmentsData, noCache?: boolean) => Promise<boolean>
10
+ type IMySegmentsUpdater = (segmentList?: string[], noCache?: boolean) => Promise<boolean>
10
11
 
11
12
  /**
12
13
  * factory of MySegments updater, a task that:
@@ -17,8 +18,9 @@ type IMySegmentsUpdater = (segmentList?: MySegmentsData, noCache?: boolean) => P
17
18
  export function mySegmentsUpdaterFactory(
18
19
  log: ILogger,
19
20
  mySegmentsFetcher: IMySegmentsFetcher,
21
+ splitsCache: ISplitsCacheSync,
20
22
  mySegmentsCache: ISegmentsCacheSync,
21
- notifyUpdate: () => void,
23
+ segmentsEventEmitter: ISegmentsEventEmitter,
22
24
  requestTimeoutBeforeReady: number,
23
25
  retriesOnFailureBeforeReady: number,
24
26
  matchingKey: string
@@ -37,24 +39,25 @@ export function mySegmentsUpdaterFactory(
37
39
  function updateSegments(segmentsData: MySegmentsData) {
38
40
 
39
41
  let shouldNotifyUpdate;
40
- if (isObject(segmentsData[0])) {
41
- // Add/Delete the segment names
42
- (segmentsData as { name: string, add: boolean }[]).forEach(({ name, add }) => {
43
- if (mySegmentsCache.isInSegment(name) !== add) {
44
- shouldNotifyUpdate = true;
45
- if (add) mySegmentsCache.addToSegment(name);
46
- else mySegmentsCache.removeFromSegment(name);
47
- }
48
- });
42
+ if (Array.isArray(segmentsData)) {
43
+ // Update the list of segment names available
44
+ shouldNotifyUpdate = mySegmentsCache.resetSegments(segmentsData);
49
45
  } else {
50
- // Reset the list of segment names
51
- shouldNotifyUpdate = mySegmentsCache.resetSegments(segmentsData as string[]);
46
+ // Add/Delete the segment
47
+ const { name, add } = segmentsData;
48
+ if (mySegmentsCache.isInSegment(name) !== add) {
49
+ shouldNotifyUpdate = true;
50
+ if (add) mySegmentsCache.addToSegment(name);
51
+ else mySegmentsCache.removeFromSegment(name);
52
+ } else {
53
+ shouldNotifyUpdate = false;
54
+ }
52
55
  }
53
56
 
54
57
  // Notify update if required
55
- if (shouldNotifyUpdate || readyOnAlreadyExistentState) {
58
+ if (splitsCache.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
56
59
  readyOnAlreadyExistentState = false;
57
- notifyUpdate();
60
+ segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
58
61
  }
59
62
  }
60
63
 
@@ -1,7 +1,7 @@
1
1
  import { IPlatform } from '../../../sdkFactory/types';
2
2
  import { IEventSourceConstructor } from '../../../services/types';
3
3
  import { ISettings } from '../../../types';
4
- import { endsWith, isString } from '../../../utils/lang';
4
+ import { isString } from '../../../utils/lang';
5
5
  import { objectAssign } from '../../../utils/lang/objectAssign';
6
6
  import { IAuthTokenPushEnabled } from '../AuthClient/types';
7
7
  import { ISSEClient, ISseEventHandler } from './types';
@@ -42,7 +42,6 @@ export class SSEClient implements ISSEClient {
42
42
  useHeaders?: boolean;
43
43
  headers: Record<string, string>;
44
44
  options?: object;
45
- lse?: boolean;
46
45
 
47
46
  /**
48
47
  * SSEClient constructor.
@@ -62,7 +61,6 @@ export class SSEClient implements ISSEClient {
62
61
  this.useHeaders = useHeaders;
63
62
  this.headers = buildSSEHeaders(settings);
64
63
  this.options = getOptions && getOptions(settings);
65
- this.lse = settings.sync.largeSegmentsEnabled;
66
64
  }
67
65
 
68
66
  setEventHandler(handler: ISseEventHandler) {
@@ -78,13 +76,12 @@ export class SSEClient implements ISSEClient {
78
76
  open(authToken: IAuthTokenPushEnabled) {
79
77
  this.close(); // it closes connection if previously opened
80
78
 
81
- const channelsQueryParam = Object.keys(authToken.channels).map((channel) => {
82
- const params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
83
- return encodeURIComponent(params + channel);
84
- }).filter(channel => {
85
- return this.lse || !endsWith(channel, 'myLargeSegments');
86
- }).join(',');
87
-
79
+ const channelsQueryParam = Object.keys(authToken.channels).map(
80
+ function (channel) {
81
+ const params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
82
+ return encodeURIComponent(params + channel);
83
+ }
84
+ ).join(',');
88
85
  const url = `${this.streamingUrl}?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${ABLY_API_VERSION}&heartbeats=true`; // same results using `&heartbeats=false`
89
86
 
90
87
  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, MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MY_LARGE_SEGMENTS_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';
@@ -83,7 +83,6 @@ export function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventEmitter,
83
83
  case SPLIT_UPDATE:
84
84
  case SEGMENT_UPDATE:
85
85
  case MY_SEGMENTS_UPDATE_V2:
86
- case MY_LARGE_SEGMENTS_UPDATE:
87
86
  case SPLIT_KILL:
88
87
  pushEmitter.emit(parsedData.type, parsedData);
89
88
  break;
@@ -1,5 +1,5 @@
1
1
  import { ControlType } from '../constants';
2
- import { MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MY_LARGE_SEGMENTS_UPDATE } from '../types';
2
+ import { MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY } from '../types';
3
3
 
4
4
  export interface IMySegmentsUpdateData {
5
5
  type: MY_SEGMENTS_UPDATE,
@@ -35,18 +35,6 @@ export interface IMySegmentsUpdateV2Data {
35
35
  u: UpdateStrategy,
36
36
  }
37
37
 
38
- export interface IMyLargeSegmentsUpdateData {
39
- type: MY_LARGE_SEGMENTS_UPDATE,
40
- changeNumber: number,
41
- largeSegments: string[],
42
- c: Compression,
43
- d: string,
44
- u: UpdateStrategy,
45
- i?: number, // time interval in millis
46
- h?: number, // hash function. 0 for murmur3_32, 1 for murmur3_64
47
- s?: number, // seed for hash function
48
- }
49
-
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 = IMySegmentsUpdateData | IMySegmentsUpdateV2Data | IMyLargeSegmentsUpdateData | ISegmentUpdateData | ISplitUpdateData | ISplitKillData | IControlData | IOccupancyData
71
+ export type INotificationData = IMySegmentsUpdateData | IMySegmentsUpdateV2Data | 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 }
@@ -1,21 +1,19 @@
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 { UpdatesFromSSEEnum } from '../../submitters/types';
6
6
 
7
7
  /**
8
8
  * MySegmentsUpdateWorker factory
9
9
  */
10
- export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker, updateType: UpdatesFromSSEEnum): IUpdateWorker<[changeNumber: number, segmentsData?: MySegmentsData, delay?: number]> {
10
+ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker): IUpdateWorker {
11
11
 
12
12
  let maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
13
13
  let currentChangeNumber = -1;
14
14
  let handleNewEvent = false;
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
- let _delay: undefined | number;
18
- let _delayTimeoutID: any;
19
17
  const backoff = new Backoff(__handleMySegmentsUpdateCall);
20
18
 
21
19
  function __handleMySegmentsUpdateCall() {
@@ -25,19 +23,10 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
25
23
  const currentMaxChangeNumber = maxChangeNumber;
26
24
 
27
25
  // 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) => {
26
+ mySegmentsSyncTask.execute(_segmentsData, true).then((result) => {
38
27
  if (!isHandlingEvent) return; // halt if `stop` has been called
39
28
  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);
29
+ if (_segmentsData) telemetryTracker.trackUpdatesFromSSE(MY_SEGMENT);
41
30
  currentChangeNumber = Math.max(currentChangeNumber, currentMaxChangeNumber); // use `currentMaxChangeNumber`, in case that `maxChangeNumber` was updated during fetch.
42
31
  }
43
32
  if (handleNewEvent) {
@@ -53,28 +42,23 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
53
42
 
54
43
  return {
55
44
  /**
56
- * Invoked by NotificationProcessor on MY_(LARGE)_SEGMENTS_UPDATE notifications
45
+ * Invoked by NotificationProcessor on MY_SEGMENTS_UPDATE event
57
46
  *
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
47
+ * @param {number} changeNumber change number of the MY_SEGMENTS_UPDATE notification
48
+ * @param {SegmentsData | undefined} segmentsData might be undefined
61
49
  */
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;
50
+ put(changeNumber: number, segmentsData?: MySegmentsData) {
51
+ if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber) return;
65
52
 
66
53
  maxChangeNumber = changeNumber;
67
54
  handleNewEvent = true;
68
55
  _segmentsData = segmentsData;
69
- _delay = delay;
70
56
 
71
57
  if (backoff.timeoutID || !isHandlingEvent) __handleMySegmentsUpdateCall();
72
58
  backoff.reset();
73
59
  },
74
60
 
75
61
  stop() {
76
- clearTimeout(_delayTimeoutID);
77
- _delay = undefined;
78
62
  isHandlingEvent = false;
79
63
  backoff.reset();
80
64
  }
@@ -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) {
@@ -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
  }
@@ -30,7 +30,6 @@ 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';
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';
@@ -1,7 +1,6 @@
1
1
  import { algorithms } from '../../utils/decompress';
2
2
  import { decodeFromBase64 } from '../../utils/base64';
3
3
  import { Compression, KeyList } from './SSEHandler/types';
4
- import { ISplit } from '../../dtos/types';
5
4
 
6
5
  const GZIP = 1;
7
6
  const ZLIB = 2;
@@ -43,7 +42,7 @@ function decompress(data: string, compression: Compression) {
43
42
  * @returns {{a?: string[], r?: string[] }}
44
43
  * @throws if data string cannot be decoded, decompressed or parsed
45
44
  */
46
- export function parseKeyList(data: string, compression: Compression, avoidPrecisionLoss = true): KeyList {
45
+ export function parseKeyList(data: string, compression: Compression, avoidPrecisionLoss: boolean = true): KeyList {
47
46
  const binKeyList = decompress(data, compression);
48
47
  let strKeyList = Uint8ArrayToString(binKeyList);
49
48
  // replace numbers to strings, to avoid losing precision
@@ -81,9 +80,14 @@ export function isInBitmap(bitmap: Uint8Array, hash64hex: string) {
81
80
 
82
81
  /**
83
82
  * Parse feature flags notifications for instant feature flag updates
83
+ *
84
+ * @param {ISplitUpdateData} data
85
+ * @returns {KeyList}
84
86
  */
85
- export function parseFFUpdatePayload(compression: Compression, data: string): ISplit | undefined {
86
- return compression > 0 ?
87
- parseKeyList(data, compression, false) :
88
- JSON.parse(decodeFromBase64(data));
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));
89
93
  }