@splitsoftware/splitio-commons 2.1.0 → 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 (154) hide show
  1. package/README.md +1 -0
  2. package/cjs/evaluator/combiners/and.js +2 -6
  3. package/cjs/evaluator/combiners/ifelseif.js +6 -6
  4. package/cjs/evaluator/condition/index.js +6 -5
  5. package/cjs/evaluator/index.js +7 -7
  6. package/cjs/evaluator/matchers/index.js +3 -1
  7. package/cjs/evaluator/matchers/matcherTypes.js +1 -0
  8. package/cjs/evaluator/matchers/rbsegment.js +43 -0
  9. package/cjs/evaluator/matchersTransform/index.js +4 -0
  10. package/cjs/evaluator/parser/index.js +2 -2
  11. package/cjs/evaluator/value/sanitize.js +1 -0
  12. package/cjs/logger/constants.js +5 -6
  13. package/cjs/logger/messages/debug.js +3 -4
  14. package/cjs/logger/messages/warn.js +1 -1
  15. package/cjs/services/splitApi.js +2 -2
  16. package/cjs/storages/AbstractSplitsCacheAsync.js +12 -1
  17. package/cjs/storages/AbstractSplitsCacheSync.js +10 -9
  18. package/cjs/storages/KeyBuilder.js +8 -15
  19. package/cjs/storages/KeyBuilderCS.js +12 -3
  20. package/cjs/storages/KeyBuilderSS.js +3 -0
  21. package/cjs/storages/dataLoader.js +1 -2
  22. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +117 -0
  23. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +14 -16
  24. package/cjs/storages/inLocalStorage/index.js +4 -0
  25. package/cjs/storages/inMemory/InMemoryStorage.js +3 -0
  26. package/cjs/storages/inMemory/InMemoryStorageCS.js +4 -0
  27. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +61 -0
  28. package/cjs/storages/inMemory/SplitsCacheInMemory.js +24 -31
  29. package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +64 -0
  30. package/cjs/storages/inRedis/SplitsCacheInRedis.js +4 -21
  31. package/cjs/storages/inRedis/index.js +2 -0
  32. package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +64 -0
  33. package/cjs/storages/pluggable/SplitsCachePluggable.js +2 -19
  34. package/cjs/storages/pluggable/index.js +2 -0
  35. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +12 -13
  36. package/cjs/sync/polling/fetchers/splitChangesFetcher.js +2 -2
  37. package/cjs/sync/polling/pollingManagerCS.js +7 -7
  38. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  39. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +2 -2
  40. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  41. package/cjs/sync/polling/updaters/splitChangesUpdater.js +53 -51
  42. package/cjs/sync/streaming/SSEHandler/index.js +1 -0
  43. package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +106 -77
  44. package/cjs/sync/streaming/constants.js +2 -1
  45. package/cjs/sync/streaming/pushManager.js +3 -16
  46. package/cjs/sync/syncManagerOnline.js +2 -2
  47. package/cjs/utils/constants/index.js +3 -2
  48. package/esm/evaluator/combiners/and.js +2 -6
  49. package/esm/evaluator/combiners/ifelseif.js +7 -7
  50. package/esm/evaluator/condition/index.js +6 -5
  51. package/esm/evaluator/index.js +7 -7
  52. package/esm/evaluator/matchers/index.js +3 -1
  53. package/esm/evaluator/matchers/matcherTypes.js +1 -0
  54. package/esm/evaluator/matchers/rbsegment.js +39 -0
  55. package/esm/evaluator/matchersTransform/index.js +4 -0
  56. package/esm/evaluator/parser/index.js +2 -2
  57. package/esm/evaluator/value/sanitize.js +1 -0
  58. package/esm/logger/constants.js +2 -3
  59. package/esm/logger/messages/debug.js +3 -4
  60. package/esm/logger/messages/warn.js +1 -1
  61. package/esm/services/splitApi.js +2 -2
  62. package/esm/storages/AbstractSplitsCacheAsync.js +12 -1
  63. package/esm/storages/AbstractSplitsCacheSync.js +10 -9
  64. package/esm/storages/KeyBuilder.js +8 -15
  65. package/esm/storages/KeyBuilderCS.js +12 -3
  66. package/esm/storages/KeyBuilderSS.js +3 -0
  67. package/esm/storages/dataLoader.js +1 -2
  68. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +114 -0
  69. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +14 -16
  70. package/esm/storages/inLocalStorage/index.js +4 -0
  71. package/esm/storages/inMemory/InMemoryStorage.js +3 -0
  72. package/esm/storages/inMemory/InMemoryStorageCS.js +4 -0
  73. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +58 -0
  74. package/esm/storages/inMemory/SplitsCacheInMemory.js +24 -31
  75. package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +61 -0
  76. package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -21
  77. package/esm/storages/inRedis/index.js +2 -0
  78. package/esm/storages/pluggable/RBSegmentsCachePluggable.js +61 -0
  79. package/esm/storages/pluggable/SplitsCachePluggable.js +2 -19
  80. package/esm/storages/pluggable/index.js +2 -0
  81. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +12 -13
  82. package/esm/sync/polling/fetchers/splitChangesFetcher.js +2 -2
  83. package/esm/sync/polling/pollingManagerCS.js +7 -7
  84. package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  85. package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
  86. package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  87. package/esm/sync/polling/updaters/splitChangesUpdater.js +53 -51
  88. package/esm/sync/streaming/SSEHandler/index.js +2 -1
  89. package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +102 -73
  90. package/esm/sync/streaming/constants.js +1 -0
  91. package/esm/sync/streaming/pushManager.js +6 -19
  92. package/esm/sync/syncManagerOnline.js +2 -2
  93. package/esm/utils/constants/index.js +2 -1
  94. package/package.json +1 -1
  95. package/src/dtos/types.ts +32 -8
  96. package/src/evaluator/Engine.ts +1 -1
  97. package/src/evaluator/combiners/and.ts +5 -4
  98. package/src/evaluator/combiners/ifelseif.ts +7 -9
  99. package/src/evaluator/condition/engineUtils.ts +1 -1
  100. package/src/evaluator/condition/index.ts +12 -12
  101. package/src/evaluator/index.ts +7 -7
  102. package/src/evaluator/matchers/index.ts +3 -1
  103. package/src/evaluator/matchers/matcherTypes.ts +1 -0
  104. package/src/evaluator/matchers/rbsegment.ts +61 -0
  105. package/src/evaluator/matchersTransform/index.ts +3 -0
  106. package/src/evaluator/parser/index.ts +3 -3
  107. package/src/evaluator/types.ts +2 -2
  108. package/src/evaluator/value/index.ts +2 -2
  109. package/src/evaluator/value/sanitize.ts +5 -4
  110. package/src/logger/constants.ts +2 -3
  111. package/src/logger/messages/debug.ts +3 -4
  112. package/src/logger/messages/warn.ts +1 -1
  113. package/src/sdkManager/index.ts +1 -1
  114. package/src/services/splitApi.ts +2 -2
  115. package/src/services/types.ts +1 -1
  116. package/src/storages/AbstractSplitsCacheAsync.ts +15 -5
  117. package/src/storages/AbstractSplitsCacheSync.ts +14 -15
  118. package/src/storages/KeyBuilder.ts +9 -17
  119. package/src/storages/KeyBuilderCS.ts +15 -4
  120. package/src/storages/KeyBuilderSS.ts +4 -0
  121. package/src/storages/dataLoader.ts +1 -2
  122. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +136 -0
  123. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +15 -16
  124. package/src/storages/inLocalStorage/index.ts +4 -0
  125. package/src/storages/inMemory/InMemoryStorage.ts +3 -0
  126. package/src/storages/inMemory/InMemoryStorageCS.ts +4 -0
  127. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +68 -0
  128. package/src/storages/inMemory/SplitsCacheInMemory.ts +22 -27
  129. package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +79 -0
  130. package/src/storages/inRedis/SplitsCacheInRedis.ts +4 -21
  131. package/src/storages/inRedis/index.ts +2 -0
  132. package/src/storages/pluggable/RBSegmentsCachePluggable.ts +76 -0
  133. package/src/storages/pluggable/SplitsCachePluggable.ts +2 -19
  134. package/src/storages/pluggable/index.ts +2 -0
  135. package/src/storages/types.ts +43 -17
  136. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +14 -15
  137. package/src/sync/polling/fetchers/splitChangesFetcher.ts +2 -1
  138. package/src/sync/polling/fetchers/types.ts +1 -0
  139. package/src/sync/polling/pollingManagerCS.ts +7 -7
  140. package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -2
  141. package/src/sync/polling/types.ts +2 -2
  142. package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -2
  143. package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
  144. package/src/sync/polling/updaters/splitChangesUpdater.ts +64 -62
  145. package/src/sync/streaming/SSEHandler/index.ts +2 -1
  146. package/src/sync/streaming/SSEHandler/types.ts +2 -2
  147. package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +98 -68
  148. package/src/sync/streaming/constants.ts +1 -0
  149. package/src/sync/streaming/parseUtils.ts +2 -2
  150. package/src/sync/streaming/pushManager.ts +6 -18
  151. package/src/sync/streaming/types.ts +3 -2
  152. package/src/sync/syncManagerOnline.ts +2 -2
  153. package/src/utils/constants/index.ts +2 -1
  154. package/src/utils/lang/index.ts +1 -1
@@ -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
- var fetcherPromise = 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,7 +165,7 @@ 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;
@@ -180,8 +182,8 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
180
182
  }
181
183
  return fetcherPromise;
182
184
  }
183
- var sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error
184
- return sincePromise.then(_splitChangesUpdater);
185
+ // `getChangeNumber` never rejects or throws error
186
+ return Promise.all([splits.getChangeNumber(), rbSegments.getChangeNumber()]).then(_splitChangesUpdater);
185
187
  };
186
188
  }
187
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 */
@@ -1,106 +1,135 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SplitsUpdateWorker = void 0;
4
- var constants_1 = require("../../../readiness/constants");
4
+ var constants_1 = require("../../../logger/constants");
5
+ var constants_2 = require("../../../readiness/constants");
5
6
  var Backoff_1 = require("../../../utils/Backoff");
6
- var constants_2 = require("../../../utils/constants");
7
- var constants_3 = require("./constants");
7
+ var constants_3 = require("../../../utils/constants");
8
+ var constants_4 = require("../constants");
9
+ var parseUtils_1 = require("../parseUtils");
10
+ var constants_5 = require("./constants");
8
11
  /**
9
12
  * SplitsUpdateWorker factory
10
13
  */
11
- function SplitsUpdateWorker(log, splitsCache, splitsSyncTask, splitsEventEmitter, telemetryTracker, segmentsSyncTask) {
12
- var maxChangeNumber = 0;
13
- var handleNewEvent = false;
14
- var isHandlingEvent;
15
- var cdnBypass;
16
- var payload;
17
- var backoff = new Backoff_1.Backoff(__handleSplitUpdateCall, constants_3.FETCH_BACKOFF_BASE, constants_3.FETCH_BACKOFF_MAX_WAIT);
18
- function __handleSplitUpdateCall() {
19
- isHandlingEvent = true;
20
- if (maxChangeNumber > splitsCache.getChangeNumber()) {
21
- handleNewEvent = false;
22
- var splitUpdateNotification_1 = payload ? { payload: payload, changeNumber: maxChangeNumber } : undefined;
23
- // fetch splits revalidating data if cached
24
- splitsSyncTask.execute(true, cdnBypass ? maxChangeNumber : undefined, splitUpdateNotification_1).then(function () {
25
- if (!isHandlingEvent)
26
- return; // halt if `stop` has been called
27
- if (handleNewEvent) {
28
- __handleSplitUpdateCall();
29
- }
30
- else {
31
- if (splitUpdateNotification_1)
32
- telemetryTracker.trackUpdatesFromSSE(constants_2.SPLITS);
33
- // fetch new registered segments for server-side API. Not retrying on error
34
- if (segmentsSyncTask)
35
- segmentsSyncTask.execute(true);
36
- var attempts = backoff.attempts + 1;
37
- if (maxChangeNumber <= splitsCache.getChangeNumber()) {
38
- log.debug("Refresh completed" + (cdnBypass ? ' bypassing the CDN' : '') + " in " + attempts + " attempts.");
39
- isHandlingEvent = false;
40
- return;
41
- }
42
- if (attempts < constants_3.FETCH_BACKOFF_MAX_RETRIES) {
43
- backoff.scheduleCall();
44
- return;
45
- }
46
- if (cdnBypass) {
47
- log.debug("No changes fetched after " + attempts + " attempts with CDN bypassed.");
48
- isHandlingEvent = false;
14
+ function SplitsUpdateWorker(log, storage, splitsSyncTask, splitsEventEmitter, telemetryTracker, segmentsSyncTask) {
15
+ var ff = SplitsUpdateWorker(storage.splits);
16
+ var rbs = SplitsUpdateWorker(storage.rbSegments);
17
+ function SplitsUpdateWorker(cache) {
18
+ var maxChangeNumber = -1;
19
+ var handleNewEvent = false;
20
+ var isHandlingEvent;
21
+ var cdnBypass;
22
+ var instantUpdate;
23
+ var backoff = new Backoff_1.Backoff(__handleSplitUpdateCall, constants_5.FETCH_BACKOFF_BASE, constants_5.FETCH_BACKOFF_MAX_WAIT);
24
+ function __handleSplitUpdateCall() {
25
+ isHandlingEvent = true;
26
+ if (maxChangeNumber > cache.getChangeNumber()) {
27
+ handleNewEvent = false;
28
+ // fetch splits revalidating data if cached
29
+ splitsSyncTask.execute(true, cdnBypass ? maxChangeNumber : undefined, instantUpdate).then(function () {
30
+ if (!isHandlingEvent)
31
+ return; // halt if `stop` has been called
32
+ if (handleNewEvent) {
33
+ __handleSplitUpdateCall();
49
34
  }
50
35
  else {
51
- backoff.reset();
52
- cdnBypass = true;
53
- __handleSplitUpdateCall();
36
+ if (instantUpdate)
37
+ telemetryTracker.trackUpdatesFromSSE(constants_3.SPLITS);
38
+ // fetch new registered segments for server-side API. Not retrying on error
39
+ if (segmentsSyncTask)
40
+ segmentsSyncTask.execute(true);
41
+ var attempts = backoff.attempts + 1;
42
+ if (ff.isSync() && rbs.isSync()) {
43
+ log.debug("Refresh completed" + (cdnBypass ? ' bypassing the CDN' : '') + " in " + attempts + " attempts.");
44
+ isHandlingEvent = false;
45
+ return;
46
+ }
47
+ if (attempts < constants_5.FETCH_BACKOFF_MAX_RETRIES) {
48
+ backoff.scheduleCall();
49
+ return;
50
+ }
51
+ if (cdnBypass) {
52
+ log.debug("No changes fetched after " + attempts + " attempts with CDN bypassed.");
53
+ isHandlingEvent = false;
54
+ }
55
+ else {
56
+ backoff.reset();
57
+ cdnBypass = true;
58
+ __handleSplitUpdateCall();
59
+ }
54
60
  }
55
- }
56
- });
57
- }
58
- else {
59
- isHandlingEvent = false;
60
- }
61
- }
62
- /**
63
- * Invoked by NotificationProcessor on SPLIT_UPDATE event
64
- *
65
- * @param changeNumber - change number of the SPLIT_UPDATE notification
66
- */
67
- function put(_a, _payload) {
68
- var changeNumber = _a.changeNumber, pcn = _a.pcn;
69
- var currentChangeNumber = splitsCache.getChangeNumber();
70
- if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber)
71
- return;
72
- maxChangeNumber = changeNumber;
73
- handleNewEvent = true;
74
- cdnBypass = false;
75
- payload = undefined;
76
- if (_payload && currentChangeNumber === pcn) {
77
- payload = _payload;
61
+ });
62
+ }
63
+ else {
64
+ isHandlingEvent = false;
65
+ }
78
66
  }
79
- if (backoff.timeoutID || !isHandlingEvent)
80
- __handleSplitUpdateCall();
81
- backoff.reset();
67
+ return {
68
+ /**
69
+ * Invoked by NotificationProcessor on SPLIT_UPDATE or RB_SEGMENT_UPDATE event
70
+ *
71
+ * @param changeNumber - change number of the notification
72
+ */
73
+ put: function (_a, payload) {
74
+ var changeNumber = _a.changeNumber, pcn = _a.pcn, type = _a.type;
75
+ var currentChangeNumber = cache.getChangeNumber();
76
+ if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber)
77
+ return;
78
+ maxChangeNumber = changeNumber;
79
+ handleNewEvent = true;
80
+ cdnBypass = false;
81
+ instantUpdate = undefined;
82
+ if (payload && currentChangeNumber === pcn) {
83
+ instantUpdate = { payload: payload, changeNumber: changeNumber, type: type };
84
+ }
85
+ if (backoff.timeoutID || !isHandlingEvent)
86
+ __handleSplitUpdateCall();
87
+ backoff.reset();
88
+ },
89
+ stop: function () {
90
+ isHandlingEvent = false;
91
+ backoff.reset();
92
+ },
93
+ isSync: function () {
94
+ return maxChangeNumber <= cache.getChangeNumber();
95
+ }
96
+ };
82
97
  }
83
98
  return {
84
- put: put,
99
+ put: function (parsedData) {
100
+ if (parsedData.d && parsedData.c !== undefined) {
101
+ try {
102
+ var payload = (0, parseUtils_1.parseFFUpdatePayload)(parsedData.c, parsedData.d);
103
+ if (payload) {
104
+ (parsedData.type === constants_4.RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData, payload);
105
+ return;
106
+ }
107
+ }
108
+ catch (e) {
109
+ log.warn(constants_1.STREAMING_PARSING_SPLIT_UPDATE, [parsedData.type, e]);
110
+ }
111
+ }
112
+ (parsedData.type === constants_4.RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData);
113
+ },
85
114
  /**
86
115
  * Invoked by NotificationProcessor on SPLIT_KILL event
87
116
  *
88
- * @param changeNumber - change number of the SPLIT_UPDATE notification
117
+ * @param changeNumber - change number of the notification
89
118
  * @param splitName - name of split to kill
90
119
  * @param defaultTreatment - default treatment value
91
120
  */
92
121
  killSplit: function (_a) {
93
122
  var changeNumber = _a.changeNumber, splitName = _a.splitName, defaultTreatment = _a.defaultTreatment;
94
- if (splitsCache.killLocally(splitName, defaultTreatment, changeNumber)) {
123
+ if (storage.splits.killLocally(splitName, defaultTreatment, changeNumber)) {
95
124
  // trigger an SDK_UPDATE if Split was killed locally
96
- splitsEventEmitter.emit(constants_1.SDK_SPLITS_ARRIVED, true);
125
+ splitsEventEmitter.emit(constants_2.SDK_SPLITS_ARRIVED, true);
97
126
  }
98
127
  // queues the SplitChanges fetch (only if changeNumber is newer)
99
- put({ changeNumber: changeNumber });
128
+ ff.put({ changeNumber: changeNumber });
100
129
  },
101
130
  stop: function () {
102
- isHandlingEvent = false;
103
- backoff.reset();
131
+ ff.stop();
132
+ rbs.stop();
104
133
  }
105
134
  };
106
135
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ControlType = exports.OCCUPANCY = exports.CONTROL = exports.SPLIT_UPDATE = exports.SPLIT_KILL = exports.SEGMENT_UPDATE = exports.MEMBERSHIPS_LS_UPDATE = exports.MEMBERSHIPS_MS_UPDATE = exports.PUSH_SUBSYSTEM_DOWN = exports.PUSH_SUBSYSTEM_UP = exports.PUSH_RETRYABLE_ERROR = exports.PUSH_NONRETRYABLE_ERROR = exports.SECONDS_BEFORE_EXPIRATION = void 0;
3
+ exports.ControlType = exports.OCCUPANCY = exports.CONTROL = exports.RB_SEGMENT_UPDATE = exports.SPLIT_UPDATE = exports.SPLIT_KILL = exports.SEGMENT_UPDATE = exports.MEMBERSHIPS_LS_UPDATE = exports.MEMBERSHIPS_MS_UPDATE = exports.PUSH_SUBSYSTEM_DOWN = exports.PUSH_SUBSYSTEM_UP = exports.PUSH_RETRYABLE_ERROR = exports.PUSH_NONRETRYABLE_ERROR = exports.SECONDS_BEFORE_EXPIRATION = void 0;
4
4
  // time for refresh token
5
5
  exports.SECONDS_BEFORE_EXPIRATION = 600;
6
6
  // Internal SDK events, subscribed by SyncManager and PushManager
@@ -30,6 +30,7 @@ exports.MEMBERSHIPS_LS_UPDATE = 'MEMBERSHIPS_LS_UPDATE';
30
30
  exports.SEGMENT_UPDATE = 'SEGMENT_UPDATE';
31
31
  exports.SPLIT_KILL = 'SPLIT_KILL';
32
32
  exports.SPLIT_UPDATE = 'SPLIT_UPDATE';
33
+ exports.RB_SEGMENT_UPDATE = 'RB_SEGMENT_UPDATE';
33
34
  // Control-type push notifications, handled by NotificationKeeper
34
35
  exports.CONTROL = 'CONTROL';
35
36
  exports.OCCUPANCY = 'OCCUPANCY';
@@ -46,7 +46,7 @@ function pushManagerFactory(params, pollingManager) {
46
46
  // MySegmentsUpdateWorker (client-side) are initiated in `add` method
47
47
  var segmentsUpdateWorker = userKey ? undefined : (0, SegmentsUpdateWorker_1.SegmentsUpdateWorker)(log, pollingManager.segmentsSyncTask, storage.segments);
48
48
  // For server-side we pass the segmentsSyncTask, used by SplitsUpdateWorker to fetch new segments
49
- var splitsUpdateWorker = (0, SplitsUpdateWorker_1.SplitsUpdateWorker)(log, storage.splits, pollingManager.splitsSyncTask, readiness.splits, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask);
49
+ var splitsUpdateWorker = (0, SplitsUpdateWorker_1.SplitsUpdateWorker)(log, storage, pollingManager.splitsSyncTask, readiness.splits, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask);
50
50
  // [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
51
51
  var userKeyHashes = {};
52
52
  // [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
@@ -182,21 +182,8 @@ function pushManagerFactory(params, pollingManager) {
182
182
  });
183
183
  /** Functions related to synchronization (Queues and Workers in the spec) */
184
184
  pushEmitter.on(constants_1.SPLIT_KILL, splitsUpdateWorker.killSplit);
185
- pushEmitter.on(constants_1.SPLIT_UPDATE, function (parsedData) {
186
- if (parsedData.d && parsedData.c !== undefined) {
187
- try {
188
- var payload = (0, parseUtils_1.parseFFUpdatePayload)(parsedData.c, parsedData.d);
189
- if (payload) {
190
- splitsUpdateWorker.put(parsedData, payload);
191
- return;
192
- }
193
- }
194
- catch (e) {
195
- log.warn(constants_2.STREAMING_PARSING_SPLIT_UPDATE, [e]);
196
- }
197
- }
198
- splitsUpdateWorker.put(parsedData);
199
- });
185
+ pushEmitter.on(constants_1.SPLIT_UPDATE, splitsUpdateWorker.put);
186
+ pushEmitter.on(constants_1.RB_SEGMENT_UPDATE, splitsUpdateWorker.put);
200
187
  function handleMySegmentsUpdate(parsedData) {
201
188
  switch (parsedData.u) {
202
189
  case types_1.UpdateStrategy.BoundedFetchRequest: {
@@ -125,7 +125,7 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
125
125
  if (pushManager) {
126
126
  if (pollingManager.isRunning()) {
127
127
  // if doing polling, we must start the periodic fetch of data
128
- if (storage.splits.usesSegments())
128
+ if (storage.splits.usesSegments() || storage.rbSegments.usesSegments())
129
129
  mySegmentsSyncTask.start();
130
130
  }
131
131
  else {
@@ -135,7 +135,7 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
135
135
  }
136
136
  }
137
137
  else {
138
- if (storage.splits.usesSegments())
138
+ if (storage.splits.usesSegments() || storage.rbSegments.usesSegments())
139
139
  mySegmentsSyncTask.start();
140
140
  }
141
141
  }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MEMBERSHIPS = exports.SEGMENT = exports.TOKEN = exports.TELEMETRY = exports.EVENTS = exports.IMPRESSIONS_COUNT = exports.IMPRESSIONS = exports.SPLITS = exports.NONE_ENUM = exports.DEBUG_ENUM = exports.OPTIMIZED_ENUM = exports.CONSUMER_PARTIAL_ENUM = exports.CONSUMER_ENUM = exports.STANDALONE_ENUM = exports.DEDUPED = exports.DROPPED = exports.QUEUED = exports.NAMES_FN_LABEL = exports.SPLITS_FN_LABEL = exports.SPLIT_FN_LABEL = exports.TRACK_FN_LABEL = exports.GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS = exports.GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET = exports.GET_TREATMENTS_BY_FLAG_SETS = exports.GET_TREATMENTS_BY_FLAG_SET = exports.GET_TREATMENTS_WITH_CONFIG = exports.GET_TREATMENT_WITH_CONFIG = exports.GET_TREATMENTS = exports.GET_TREATMENT = exports.CONSENT_UNKNOWN = exports.CONSENT_DECLINED = exports.CONSENT_GRANTED = exports.STORAGE_PLUGGABLE = exports.STORAGE_REDIS = exports.STORAGE_LOCALSTORAGE = exports.STORAGE_MEMORY = exports.CONSUMER_PARTIAL_MODE = exports.CONSUMER_MODE = exports.PRODUCER_MODE = exports.STANDALONE_MODE = exports.LOCALHOST_MODE = exports.NONE = exports.OPTIMIZED = exports.DEBUG = exports.SPLIT_EVENT = exports.SPLIT_IMPRESSION = exports.NA = exports.UNKNOWN = exports.CONTROL_WITH_CONFIG = exports.CONTROL = void 0;
4
- exports.IN_LARGE_SEGMENT = exports.IN_SEGMENT = exports.FLAG_SPEC_VERSION = exports.PAUSED = exports.ENABLED = exports.DISABLED = exports.NON_REQUESTED = exports.REQUESTED = exports.POLLING = exports.STREAMING = exports.AUTH_REJECTION = exports.SYNC_MODE_UPDATE = exports.ABLY_ERROR = exports.TOKEN_REFRESH = exports.SSE_CONNECTION_ERROR = exports.STREAMING_STATUS = exports.OCCUPANCY_SEC = exports.OCCUPANCY_PRI = exports.CONNECTION_ESTABLISHED = exports.TRACK = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSETS = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSET = exports.TREATMENTS_BY_FLAGSETS = exports.TREATMENTS_BY_FLAGSET = exports.TREATMENTS_WITH_CONFIG = exports.TREATMENT_WITH_CONFIG = exports.TREATMENTS = exports.TREATMENT = void 0;
4
+ exports.IN_RULE_BASED_SEGMENT = exports.IN_LARGE_SEGMENT = exports.IN_SEGMENT = exports.FLAG_SPEC_VERSION = exports.PAUSED = exports.ENABLED = exports.DISABLED = exports.NON_REQUESTED = exports.REQUESTED = exports.POLLING = exports.STREAMING = exports.AUTH_REJECTION = exports.SYNC_MODE_UPDATE = exports.ABLY_ERROR = exports.TOKEN_REFRESH = exports.SSE_CONNECTION_ERROR = exports.STREAMING_STATUS = exports.OCCUPANCY_SEC = exports.OCCUPANCY_PRI = exports.CONNECTION_ESTABLISHED = exports.TRACK = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSETS = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSET = exports.TREATMENTS_BY_FLAGSETS = exports.TREATMENTS_BY_FLAGSET = exports.TREATMENTS_WITH_CONFIG = exports.TREATMENT_WITH_CONFIG = exports.TREATMENTS = exports.TREATMENT = void 0;
5
5
  // Special treatments
6
6
  exports.CONTROL = 'control';
7
7
  exports.CONTROL_WITH_CONFIG = {
@@ -90,7 +90,8 @@ exports.NON_REQUESTED = 1;
90
90
  exports.DISABLED = 0;
91
91
  exports.ENABLED = 1;
92
92
  exports.PAUSED = 2;
93
- exports.FLAG_SPEC_VERSION = '1.2';
93
+ exports.FLAG_SPEC_VERSION = '1.3';
94
94
  // Matcher types
95
95
  exports.IN_SEGMENT = 'IN_SEGMENT';
96
96
  exports.IN_LARGE_SEGMENT = 'IN_LARGE_SEGMENT';
97
+ exports.IN_RULE_BASED_SEGMENT = 'IN_RULE_BASED_SEGMENT';
@@ -8,12 +8,8 @@ export function andCombinerContext(log, matchers) {
8
8
  log.debug(ENGINE_COMBINER_AND, [hasMatchedAll]);
9
9
  return hasMatchedAll;
10
10
  }
11
- return function andCombiner() {
12
- var params = [];
13
- for (var _i = 0; _i < arguments.length; _i++) {
14
- params[_i] = arguments[_i];
15
- }
16
- var matcherResults = matchers.map(function (matcher) { return matcher.apply(void 0, params); });
11
+ return function andCombiner(key, attributes, splitEvaluator) {
12
+ var matcherResults = matchers.map(function (matcher) { return matcher(key, attributes, splitEvaluator); });
17
13
  // If any matching result is a thenable we should use Promise.all
18
14
  if (findIndex(matcherResults, thenable) !== -1) {
19
15
  return Promise.all(matcherResults).then(andResults);
@@ -1,4 +1,4 @@
1
- import { findIndex } from '../../utils/lang';
1
+ import { findIndex, isBoolean } from '../../utils/lang';
2
2
  import { thenable } from '../../utils/promise/thenable';
3
3
  import { UNSUPPORTED_MATCHER_TYPE } from '../../utils/labels';
4
4
  import { CONTROL } from '../../utils/constants';
@@ -11,12 +11,12 @@ export function ifElseIfCombinerContext(log, predicates) {
11
11
  label: UNSUPPORTED_MATCHER_TYPE
12
12
  };
13
13
  }
14
- function computeTreatment(predicateResults) {
15
- var len = predicateResults.length;
16
- for (var i = 0; i < len; i++) {
14
+ function computeEvaluation(predicateResults) {
15
+ for (var i = 0, len = predicateResults.length; i < len; i++) {
17
16
  var evaluation = predicateResults[i];
18
17
  if (evaluation !== undefined) {
19
- log.debug(ENGINE_COMBINER_IFELSEIF, [evaluation.treatment]);
18
+ if (!isBoolean(evaluation))
19
+ log.debug(ENGINE_COMBINER_IFELSEIF, [evaluation.treatment]);
20
20
  return evaluation;
21
21
  }
22
22
  }
@@ -30,9 +30,9 @@ export function ifElseIfCombinerContext(log, predicates) {
30
30
  var predicateResults = predicates.map(function (evaluator) { return evaluator(key, seed, trafficAllocation, trafficAllocationSeed, attributes, splitEvaluator); });
31
31
  // if we find a thenable
32
32
  if (findIndex(predicateResults, thenable) !== -1) {
33
- return Promise.all(predicateResults).then(function (results) { return computeTreatment(results); });
33
+ return Promise.all(predicateResults).then(function (results) { return computeEvaluation(results); });
34
34
  }
35
- return computeTreatment(predicateResults);
35
+ return computeEvaluation(predicateResults);
36
36
  }
37
37
  // if there is none predicates, then there was an error in parsing phase
38
38
  if (!Array.isArray(predicates) || predicates.length === 0) {
@@ -4,11 +4,12 @@ import { NOT_IN_SPLIT } from '../../utils/labels';
4
4
  // Build Evaluation object if and only if matchingResult is true
5
5
  function match(log, matchingResult, bucketingKey, seed, treatments, label) {
6
6
  if (matchingResult) {
7
- var treatment = getTreatment(log, bucketingKey, seed, treatments);
8
- return {
9
- treatment: treatment,
10
- label: label
11
- };
7
+ return treatments ? // Feature flag
8
+ {
9
+ treatment: getTreatment(log, bucketingKey, seed, treatments),
10
+ label: label
11
+ } : // Rule-based segment
12
+ true;
12
13
  }
13
14
  // else we should notify the engine to continue evaluating
14
15
  return undefined;
@@ -26,12 +26,12 @@ export function evaluateFeature(log, key, splitName, attributes, storage) {
26
26
  return treatmentException;
27
27
  }
28
28
  if (thenable(parsedSplit)) {
29
- return parsedSplit.then(function (split) { return getEvaluation(log, split, key, attributes, storage); }).catch(
29
+ return parsedSplit.then(function (split) { return getEvaluation(log, key, split, attributes, storage); }).catch(
30
30
  // Exception on async `getSplit` storage. For example, when the storage is redis or
31
31
  // pluggable and there is a connection issue and we can't retrieve the split to be evaluated
32
32
  function () { return treatmentException; });
33
33
  }
34
- return getEvaluation(log, parsedSplit, key, attributes, storage);
34
+ return getEvaluation(log, key, parsedSplit, attributes, storage);
35
35
  }
36
36
  export function evaluateFeatures(log, key, splitNames, attributes, storage) {
37
37
  var parsedSplits;
@@ -43,13 +43,13 @@ export function evaluateFeatures(log, key, splitNames, attributes, storage) {
43
43
  return treatmentsException(splitNames);
44
44
  }
45
45
  return thenable(parsedSplits) ?
46
- parsedSplits.then(function (splits) { return getEvaluations(log, splitNames, splits, key, attributes, storage); })
46
+ parsedSplits.then(function (splits) { return getEvaluations(log, key, splitNames, splits, attributes, storage); })
47
47
  .catch(function () {
48
48
  // Exception on async `getSplits` storage. For example, when the storage is redis or
49
49
  // pluggable and there is a connection issue and we can't retrieve the split to be evaluated
50
50
  return treatmentsException(splitNames);
51
51
  }) :
52
- getEvaluations(log, splitNames, parsedSplits, key, attributes, storage);
52
+ getEvaluations(log, key, splitNames, parsedSplits, attributes, storage);
53
53
  }
54
54
  export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method) {
55
55
  var storedFlagNames;
@@ -84,7 +84,7 @@ export function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, stora
84
84
  }) :
85
85
  evaluate(storedFlagNames);
86
86
  }
87
- function getEvaluation(log, splitJSON, key, attributes, storage) {
87
+ function getEvaluation(log, key, splitJSON, attributes, storage) {
88
88
  var evaluation = {
89
89
  treatment: CONTROL,
90
90
  label: SPLIT_NOT_FOUND,
@@ -110,11 +110,11 @@ function getEvaluation(log, splitJSON, key, attributes, storage) {
110
110
  }
111
111
  return evaluation;
112
112
  }
113
- function getEvaluations(log, splitNames, splits, key, attributes, storage) {
113
+ function getEvaluations(log, key, splitNames, splits, attributes, storage) {
114
114
  var result = {};
115
115
  var thenables = [];
116
116
  splitNames.forEach(function (splitName) {
117
- var evaluation = getEvaluation(log, splits[splitName], key, attributes, storage);
117
+ var evaluation = getEvaluation(log, key, splits[splitName], attributes, storage);
118
118
  if (thenable(evaluation)) {
119
119
  thenables.push(evaluation.then(function (res) {
120
120
  result[splitName] = res;