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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/CHANGES.txt +28 -29
  2. package/LICENSE +1 -1
  3. package/README.md +4 -3
  4. package/cjs/consent/sdkUserConsent.js +4 -2
  5. package/cjs/evaluator/matchers/index.js +1 -3
  6. package/cjs/evaluator/matchers/matcherTypes.js +0 -1
  7. package/cjs/evaluator/matchers/segment.js +0 -6
  8. package/cjs/evaluator/matchersTransform/index.js +1 -4
  9. package/cjs/evaluator/matchersTransform/segment.js +1 -3
  10. package/cjs/logger/constants.js +2 -2
  11. package/cjs/logger/messages/info.js +1 -1
  12. package/cjs/logger/messages/warn.js +1 -1
  13. package/cjs/readiness/readinessManager.js +8 -18
  14. package/cjs/readiness/sdkReadinessManager.js +6 -5
  15. package/cjs/sdkClient/sdkClient.js +5 -5
  16. package/cjs/sdkClient/sdkClientMethod.js +1 -3
  17. package/cjs/sdkClient/sdkClientMethodCS.js +15 -9
  18. package/cjs/sdkClient/sdkClientMethodCSWithTT.js +15 -9
  19. package/cjs/sdkFactory/index.js +10 -32
  20. package/cjs/services/decorateHeaders.js +6 -1
  21. package/cjs/services/splitApi.js +5 -5
  22. package/cjs/services/splitHttpClient.js +5 -2
  23. package/cjs/storages/AbstractSegmentsCacheSync.js +33 -0
  24. package/cjs/storages/AbstractSplitsCacheSync.js +1 -2
  25. package/cjs/storages/KeyBuilderCS.js +5 -23
  26. package/cjs/storages/dataLoader.js +1 -1
  27. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +56 -33
  28. package/cjs/storages/inLocalStorage/index.js +2 -6
  29. package/cjs/storages/inMemory/InMemoryStorageCS.js +1 -6
  30. package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +44 -13
  31. package/cjs/storages/inMemory/SegmentsCacheInMemory.js +28 -14
  32. package/cjs/storages/inMemory/SplitsCacheInMemory.js +9 -8
  33. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +10 -7
  34. package/cjs/storages/inRedis/SegmentsCacheInRedis.js +21 -15
  35. package/cjs/storages/inRedis/index.js +11 -5
  36. package/cjs/storages/pluggable/SegmentsCachePluggable.js +34 -13
  37. package/cjs/storages/pluggable/inMemoryWrapper.js +1 -1
  38. package/cjs/sync/offline/syncManagerOffline.js +11 -18
  39. package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +8 -5
  40. package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
  41. package/cjs/sync/polling/pollingManagerCS.js +1 -1
  42. package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  43. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +21 -15
  44. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +28 -12
  45. package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -1
  46. package/cjs/sync/streaming/AuthClient/index.js +1 -1
  47. package/cjs/sync/streaming/SSEHandler/index.js +5 -3
  48. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +48 -107
  49. package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
  50. package/cjs/sync/streaming/constants.js +3 -3
  51. package/cjs/sync/streaming/parseUtils.js +9 -14
  52. package/cjs/sync/streaming/pushManager.js +67 -69
  53. package/cjs/sync/syncManagerOnline.js +21 -20
  54. package/cjs/sync/syncTask.js +2 -2
  55. package/cjs/trackers/eventTracker.js +10 -12
  56. package/cjs/trackers/impressionsTracker.js +14 -16
  57. package/cjs/trackers/uniqueKeysTracker.js +3 -5
  58. package/cjs/utils/constants/index.js +4 -5
  59. package/cjs/utils/settingsValidation/index.js +1 -2
  60. package/esm/consent/sdkUserConsent.js +4 -2
  61. package/esm/evaluator/matchers/index.js +1 -3
  62. package/esm/evaluator/matchers/matcherTypes.js +0 -1
  63. package/esm/evaluator/matchers/segment.js +0 -6
  64. package/esm/evaluator/matchersTransform/index.js +1 -4
  65. package/esm/evaluator/matchersTransform/segment.js +1 -3
  66. package/esm/logger/constants.js +1 -1
  67. package/esm/logger/messages/info.js +1 -1
  68. package/esm/logger/messages/warn.js +1 -1
  69. package/esm/readiness/readinessManager.js +8 -18
  70. package/esm/readiness/sdkReadinessManager.js +6 -5
  71. package/esm/sdkClient/sdkClient.js +5 -5
  72. package/esm/sdkClient/sdkClientMethod.js +1 -3
  73. package/esm/sdkClient/sdkClientMethodCS.js +13 -7
  74. package/esm/sdkClient/sdkClientMethodCSWithTT.js +13 -7
  75. package/esm/sdkFactory/index.js +10 -32
  76. package/esm/services/decorateHeaders.js +4 -0
  77. package/esm/services/splitApi.js +6 -6
  78. package/esm/services/splitHttpClient.js +6 -3
  79. package/esm/storages/AbstractSegmentsCacheSync.js +30 -0
  80. package/esm/storages/AbstractSplitsCacheSync.js +2 -3
  81. package/esm/storages/KeyBuilderCS.js +4 -21
  82. package/esm/storages/dataLoader.js +1 -1
  83. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +56 -33
  84. package/esm/storages/inLocalStorage/index.js +3 -7
  85. package/esm/storages/inMemory/InMemoryStorageCS.js +1 -6
  86. package/esm/storages/inMemory/MySegmentsCacheInMemory.js +44 -13
  87. package/esm/storages/inMemory/SegmentsCacheInMemory.js +28 -14
  88. package/esm/storages/inMemory/SplitsCacheInMemory.js +9 -8
  89. package/esm/storages/inMemory/TelemetryCacheInMemory.js +10 -7
  90. package/esm/storages/inRedis/SegmentsCacheInRedis.js +21 -15
  91. package/esm/storages/inRedis/index.js +11 -5
  92. package/esm/storages/pluggable/SegmentsCachePluggable.js +34 -13
  93. package/esm/storages/pluggable/inMemoryWrapper.js +1 -1
  94. package/esm/sync/offline/syncManagerOffline.js +11 -18
  95. package/esm/sync/polling/fetchers/mySegmentsFetcher.js +8 -5
  96. package/esm/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
  97. package/esm/sync/polling/pollingManagerCS.js +1 -1
  98. package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  99. package/esm/sync/polling/updaters/mySegmentsUpdater.js +21 -15
  100. package/esm/sync/polling/updaters/segmentChangesUpdater.js +28 -12
  101. package/esm/sync/polling/updaters/splitChangesUpdater.js +1 -1
  102. package/esm/sync/streaming/AuthClient/index.js +1 -1
  103. package/esm/sync/streaming/SSEHandler/index.js +6 -4
  104. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +49 -108
  105. package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
  106. package/esm/sync/streaming/constants.js +2 -2
  107. package/esm/sync/streaming/parseUtils.js +8 -12
  108. package/esm/sync/streaming/pushManager.js +70 -72
  109. package/esm/sync/syncManagerOnline.js +21 -20
  110. package/esm/sync/syncTask.js +2 -2
  111. package/esm/trackers/eventTracker.js +10 -12
  112. package/esm/trackers/impressionsTracker.js +14 -16
  113. package/esm/trackers/uniqueKeysTracker.js +3 -5
  114. package/esm/utils/constants/index.js +2 -3
  115. package/esm/utils/settingsValidation/index.js +1 -2
  116. package/package.json +1 -1
  117. package/src/consent/sdkUserConsent.ts +3 -2
  118. package/src/dtos/types.ts +7 -21
  119. package/src/evaluator/matchers/index.ts +0 -2
  120. package/src/evaluator/matchers/matcherTypes.ts +0 -1
  121. package/src/evaluator/matchers/segment.ts +0 -7
  122. package/src/evaluator/matchersTransform/index.ts +1 -4
  123. package/src/evaluator/matchersTransform/segment.ts +3 -5
  124. package/src/logger/constants.ts +1 -1
  125. package/src/logger/messages/info.ts +1 -1
  126. package/src/logger/messages/warn.ts +1 -1
  127. package/src/readiness/readinessManager.ts +8 -19
  128. package/src/readiness/sdkReadinessManager.ts +7 -7
  129. package/src/readiness/types.ts +2 -5
  130. package/src/sdkClient/sdkClient.ts +5 -5
  131. package/src/sdkClient/sdkClientMethod.ts +1 -4
  132. package/src/sdkClient/sdkClientMethodCS.ts +15 -7
  133. package/src/sdkClient/sdkClientMethodCSWithTT.ts +15 -7
  134. package/src/sdkFactory/index.ts +12 -35
  135. package/src/sdkFactory/types.ts +1 -4
  136. package/src/services/decorateHeaders.ts +5 -0
  137. package/src/services/splitApi.ts +7 -7
  138. package/src/services/splitHttpClient.ts +7 -4
  139. package/src/services/types.ts +2 -2
  140. package/src/storages/AbstractSegmentsCacheSync.ts +68 -0
  141. package/src/storages/AbstractSplitsCacheSync.ts +3 -4
  142. package/src/storages/KeyBuilderCS.ts +5 -34
  143. package/src/storages/dataLoader.ts +1 -1
  144. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +63 -33
  145. package/src/storages/inLocalStorage/index.ts +4 -8
  146. package/src/storages/inMemory/InMemoryStorageCS.ts +1 -6
  147. package/src/storages/inMemory/MySegmentsCacheInMemory.ts +47 -13
  148. package/src/storages/inMemory/SegmentsCacheInMemory.ts +27 -13
  149. package/src/storages/inMemory/SplitsCacheInMemory.ts +9 -7
  150. package/src/storages/inMemory/TelemetryCacheInMemory.ts +11 -7
  151. package/src/storages/inRedis/SegmentsCacheInRedis.ts +24 -15
  152. package/src/storages/inRedis/index.ts +12 -6
  153. package/src/storages/pluggable/SegmentsCachePluggable.ts +37 -13
  154. package/src/storages/pluggable/inMemoryWrapper.ts +1 -1
  155. package/src/storages/types.ts +17 -15
  156. package/src/sync/offline/syncManagerOffline.ts +13 -21
  157. package/src/sync/polling/fetchers/mySegmentsFetcher.ts +10 -8
  158. package/src/sync/polling/fetchers/segmentChangesFetcher.ts +1 -1
  159. package/src/sync/polling/fetchers/types.ts +2 -3
  160. package/src/sync/polling/pollingManagerCS.ts +4 -4
  161. package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +5 -4
  162. package/src/sync/polling/types.ts +6 -7
  163. package/src/sync/polling/updaters/mySegmentsUpdater.ts +22 -19
  164. package/src/sync/polling/updaters/segmentChangesUpdater.ts +29 -13
  165. package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -1
  166. package/src/sync/streaming/AuthClient/index.ts +1 -1
  167. package/src/sync/streaming/SSEClient/index.ts +6 -4
  168. package/src/sync/streaming/SSEHandler/index.ts +8 -5
  169. package/src/sync/streaming/SSEHandler/types.ts +15 -15
  170. package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +49 -116
  171. package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +4 -4
  172. package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +1 -1
  173. package/src/sync/streaming/UpdateWorkers/types.ts +2 -2
  174. package/src/sync/streaming/constants.ts +2 -2
  175. package/src/sync/streaming/parseUtils.ts +11 -19
  176. package/src/sync/streaming/pushManager.ts +72 -73
  177. package/src/sync/streaming/types.ts +10 -10
  178. package/src/sync/submitters/types.ts +5 -8
  179. package/src/sync/syncManagerOnline.ts +17 -17
  180. package/src/sync/syncTask.ts +2 -2
  181. package/src/sync/types.ts +1 -1
  182. package/src/trackers/eventTracker.ts +8 -11
  183. package/src/trackers/impressionsTracker.ts +10 -13
  184. package/src/trackers/types.ts +0 -1
  185. package/src/trackers/uniqueKeysTracker.ts +4 -6
  186. package/src/types.ts +1 -7
  187. package/src/utils/constants/index.ts +2 -3
  188. package/src/utils/settingsValidation/index.ts +2 -3
  189. package/src/utils/settingsValidation/types.ts +1 -1
  190. package/types/dtos/types.d.ts +7 -18
  191. package/types/evaluator/matchersTransform/segment.d.ts +2 -2
  192. package/types/logger/constants.d.ts +1 -1
  193. package/types/readiness/readinessManager.d.ts +2 -2
  194. package/types/readiness/sdkReadinessManager.d.ts +3 -2
  195. package/types/readiness/types.d.ts +2 -5
  196. package/types/sdkClient/sdkClientMethod.d.ts +1 -1
  197. package/types/sdkFactory/types.d.ts +1 -3
  198. package/types/services/decorateHeaders.d.ts +1 -0
  199. package/types/services/splitApi.d.ts +1 -1
  200. package/types/services/splitHttpClient.d.ts +1 -1
  201. package/types/services/types.d.ts +2 -2
  202. package/types/storages/AbstractSegmentsCacheSync.d.ts +11 -9
  203. package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
  204. package/types/storages/KeyBuilderCS.d.ts +2 -9
  205. package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +18 -8
  206. package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +13 -7
  207. package/types/storages/inMemory/SegmentsCacheInMemory.d.ts +8 -6
  208. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +2 -1
  209. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -4
  210. package/types/storages/inRedis/SegmentsCacheInRedis.d.ts +4 -7
  211. package/types/storages/inRedis/index.d.ts +1 -1
  212. package/types/storages/pluggable/SegmentsCachePluggable.d.ts +17 -5
  213. package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -1
  214. package/types/storages/types.d.ts +15 -11
  215. package/types/sync/polling/fetchers/mySegmentsFetcher.d.ts +2 -2
  216. package/types/sync/polling/fetchers/types.d.ts +2 -2
  217. package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +2 -2
  218. package/types/sync/polling/types.d.ts +4 -7
  219. package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +3 -4
  220. package/types/sync/streaming/SSEHandler/types.d.ts +14 -16
  221. package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -4
  222. package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +1 -2
  223. package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +2 -3
  224. package/types/sync/streaming/UpdateWorkers/types.d.ts +2 -2
  225. package/types/sync/streaming/constants.d.ts +2 -2
  226. package/types/sync/streaming/parseUtils.d.ts +5 -4
  227. package/types/sync/streaming/types.d.ts +8 -8
  228. package/types/sync/submitters/types.d.ts +4 -7
  229. package/types/sync/types.d.ts +1 -1
  230. package/types/trackers/eventTracker.d.ts +1 -1
  231. package/types/trackers/impressionsTracker.d.ts +1 -1
  232. package/types/trackers/types.d.ts +0 -1
  233. package/types/types.d.ts +1 -7
  234. package/types/utils/constants/index.d.ts +2 -3
  235. package/types/utils/settingsValidation/types.d.ts +1 -1
  236. package/cjs/evaluator/matchers/large_segment.js +0 -16
  237. package/cjs/sdkClient/identity.js +0 -7
  238. package/cjs/storages/AbstractMySegmentsCacheSync.js +0 -60
  239. package/esm/evaluator/matchers/large_segment.js +0 -12
  240. package/esm/sdkClient/identity.js +0 -3
  241. package/esm/storages/AbstractMySegmentsCacheSync.js +0 -57
  242. package/src/evaluator/matchers/large_segment.ts +0 -18
  243. package/src/sdkClient/identity.ts +0 -5
  244. package/src/storages/AbstractMySegmentsCacheSync.ts +0 -94
  245. package/types/evaluator/matchers/large_segment.d.ts +0 -5
  246. package/types/evaluator/matchers/sember_inlist.d.ts +0 -3
  247. package/types/evaluator/matchersTransform/set.d.ts +0 -5
  248. package/types/evaluator/matchersTransform/string.d.ts +0 -7
  249. package/types/sdkClient/identity.d.ts +0 -2
  250. package/types/storages/AbstractMySegmentsCacheSync.d.ts +0 -39
  251. package/types/storages/AbstractSplitsCache.d.ts +0 -46
  252. package/types/sync/streaming/mySegmentsV2utils.d.ts +0 -27
  253. package/types/sync/streaming/pushManagerCS_Spec1_3.d.ts +0 -9
  254. package/types/sync/streaming/pushManager_Spec1_3.d.ts +0 -9
  255. package/types/trackers/impressionObserver/utils.d.ts +0 -5
  256. package/types/utils/inputValidation/sdkKey.d.ts +0 -7
  257. package/types/utils/inputValidation/splitExistance.d.ts +0 -7
  258. package/types/utils/inputValidation/trafficTypeExistance.d.ts +0 -9
  259. package/types/utils/redis/RedisMock.d.ts +0 -4
  260. package/types/utils/settingsValidation/logger/globalLogLevel.d.ts +0 -8
  261. /package/types/utils/{semVer.d.ts → Semver.d.ts} +0 -0
@@ -17,19 +17,25 @@ export interface InRedisStorageOptions {
17
17
  options?: Record<string, any>
18
18
  }
19
19
 
20
+ let RD: typeof RedisAdapter | undefined;
21
+
22
+ try {
23
+ // Using `require` to prevent error when bundling or importing the SDK in a .mjs file, since ioredis is a CommonJS module.
24
+ // Redis storage is not supported with .mjs files.
25
+ RD = require('./RedisAdapter').RedisAdapter;
26
+ } catch (error) { /* empty */ }
27
+
20
28
  /**
21
- * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.
29
+ * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.js
22
30
  * @see {@link https://www.npmjs.com/package/ioredis}
23
31
  */
24
32
  export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsyncFactory {
25
33
 
26
- // Lazy loading to prevent error when bundling or importing the SDK in a .mjs file, since ioredis is a CommonJS module.
27
- // Redis storage is not supported with .mjs files.
28
- const RD = require('./RedisAdapter').RedisAdapter;
29
-
30
34
  const prefix = validatePrefix(options.prefix);
31
35
 
32
36
  function InRedisStorageFactory(params: IStorageFactoryParams): IStorageAsync {
37
+ if (!RD) throw new Error('The SDK Redis storage is unavailable. Make sure your runtime environment supports CommonJS (`require`) so the `ioredis` dependency can be imported.');
38
+
33
39
  const { onReadyCb, settings, settings: { log, sync: { impressionsMode } } } = params;
34
40
  const metadata = metadataBuilder(settings);
35
41
  const keys = new KeyBuilderSS(prefix, metadata);
@@ -38,7 +44,7 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
38
44
  const impressionCountsCache = impressionsMode !== DEBUG ? new ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient) : undefined;
39
45
  const uniqueKeysCache = impressionsMode === NONE ? new UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient) : undefined;
40
46
 
41
- // subscription to Redis connect event in order to emit SDK_READY event on consumer mode
47
+ // Subscription to Redis connect event in order to emit SDK_READY event on consumer mode
42
48
  redisClient.on('connect', () => {
43
49
  onReadyCb();
44
50
  if (impressionCountsCache) impressionCountsCache.start();
@@ -23,20 +23,33 @@ export class SegmentsCachePluggable implements ISegmentsCacheAsync {
23
23
  }
24
24
 
25
25
  /**
26
- * Update the given segment `name` with the lists of `addedKeys`, `removedKeys` and `changeNumber`.
27
- * The returned promise is resolved if the operation success, with `true` if the segment was updated (i.e., some key was added or removed),
28
- * or rejected if it fails (e.g., wrapper operation fails).
26
+ * Add a list of `segmentKeys` to the given segment `name`.
27
+ * The returned promise is resolved when the operation success
28
+ * or rejected if wrapper operation fails.
29
29
  */
30
- update(name: string, addedKeys: string[], removedKeys: string[], changeNumber: number) {
30
+ addToSegment(name: string, segmentKeys: string[]) {
31
31
  const segmentKey = this.keys.buildSegmentNameKey(name);
32
32
 
33
- return Promise.all<any>([
34
- addedKeys.length && this.wrapper.addItems(segmentKey, addedKeys),
35
- removedKeys.length && this.wrapper.removeItems(segmentKey, removedKeys),
36
- this.wrapper.set(this.keys.buildSegmentTillKey(name), changeNumber + '')
37
- ]).then(() => {
38
- return addedKeys.length > 0 || removedKeys.length > 0;
39
- });
33
+ if (segmentKeys.length) {
34
+ return this.wrapper.addItems(segmentKey, segmentKeys);
35
+ } else {
36
+ return Promise.resolve();
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Remove a list of `segmentKeys` from the given segment `name`.
42
+ * The returned promise is resolved when the operation success
43
+ * or rejected if wrapper operation fails.
44
+ */
45
+ removeFromSegment(name: string, segmentKeys: string[]) {
46
+ const segmentKey = this.keys.buildSegmentNameKey(name);
47
+
48
+ if (segmentKeys.length) {
49
+ return this.wrapper.removeItems(segmentKey, segmentKeys);
50
+ } else {
51
+ return Promise.resolve();
52
+ }
40
53
  }
41
54
 
42
55
  /**
@@ -47,6 +60,17 @@ export class SegmentsCachePluggable implements ISegmentsCacheAsync {
47
60
  return this.wrapper.itemContains(this.keys.buildSegmentNameKey(name), key);
48
61
  }
49
62
 
63
+ /**
64
+ * Set till number for the given segment `name`.
65
+ * The returned promise is resolved when the operation success,
66
+ * or rejected if it fails (e.g., wrapper operation fails).
67
+ */
68
+ setChangeNumber(name: string, changeNumber: number) {
69
+ return this.wrapper.set(
70
+ this.keys.buildSegmentTillKey(name), changeNumber + ''
71
+ );
72
+ }
73
+
50
74
  /**
51
75
  * Get till number or -1 if it's not defined.
52
76
  * The returned promise is resolved with the changeNumber or -1 if it doesn't exist or a wrapper operation fails.
@@ -56,10 +80,10 @@ export class SegmentsCachePluggable implements ISegmentsCacheAsync {
56
80
  return this.wrapper.get(this.keys.buildSegmentTillKey(name)).then((value: string | null) => {
57
81
  const i = parseInt(value as string, 10);
58
82
 
59
- return isNaNNumber(i) ? -1 : i;
83
+ return isNaNNumber(i) ? undefined : i;
60
84
  }).catch((e) => {
61
85
  this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e);
62
- return -1;
86
+ return undefined;
63
87
  });
64
88
  }
65
89
 
@@ -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
 
@@ -1,5 +1,4 @@
1
- import { MaybeThenable, ISplit, IMySegmentsResponse } from '../dtos/types';
2
- import { MySegmentsData } from '../sync/polling/types';
1
+ import { MaybeThenable, ISplit } from '../dtos/types';
3
2
  import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, MultiMethodExceptions, MultiMethodLatencies, MultiConfigs, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent, UniqueKeysPayloadCs, UniqueKeysPayloadSs, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../sync/submitters/types';
4
3
  import { SplitIO, ImpressionDTO, ISettings } from '../types';
5
4
  import { ISet } from '../utils/lang/sets';
@@ -205,7 +204,7 @@ export interface ISplitsCacheBase {
205
204
  getSplitNames(): MaybeThenable<string[]>,
206
205
  // should never reject or throw an exception. Instead return true by default, asssuming the TT might exist.
207
206
  trafficTypeExists(trafficType: string): MaybeThenable<boolean>,
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
207
+ // only for Client-Side
209
208
  usesSegments(): MaybeThenable<boolean>,
210
209
  clear(): MaybeThenable<boolean | void>,
211
210
  // should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE.
@@ -219,7 +218,7 @@ export interface ISplitsCacheSync extends ISplitsCacheBase {
219
218
  removeSplits(names: string[]): boolean[],
220
219
  getSplit(name: string): ISplit | null,
221
220
  getSplits(names: string[]): Record<string, ISplit | null>,
222
- setChangeNumber(changeNumber: number): boolean | void,
221
+ setChangeNumber(changeNumber: number): boolean,
223
222
  getChangeNumber(): number,
224
223
  getAll(): ISplit[],
225
224
  getSplitNames(): string[],
@@ -251,32 +250,38 @@ export interface ISplitsCacheAsync extends ISplitsCacheBase {
251
250
  /** Segments cache */
252
251
 
253
252
  export interface ISegmentsCacheBase {
253
+ addToSegment(name: string, segmentKeys: string[]): MaybeThenable<boolean | void> // different signature on Server and Client-Side
254
+ removeFromSegment(name: string, segmentKeys: string[]): MaybeThenable<boolean | void> // different signature on Server and Client-Side
254
255
  isInSegment(name: string, key?: string): MaybeThenable<boolean> // different signature on Server and Client-Side
255
256
  registerSegments(names: string[]): MaybeThenable<boolean | void> // only for Server-Side
256
257
  getRegisteredSegments(): MaybeThenable<string[]> // only for Server-Side
257
- getChangeNumber(name: string): MaybeThenable<number> // only for Server-Side
258
- update(name: string, addedKeys: string[], removedKeys: string[], changeNumber: number): MaybeThenable<boolean> // only for Server-Side
258
+ setChangeNumber(name: string, changeNumber: number): MaybeThenable<boolean | void> // only for Server-Side
259
+ getChangeNumber(name: string): MaybeThenable<number | undefined> // only for Server-Side
259
260
  clear(): MaybeThenable<boolean | void>
260
261
  }
261
262
 
262
263
  // Same API for both variants: SegmentsCache and MySegmentsCache (client-side API)
263
264
  export interface ISegmentsCacheSync extends ISegmentsCacheBase {
265
+ addToSegment(name: string, segmentKeys?: string[]): boolean
266
+ removeFromSegment(name: string, segmentKeys?: string[]): boolean
264
267
  isInSegment(name: string, key?: string): boolean
265
268
  registerSegments(names: string[]): boolean
266
269
  getRegisteredSegments(): string[]
267
270
  getKeysCount(): number // only used for telemetry
268
- getChangeNumber(name?: string): number
269
- update(name: string, addedKeys: string[], removedKeys: string[], changeNumber: number): boolean // only for Server-Side
270
- resetSegments(segmentsData: MySegmentsData | IMySegmentsResponse): boolean // only for Sync Client-Side
271
+ setChangeNumber(name: string, changeNumber: number): boolean
272
+ getChangeNumber(name: string): number | undefined
273
+ resetSegments(names: string[]): boolean // only for Sync Client-Side
271
274
  clear(): void
272
275
  }
273
276
 
274
277
  export interface ISegmentsCacheAsync extends ISegmentsCacheBase {
278
+ addToSegment(name: string, segmentKeys: string[]): Promise<boolean | void>
279
+ removeFromSegment(name: string, segmentKeys: string[]): Promise<boolean | void>
275
280
  isInSegment(name: string, key: string): Promise<boolean>
276
281
  registerSegments(names: string[]): Promise<boolean | void>
277
282
  getRegisteredSegments(): Promise<string[]>
278
- getChangeNumber(name: string): Promise<number>
279
- update(name: string, addedKeys: string[], removedKeys: string[], changeNumber: number): Promise<boolean>
283
+ setChangeNumber(name: string, changeNumber: number): Promise<boolean | void>
284
+ getChangeNumber(name: string): Promise<number | undefined>
280
285
  clear(): Promise<boolean | void>
281
286
  }
282
287
 
@@ -472,10 +477,7 @@ export interface IStorageSync extends IStorageBase<
472
477
  IEventsCacheSync,
473
478
  ITelemetryCacheSync,
474
479
  IUniqueKeysCacheSync
475
- > {
476
- // Defined in client-side
477
- largeSegments?: ISegmentsCacheSync,
478
- }
480
+ > { }
479
481
 
480
482
  export interface IStorageAsync extends IStorageBase<
481
483
  ISplitsCacheAsync,
@@ -1,4 +1,4 @@
1
- import { ISyncManagerCS } from '../types';
1
+ import { ISyncManager, ISyncManagerCS } from '../types';
2
2
  import { fromObjectSyncTaskFactory } from './syncTasks/fromObjectSyncTask';
3
3
  import { objectAssign } from '../../utils/lang/objectAssign';
4
4
  import { ISplitsParser } from './splitsParser/types';
@@ -29,34 +29,26 @@ export function syncManagerOfflineFactory(
29
29
  storage,
30
30
  }: ISdkFactoryContextSync): ISyncManagerCS {
31
31
 
32
- const mainSyncManager = fromObjectSyncTaskFactory(splitsParserFactory(), storage, readiness, settings);
33
- const mainStart = mainSyncManager.start;
34
- const sharedStarts: Array<() => void> = [];
35
-
36
32
  return objectAssign(
37
- mainSyncManager,
33
+ fromObjectSyncTaskFactory(splitsParserFactory(), storage, readiness, settings),
38
34
  {
39
- start() {
40
- mainStart();
41
- sharedStarts.forEach(cb => cb());
42
- sharedStarts.length = 0;
43
- },
44
35
  // fake flush, that resolves immediately
45
36
  flush,
46
37
 
47
38
  // [Only used for client-side]
48
- shared(matchingKey: string, readinessManager: IReadinessManager) {
49
- // In LOCALHOST mode, shared clients are ready in the next event-loop cycle than created
50
- // SDK_READY cannot be emitted directly because this will not update the readiness status
51
- function emitSdkReady() {
52
- readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED); // SDK_SPLITS_ARRIVED emitted by main SyncManager
53
- }
54
-
55
- if (mainSyncManager.isRunning()) setTimeout(emitSdkReady);
56
- else sharedStarts.push(emitSdkReady);
57
-
39
+ shared(matchingKey: string, readinessManager: IReadinessManager): ISyncManager {
58
40
  return {
41
+ start() {
42
+ // In LOCALHOST mode, shared clients are ready in the next event-loop cycle than created
43
+ // SDK_READY cannot be emitted directly because this will not update the readiness status
44
+ setTimeout(() => {
45
+ readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED); // SDK_SPLITS_ARRIVED emitted by main SyncManager
46
+ }, 0);
47
+ },
59
48
  stop() { },
49
+ isRunning() {
50
+ return true;
51
+ },
60
52
  flush,
61
53
  };
62
54
  }
@@ -1,25 +1,27 @@
1
- import { IFetchMemberships, IResponse } from '../../../services/types';
2
- import { IMembershipsResponse } from '../../../dtos/types';
1
+ import { IFetchMySegments, IResponse } from '../../../services/types';
2
+ import { IMySegmentsResponseItem } 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(fetchMemberships: IFetchMemberships): IMySegmentsFetcher {
9
+ export function mySegmentsFetcherFactory(fetchMySegments: IFetchMySegments): IMySegmentsFetcher {
10
10
 
11
11
  return function mySegmentsFetcher(
12
12
  userMatchingKey: string,
13
13
  noCache?: boolean,
14
- till?: number,
15
- // Optional decorator for `fetchMemberships` promise, such as timeout or time tracker
14
+ // Optional decorator for `fetchMySegments` promise, such as timeout or time tracker
16
15
  decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
17
- ): Promise<IMembershipsResponse> {
16
+ ): Promise<string[]> {
18
17
 
19
- let mySegmentsPromise = fetchMemberships(userMatchingKey, noCache, till);
18
+ let mySegmentsPromise = fetchMySegments(userMatchingKey, noCache);
20
19
  if (decorator) mySegmentsPromise = decorator(mySegmentsPromise);
21
20
 
22
- return mySegmentsPromise.then(resp => resp.json());
21
+ // Extract segment names
22
+ return mySegmentsPromise
23
+ .then(resp => resp.json())
24
+ .then(json => json.mySegments.map((segment: IMySegmentsResponseItem) => segment.name));
23
25
  };
24
26
 
25
27
  }
@@ -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 `fetchSegmentChanges` promise, such as timeout or time tracker
31
+ // Optional decorator for `fetchMySegments` 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, IMembershipsResponse } from '../../../dtos/types';
1
+ import { ISplitChangesResponse, ISegmentChangesResponse } from '../../../dtos/types';
2
2
  import { IResponse } from '../../../services/types';
3
3
 
4
4
  export type ISplitChangesFetcher = (
@@ -19,6 +19,5 @@ export type ISegmentChangesFetcher = (
19
19
  export type IMySegmentsFetcher = (
20
20
  userMatchingKey: string,
21
21
  noCache?: boolean,
22
- till?: number,
23
22
  decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
24
- ) => Promise<IMembershipsResponse>
23
+ ) => Promise<string[]>
@@ -29,13 +29,13 @@ export function pollingManagerCSFactory(
29
29
  const mySegmentsSyncTask = add(matchingKey, readiness, storage);
30
30
 
31
31
  function startMySegmentsSyncTasks() {
32
- forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask) => {
32
+ forOwn(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
33
33
  mySegmentsSyncTask.start();
34
34
  });
35
35
  }
36
36
 
37
37
  function stopMySegmentsSyncTasks() {
38
- forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask) => {
38
+ forOwn(mySegmentsSyncTasks, function (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.fetchMemberships, storage, readiness, settings, matchingKey);
58
+ const mySegmentsSyncTask = mySegmentsSyncTaskFactory(splitApi.fetchMySegments, 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, (mySegmentsSyncTask) => {
97
+ forOwn(mySegmentsSyncTasks, function (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 { IFetchMemberships } from '../../../services/types';
5
+ import { IFetchMySegments } 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
- fetchMemberships: IFetchMemberships,
14
+ fetchMySegments: IFetchMySegments,
15
15
  storage: IStorageSync,
16
16
  readiness: IReadinessManager,
17
17
  settings: ISettings,
@@ -21,8 +21,9 @@ export function mySegmentsSyncTaskFactory(
21
21
  settings.log,
22
22
  mySegmentsUpdaterFactory(
23
23
  settings.log,
24
- mySegmentsFetcherFactory(fetchMemberships),
25
- storage,
24
+ mySegmentsFetcherFactory(fetchMySegments),
25
+ storage.splits,
26
+ storage.segments,
26
27
  readiness.segments,
27
28
  settings.startup.requestTimeoutBeforeReady,
28
29
  settings.startup.retriesOnFailureBeforeReady,
@@ -1,21 +1,20 @@
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';
5
4
  import { ITask, ISyncTask } from '../types';
6
5
 
7
6
  export interface ISplitsSyncTask extends ISyncTask<[noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }], boolean> { }
8
7
 
9
8
  export interface ISegmentsSyncTask extends ISyncTask<[fetchOnlyNew?: boolean, segmentName?: string, noCache?: boolean, till?: number], boolean> { }
10
9
 
11
- export type MySegmentsData = {
12
- type: MEMBERSHIPS_MS_UPDATE | MEMBERSHIPS_LS_UPDATE
13
- cn: number
14
- added: string[]
15
- removed: string[]
10
+ export type MySegmentsData = string[] | {
11
+ /* segment name */
12
+ name: string,
13
+ /* action: `true` for add, and `false` for delete */
14
+ add: boolean
16
15
  }
17
16
 
18
- export interface IMySegmentsSyncTask extends ISyncTask<[segmentsData?: MySegmentsData, noCache?: boolean, till?: number], boolean> { }
17
+ export interface IMySegmentsSyncTask extends ISyncTask<[segmentsData?: MySegmentsData, noCache?: boolean], boolean> { }
19
18
 
20
19
  export interface IPollingManager extends ITask {
21
20
  syncAll(): Promise<any>
@@ -1,15 +1,13 @@
1
1
  import { IMySegmentsFetcher } from '../fetchers/types';
2
- import { IStorageSync } from '../../../storages/types';
2
+ import { ISegmentsCacheSync, ISplitsCacheSync } 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';
11
9
 
12
- type IMySegmentsUpdater = (segmentsData?: MySegmentsData, noCache?: boolean, till?: number) => Promise<boolean>
10
+ type IMySegmentsUpdater = (segmentList?: string[], noCache?: boolean) => Promise<boolean>
13
11
 
14
12
  /**
15
13
  * factory of MySegments updater, a task that:
@@ -20,14 +18,14 @@ type IMySegmentsUpdater = (segmentsData?: MySegmentsData, noCache?: boolean, til
20
18
  export function mySegmentsUpdaterFactory(
21
19
  log: ILogger,
22
20
  mySegmentsFetcher: IMySegmentsFetcher,
23
- storage: IStorageSync,
21
+ splitsCache: ISplitsCacheSync,
22
+ mySegmentsCache: ISegmentsCacheSync,
24
23
  segmentsEventEmitter: ISegmentsEventEmitter,
25
24
  requestTimeoutBeforeReady: number,
26
25
  retriesOnFailureBeforeReady: number,
27
26
  matchingKey: string
28
27
  ): IMySegmentsUpdater {
29
28
 
30
- const { splits, segments, largeSegments } = storage;
31
29
  let readyOnAlreadyExistentState = true;
32
30
  let startingUp = true;
33
31
 
@@ -38,31 +36,37 @@ export function mySegmentsUpdaterFactory(
38
36
  }
39
37
 
40
38
  // @TODO if allowing pluggable storages, handle async execution
41
- function updateSegments(segmentsData: IMembershipsResponse | MySegmentsData) {
39
+ function updateSegments(segmentsData: MySegmentsData) {
42
40
 
43
41
  let shouldNotifyUpdate;
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);
42
+ if (Array.isArray(segmentsData)) {
43
+ // Update the list of segment names available
44
+ shouldNotifyUpdate = mySegmentsCache.resetSegments(segmentsData);
48
45
  } else {
49
- shouldNotifyUpdate = segments.resetSegments((segmentsData as IMembershipsResponse).ms || {});
50
- shouldNotifyUpdate = largeSegments!.resetSegments((segmentsData as IMembershipsResponse).ls || {}) || shouldNotifyUpdate;
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
+ }
51
55
  }
52
56
 
53
57
  // Notify update if required
54
- if (splits.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
58
+ if (splitsCache.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
55
59
  readyOnAlreadyExistentState = false;
56
60
  segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
57
61
  }
58
62
  }
59
63
 
60
- function _mySegmentsUpdater(retry: number, segmentsData?: MySegmentsData, noCache?: boolean, till?: number): Promise<boolean> {
64
+ function _mySegmentsUpdater(retry: number, segmentsData?: MySegmentsData, noCache?: boolean): Promise<boolean> {
61
65
  const updaterPromise: Promise<boolean> = segmentsData ?
62
66
  // If segmentsData is provided, there is no need to fetch mySegments
63
67
  new Promise((res) => { updateSegments(segmentsData); res(true); }) :
64
68
  // If not provided, fetch mySegments
65
- mySegmentsFetcher(matchingKey, noCache, till, _promiseDecorator).then(segments => {
69
+ mySegmentsFetcher(matchingKey, noCache, _promiseDecorator).then(segments => {
66
70
  // Only when we have downloaded segments completely, we should not keep retrying anymore
67
71
  startingUp = false;
68
72
 
@@ -92,10 +96,9 @@ export function mySegmentsUpdaterFactory(
92
96
  * (2) an object with a segment name and action (true: add, or false: delete) to update the storage,
93
97
  * (3) or `undefined`, for which the updater will fetch mySegments in order to sync the storage.
94
98
  * @param {boolean | undefined} noCache true to revalidate data to fetch
95
- * @param {boolean | undefined} till query param to bypass CDN requests
96
99
  */
97
- return function mySegmentsUpdater(segmentsData?: MySegmentsData, noCache?: boolean, till?: number) {
98
- return _mySegmentsUpdater(0, segmentsData, noCache, till);
100
+ return function mySegmentsUpdater(segmentsData?: MySegmentsData, noCache?: boolean) {
101
+ return _mySegmentsUpdater(0, segmentsData, noCache);
99
102
  };
100
103
 
101
104
  }
@@ -1,9 +1,12 @@
1
1
  import { ISegmentChangesFetcher } from '../fetchers/types';
2
2
  import { ISegmentsCacheBase } from '../../../storages/types';
3
3
  import { IReadinessManager } from '../../../readiness/types';
4
+ import { MaybeThenable } from '../../../dtos/types';
5
+ import { findIndex } from '../../../utils/lang';
4
6
  import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
5
7
  import { ILogger } from '../../../logger/types';
6
8
  import { LOG_PREFIX_INSTANTIATION, LOG_PREFIX_SYNC_SEGMENTS } from '../../../logger/constants';
9
+ import { thenable } from '../../../utils/promise/thenable';
7
10
 
8
11
  type ISegmentChangesUpdater = (fetchOnlyNew?: boolean, segmentName?: string, noCache?: boolean, till?: number) => Promise<boolean>
9
12
 
@@ -27,22 +30,31 @@ export function segmentChangesUpdaterFactory(
27
30
 
28
31
  let readyOnAlreadyExistentState = true;
29
32
 
30
- function updateSegment(segmentName: string, noCache?: boolean, till?: number, fetchOnlyNew?: boolean): Promise<boolean> {
33
+ function updateSegment(segmentName: string, noCache?: boolean, till?: number, fetchOnlyNew?: boolean) {
31
34
  log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Processing segment ${segmentName}`);
32
35
  let sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
33
36
 
34
37
  return sincePromise.then(since => {
35
38
  // if fetchOnlyNew flag, avoid processing already fetched segments
36
- return fetchOnlyNew && since !== -1 ?
37
- false :
38
- segmentChangesFetcher(since, segmentName, noCache, till).then((changes) => {
39
- return Promise.all(changes.map(x => {
40
- log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Processing ${segmentName} with till = ${x.till}. Added: ${x.added.length}. Removed: ${x.removed.length}`);
41
- return segments.update(x.name, x.added, x.removed, x.till);
42
- })).then((updates) => {
43
- return updates.some(update => update);
44
- });
39
+ if (fetchOnlyNew && since !== undefined) return -1;
40
+
41
+ return segmentChangesFetcher(since || -1, segmentName, noCache, till).then(function (changes) {
42
+ let changeNumber = -1;
43
+ const results: MaybeThenable<boolean | void>[] = [];
44
+ changes.forEach(x => {
45
+ if (x.added.length > 0) results.push(segments.addToSegment(segmentName, x.added));
46
+ if (x.removed.length > 0) results.push(segments.removeFromSegment(segmentName, x.removed));
47
+ if (x.added.length > 0 || x.removed.length > 0) {
48
+ results.push(segments.setChangeNumber(segmentName, x.till));
49
+ changeNumber = x.till;
50
+ }
51
+
52
+ log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Processed ${segmentName} with till = ${x.till}. Added: ${x.added.length}. Removed: ${x.removed.length}`);
45
53
  });
54
+ // If at least one storage operation result is a promise, join all in a single promise.
55
+ if (results.some(result => thenable(result))) return Promise.all(results).then(() => changeNumber);
56
+ return changeNumber;
57
+ });
46
58
  });
47
59
  }
48
60
  /**
@@ -63,12 +75,16 @@ export function segmentChangesUpdaterFactory(
63
75
  let segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
64
76
 
65
77
  return segmentsPromise.then(segmentNames => {
66
- // Async fetchers
67
- const updaters = segmentNames.map(segmentName => updateSegment(segmentName, noCache, till, fetchOnlyNew));
78
+ // Async fetchers are collected here.
79
+ const updaters: Promise<number>[] = [];
80
+
81
+ for (let index = 0; index < segmentNames.length; index++) {
82
+ updaters.push(updateSegment(segmentNames[index], noCache, till, fetchOnlyNew));
83
+ }
68
84
 
69
85
  return Promise.all(updaters).then(shouldUpdateFlags => {
70
86
  // if at least one segment fetch succeeded, mark segments ready
71
- if (shouldUpdateFlags.some(update => update) || readyOnAlreadyExistentState) {
87
+ if (findIndex(shouldUpdateFlags, v => v !== -1) !== -1 || readyOnAlreadyExistentState) {
72
88
  readyOnAlreadyExistentState = false;
73
89
  if (readiness) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
74
90
  }
@@ -19,7 +19,7 @@ function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
19
19
  let registeredSegments = Promise.resolve(segments.getRegisteredSegments());
20
20
  return registeredSegments.then(segmentNames => {
21
21
  return Promise.all(segmentNames.map(segmentName => segments.getChangeNumber(segmentName)))
22
- .then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !== -1));
22
+ .then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !== undefined));
23
23
  });
24
24
  }
25
25
 
@@ -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 membership updates. It is undefined for server-side API.
17
+ * @param {string[] | undefined} userKeys set of user Keys to track MY_SEGMENTS_CHANGES. It is undefined for server-side API.
18
18
  */
19
19
  return function authenticate(userKeys?: string[]): Promise<IAuthToken> {
20
20
  return fetchAuth(userKeys)
@@ -71,10 +71,12 @@ 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((channel) => {
75
- const params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
76
- return encodeURIComponent(params + channel);
77
- }).join(',');
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(',');
78
80
  const url = `${this.settings.urls.streaming}/sse?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${ABLY_API_VERSION}&heartbeats=true`; // same results using `&heartbeats=false`
79
81
  const isServerSide = !this.settings.core.key;
80
82