@splitsoftware/splitio-commons 2.1.0-rc.2 → 2.1.1-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/CHANGES.txt +2 -7
  2. package/README.md +1 -0
  3. package/cjs/evaluator/combiners/and.js +2 -6
  4. package/cjs/evaluator/combiners/ifelseif.js +6 -6
  5. package/cjs/evaluator/condition/index.js +6 -5
  6. package/cjs/evaluator/index.js +7 -7
  7. package/cjs/evaluator/matchers/index.js +3 -1
  8. package/cjs/evaluator/matchers/matcherTypes.js +1 -0
  9. package/cjs/evaluator/matchers/rbsegment.js +43 -0
  10. package/cjs/evaluator/matchersTransform/index.js +4 -0
  11. package/cjs/evaluator/parser/index.js +2 -2
  12. package/cjs/evaluator/value/sanitize.js +1 -0
  13. package/cjs/logger/constants.js +5 -6
  14. package/cjs/logger/messages/debug.js +3 -4
  15. package/cjs/logger/messages/warn.js +1 -1
  16. package/cjs/readiness/readinessManager.js +0 -6
  17. package/cjs/services/splitApi.js +2 -2
  18. package/cjs/storages/AbstractSplitsCacheAsync.js +19 -1
  19. package/cjs/storages/AbstractSplitsCacheSync.js +17 -9
  20. package/cjs/storages/KeyBuilder.js +8 -15
  21. package/cjs/storages/KeyBuilderCS.js +11 -5
  22. package/cjs/storages/KeyBuilderSS.js +3 -0
  23. package/cjs/storages/dataLoader.js +3 -5
  24. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +117 -0
  25. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +69 -15
  26. package/cjs/storages/inLocalStorage/index.js +7 -5
  27. package/cjs/storages/inMemory/InMemoryStorage.js +3 -0
  28. package/cjs/storages/inMemory/InMemoryStorageCS.js +4 -0
  29. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +61 -0
  30. package/cjs/storages/inMemory/SplitsCacheInMemory.js +24 -31
  31. package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +64 -0
  32. package/cjs/storages/inRedis/SplitsCacheInRedis.js +4 -21
  33. package/cjs/storages/inRedis/constants.js +1 -1
  34. package/cjs/storages/inRedis/index.js +2 -0
  35. package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +64 -0
  36. package/cjs/storages/pluggable/SplitsCachePluggable.js +2 -19
  37. package/cjs/storages/pluggable/index.js +3 -2
  38. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +14 -16
  39. package/cjs/sync/polling/fetchers/splitChangesFetcher.js +2 -2
  40. package/cjs/sync/polling/pollingManagerCS.js +7 -7
  41. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  42. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +2 -2
  43. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  44. package/cjs/sync/polling/updaters/splitChangesUpdater.js +62 -51
  45. package/cjs/sync/streaming/SSEHandler/index.js +1 -0
  46. package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +106 -77
  47. package/cjs/sync/streaming/constants.js +2 -1
  48. package/cjs/sync/streaming/pushManager.js +3 -16
  49. package/cjs/sync/syncManagerOnline.js +5 -10
  50. package/cjs/trackers/uniqueKeysTracker.js +1 -1
  51. package/cjs/utils/constants/browser.js +5 -0
  52. package/cjs/utils/constants/index.js +3 -2
  53. package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
  54. package/esm/evaluator/combiners/and.js +2 -6
  55. package/esm/evaluator/combiners/ifelseif.js +7 -7
  56. package/esm/evaluator/condition/index.js +6 -5
  57. package/esm/evaluator/index.js +7 -7
  58. package/esm/evaluator/matchers/index.js +3 -1
  59. package/esm/evaluator/matchers/matcherTypes.js +1 -0
  60. package/esm/evaluator/matchers/rbsegment.js +39 -0
  61. package/esm/evaluator/matchersTransform/index.js +4 -0
  62. package/esm/evaluator/parser/index.js +2 -2
  63. package/esm/evaluator/value/sanitize.js +1 -0
  64. package/esm/logger/constants.js +2 -3
  65. package/esm/logger/messages/debug.js +3 -4
  66. package/esm/logger/messages/warn.js +1 -1
  67. package/esm/readiness/readinessManager.js +0 -6
  68. package/esm/services/splitApi.js +2 -2
  69. package/esm/storages/AbstractSplitsCacheAsync.js +19 -1
  70. package/esm/storages/AbstractSplitsCacheSync.js +17 -9
  71. package/esm/storages/KeyBuilder.js +8 -15
  72. package/esm/storages/KeyBuilderCS.js +11 -5
  73. package/esm/storages/KeyBuilderSS.js +3 -0
  74. package/esm/storages/dataLoader.js +2 -4
  75. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +114 -0
  76. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +69 -15
  77. package/esm/storages/inLocalStorage/index.js +7 -5
  78. package/esm/storages/inMemory/InMemoryStorage.js +3 -0
  79. package/esm/storages/inMemory/InMemoryStorageCS.js +4 -0
  80. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +58 -0
  81. package/esm/storages/inMemory/SplitsCacheInMemory.js +24 -31
  82. package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +61 -0
  83. package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -21
  84. package/esm/storages/inRedis/constants.js +1 -1
  85. package/esm/storages/inRedis/index.js +2 -0
  86. package/esm/storages/pluggable/RBSegmentsCachePluggable.js +61 -0
  87. package/esm/storages/pluggable/SplitsCachePluggable.js +2 -19
  88. package/esm/storages/pluggable/index.js +3 -2
  89. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +14 -16
  90. package/esm/sync/polling/fetchers/splitChangesFetcher.js +2 -2
  91. package/esm/sync/polling/pollingManagerCS.js +7 -7
  92. package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  93. package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
  94. package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  95. package/esm/sync/polling/updaters/splitChangesUpdater.js +63 -52
  96. package/esm/sync/streaming/SSEHandler/index.js +2 -1
  97. package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +102 -73
  98. package/esm/sync/streaming/constants.js +1 -0
  99. package/esm/sync/streaming/pushManager.js +6 -19
  100. package/esm/sync/syncManagerOnline.js +5 -10
  101. package/esm/trackers/uniqueKeysTracker.js +1 -1
  102. package/esm/utils/constants/browser.js +2 -0
  103. package/esm/utils/constants/index.js +2 -1
  104. package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
  105. package/package.json +1 -1
  106. package/src/dtos/types.ts +32 -8
  107. package/src/evaluator/Engine.ts +1 -1
  108. package/src/evaluator/combiners/and.ts +5 -4
  109. package/src/evaluator/combiners/ifelseif.ts +7 -9
  110. package/src/evaluator/condition/engineUtils.ts +1 -1
  111. package/src/evaluator/condition/index.ts +12 -12
  112. package/src/evaluator/index.ts +7 -7
  113. package/src/evaluator/matchers/index.ts +3 -1
  114. package/src/evaluator/matchers/matcherTypes.ts +1 -0
  115. package/src/evaluator/matchers/rbsegment.ts +61 -0
  116. package/src/evaluator/matchersTransform/index.ts +3 -0
  117. package/src/evaluator/parser/index.ts +3 -3
  118. package/src/evaluator/types.ts +2 -2
  119. package/src/evaluator/value/index.ts +2 -2
  120. package/src/evaluator/value/sanitize.ts +5 -4
  121. package/src/logger/constants.ts +2 -3
  122. package/src/logger/messages/debug.ts +3 -4
  123. package/src/logger/messages/warn.ts +1 -1
  124. package/src/readiness/readinessManager.ts +0 -5
  125. package/src/sdkManager/index.ts +1 -1
  126. package/src/services/splitApi.ts +2 -2
  127. package/src/services/types.ts +1 -1
  128. package/src/storages/AbstractSplitsCacheAsync.ts +23 -5
  129. package/src/storages/AbstractSplitsCacheSync.ts +22 -15
  130. package/src/storages/KeyBuilder.ts +9 -17
  131. package/src/storages/KeyBuilderCS.ts +13 -6
  132. package/src/storages/KeyBuilderSS.ts +4 -0
  133. package/src/storages/dataLoader.ts +2 -5
  134. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +136 -0
  135. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +80 -16
  136. package/src/storages/inLocalStorage/index.ts +12 -8
  137. package/src/storages/inMemory/InMemoryStorage.ts +3 -0
  138. package/src/storages/inMemory/InMemoryStorageCS.ts +4 -0
  139. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +68 -0
  140. package/src/storages/inMemory/SplitsCacheInMemory.ts +22 -27
  141. package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +79 -0
  142. package/src/storages/inRedis/SplitsCacheInRedis.ts +4 -21
  143. package/src/storages/inRedis/constants.ts +1 -1
  144. package/src/storages/inRedis/index.ts +2 -0
  145. package/src/storages/pluggable/RBSegmentsCachePluggable.ts +76 -0
  146. package/src/storages/pluggable/SplitsCachePluggable.ts +2 -19
  147. package/src/storages/pluggable/index.ts +3 -2
  148. package/src/storages/types.ts +47 -18
  149. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +19 -21
  150. package/src/sync/polling/fetchers/splitChangesFetcher.ts +2 -1
  151. package/src/sync/polling/fetchers/types.ts +1 -0
  152. package/src/sync/polling/pollingManagerCS.ts +7 -7
  153. package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -2
  154. package/src/sync/polling/types.ts +2 -2
  155. package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -2
  156. package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
  157. package/src/sync/polling/updaters/splitChangesUpdater.ts +74 -63
  158. package/src/sync/streaming/SSEHandler/index.ts +2 -1
  159. package/src/sync/streaming/SSEHandler/types.ts +2 -2
  160. package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +98 -68
  161. package/src/sync/streaming/constants.ts +1 -0
  162. package/src/sync/streaming/parseUtils.ts +2 -2
  163. package/src/sync/streaming/pushManager.ts +6 -18
  164. package/src/sync/streaming/types.ts +3 -2
  165. package/src/sync/syncManagerOnline.ts +5 -11
  166. package/src/trackers/uniqueKeysTracker.ts +1 -1
  167. package/src/utils/constants/browser.ts +2 -0
  168. package/src/utils/constants/index.ts +2 -1
  169. package/src/utils/lang/index.ts +2 -2
  170. package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
  171. package/types/splitio.d.ts +1 -25
  172. package/cjs/storages/inLocalStorage/validateCache.js +0 -79
  173. package/esm/storages/inLocalStorage/validateCache.js +0 -75
  174. package/src/storages/inLocalStorage/validateCache.ts +0 -91
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RBSegmentsCachePluggable = void 0;
4
+ var lang_1 = require("../../utils/lang");
5
+ var constants_1 = require("./constants");
6
+ var sets_1 = require("../../utils/lang/sets");
7
+ var RBSegmentsCachePluggable = /** @class */ (function () {
8
+ function RBSegmentsCachePluggable(log, keys, wrapper) {
9
+ this.log = log;
10
+ this.keys = keys;
11
+ this.wrapper = wrapper;
12
+ }
13
+ RBSegmentsCachePluggable.prototype.get = function (name) {
14
+ return this.wrapper.get(this.keys.buildRBSegmentKey(name))
15
+ .then(function (maybeRBSegment) { return maybeRBSegment && JSON.parse(maybeRBSegment); });
16
+ };
17
+ RBSegmentsCachePluggable.prototype.getNames = function () {
18
+ var _this = this;
19
+ return this.wrapper.getKeysByPrefix(this.keys.buildRBSegmentKeyPrefix()).then(function (listOfKeys) { return listOfKeys.map(_this.keys.extractKey); });
20
+ };
21
+ RBSegmentsCachePluggable.prototype.contains = function (names) {
22
+ var namesArray = (0, sets_1.setToArray)(names);
23
+ return this.getNames().then(function (namesInStorage) {
24
+ return namesArray.every(function (name) { return namesInStorage.includes(name); });
25
+ });
26
+ };
27
+ RBSegmentsCachePluggable.prototype.update = function (toAdd, toRemove, changeNumber) {
28
+ var _this = this;
29
+ return Promise.all([
30
+ this.setChangeNumber(changeNumber),
31
+ Promise.all(toAdd.map(function (toAdd) {
32
+ var key = _this.keys.buildRBSegmentKey(toAdd.name);
33
+ var stringifiedNewRBSegment = JSON.stringify(toAdd);
34
+ return _this.wrapper.set(key, stringifiedNewRBSegment).then(function () { return true; });
35
+ })),
36
+ Promise.all(toRemove.map(function (toRemove) {
37
+ var key = _this.keys.buildRBSegmentKey(toRemove.name);
38
+ return _this.wrapper.del(key);
39
+ }))
40
+ ]).then(function (_a) {
41
+ var added = _a[1], removed = _a[2];
42
+ return added.some(function (result) { return result; }) || removed.some(function (result) { return result; });
43
+ });
44
+ };
45
+ RBSegmentsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
46
+ return this.wrapper.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
47
+ };
48
+ RBSegmentsCachePluggable.prototype.getChangeNumber = function () {
49
+ var _this = this;
50
+ return this.wrapper.get(this.keys.buildRBSegmentsTillKey()).then(function (value) {
51
+ var i = parseInt(value, 10);
52
+ return (0, lang_1.isNaNNumber)(i) ? -1 : i;
53
+ }).catch(function (e) {
54
+ _this.log.error(constants_1.LOG_PREFIX + 'Could not retrieve changeNumber from storage. Error: ' + e);
55
+ return -1;
56
+ });
57
+ };
58
+ // @TODO implement if required by DataLoader or producer mode
59
+ RBSegmentsCachePluggable.prototype.clear = function () {
60
+ return Promise.resolve();
61
+ };
62
+ return RBSegmentsCachePluggable;
63
+ }());
64
+ exports.RBSegmentsCachePluggable = RBSegmentsCachePluggable;
@@ -54,8 +54,9 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
54
54
  * The returned promise is resolved when the operation success
55
55
  * or rejected if it fails (e.g., wrapper operation fails)
56
56
  */
57
- SplitsCachePluggable.prototype.addSplit = function (name, split) {
57
+ SplitsCachePluggable.prototype.addSplit = function (split) {
58
58
  var _this = this;
59
+ var name = split.name;
59
60
  var splitKey = this.keys.buildSplitKey(name);
60
61
  return this.wrapper.get(splitKey).then(function (splitFromStorage) {
61
62
  // handling parsing error
@@ -79,15 +80,6 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
79
80
  }).then(function () { return _this._updateFlagSets(name, parsedPreviousSplit && parsedPreviousSplit.sets, split.sets); });
80
81
  }).then(function () { return true; });
81
82
  };
82
- /**
83
- * Add a list of splits.
84
- * The returned promise is resolved when the operation success
85
- * or rejected if it fails (e.g., wrapper operation fails)
86
- */
87
- SplitsCachePluggable.prototype.addSplits = function (entries) {
88
- var _this = this;
89
- return Promise.all(entries.map(function (keyValuePair) { return _this.addSplit(keyValuePair[0], keyValuePair[1]); }));
90
- };
91
83
  /**
92
84
  * Remove a given split.
93
85
  * The returned promise is resolved when the operation success, with a boolean indicating if the split existed or not.
@@ -103,15 +95,6 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
103
95
  return _this.wrapper.del(_this.keys.buildSplitKey(name));
104
96
  });
105
97
  };
106
- /**
107
- * Remove a list of splits.
108
- * The returned promise is resolved when the operation success, with a boolean array indicating if the splits existed or not.
109
- * or rejected if it fails (e.g., wrapper operation fails).
110
- */
111
- SplitsCachePluggable.prototype.removeSplits = function (names) {
112
- var _this = this;
113
- return Promise.all(names.map(function (name) { return _this.removeSplit(name); }));
114
- };
115
98
  /**
116
99
  * Get split.
117
100
  * The returned promise is resolved with the split definition or null if it's not defined,
@@ -22,6 +22,7 @@ var UniqueKeysCacheInMemory_1 = require("../inMemory/UniqueKeysCacheInMemory");
22
22
  var UniqueKeysCacheInMemoryCS_1 = require("../inMemory/UniqueKeysCacheInMemoryCS");
23
23
  var utils_1 = require("../utils");
24
24
  var constants_2 = require("../pluggable/constants");
25
+ var RBSegmentsCachePluggable_1 = require("./RBSegmentsCachePluggable");
25
26
  var NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.';
26
27
  var NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.';
27
28
  /**
@@ -74,8 +75,7 @@ function PluggableStorage(options) {
74
75
  // Connects to wrapper and emits SDK_READY event on main client
75
76
  var connectPromise = wrapper.connect().then(function () {
76
77
  if (isSynchronizer) {
77
- // @TODO reuse InLocalStorage::validateCache logic
78
- // In standalone or producer mode, clear storage if SDK key, flags filter criteria or flags spec version was modified
78
+ // In standalone or producer mode, clear storage if SDK key or feature flag filter has changed
79
79
  return wrapper.get(keys.buildHashKey()).then(function (hash) {
80
80
  var currentHash = (0, KeyBuilder_1.getStorageHash)(settings);
81
81
  if (hash !== currentHash) {
@@ -105,6 +105,7 @@ function PluggableStorage(options) {
105
105
  });
106
106
  return {
107
107
  splits: new SplitsCachePluggable_1.SplitsCachePluggable(log, keys, wrapper, settings.sync.__splitFiltersValidation),
108
+ rbSegments: new RBSegmentsCachePluggable_1.RBSegmentsCachePluggable(log, keys, wrapper),
108
109
  segments: new SegmentsCachePluggable_1.SegmentsCachePluggable(log, keys, wrapper),
109
110
  impressions: isPartialConsumer ? new ImpressionsCacheInMemory_1.ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable_1.ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
110
111
  impressionCounts: impressionCountsCache,
@@ -26,30 +26,28 @@ function fromObjectUpdaterFactory(splitsParser, storage, readiness, settings) {
26
26
  if (!loadError && splitsMock) {
27
27
  log.debug(constants_3.SYNC_OFFLINE_DATA, [JSON.stringify(splitsMock)]);
28
28
  (0, lang_1.forOwn)(splitsMock, function (val, name) {
29
- splits.push([
30
- name, {
31
- name: name,
32
- status: 'ACTIVE',
33
- killed: false,
34
- trafficAllocation: 100,
35
- defaultTreatment: constants_1.CONTROL,
36
- conditions: val.conditions || [],
37
- configurations: val.configurations,
38
- trafficTypeName: val.trafficTypeName
39
- }
40
- ]);
29
+ // @ts-ignore Split changeNumber and seed is undefined in localhost mode
30
+ splits.push({
31
+ name: name,
32
+ status: 'ACTIVE',
33
+ killed: false,
34
+ trafficAllocation: 100,
35
+ defaultTreatment: constants_1.CONTROL,
36
+ conditions: val.conditions || [],
37
+ configurations: val.configurations,
38
+ trafficTypeName: val.trafficTypeName
39
+ });
41
40
  });
42
41
  return Promise.all([
43
42
  splitsCache.clear(),
44
- splitsCache.addSplits(splits)
43
+ splitsCache.update(splits, [], Date.now())
45
44
  ]).then(function () {
46
45
  readiness.splits.emit(constants_2.SDK_SPLITS_ARRIVED);
47
46
  if (startingUp) {
48
47
  startingUp = false;
49
- var isCacheLoaded_1 = storage.validateCache ? storage.validateCache() : false;
50
- Promise.resolve().then(function () {
48
+ Promise.resolve(splitsCache.checkCache()).then(function (cacheReady) {
51
49
  // Emits SDK_READY_FROM_CACHE
52
- if (isCacheLoaded_1)
50
+ if (cacheReady)
53
51
  readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED);
54
52
  // Emits SDK_READY
55
53
  readiness.segments.emit(constants_2.SDK_SEGMENTS_ARRIVED);
@@ -6,10 +6,10 @@ exports.splitChangesFetcherFactory = void 0;
6
6
  * SplitChanges fetcher is a wrapper around `splitChanges` API service that parses the response and handle errors.
7
7
  */
8
8
  function splitChangesFetcherFactory(fetchSplitChanges) {
9
- return function splitChangesFetcher(since, noCache, till,
9
+ return function splitChangesFetcher(since, noCache, till, rbSince,
10
10
  // Optional decorator for `fetchSplitChanges` promise, such as timeout or time tracker
11
11
  decorator) {
12
- var splitsPromise = fetchSplitChanges(since, noCache, till);
12
+ var splitsPromise = fetchSplitChanges(since, noCache, till, rbSince);
13
13
  if (decorator)
14
14
  splitsPromise = decorator(splitsPromise);
15
15
  return splitsPromise.then(function (resp) { return resp.json(); });
@@ -34,10 +34,10 @@ function pollingManagerCSFactory(params) {
34
34
  readiness.splits.on(constants_1.SDK_SPLITS_ARRIVED, function () {
35
35
  if (!splitsSyncTask.isRunning())
36
36
  return; // noop if not doing polling
37
- var splitsHaveSegments = storage.splits.usesSegments();
38
- if (splitsHaveSegments !== mySegmentsSyncTask.isRunning()) {
39
- log.info(constants_2.POLLING_SMART_PAUSING, [splitsHaveSegments ? 'ON' : 'OFF']);
40
- if (splitsHaveSegments) {
37
+ var usingSegments = storage.splits.usesSegments() || storage.rbSegments.usesSegments();
38
+ if (usingSegments !== mySegmentsSyncTask.isRunning()) {
39
+ log.info(constants_2.POLLING_SMART_PAUSING, [usingSegments ? 'ON' : 'OFF']);
40
+ if (usingSegments) {
41
41
  startMySegmentsSyncTasks();
42
42
  }
43
43
  else {
@@ -49,10 +49,10 @@ function pollingManagerCSFactory(params) {
49
49
  var mySegmentsSyncTask = (0, mySegmentsSyncTask_1.mySegmentsSyncTaskFactory)(splitApi.fetchMemberships, storage, readiness, settings, matchingKey);
50
50
  // smart ready
51
51
  function smartReady() {
52
- if (!readiness.isReady() && !storage.splits.usesSegments())
52
+ if (!readiness.isReady() && !storage.splits.usesSegments() && !storage.rbSegments.usesSegments())
53
53
  readiness.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED);
54
54
  }
55
- if (!storage.splits.usesSegments())
55
+ if (!storage.splits.usesSegments() && !storage.rbSegments.usesSegments())
56
56
  setTimeout(smartReady, 0);
57
57
  else
58
58
  readiness.splits.once(constants_1.SDK_SPLITS_ARRIVED, smartReady);
@@ -66,7 +66,7 @@ function pollingManagerCSFactory(params) {
66
66
  start: function () {
67
67
  log.info(constants_2.POLLING_START);
68
68
  splitsSyncTask.start();
69
- if (storage.splits.usesSegments())
69
+ if (storage.splits.usesSegments() || storage.rbSegments.usesSegments())
70
70
  startMySegmentsSyncTasks();
71
71
  },
72
72
  // Stop periodic fetching (polling)
@@ -8,6 +8,6 @@ var splitChangesUpdater_1 = require("../updaters/splitChangesUpdater");
8
8
  * Creates a sync task that periodically executes a `splitChangesUpdater` task
9
9
  */
10
10
  function splitsSyncTaskFactory(fetchSplitChanges, storage, readiness, settings, isClientSide) {
11
- return (0, syncTask_1.syncTaskFactory)(settings.log, (0, splitChangesUpdater_1.splitChangesUpdaterFactory)(settings.log, (0, splitChangesFetcher_1.splitChangesFetcherFactory)(fetchSplitChanges), storage.splits, storage.segments, settings.sync.__splitFiltersValidation, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
11
+ return (0, syncTask_1.syncTaskFactory)(settings.log, (0, splitChangesUpdater_1.splitChangesUpdaterFactory)(settings.log, (0, splitChangesFetcher_1.splitChangesFetcherFactory)(fetchSplitChanges), storage, settings.sync.__splitFiltersValidation, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
12
12
  }
13
13
  exports.splitsSyncTaskFactory = splitsSyncTaskFactory;
@@ -12,7 +12,7 @@ var constants_3 = require("../../streaming/constants");
12
12
  * - uses `segmentsEventEmitter` to emit events related to segments data updates
13
13
  */
14
14
  function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmentsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, matchingKey) {
15
- var splits = storage.splits, segments = storage.segments, largeSegments = storage.largeSegments;
15
+ var splits = storage.splits, rbSegments = storage.rbSegments, segments = storage.segments, largeSegments = storage.largeSegments;
16
16
  var readyOnAlreadyExistentState = true;
17
17
  var startingUp = true;
18
18
  /** timeout and telemetry decorator for `splitChangesFetcher` promise */
@@ -34,7 +34,7 @@ function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmentsEvent
34
34
  shouldNotifyUpdate = largeSegments.resetSegments(segmentsData.ls || {}) || shouldNotifyUpdate;
35
35
  }
36
36
  // Notify update if required
37
- if (splits.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
37
+ if ((splits.usesSegments() || rbSegments.usesSegments()) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
38
38
  readyOnAlreadyExistentState = false;
39
39
  segmentsEventEmitter.emit(constants_1.SDK_SEGMENTS_ARRIVED);
40
40
  }
@@ -39,7 +39,7 @@ function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, read
39
39
  * Returned promise will not be rejected.
40
40
  *
41
41
  * @param fetchOnlyNew - if true, only fetch the segments that not exists, i.e., which `changeNumber` is equal to -1.
42
- * This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE notifications.
42
+ * This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE or RB_SEGMENT_UPDATE notifications.
43
43
  * @param segmentName - segment name to fetch. By passing `undefined` it fetches the list of segments registered at the storage
44
44
  * @param noCache - true to revalidate data to fetch on a SEGMENT_UPDATE notifications.
45
45
  * @param till - till target for the provided segmentName, for CDN bypass.
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.splitChangesUpdaterFactory = exports.computeSplitsMutation = exports.parseSegments = void 0;
3
+ exports.splitChangesUpdaterFactory = exports.computeMutation = exports.parseSegments = void 0;
4
4
  var timeout_1 = require("../../../utils/promise/timeout");
5
5
  var constants_1 = require("../../../readiness/constants");
6
6
  var constants_2 = require("../../../logger/constants");
7
7
  var lang_1 = require("../../../utils/lang");
8
8
  var constants_3 = require("../../../utils/constants");
9
9
  var sets_1 = require("../../../utils/lang/sets");
10
+ var constants_4 = require("../../streaming/constants");
10
11
  // Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
11
12
  // Returns a promise that could be rejected.
12
13
  // @TODO review together with Segments and MySegments storage APIs
@@ -21,13 +22,14 @@ function checkAllSegmentsExist(segments) {
21
22
  * Collect segments from a raw split definition.
22
23
  * Exported for testing purposes.
23
24
  */
24
- function parseSegments(_a) {
25
- var conditions = _a.conditions;
26
- var segments = new Set();
25
+ function parseSegments(ruleEntity, matcherType) {
26
+ if (matcherType === void 0) { matcherType = constants_3.IN_SEGMENT; }
27
+ var _a = ruleEntity, conditions = _a.conditions, excluded = _a.excluded;
28
+ var segments = new Set(excluded && excluded.segments);
27
29
  for (var i = 0; i < conditions.length; i++) {
28
30
  var matchers = conditions[i].matcherGroup.matchers;
29
31
  matchers.forEach(function (matcher) {
30
- if (matcher.matcherType === constants_3.IN_SEGMENT)
32
+ if (matcher.matcherType === matcherType)
31
33
  segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
32
34
  });
33
35
  }
@@ -58,24 +60,21 @@ function matchFilters(featureFlag, filters) {
58
60
  * i.e., an object with added splits, removed splits and used segments.
59
61
  * Exported for testing purposes.
60
62
  */
61
- function computeSplitsMutation(entries, filters) {
62
- var segments = new Set();
63
- var computed = entries.reduce(function (accum, split) {
64
- if (split.status === 'ACTIVE' && matchFilters(split, filters)) {
65
- accum.added.push([split.name, split]);
66
- parseSegments(split).forEach(function (segmentName) {
63
+ function computeMutation(rules, segments, filters) {
64
+ return rules.reduce(function (accum, ruleEntity) {
65
+ if (ruleEntity.status === 'ACTIVE' && (!filters || matchFilters(ruleEntity, filters))) {
66
+ accum.added.push(ruleEntity);
67
+ parseSegments(ruleEntity).forEach(function (segmentName) {
67
68
  segments.add(segmentName);
68
69
  });
69
70
  }
70
71
  else {
71
- accum.removed.push(split.name);
72
+ accum.removed.push(ruleEntity);
72
73
  }
73
74
  return accum;
74
- }, { added: [], removed: [], segments: [] });
75
- computed.segments = (0, sets_1.setToArray)(segments);
76
- return computed;
75
+ }, { added: [], removed: [] });
77
76
  }
78
- exports.computeSplitsMutation = computeSplitsMutation;
77
+ exports.computeMutation = computeMutation;
79
78
  /**
80
79
  * factory of SplitChanges updater, a task that:
81
80
  * - fetches split changes using `splitChangesFetcher`
@@ -90,9 +89,10 @@ exports.computeSplitsMutation = computeSplitsMutation;
90
89
  * @param requestTimeoutBeforeReady - How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
91
90
  * @param retriesOnFailureBeforeReady - How many retries on `/splitChanges` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
92
91
  */
93
- function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments, splitFiltersValidation, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
92
+ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFiltersValidation, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
94
93
  if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
95
94
  if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
95
+ var splits = storage.splits, rbSegments = storage.rbSegments, segments = storage.segments;
96
96
  var startingUp = true;
97
97
  /** timeout decorator for `splitChangesFetcher` promise */
98
98
  function _promiseDecorator(promise) {
@@ -100,17 +100,6 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
100
100
  promise = (0, timeout_1.timeout)(requestTimeoutBeforeReady, promise);
101
101
  return promise;
102
102
  }
103
- /** Returns true if at least one split was updated */
104
- function isThereUpdate(flagsChange) {
105
- var added = flagsChange[1], removed = flagsChange[2];
106
- // There is at least one added or modified feature flag
107
- if (added && added.some(function (update) { return update; }))
108
- return true;
109
- // There is at least one removed feature flag
110
- if (removed && removed.some(function (update) { return update; }))
111
- return true;
112
- return false;
113
- }
114
103
  /**
115
104
  * SplitChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch splits or synchronize them with the storage.
116
105
  * Returned promise will not be rejected.
@@ -118,35 +107,48 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
118
107
  * @param noCache - true to revalidate data to fetch
119
108
  * @param till - query param to bypass CDN requests
120
109
  */
121
- return function splitChangesUpdater(noCache, till, splitUpdateNotification) {
110
+ return function splitChangesUpdater(noCache, till, instantUpdate) {
122
111
  /**
123
112
  * @param since - current changeNumber at splitsCache
124
113
  * @param retry - current number of retry attempts
125
114
  */
126
- function _splitChangesUpdater(since, retry) {
115
+ function _splitChangesUpdater(sinces, retry) {
127
116
  if (retry === void 0) { retry = 0; }
128
- log.debug(constants_2.SYNC_SPLITS_FETCH, [since]);
129
- return Promise.resolve(splitUpdateNotification ?
130
- { splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
131
- splitChangesFetcher(since, noCache, till, _promiseDecorator))
117
+ var since = sinces[0], rbSince = sinces[1];
118
+ log.debug(constants_2.SYNC_SPLITS_FETCH, sinces);
119
+ var fetcherPromise = Promise.resolve(instantUpdate ?
120
+ instantUpdate.type === constants_4.SPLIT_UPDATE ?
121
+ // IFFU edge case: a change to a flag that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
122
+ Promise.resolve(rbSegments.contains(parseSegments(instantUpdate.payload, constants_3.IN_RULE_BASED_SEGMENT))).then(function (contains) {
123
+ return contains ?
124
+ { ff: { d: [instantUpdate.payload], t: instantUpdate.changeNumber } } :
125
+ splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
126
+ }) :
127
+ { rbs: { d: [instantUpdate.payload], t: instantUpdate.changeNumber } } :
128
+ splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator))
132
129
  .then(function (splitChanges) {
133
130
  startingUp = false;
134
- var mutation = computeSplitsMutation(splitChanges.splits, splitFiltersValidation);
135
- log.debug(constants_2.SYNC_SPLITS_NEW, [mutation.added.length]);
136
- log.debug(constants_2.SYNC_SPLITS_REMOVED, [mutation.removed.length]);
137
- log.debug(constants_2.SYNC_SPLITS_SEGMENTS, [mutation.segments.length]);
138
- // Write into storage
139
- // @TODO call `setChangeNumber` only if the other storage operations have succeeded, in order to keep storage consistency
140
- return Promise.all([
141
- // calling first `setChangenumber` method, to perform cache flush if split filter queryString changed
142
- splits.setChangeNumber(splitChanges.till),
143
- splits.addSplits(mutation.added),
144
- splits.removeSplits(mutation.removed),
145
- segments.registerSegments(mutation.segments)
146
- ]).then(function (flagsChange) {
131
+ var usedSegments = new Set();
132
+ var ffUpdate = false;
133
+ if (splitChanges.ff) {
134
+ var _a = computeMutation(splitChanges.ff.d, usedSegments, splitFiltersValidation), added = _a.added, removed = _a.removed;
135
+ log.debug(constants_2.SYNC_SPLITS_UPDATE, [added.length, removed.length]);
136
+ ffUpdate = splits.update(added, removed, splitChanges.ff.t);
137
+ }
138
+ var rbsUpdate = false;
139
+ if (splitChanges.rbs) {
140
+ var _b = computeMutation(splitChanges.rbs.d, usedSegments), added = _b.added, removed = _b.removed;
141
+ log.debug(constants_2.SYNC_RBS_UPDATE, [added.length, removed.length]);
142
+ rbsUpdate = rbSegments.update(added, removed, splitChanges.rbs.t);
143
+ }
144
+ return Promise.all([ffUpdate, rbsUpdate,
145
+ // @TODO if at least 1 segment fetch fails due to 404 and other segments are updated in the storage, SDK_UPDATE is not emitted
146
+ segments.registerSegments((0, sets_1.setToArray)(usedSegments))
147
+ ]).then(function (_a) {
148
+ var ffChanged = _a[0], rbsChanged = _a[1];
147
149
  if (splitsEventEmitter) {
148
150
  // To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
149
- return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate(flagsChange) && (isClientSide || checkAllSegmentsExist(segments))))
151
+ return Promise.resolve(!splitsEventEmitter.splitsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
150
152
  .catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
151
153
  .then(function (emitSplitsArrivedEvent) {
152
154
  // emit SDK events
@@ -163,16 +165,25 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
163
165
  if (startingUp && retriesOnFailureBeforeReady > retry) {
164
166
  retry += 1;
165
167
  log.info(constants_2.SYNC_SPLITS_FETCH_RETRY, [retry, error]);
166
- return _splitChangesUpdater(since, retry);
168
+ return _splitChangesUpdater(sinces, retry);
167
169
  }
168
170
  else {
169
171
  startingUp = false;
170
172
  }
171
173
  return false;
172
174
  });
175
+ // After triggering the requests, if we have cached splits information let's notify that to emit SDK_READY_FROM_CACHE.
176
+ // Wrapping in a promise since checkCache can be async.
177
+ if (splitsEventEmitter && startingUp) {
178
+ Promise.resolve(splits.checkCache()).then(function (isCacheReady) {
179
+ if (isCacheReady)
180
+ splitsEventEmitter.emit(constants_1.SDK_SPLITS_CACHE_LOADED);
181
+ });
182
+ }
183
+ return fetcherPromise;
173
184
  }
174
- var sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error
175
- return sincePromise.then(_splitChangesUpdater);
185
+ // `getChangeNumber` never rejects or throws error
186
+ return Promise.all([splits.getChangeNumber(), rbSegments.getChangeNumber()]).then(_splitChangesUpdater);
176
187
  };
177
188
  }
178
189
  exports.splitChangesUpdaterFactory = splitChangesUpdaterFactory;
@@ -78,6 +78,7 @@ function SSEHandlerFactory(log, pushEmitter, telemetryTracker) {
78
78
  case constants_1.MEMBERSHIPS_MS_UPDATE:
79
79
  case constants_1.MEMBERSHIPS_LS_UPDATE:
80
80
  case constants_1.SPLIT_KILL:
81
+ case constants_1.RB_SEGMENT_UPDATE:
81
82
  pushEmitter.emit(parsedData.type, parsedData);
82
83
  break;
83
84
  /* occupancy & control events, handled by NotificationManagerKeeper */