@splitsoftware/splitio-commons 1.16.1-rc.8 → 1.17.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) 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 +43 -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 +9 -12
  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 +69 -100
  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 +39 -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 +10 -13
  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 +70 -100
  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 +41 -0
  90. package/src/services/splitApi.ts +2 -7
  91. package/src/services/splitHttpClient.ts +6 -5
  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 +14 -20
  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 +10 -26
  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 +68 -104
  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/splitApi.d.ts +1 -1
  135. package/types/services/splitHttpClient.d.ts +1 -1
  136. package/types/services/types.d.ts +0 -1
  137. package/types/storages/AbstractSplitsCacheAsync.d.ts +1 -1
  138. package/types/storages/AbstractSplitsCacheSync.d.ts +3 -3
  139. package/types/storages/KeyBuilder.d.ts +0 -1
  140. package/types/storages/KeyBuilderCS.d.ts +2 -7
  141. package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +2 -2
  142. package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +1 -1
  143. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +2 -3
  144. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -4
  145. package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -1
  146. package/types/storages/types.d.ts +3 -4
  147. package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +3 -2
  148. package/types/sync/polling/types.d.ts +3 -10
  149. package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +4 -4
  150. package/types/sync/streaming/SSEClient/index.d.ts +2 -5
  151. package/types/sync/streaming/SSEHandler/types.d.ts +2 -13
  152. package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -3
  153. package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +1 -2
  154. package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +2 -3
  155. package/types/sync/streaming/UpdateWorkers/types.d.ts +2 -2
  156. package/types/sync/streaming/constants.d.ts +0 -1
  157. package/types/sync/streaming/parseUtils.d.ts +4 -2
  158. package/types/sync/streaming/pushManager.d.ts +0 -2
  159. package/types/sync/streaming/types.d.ts +4 -5
  160. package/types/sync/submitters/types.d.ts +3 -10
  161. package/types/types.d.ts +11 -26
  162. package/types/utils/constants/index.d.ts +1 -3
  163. package/types/utils/settingsValidation/index.d.ts +0 -2
  164. package/types/utils/settingsValidation/types.d.ts +1 -1
  165. package/cjs/evaluator/matchers/large_segment.js +0 -16
  166. package/esm/evaluator/matchers/large_segment.js +0 -12
  167. package/src/evaluator/matchers/large_segment.ts +0 -18
@@ -1,8 +1,7 @@
1
1
  import { ISplit, ISplitFiltersValidation } from '../../dtos/types';
2
- import { AbstractSplitsCacheSync, usesMatcher } from '../AbstractSplitsCacheSync';
2
+ import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
3
3
  import { isFiniteNumber } from '../../utils/lang';
4
4
  import { ISet, _Set } from '../../utils/lang/sets';
5
- import { IN_LARGE_SEGMENT, IN_SEGMENT } from '../../utils/constants';
6
5
 
7
6
  /**
8
7
  * Default ISplitsCacheSync implementation that stores split definitions in memory.
@@ -14,8 +13,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
14
13
  private splitsCache: Record<string, ISplit> = {};
15
14
  private ttCache: Record<string, number> = {};
16
15
  private changeNumber: number = -1;
17
- private segmentsCount: number = 0;
18
- private largeSegmentsCount: number = 0;
16
+ private splitsWithSegmentsCount: number = 0;
19
17
  private flagSetsCache: Record<string, ISet<string>> = {};
20
18
 
21
19
  constructor(splitFiltersValidation?: ISplitFiltersValidation) {
@@ -27,8 +25,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
27
25
  this.splitsCache = {};
28
26
  this.ttCache = {};
29
27
  this.changeNumber = -1;
30
- this.segmentsCount = 0;
31
- this.largeSegmentsCount = 0;
28
+ this.splitsWithSegmentsCount = 0;
32
29
  }
33
30
 
34
31
  addSplit(name: string, split: ISplit): boolean {
@@ -41,9 +38,9 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
41
38
 
42
39
  this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
43
40
 
44
- // Substract from segments count for the previous version of this Split.
45
- if (usesMatcher(previousSplit, IN_SEGMENT)) this.segmentsCount--;
46
- if (usesMatcher(previousSplit, IN_LARGE_SEGMENT)) this.largeSegmentsCount--;
41
+ if (usesSegments(previousSplit)) { // Substract from segments count for the previous version of this Split.
42
+ this.splitsWithSegmentsCount--;
43
+ }
47
44
  }
48
45
 
49
46
  if (split) {
@@ -55,8 +52,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
55
52
  this.addToFlagSets(split);
56
53
 
57
54
  // Add to segments count for the new version of the Split
58
- if (usesMatcher(split, IN_SEGMENT)) this.segmentsCount++;
59
- if (usesMatcher(split, IN_LARGE_SEGMENT)) this.largeSegmentsCount++;
55
+ if (usesSegments(split)) this.splitsWithSegmentsCount++;
60
56
 
61
57
  return true;
62
58
  } else {
@@ -76,8 +72,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
76
72
  this.removeFromFlagSets(split.name, split.sets);
77
73
 
78
74
  // Update the segments count.
79
- if (usesMatcher(split, IN_SEGMENT)) this.segmentsCount--;
80
- if (usesMatcher(split, IN_LARGE_SEGMENT)) this.largeSegmentsCount--;
75
+ if (usesSegments(split)) this.splitsWithSegmentsCount--;
81
76
 
82
77
  return true;
83
78
  } else {
@@ -106,8 +101,8 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
106
101
  return isFiniteNumber(this.ttCache[trafficType]) && this.ttCache[trafficType] > 0;
107
102
  }
108
103
 
109
- usesMatcher(matcherType: string): boolean {
110
- return this.getChangeNumber() === -1 || (matcherType === IN_SEGMENT ? this.segmentsCount > 0 : this.largeSegmentsCount > 0);
104
+ usesSegments(): boolean {
105
+ return this.getChangeNumber() === -1 || this.splitsWithSegmentsCount > 0;
111
106
  }
112
107
 
113
108
  getNamesByFlagSets(flagSets: string[]): ISet<string>[] {
@@ -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,8 @@
1
1
  import { IPlatform } from '../../../sdkFactory/types';
2
+ import { decorateHeaders } from '../../../services/decorateHeaders';
2
3
  import { IEventSourceConstructor } from '../../../services/types';
3
4
  import { ISettings } from '../../../types';
4
- import { endsWith, isString } from '../../../utils/lang';
5
+ import { isString } from '../../../utils/lang';
5
6
  import { objectAssign } from '../../../utils/lang/objectAssign';
6
7
  import { IAuthTokenPushEnabled } from '../AuthClient/types';
7
8
  import { ISSEClient, ISseEventHandler } from './types';
@@ -36,33 +37,25 @@ function buildSSEHeaders(settings: ISettings) {
36
37
  export class SSEClient implements ISSEClient {
37
38
  // Instance properties:
38
39
  eventSource?: IEventSourceConstructor;
39
- streamingUrl: string;
40
40
  connection?: InstanceType<IEventSourceConstructor>;
41
41
  handler?: ISseEventHandler;
42
- useHeaders?: boolean;
43
42
  headers: Record<string, string>;
44
43
  options?: object;
45
- lse?: boolean;
46
44
 
47
45
  /**
48
46
  * SSEClient constructor.
49
47
  *
50
48
  * @param settings Validated settings.
51
- * @param useHeaders True to send metadata as headers or false to send as query params. If `true`, the provided EventSource must support headers.
52
49
  * @param platform object containing environment-specific dependencies
53
50
  * @throws 'EventSource API is not available.' if EventSource is not available.
54
51
  */
55
- constructor(settings: ISettings, useHeaders: boolean, { getEventSource, getOptions }: IPlatform) {
52
+ constructor(private settings: ISettings, { getEventSource, getOptions }: IPlatform) {
56
53
  this.eventSource = getEventSource && getEventSource(settings);
57
54
  // if eventSource is not available, throw an exception
58
55
  if (!this.eventSource) throw new Error('EventSource API is not available.');
59
56
 
60
- this.streamingUrl = settings.urls.streaming + '/sse';
61
- // @TODO get `useHeaders` flag from `getEventSource`, to use EventSource headers on client-side SDKs when possible.
62
- this.useHeaders = useHeaders;
63
57
  this.headers = buildSSEHeaders(settings);
64
58
  this.options = getOptions && getOptions(settings);
65
- this.lse = settings.sync.largeSegmentsEnabled;
66
59
  }
67
60
 
68
61
  setEventHandler(handler: ISseEventHandler) {
@@ -78,21 +71,22 @@ export class SSEClient implements ISSEClient {
78
71
  open(authToken: IAuthTokenPushEnabled) {
79
72
  this.close(); // it closes connection if previously opened
80
73
 
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
-
88
- const url = `${this.streamingUrl}?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${ABLY_API_VERSION}&heartbeats=true`; // same results using `&heartbeats=false`
74
+ const channelsQueryParam = Object.keys(authToken.channels).map(
75
+ function (channel) {
76
+ const params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
77
+ return encodeURIComponent(params + channel);
78
+ }
79
+ ).join(',');
80
+ const url = `${this.settings.urls.streaming}/sse?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${ABLY_API_VERSION}&heartbeats=true`; // same results using `&heartbeats=false`
81
+ // use headers in server-side or if getHeaderOverrides is defined
82
+ const useHeaders = !this.settings.core.key || this.settings.sync.requestOptions?.getHeaderOverrides;
89
83
 
90
84
  this.connection = new this.eventSource!(
91
85
  // For client-side SDKs, SplitSDKClientKey and SplitSDKClientKey metadata is passed as query params,
92
86
  // because native EventSource implementations for browser doesn't support headers.
93
- this.useHeaders ? url : url + `&SplitSDKVersion=${this.headers.SplitSDKVersion}&SplitSDKClientKey=${this.headers.SplitSDKClientKey}`,
87
+ useHeaders ? url : url + `&SplitSDKVersion=${this.headers.SplitSDKVersion}&SplitSDKClientKey=${this.headers.SplitSDKClientKey}`,
94
88
  // For server-side SDKs, metadata is passed via headers. EventSource must support headers, like 'eventsource' package for Node.
95
- objectAssign(this.useHeaders ? { headers: this.headers } : {}, this.options)
89
+ objectAssign(useHeaders ? { headers: decorateHeaders(this.settings, this.headers) } : {}, this.options)
96
90
  );
97
91
 
98
92
  if (this.handler) { // no need to check if SSEClient is used only by PushManager
@@ -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
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 }