@splitsoftware/splitio-commons 1.17.0 → 1.17.1-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 (181) hide show
  1. package/CHANGES.txt +8 -0
  2. package/cjs/evaluator/matchers/index.js +3 -1
  3. package/cjs/evaluator/matchers/large_segment.js +16 -0
  4. package/cjs/evaluator/matchers/matcherTypes.js +1 -0
  5. package/cjs/evaluator/matchersTransform/index.js +4 -1
  6. package/cjs/evaluator/matchersTransform/segment.js +3 -1
  7. package/cjs/logger/constants.js +2 -2
  8. package/cjs/logger/messages/info.js +1 -1
  9. package/cjs/logger/messages/warn.js +1 -1
  10. package/cjs/readiness/readinessManager.js +5 -6
  11. package/cjs/readiness/sdkReadinessManager.js +5 -6
  12. package/cjs/sdkClient/identity.js +7 -0
  13. package/cjs/sdkClient/sdkClient.js +5 -5
  14. package/cjs/sdkClient/sdkClientMethod.js +3 -1
  15. package/cjs/sdkClient/sdkClientMethodCS.js +9 -14
  16. package/cjs/sdkClient/sdkClientMethodCSWithTT.js +9 -14
  17. package/cjs/sdkFactory/index.js +6 -2
  18. package/cjs/services/splitApi.js +5 -5
  19. package/cjs/storages/AbstractSegmentsCacheSync.js +41 -12
  20. package/cjs/storages/AbstractSplitsCacheSync.js +2 -1
  21. package/cjs/storages/KeyBuilderCS.js +23 -5
  22. package/cjs/storages/dataLoader.js +1 -1
  23. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +29 -52
  24. package/cjs/storages/inLocalStorage/index.js +6 -2
  25. package/cjs/storages/inMemory/InMemoryStorageCS.js +5 -0
  26. package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +9 -40
  27. package/cjs/storages/inMemory/SplitsCacheInMemory.js +8 -8
  28. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +7 -10
  29. package/cjs/storages/pluggable/inMemoryWrapper.js +1 -1
  30. package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +5 -8
  31. package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
  32. package/cjs/sync/polling/pollingManagerCS.js +1 -1
  33. package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  34. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +15 -21
  35. package/cjs/sync/streaming/AuthClient/index.js +1 -1
  36. package/cjs/sync/streaming/SSEHandler/index.js +3 -5
  37. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +107 -48
  38. package/cjs/sync/streaming/constants.js +3 -3
  39. package/cjs/sync/streaming/parseUtils.js +14 -9
  40. package/cjs/sync/streaming/pushManager.js +69 -67
  41. package/cjs/utils/constants/index.js +5 -4
  42. package/cjs/utils/settingsValidation/index.js +2 -1
  43. package/esm/evaluator/matchers/index.js +3 -1
  44. package/esm/evaluator/matchers/large_segment.js +12 -0
  45. package/esm/evaluator/matchers/matcherTypes.js +1 -0
  46. package/esm/evaluator/matchersTransform/index.js +4 -1
  47. package/esm/evaluator/matchersTransform/segment.js +3 -1
  48. package/esm/logger/constants.js +1 -1
  49. package/esm/logger/messages/info.js +1 -1
  50. package/esm/logger/messages/warn.js +1 -1
  51. package/esm/readiness/readinessManager.js +5 -6
  52. package/esm/readiness/sdkReadinessManager.js +5 -6
  53. package/esm/sdkClient/identity.js +3 -0
  54. package/esm/sdkClient/sdkClient.js +5 -5
  55. package/esm/sdkClient/sdkClientMethod.js +3 -1
  56. package/esm/sdkClient/sdkClientMethodCS.js +7 -12
  57. package/esm/sdkClient/sdkClientMethodCSWithTT.js +7 -12
  58. package/esm/sdkFactory/index.js +6 -2
  59. package/esm/services/splitApi.js +6 -6
  60. package/esm/storages/AbstractSegmentsCacheSync.js +41 -12
  61. package/esm/storages/AbstractSplitsCacheSync.js +3 -2
  62. package/esm/storages/KeyBuilderCS.js +21 -4
  63. package/esm/storages/dataLoader.js +1 -1
  64. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +29 -52
  65. package/esm/storages/inLocalStorage/index.js +7 -3
  66. package/esm/storages/inMemory/InMemoryStorageCS.js +5 -0
  67. package/esm/storages/inMemory/MySegmentsCacheInMemory.js +9 -40
  68. package/esm/storages/inMemory/SplitsCacheInMemory.js +8 -8
  69. package/esm/storages/inMemory/TelemetryCacheInMemory.js +7 -10
  70. package/esm/storages/pluggable/inMemoryWrapper.js +1 -1
  71. package/esm/sync/polling/fetchers/mySegmentsFetcher.js +5 -8
  72. package/esm/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
  73. package/esm/sync/polling/pollingManagerCS.js +1 -1
  74. package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  75. package/esm/sync/polling/updaters/mySegmentsUpdater.js +15 -21
  76. package/esm/sync/streaming/AuthClient/index.js +1 -1
  77. package/esm/sync/streaming/SSEHandler/index.js +4 -6
  78. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +108 -49
  79. package/esm/sync/streaming/constants.js +2 -2
  80. package/esm/sync/streaming/parseUtils.js +12 -8
  81. package/esm/sync/streaming/pushManager.js +72 -70
  82. package/esm/utils/constants/index.js +3 -2
  83. package/esm/utils/settingsValidation/index.js +2 -1
  84. package/package.json +1 -1
  85. package/src/dtos/types.ts +21 -7
  86. package/src/evaluator/matchers/index.ts +2 -0
  87. package/src/evaluator/matchers/large_segment.ts +18 -0
  88. package/src/evaluator/matchers/matcherTypes.ts +1 -0
  89. package/src/evaluator/matchersTransform/index.ts +4 -1
  90. package/src/evaluator/matchersTransform/segment.ts +5 -3
  91. package/src/logger/constants.ts +1 -1
  92. package/src/logger/messages/info.ts +1 -1
  93. package/src/logger/messages/warn.ts +1 -1
  94. package/src/readiness/readinessManager.ts +7 -5
  95. package/src/readiness/sdkReadinessManager.ts +7 -7
  96. package/src/readiness/types.ts +2 -2
  97. package/src/sdkClient/identity.ts +5 -0
  98. package/src/sdkClient/sdkClient.ts +5 -5
  99. package/src/sdkClient/sdkClientMethod.ts +4 -1
  100. package/src/sdkClient/sdkClientMethodCS.ts +7 -13
  101. package/src/sdkClient/sdkClientMethodCSWithTT.ts +7 -13
  102. package/src/sdkFactory/index.ts +8 -4
  103. package/src/sdkFactory/types.ts +2 -1
  104. package/src/services/splitApi.ts +7 -7
  105. package/src/services/splitHttpClient.ts +1 -1
  106. package/src/services/types.ts +2 -2
  107. package/src/storages/AbstractSegmentsCacheSync.ts +53 -12
  108. package/src/storages/AbstractSplitsCacheSync.ts +4 -3
  109. package/src/storages/KeyBuilderCS.ts +34 -5
  110. package/src/storages/dataLoader.ts +1 -1
  111. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +29 -59
  112. package/src/storages/inLocalStorage/index.ts +8 -4
  113. package/src/storages/inMemory/InMemoryStorageCS.ts +5 -0
  114. package/src/storages/inMemory/MySegmentsCacheInMemory.ts +10 -44
  115. package/src/storages/inMemory/SplitsCacheInMemory.ts +7 -8
  116. package/src/storages/inMemory/TelemetryCacheInMemory.ts +7 -11
  117. package/src/storages/pluggable/inMemoryWrapper.ts +1 -1
  118. package/src/storages/types.ts +11 -7
  119. package/src/sync/polling/fetchers/mySegmentsFetcher.ts +8 -10
  120. package/src/sync/polling/fetchers/segmentChangesFetcher.ts +1 -1
  121. package/src/sync/polling/fetchers/types.ts +3 -2
  122. package/src/sync/polling/pollingManagerCS.ts +4 -4
  123. package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +4 -5
  124. package/src/sync/polling/types.ts +7 -6
  125. package/src/sync/polling/updaters/mySegmentsUpdater.ts +19 -22
  126. package/src/sync/streaming/AuthClient/index.ts +1 -1
  127. package/src/sync/streaming/SSEClient/index.ts +4 -6
  128. package/src/sync/streaming/SSEHandler/index.ts +5 -8
  129. package/src/sync/streaming/SSEHandler/types.ts +15 -15
  130. package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +116 -49
  131. package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +1 -1
  132. package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +1 -1
  133. package/src/sync/streaming/UpdateWorkers/types.ts +2 -2
  134. package/src/sync/streaming/constants.ts +2 -2
  135. package/src/sync/streaming/parseUtils.ts +19 -11
  136. package/src/sync/streaming/pushManager.ts +73 -72
  137. package/src/sync/streaming/types.ts +10 -10
  138. package/src/sync/submitters/types.ts +8 -5
  139. package/src/types.ts +7 -1
  140. package/src/utils/constants/index.ts +3 -2
  141. package/src/utils/settingsValidation/index.ts +3 -2
  142. package/src/utils/settingsValidation/types.ts +1 -1
  143. package/types/dtos/types.d.ts +18 -7
  144. package/types/evaluator/matchersTransform/segment.d.ts +2 -2
  145. package/types/logger/constants.d.ts +1 -1
  146. package/types/readiness/readinessManager.d.ts +2 -2
  147. package/types/readiness/sdkReadinessManager.d.ts +2 -3
  148. package/types/readiness/types.d.ts +2 -2
  149. package/types/sdkClient/identity.d.ts +0 -4
  150. package/types/sdkClient/sdkClientMethod.d.ts +1 -1
  151. package/types/sdkFactory/types.d.ts +2 -1
  152. package/types/services/splitApi.d.ts +1 -1
  153. package/types/services/splitHttpClient.d.ts +1 -1
  154. package/types/services/types.d.ts +2 -2
  155. package/types/storages/AbstractMySegmentsCacheSync.d.ts +39 -0
  156. package/types/storages/AbstractSegmentsCacheSync.d.ts +9 -11
  157. package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
  158. package/types/storages/KeyBuilderCS.d.ts +9 -2
  159. package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +4 -14
  160. package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +3 -9
  161. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +1 -1
  162. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +4 -6
  163. package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -1
  164. package/types/storages/types.d.ts +7 -5
  165. package/types/sync/polling/fetchers/mySegmentsFetcher.d.ts +2 -2
  166. package/types/sync/polling/fetchers/types.d.ts +2 -2
  167. package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +2 -2
  168. package/types/sync/polling/types.d.ts +7 -4
  169. package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +4 -3
  170. package/types/sync/streaming/SSEHandler/types.d.ts +16 -14
  171. package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +4 -2
  172. package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +2 -1
  173. package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +3 -2
  174. package/types/sync/streaming/UpdateWorkers/types.d.ts +2 -2
  175. package/types/sync/streaming/constants.d.ts +2 -2
  176. package/types/sync/streaming/parseUtils.d.ts +4 -5
  177. package/types/sync/streaming/types.d.ts +8 -8
  178. package/types/sync/submitters/types.d.ts +7 -4
  179. package/types/types.d.ts +7 -1
  180. package/types/utils/constants/index.d.ts +3 -2
  181. package/types/utils/settingsValidation/types.d.ts +1 -1
@@ -7,18 +7,19 @@ import { AbstractSegmentsCacheSync } from '../AbstractSegmentsCacheSync';
7
7
  export class MySegmentsCacheInMemory extends AbstractSegmentsCacheSync {
8
8
 
9
9
  private segmentCache: Record<string, boolean> = {};
10
-
11
- clear() {
12
- this.segmentCache = {};
13
- }
10
+ private cn?: number;
14
11
 
15
12
  addToSegment(name: string): boolean {
13
+ if (this.segmentCache[name]) return false;
14
+
16
15
  this.segmentCache[name] = true;
17
16
 
18
17
  return true;
19
18
  }
20
19
 
21
20
  removeFromSegment(name: string): boolean {
21
+ if (!this.segmentCache[name]) return false;
22
+
22
23
  delete this.segmentCache[name];
23
24
 
24
25
  return true;
@@ -28,48 +29,13 @@ export class MySegmentsCacheInMemory extends AbstractSegmentsCacheSync {
28
29
  return this.segmentCache[name] === true;
29
30
  }
30
31
 
31
- /**
32
- * Reset (update) the cached list of segments with the given list, removing and adding segments if necessary.
33
- * @NOTE based on the way we use segments in the browser, this way is the best option
34
- *
35
- * @param {string[]} names list of segment names
36
- * @returns boolean indicating if the cache was updated (i.e., given list was different from the cached one)
37
- */
38
- resetSegments(names: string[]): boolean {
39
- let isDiff = false;
40
- let index;
41
-
42
- const storedSegmentKeys = Object.keys(this.segmentCache);
43
32
 
44
- // Extreme fast => everything is empty
45
- if (names.length === 0 && storedSegmentKeys.length === names.length)
46
- return isDiff;
47
-
48
- // Quick path
49
- if (storedSegmentKeys.length !== names.length) {
50
- isDiff = true;
51
-
52
- this.segmentCache = {};
53
- names.forEach(s => {
54
- this.addToSegment(s);
55
- });
56
- } else {
57
- // Slowest path => we need to find at least 1 difference because
58
- for (index = 0; index < names.length && this.isInSegment(names[index]); index++) {
59
- // TODO: why empty statement?
60
- }
61
-
62
- if (index < names.length) {
63
- isDiff = true;
64
-
65
- this.segmentCache = {};
66
- names.forEach(s => {
67
- this.addToSegment(s);
68
- });
69
- }
70
- }
33
+ setChangeNumber(name?: string, changeNumber?: number) {
34
+ this.cn = changeNumber;
35
+ }
71
36
 
72
- return isDiff;
37
+ getChangeNumber() {
38
+ return this.cn || -1;
73
39
  }
74
40
 
75
41
  getRegisteredSegments() {
@@ -13,7 +13,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
13
13
  private splitsCache: Record<string, ISplit> = {};
14
14
  private ttCache: Record<string, number> = {};
15
15
  private changeNumber: number = -1;
16
- private splitsWithSegmentsCount: number = 0;
16
+ private segmentsCount: number = 0;
17
17
  private flagSetsCache: Record<string, ISet<string>> = {};
18
18
 
19
19
  constructor(splitFiltersValidation?: ISplitFiltersValidation) {
@@ -25,7 +25,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
25
25
  this.splitsCache = {};
26
26
  this.ttCache = {};
27
27
  this.changeNumber = -1;
28
- this.splitsWithSegmentsCount = 0;
28
+ this.segmentsCount = 0;
29
29
  }
30
30
 
31
31
  addSplit(name: string, split: ISplit): boolean {
@@ -38,9 +38,8 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
38
38
 
39
39
  this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
40
40
 
41
- if (usesSegments(previousSplit)) { // Substract from segments count for the previous version of this Split.
42
- this.splitsWithSegmentsCount--;
43
- }
41
+ // Subtract from segments count for the previous version of this Split
42
+ if (usesSegments(previousSplit)) this.segmentsCount--;
44
43
  }
45
44
 
46
45
  if (split) {
@@ -52,7 +51,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
52
51
  this.addToFlagSets(split);
53
52
 
54
53
  // Add to segments count for the new version of the Split
55
- if (usesSegments(split)) this.splitsWithSegmentsCount++;
54
+ if (usesSegments(split)) this.segmentsCount++;
56
55
 
57
56
  return true;
58
57
  } else {
@@ -72,7 +71,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
72
71
  this.removeFromFlagSets(split.name, split.sets);
73
72
 
74
73
  // Update the segments count.
75
- if (usesSegments(split)) this.splitsWithSegmentsCount--;
74
+ if (usesSegments(split)) this.segmentsCount--;
76
75
 
77
76
  return true;
78
77
  } else {
@@ -102,7 +101,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
102
101
  }
103
102
 
104
103
  usesSegments(): boolean {
105
- return this.getChangeNumber() === -1 || this.splitsWithSegmentsCount > 0;
104
+ return this.getChangeNumber() === -1 || this.segmentsCount > 0;
106
105
  }
107
106
 
108
107
  getNamesByFlagSets(flagSets: string[]): ISet<string>[] {
@@ -1,4 +1,4 @@
1
- import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../../sync/submitters/types';
1
+ import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies, TelemetryUsageStatsPayload, UpdatesFromSSEEnum, UpdatesFromSSE } 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) { }
28
+ constructor(private splits?: ISplitsCacheSync, private segments?: ISegmentsCacheSync, private largeSegments?: ISegmentsCacheSync) { }
29
29
 
30
30
  // isEmpty flag
31
31
  private e = true;
@@ -51,6 +51,8 @@ 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
+ lsC: this.largeSegments && this.largeSegments.getRegisteredSegments().length,
55
+ lskC: this.largeSegments && this.largeSegments.getKeysCount(),
54
56
  sL: this.getSessionLength(),
55
57
  eQ: this.getEventStats(QUEUED),
56
58
  eD: this.getEventStats(DROPPED),
@@ -245,22 +247,16 @@ export class TelemetryCacheInMemory implements ITelemetryCacheSync {
245
247
  this.e = false;
246
248
  }
247
249
 
248
- private updatesFromSSE = {
249
- sp: 0,
250
- ms: 0
251
- };
250
+ private updatesFromSSE: UpdatesFromSSE = {};
252
251
 
253
252
  popUpdatesFromSSE() {
254
253
  const result = this.updatesFromSSE;
255
- this.updatesFromSSE = {
256
- sp: 0,
257
- ms: 0,
258
- };
254
+ this.updatesFromSSE = {};
259
255
  return result;
260
256
  }
261
257
 
262
258
  recordUpdatesFromSSE(type: UpdatesFromSSEEnum) {
263
- this.updatesFromSSE[type]++;
259
+ this.updatesFromSSE[type] = (this.updatesFromSSE[type] || 0) + 1;
264
260
  this.e = false;
265
261
  }
266
262
 
@@ -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 inmediatelly.
10
+ * @param connDelay delay in millis for `connect` resolve. If not provided, `connect` resolves immediately.
11
11
  */
12
12
  export function inMemoryWrapperFactory(connDelay?: number): IPluggableStorageWrapper & { _cache: Record<string, string | string[] | ISet<string>>, _setConnDelay(connDelay: number): void } {
13
13
 
@@ -1,4 +1,5 @@
1
- import { MaybeThenable, ISplit } from '../dtos/types';
1
+ import { MaybeThenable, ISplit, IMySegmentsResponse } from '../dtos/types';
2
+ import { MySegmentsData } from '../sync/polling/types';
2
3
  import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, MultiMethodExceptions, MultiMethodLatencies, MultiConfigs, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent, UniqueKeysPayloadCs, UniqueKeysPayloadSs, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../sync/submitters/types';
3
4
  import { SplitIO, ImpressionDTO, ISettings } from '../types';
4
5
  import { ISet } from '../utils/lang/sets';
@@ -204,7 +205,7 @@ export interface ISplitsCacheBase {
204
205
  getSplitNames(): MaybeThenable<string[]>,
205
206
  // should never reject or throw an exception. Instead return true by default, asssuming the TT might exist.
206
207
  trafficTypeExists(trafficType: string): MaybeThenable<boolean>,
207
- // only for Client-Side
208
+ // only for Client-Side. Returns true if the storage is not synchronized yet (getChangeNumber() === -1) or contains a FF using segments or large segments
208
209
  usesSegments(): MaybeThenable<boolean>,
209
210
  clear(): MaybeThenable<boolean | void>,
210
211
  // should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE.
@@ -218,7 +219,7 @@ export interface ISplitsCacheSync extends ISplitsCacheBase {
218
219
  removeSplits(names: string[]): boolean[],
219
220
  getSplit(name: string): ISplit | null,
220
221
  getSplits(names: string[]): Record<string, ISplit | null>,
221
- setChangeNumber(changeNumber: number): boolean,
222
+ setChangeNumber(changeNumber: number): boolean | void,
222
223
  getChangeNumber(): number,
223
224
  getAll(): ISplit[],
224
225
  getSplitNames(): string[],
@@ -268,9 +269,9 @@ export interface ISegmentsCacheSync extends ISegmentsCacheBase {
268
269
  registerSegments(names: string[]): boolean
269
270
  getRegisteredSegments(): string[]
270
271
  getKeysCount(): number // only used for telemetry
271
- setChangeNumber(name: string, changeNumber: number): boolean
272
- getChangeNumber(name: string): number
273
- resetSegments(names: string[]): boolean // only for Sync Client-Side
272
+ setChangeNumber(name: string, changeNumber: number): boolean | void
273
+ getChangeNumber(name?: string): number
274
+ resetSegments(segmentsData: MySegmentsData | IMySegmentsResponse): boolean // only for Sync Client-Side
274
275
  clear(): void
275
276
  }
276
277
 
@@ -477,7 +478,10 @@ export interface IStorageSync extends IStorageBase<
477
478
  IEventsCacheSync,
478
479
  ITelemetryCacheSync,
479
480
  IUniqueKeysCacheSync
480
- > { }
481
+ > {
482
+ // Defined in client-side
483
+ largeSegments?: ISegmentsCacheSync,
484
+ }
481
485
 
482
486
  export interface IStorageAsync extends IStorageBase<
483
487
  ISplitsCacheAsync,
@@ -1,27 +1,25 @@
1
- import { IFetchMySegments, IResponse } from '../../../services/types';
2
- import { IMySegmentsResponseItem } from '../../../dtos/types';
1
+ import { IFetchMemberships, IResponse } from '../../../services/types';
2
+ import { IMembershipsResponse } from '../../../dtos/types';
3
3
  import { IMySegmentsFetcher } from './types';
4
4
 
5
5
  /**
6
6
  * Factory of MySegments fetcher.
7
7
  * MySegments fetcher is a wrapper around `mySegments` API service that parses the response and handle errors.
8
8
  */
9
- export function mySegmentsFetcherFactory(fetchMySegments: IFetchMySegments): IMySegmentsFetcher {
9
+ export function mySegmentsFetcherFactory(fetchMemberships: IFetchMemberships): IMySegmentsFetcher {
10
10
 
11
11
  return function mySegmentsFetcher(
12
12
  userMatchingKey: string,
13
13
  noCache?: boolean,
14
- // Optional decorator for `fetchMySegments` promise, such as timeout or time tracker
14
+ till?: number,
15
+ // Optional decorator for `fetchMemberships` promise, such as timeout or time tracker
15
16
  decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
16
- ): Promise<string[]> {
17
+ ): Promise<IMembershipsResponse> {
17
18
 
18
- let mySegmentsPromise = fetchMySegments(userMatchingKey, noCache);
19
+ let mySegmentsPromise = fetchMemberships(userMatchingKey, noCache, till);
19
20
  if (decorator) mySegmentsPromise = decorator(mySegmentsPromise);
20
21
 
21
- // Extract segment names
22
- return mySegmentsPromise
23
- .then(resp => resp.json())
24
- .then(json => json.mySegments.map((segment: IMySegmentsResponseItem) => segment.name));
22
+ return mySegmentsPromise.then(resp => resp.json());
25
23
  };
26
24
 
27
25
  }
@@ -28,7 +28,7 @@ export function segmentChangesFetcherFactory(fetchSegmentChanges: IFetchSegmentC
28
28
  segmentName: string,
29
29
  noCache?: boolean,
30
30
  till?: number,
31
- // Optional decorator for `fetchMySegments` promise, such as timeout or time tracker
31
+ // Optional decorator for `fetchSegmentChanges` promise, such as timeout or time tracker
32
32
  decorator?: (promise: Promise<ISegmentChangesResponse[]>) => Promise<ISegmentChangesResponse[]>
33
33
  ): Promise<ISegmentChangesResponse[]> {
34
34
 
@@ -1,4 +1,4 @@
1
- import { ISplitChangesResponse, ISegmentChangesResponse } from '../../../dtos/types';
1
+ import { ISplitChangesResponse, ISegmentChangesResponse, IMembershipsResponse } from '../../../dtos/types';
2
2
  import { IResponse } from '../../../services/types';
3
3
 
4
4
  export type ISplitChangesFetcher = (
@@ -19,5 +19,6 @@ export type ISegmentChangesFetcher = (
19
19
  export type IMySegmentsFetcher = (
20
20
  userMatchingKey: string,
21
21
  noCache?: boolean,
22
+ till?: number,
22
23
  decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
23
- ) => Promise<string[]>
24
+ ) => Promise<IMembershipsResponse>
@@ -29,13 +29,13 @@ export function pollingManagerCSFactory(
29
29
  const mySegmentsSyncTask = add(matchingKey, readiness, storage);
30
30
 
31
31
  function startMySegmentsSyncTasks() {
32
- forOwn(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
32
+ forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask) => {
33
33
  mySegmentsSyncTask.start();
34
34
  });
35
35
  }
36
36
 
37
37
  function stopMySegmentsSyncTasks() {
38
- forOwn(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
38
+ forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask) => {
39
39
  if (mySegmentsSyncTask.isRunning()) mySegmentsSyncTask.stop();
40
40
  });
41
41
  }
@@ -55,7 +55,7 @@ export function pollingManagerCSFactory(
55
55
  });
56
56
 
57
57
  function add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync) {
58
- const mySegmentsSyncTask = mySegmentsSyncTaskFactory(splitApi.fetchMySegments, storage, readiness, settings, matchingKey);
58
+ const mySegmentsSyncTask = mySegmentsSyncTaskFactory(splitApi.fetchMemberships, storage, readiness, settings, matchingKey);
59
59
 
60
60
  // smart ready
61
61
  function smartReady() {
@@ -94,7 +94,7 @@ export function pollingManagerCSFactory(
94
94
  // fetch splits and segments
95
95
  syncAll() {
96
96
  const promises = [splitsSyncTask.execute()];
97
- forOwn(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
97
+ forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask) => {
98
98
  promises.push(mySegmentsSyncTask.execute());
99
99
  });
100
100
  return Promise.all(promises);
@@ -2,7 +2,7 @@ import { IStorageSync } from '../../../storages/types';
2
2
  import { IReadinessManager } from '../../../readiness/types';
3
3
  import { syncTaskFactory } from '../../syncTask';
4
4
  import { IMySegmentsSyncTask } from '../types';
5
- import { IFetchMySegments } from '../../../services/types';
5
+ import { IFetchMemberships } from '../../../services/types';
6
6
  import { mySegmentsFetcherFactory } from '../fetchers/mySegmentsFetcher';
7
7
  import { ISettings } from '../../../types';
8
8
  import { mySegmentsUpdaterFactory } from '../updaters/mySegmentsUpdater';
@@ -11,7 +11,7 @@ import { mySegmentsUpdaterFactory } from '../updaters/mySegmentsUpdater';
11
11
  * Creates a sync task that periodically executes a `mySegmentsUpdater` task
12
12
  */
13
13
  export function mySegmentsSyncTaskFactory(
14
- fetchMySegments: IFetchMySegments,
14
+ fetchMemberships: IFetchMemberships,
15
15
  storage: IStorageSync,
16
16
  readiness: IReadinessManager,
17
17
  settings: ISettings,
@@ -21,9 +21,8 @@ export function mySegmentsSyncTaskFactory(
21
21
  settings.log,
22
22
  mySegmentsUpdaterFactory(
23
23
  settings.log,
24
- mySegmentsFetcherFactory(fetchMySegments),
25
- storage.splits,
26
- storage.segments,
24
+ mySegmentsFetcherFactory(fetchMemberships),
25
+ storage,
27
26
  readiness.segments,
28
27
  settings.startup.requestTimeoutBeforeReady,
29
28
  settings.startup.retriesOnFailureBeforeReady,
@@ -1,20 +1,21 @@
1
1
  import { ISplit } from '../../dtos/types';
2
2
  import { IReadinessManager } from '../../readiness/types';
3
3
  import { IStorageSync } from '../../storages/types';
4
+ import { MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../streaming/types';
4
5
  import { ITask, ISyncTask } from '../types';
5
6
 
6
7
  export interface ISplitsSyncTask extends ISyncTask<[noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }], boolean> { }
7
8
 
8
9
  export interface ISegmentsSyncTask extends ISyncTask<[fetchOnlyNew?: boolean, segmentName?: string, noCache?: boolean, till?: number], boolean> { }
9
10
 
10
- export type MySegmentsData = string[] | {
11
- /* segment name */
12
- name: string,
13
- /* action: `true` for add, and `false` for delete */
14
- add: boolean
11
+ export type MySegmentsData = {
12
+ type: MEMBERSHIPS_MS_UPDATE | MEMBERSHIPS_LS_UPDATE
13
+ cn: number
14
+ added: string[]
15
+ removed: string[]
15
16
  }
16
17
 
17
- export interface IMySegmentsSyncTask extends ISyncTask<[segmentsData?: MySegmentsData, noCache?: boolean], boolean> { }
18
+ export interface IMySegmentsSyncTask extends ISyncTask<[segmentsData?: MySegmentsData, noCache?: boolean, till?: number], boolean> { }
18
19
 
19
20
  export interface IPollingManager extends ITask {
20
21
  syncAll(): Promise<any>
@@ -1,13 +1,15 @@
1
1
  import { IMySegmentsFetcher } from '../fetchers/types';
2
- import { ISegmentsCacheSync, ISplitsCacheSync } from '../../../storages/types';
2
+ import { IStorageSync } from '../../../storages/types';
3
3
  import { ISegmentsEventEmitter } from '../../../readiness/types';
4
4
  import { timeout } from '../../../utils/promise/timeout';
5
5
  import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
6
6
  import { ILogger } from '../../../logger/types';
7
7
  import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants';
8
8
  import { MySegmentsData } from '../types';
9
+ import { IMembershipsResponse } from '../../../dtos/types';
10
+ import { MEMBERSHIPS_LS_UPDATE } from '../../streaming/constants';
9
11
 
10
- type IMySegmentsUpdater = (segmentList?: string[], noCache?: boolean) => Promise<boolean>
12
+ type IMySegmentsUpdater = (segmentsData?: MySegmentsData, noCache?: boolean, till?: number) => Promise<boolean>
11
13
 
12
14
  /**
13
15
  * factory of MySegments updater, a task that:
@@ -18,14 +20,14 @@ type IMySegmentsUpdater = (segmentList?: string[], noCache?: boolean) => Promise
18
20
  export function mySegmentsUpdaterFactory(
19
21
  log: ILogger,
20
22
  mySegmentsFetcher: IMySegmentsFetcher,
21
- splitsCache: ISplitsCacheSync,
22
- mySegmentsCache: ISegmentsCacheSync,
23
+ storage: IStorageSync,
23
24
  segmentsEventEmitter: ISegmentsEventEmitter,
24
25
  requestTimeoutBeforeReady: number,
25
26
  retriesOnFailureBeforeReady: number,
26
27
  matchingKey: string
27
28
  ): IMySegmentsUpdater {
28
29
 
30
+ const { splits, segments, largeSegments } = storage;
29
31
  let readyOnAlreadyExistentState = true;
30
32
  let startingUp = true;
31
33
 
@@ -36,37 +38,31 @@ export function mySegmentsUpdaterFactory(
36
38
  }
37
39
 
38
40
  // @TODO if allowing pluggable storages, handle async execution
39
- function updateSegments(segmentsData: MySegmentsData) {
41
+ function updateSegments(segmentsData: IMembershipsResponse | MySegmentsData) {
40
42
 
41
43
  let shouldNotifyUpdate;
42
- if (Array.isArray(segmentsData)) {
43
- // Update the list of segment names available
44
- shouldNotifyUpdate = mySegmentsCache.resetSegments(segmentsData);
44
+ if ((segmentsData as MySegmentsData).type !== undefined) {
45
+ shouldNotifyUpdate = (segmentsData as MySegmentsData).type === MEMBERSHIPS_LS_UPDATE ?
46
+ largeSegments!.resetSegments(segmentsData as MySegmentsData) :
47
+ segments.resetSegments(segmentsData as MySegmentsData);
45
48
  } else {
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
- }
49
+ shouldNotifyUpdate = segments.resetSegments((segmentsData as IMembershipsResponse).ms || {});
50
+ shouldNotifyUpdate = largeSegments!.resetSegments((segmentsData as IMembershipsResponse).ls || {}) || shouldNotifyUpdate;
55
51
  }
56
52
 
57
53
  // Notify update if required
58
- if (splitsCache.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
54
+ if (splits.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
59
55
  readyOnAlreadyExistentState = false;
60
56
  segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
61
57
  }
62
58
  }
63
59
 
64
- function _mySegmentsUpdater(retry: number, segmentsData?: MySegmentsData, noCache?: boolean): Promise<boolean> {
60
+ function _mySegmentsUpdater(retry: number, segmentsData?: MySegmentsData, noCache?: boolean, till?: number): Promise<boolean> {
65
61
  const updaterPromise: Promise<boolean> = segmentsData ?
66
62
  // If segmentsData is provided, there is no need to fetch mySegments
67
63
  new Promise((res) => { updateSegments(segmentsData); res(true); }) :
68
64
  // If not provided, fetch mySegments
69
- mySegmentsFetcher(matchingKey, noCache, _promiseDecorator).then(segments => {
65
+ mySegmentsFetcher(matchingKey, noCache, till, _promiseDecorator).then(segments => {
70
66
  // Only when we have downloaded segments completely, we should not keep retrying anymore
71
67
  startingUp = false;
72
68
 
@@ -96,9 +92,10 @@ export function mySegmentsUpdaterFactory(
96
92
  * (2) an object with a segment name and action (true: add, or false: delete) to update the storage,
97
93
  * (3) or `undefined`, for which the updater will fetch mySegments in order to sync the storage.
98
94
  * @param {boolean | undefined} noCache true to revalidate data to fetch
95
+ * @param {boolean | undefined} till query param to bypass CDN requests
99
96
  */
100
- return function mySegmentsUpdater(segmentsData?: MySegmentsData, noCache?: boolean) {
101
- return _mySegmentsUpdater(0, segmentsData, noCache);
97
+ return function mySegmentsUpdater(segmentsData?: MySegmentsData, noCache?: boolean, till?: number) {
98
+ return _mySegmentsUpdater(0, segmentsData, noCache, till);
102
99
  };
103
100
 
104
101
  }
@@ -14,7 +14,7 @@ export function authenticateFactory(fetchAuth: IFetchAuth): IAuthenticate {
14
14
 
15
15
  /**
16
16
  * Run authentication requests to Auth Server, and returns a promise that resolves with the decoded JTW token.
17
- * @param {string[] | undefined} userKeys set of user Keys to track MY_SEGMENTS_CHANGES. It is undefined for server-side API.
17
+ * @param {string[] | undefined} userKeys set of user Keys to track membership updates. It is undefined for server-side API.
18
18
  */
19
19
  return function authenticate(userKeys?: string[]): Promise<IAuthToken> {
20
20
  return fetchAuth(userKeys)
@@ -71,12 +71,10 @@ export class SSEClient implements ISSEClient {
71
71
  open(authToken: IAuthTokenPushEnabled) {
72
72
  this.close(); // it closes connection if previously opened
73
73
 
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(',');
74
+ const channelsQueryParam = Object.keys(authToken.channels).map((channel) => {
75
+ const params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
76
+ return encodeURIComponent(params + channel);
77
+ }).join(',');
80
78
  const url = `${this.settings.urls.streaming}/sse?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${ABLY_API_VERSION}&heartbeats=true`; // same results using `&heartbeats=false`
81
79
  const isServerSide = !this.settings.core.key;
82
80
 
@@ -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 } from '../constants';
3
+ import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE } from '../constants';
4
4
  import { IPushEventEmitter } from '../types';
5
5
  import { ISseEventHandler } from '../SSEClient/types';
6
6
  import { INotificationError, INotificationMessage } from './types';
@@ -74,21 +74,18 @@ export function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventEmitter,
74
74
  const { parsedData, data, channel, timestamp } = messageWithParsedData;
75
75
  log.debug(STREAMING_NEW_MESSAGE, [data]);
76
76
 
77
- // we only handle update events if streaming is up.
78
- if (!notificationKeeper.isStreamingUp() && [OCCUPANCY, CONTROL].indexOf(parsedData.type) === -1)
79
- return;
77
+ // we only handle update events if streaming is up
78
+ if (!notificationKeeper.isStreamingUp() && [OCCUPANCY, CONTROL].indexOf(parsedData.type) === -1) return;
80
79
 
81
80
  switch (parsedData.type) {
82
81
  /* update events */
83
82
  case SPLIT_UPDATE:
84
83
  case SEGMENT_UPDATE:
85
- case MY_SEGMENTS_UPDATE_V2:
84
+ case MEMBERSHIPS_MS_UPDATE:
85
+ case MEMBERSHIPS_LS_UPDATE:
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;
92
89
 
93
90
  /* occupancy & control events, handled by NotificationManagerKeeper */
94
91
  case OCCUPANCY:
@@ -1,12 +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 } from '../types';
3
-
4
- export interface IMySegmentsUpdateData {
5
- type: MY_SEGMENTS_UPDATE,
6
- changeNumber: number,
7
- includesPayload: boolean,
8
- segmentList?: string[]
9
- }
2
+ import { SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../types';
10
3
 
11
4
  export enum Compression {
12
5
  None = 0,
@@ -26,15 +19,22 @@ export interface KeyList {
26
19
  r?: string[], // decimal hash64 of user keys
27
20
  }
28
21
 
29
- export interface IMySegmentsUpdateV2Data {
30
- type: MY_SEGMENTS_UPDATE_V2,
31
- changeNumber: number,
32
- segmentName: string,
33
- c: Compression,
34
- d: string,
22
+ interface IMembershipUpdateData<T extends string> {
23
+ type: T,
24
+ cn: number,
25
+ n?: string[],
26
+ c?: Compression,
27
+ d?: string,
35
28
  u: UpdateStrategy,
29
+ i?: number, // time interval in millis
30
+ h?: number, // hash function
31
+ s?: number, // seed for hash function
36
32
  }
37
33
 
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 = IMySegmentsUpdateData | IMySegmentsUpdateV2Data | ISegmentUpdateData | ISplitUpdateData | ISplitKillData | IControlData | IOccupancyData
71
+ export type INotificationData = IMembershipMSUpdateData | IMembershipLSUpdateData | 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 }