@splitsoftware/splitio-commons 2.2.1-rc.3 → 2.2.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 (152) hide show
  1. package/CHANGES.txt +5 -2
  2. package/README.md +1 -0
  3. package/cjs/consent/sdkUserConsent.js +5 -3
  4. package/cjs/evaluator/combiners/and.js +2 -6
  5. package/cjs/evaluator/combiners/ifelseif.js +6 -6
  6. package/cjs/evaluator/condition/index.js +6 -5
  7. package/cjs/evaluator/index.js +7 -7
  8. package/cjs/evaluator/matchers/index.js +3 -1
  9. package/cjs/evaluator/matchers/matcherTypes.js +1 -0
  10. package/cjs/evaluator/matchers/rbsegment.js +56 -0
  11. package/cjs/evaluator/matchersTransform/index.js +4 -0
  12. package/cjs/evaluator/parser/index.js +2 -2
  13. package/cjs/evaluator/value/sanitize.js +1 -0
  14. package/cjs/listeners/browser.js +2 -5
  15. package/cjs/logger/constants.js +4 -3
  16. package/cjs/logger/messages/debug.js +3 -2
  17. package/cjs/logger/messages/warn.js +1 -1
  18. package/cjs/services/splitApi.js +3 -4
  19. package/cjs/services/splitHttpClient.js +3 -1
  20. package/cjs/storages/AbstractSplitsCacheSync.js +5 -2
  21. package/cjs/storages/KeyBuilder.js +9 -0
  22. package/cjs/storages/KeyBuilderCS.js +3 -0
  23. package/cjs/storages/KeyBuilderSS.js +3 -0
  24. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +117 -0
  25. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +9 -14
  26. package/cjs/storages/inLocalStorage/index.js +5 -1
  27. package/cjs/storages/inLocalStorage/validateCache.js +2 -1
  28. package/cjs/storages/inMemory/InMemoryStorage.js +3 -0
  29. package/cjs/storages/inMemory/InMemoryStorageCS.js +4 -0
  30. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +61 -0
  31. package/cjs/storages/inMemory/SplitsCacheInMemory.js +1 -0
  32. package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +64 -0
  33. package/cjs/storages/inRedis/index.js +5 -3
  34. package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +64 -0
  35. package/cjs/storages/pluggable/index.js +2 -0
  36. package/cjs/sync/polling/fetchers/splitChangesFetcher.js +54 -4
  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 +59 -33
  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 +6 -2
  48. package/esm/consent/sdkUserConsent.js +5 -3
  49. package/esm/evaluator/combiners/and.js +2 -6
  50. package/esm/evaluator/combiners/ifelseif.js +7 -7
  51. package/esm/evaluator/condition/index.js +6 -5
  52. package/esm/evaluator/index.js +7 -7
  53. package/esm/evaluator/matchers/index.js +3 -1
  54. package/esm/evaluator/matchers/matcherTypes.js +1 -0
  55. package/esm/evaluator/matchers/rbsegment.js +52 -0
  56. package/esm/evaluator/matchersTransform/index.js +4 -0
  57. package/esm/evaluator/parser/index.js +2 -2
  58. package/esm/evaluator/value/sanitize.js +1 -0
  59. package/esm/listeners/browser.js +2 -5
  60. package/esm/logger/constants.js +1 -0
  61. package/esm/logger/messages/debug.js +3 -2
  62. package/esm/logger/messages/warn.js +1 -1
  63. package/esm/services/splitApi.js +3 -4
  64. package/esm/services/splitHttpClient.js +3 -1
  65. package/esm/storages/AbstractSplitsCacheSync.js +5 -2
  66. package/esm/storages/KeyBuilder.js +9 -0
  67. package/esm/storages/KeyBuilderCS.js +3 -0
  68. package/esm/storages/KeyBuilderSS.js +3 -0
  69. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +114 -0
  70. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +9 -14
  71. package/esm/storages/inLocalStorage/index.js +5 -1
  72. package/esm/storages/inLocalStorage/validateCache.js +2 -1
  73. package/esm/storages/inMemory/InMemoryStorage.js +3 -0
  74. package/esm/storages/inMemory/InMemoryStorageCS.js +4 -0
  75. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +58 -0
  76. package/esm/storages/inMemory/SplitsCacheInMemory.js +1 -0
  77. package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +61 -0
  78. package/esm/storages/inRedis/index.js +5 -3
  79. package/esm/storages/pluggable/RBSegmentsCachePluggable.js +61 -0
  80. package/esm/storages/pluggable/index.js +2 -0
  81. package/esm/sync/polling/fetchers/splitChangesFetcher.js +54 -4
  82. package/esm/sync/polling/pollingManagerCS.js +7 -7
  83. package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  84. package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
  85. package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  86. package/esm/sync/polling/updaters/splitChangesUpdater.js +59 -33
  87. package/esm/sync/streaming/SSEHandler/index.js +2 -1
  88. package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +102 -73
  89. package/esm/sync/streaming/constants.js +1 -0
  90. package/esm/sync/streaming/pushManager.js +6 -19
  91. package/esm/sync/syncManagerOnline.js +2 -2
  92. package/esm/utils/constants/index.js +5 -1
  93. package/package.json +1 -1
  94. package/src/consent/sdkUserConsent.ts +3 -2
  95. package/src/dtos/types.ts +37 -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 +74 -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/listeners/browser.ts +2 -3
  111. package/src/logger/constants.ts +1 -0
  112. package/src/logger/messages/debug.ts +3 -2
  113. package/src/logger/messages/warn.ts +1 -1
  114. package/src/sdkManager/index.ts +1 -1
  115. package/src/services/splitApi.ts +3 -4
  116. package/src/services/splitHttpClient.ts +3 -1
  117. package/src/services/types.ts +1 -1
  118. package/src/storages/AbstractSplitsCacheSync.ts +6 -3
  119. package/src/storages/KeyBuilder.ts +12 -0
  120. package/src/storages/KeyBuilderCS.ts +4 -0
  121. package/src/storages/KeyBuilderSS.ts +4 -0
  122. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +136 -0
  123. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +10 -14
  124. package/src/storages/inLocalStorage/index.ts +5 -1
  125. package/src/storages/inLocalStorage/validateCache.ts +3 -1
  126. package/src/storages/inMemory/InMemoryStorage.ts +3 -0
  127. package/src/storages/inMemory/InMemoryStorageCS.ts +4 -0
  128. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +68 -0
  129. package/src/storages/inMemory/SplitsCacheInMemory.ts +1 -0
  130. package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +79 -0
  131. package/src/storages/inRedis/index.ts +5 -3
  132. package/src/storages/pluggable/RBSegmentsCachePluggable.ts +76 -0
  133. package/src/storages/pluggable/index.ts +2 -0
  134. package/src/storages/types.ts +33 -1
  135. package/src/sync/polling/fetchers/splitChangesFetcher.ts +65 -4
  136. package/src/sync/polling/fetchers/types.ts +1 -0
  137. package/src/sync/polling/pollingManagerCS.ts +7 -7
  138. package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -1
  139. package/src/sync/polling/types.ts +2 -2
  140. package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -2
  141. package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
  142. package/src/sync/polling/updaters/splitChangesUpdater.ts +70 -43
  143. package/src/sync/streaming/SSEHandler/index.ts +2 -1
  144. package/src/sync/streaming/SSEHandler/types.ts +2 -2
  145. package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +98 -68
  146. package/src/sync/streaming/constants.ts +1 -0
  147. package/src/sync/streaming/parseUtils.ts +2 -2
  148. package/src/sync/streaming/pushManager.ts +6 -18
  149. package/src/sync/streaming/types.ts +3 -2
  150. package/src/sync/syncManagerOnline.ts +2 -2
  151. package/src/utils/constants/index.ts +6 -1
  152. package/src/utils/lang/index.ts +1 -1
package/CHANGES.txt CHANGED
@@ -1,5 +1,8 @@
1
- 2.2.1 (May 7, 2025)
2
- - Updated Redis storage to avoid lazy require of the `ioredis` dependency when the SDK is initialized.
1
+ 2.3.0 (May 12, 2025)
2
+ - Added support for targeting rules based on rule-based segments.
3
+ - Updated the Redis storage to:
4
+ - Avoid lazy require of the `ioredis` dependency when the SDK is initialized, and
5
+ - Flag the SDK as ready from cache immediately to allow queueing feature flag evaluations before SDK_READY event is emitted (Reverted in v1.7.0).
3
6
 
4
7
  2.2.0 (March 28, 2025)
5
8
  - Added a new optional argument to the client `getTreatment` methods to allow passing additional evaluation options, such as a map of properties to append to the generated impressions sent to Split backend. Read more in our docs.
package/README.md CHANGED
@@ -27,6 +27,7 @@ Split has built and maintains SDKs for:
27
27
  * .NET [Github](https://github.com/splitio/dotnet-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK)
28
28
  * Android [Github](https://github.com/splitio/android-client) [Docs](https://help.split.io/hc/en-us/articles/360020343291-Android-SDK)
29
29
  * Angular [Github](https://github.com/splitio/angular-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/6495326064397-Angular-utilities)
30
+ * Elixir thin-client [Github](https://github.com/splitio/elixir-thin-client) [Docs](https://help.split.io/hc/en-us/articles/26988707417869-Elixir-Thin-Client-SDK)
30
31
  * Flutter [Github](https://github.com/splitio/flutter-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/8096158017165-Flutter-plugin)
31
32
  * GO [Github](https://github.com/splitio/go-client) [Docs](https://help.split.io/hc/en-us/articles/360020093652-Go-SDK)
32
33
  * iOS [Github](https://github.com/splitio/ios-client) [Docs](https://help.split.io/hc/en-us/articles/360020401491-iOS-SDK)
@@ -15,7 +15,7 @@ var ConsentStatus = {
15
15
  * The public user consent API exposed via SplitFactory, used to control if the SDK tracks and sends impressions and events or not.
16
16
  */
17
17
  function createUserConsentAPI(params) {
18
- var settings = params.settings, log = params.settings.log, syncManager = params.syncManager, _a = params.storage, events = _a.events, impressions = _a.impressions, impressionCounts = _a.impressionCounts;
18
+ var settings = params.settings, log = params.settings.log, syncManager = params.syncManager, _a = params.storage, events = _a.events, impressions = _a.impressions, impressionCounts = _a.impressionCounts, uniqueKeys = _a.uniqueKeys;
19
19
  if (!(0, index_1.isConsentGranted)(settings))
20
20
  log.info(constants_1.USER_CONSENT_INITIAL, [settings.userConsent]);
21
21
  return {
@@ -40,8 +40,10 @@ function createUserConsentAPI(params) {
40
40
  events.clear(); // @ts-ignore
41
41
  if (impressions.clear)
42
42
  impressions.clear(); // @ts-ignore
43
- if (impressionCounts && impressionCounts.clear)
44
- impressionCounts.clear();
43
+ if (impressionCounts.clear)
44
+ impressionCounts.clear(); // @ts-ignore
45
+ if (uniqueKeys.clear)
46
+ uniqueKeys.clear();
45
47
  }
46
48
  }
47
49
  else {
@@ -11,12 +11,8 @@ function andCombinerContext(log, matchers) {
11
11
  log.debug(constants_1.ENGINE_COMBINER_AND, [hasMatchedAll]);
12
12
  return hasMatchedAll;
13
13
  }
14
- return function andCombiner() {
15
- var params = [];
16
- for (var _i = 0; _i < arguments.length; _i++) {
17
- params[_i] = arguments[_i];
18
- }
19
- var matcherResults = matchers.map(function (matcher) { return matcher.apply(void 0, params); });
14
+ return function andCombiner(key, attributes, splitEvaluator) {
15
+ var matcherResults = matchers.map(function (matcher) { return matcher(key, attributes, splitEvaluator); });
20
16
  // If any matching result is a thenable we should use Promise.all
21
17
  if ((0, lang_1.findIndex)(matcherResults, thenable_1.thenable) !== -1) {
22
18
  return Promise.all(matcherResults).then(andResults);
@@ -14,12 +14,12 @@ function ifElseIfCombinerContext(log, predicates) {
14
14
  label: labels_1.UNSUPPORTED_MATCHER_TYPE
15
15
  };
16
16
  }
17
- function computeTreatment(predicateResults) {
18
- var len = predicateResults.length;
19
- for (var i = 0; i < len; i++) {
17
+ function computeEvaluation(predicateResults) {
18
+ for (var i = 0, len = predicateResults.length; i < len; i++) {
20
19
  var evaluation = predicateResults[i];
21
20
  if (evaluation !== undefined) {
22
- log.debug(constants_2.ENGINE_COMBINER_IFELSEIF, [evaluation.treatment]);
21
+ if (!(0, lang_1.isBoolean)(evaluation))
22
+ log.debug(constants_2.ENGINE_COMBINER_IFELSEIF, [evaluation.treatment]);
23
23
  return evaluation;
24
24
  }
25
25
  }
@@ -33,9 +33,9 @@ function ifElseIfCombinerContext(log, predicates) {
33
33
  var predicateResults = predicates.map(function (evaluator) { return evaluator(key, seed, trafficAllocation, trafficAllocationSeed, attributes, splitEvaluator); });
34
34
  // if we find a thenable
35
35
  if ((0, lang_1.findIndex)(predicateResults, thenable_1.thenable) !== -1) {
36
- return Promise.all(predicateResults).then(function (results) { return computeTreatment(results); });
36
+ return Promise.all(predicateResults).then(function (results) { return computeEvaluation(results); });
37
37
  }
38
- return computeTreatment(predicateResults);
38
+ return computeEvaluation(predicateResults);
39
39
  }
40
40
  // if there is none predicates, then there was an error in parsing phase
41
41
  if (!Array.isArray(predicates) || predicates.length === 0) {
@@ -7,11 +7,12 @@ var labels_1 = require("../../utils/labels");
7
7
  // Build Evaluation object if and only if matchingResult is true
8
8
  function match(log, matchingResult, bucketingKey, seed, treatments, label) {
9
9
  if (matchingResult) {
10
- var treatment = (0, engineUtils_1.getTreatment)(log, bucketingKey, seed, treatments);
11
- return {
12
- treatment: treatment,
13
- label: label
14
- };
10
+ return treatments ? // Feature flag
11
+ {
12
+ treatment: (0, engineUtils_1.getTreatment)(log, bucketingKey, seed, treatments),
13
+ label: label
14
+ } : // Rule-based segment
15
+ true;
15
16
  }
16
17
  // else we should notify the engine to continue evaluating
17
18
  return undefined;
@@ -29,12 +29,12 @@ function evaluateFeature(log, key, splitName, attributes, storage) {
29
29
  return treatmentException;
30
30
  }
31
31
  if ((0, thenable_1.thenable)(parsedSplit)) {
32
- return parsedSplit.then(function (split) { return getEvaluation(log, split, key, attributes, storage); }).catch(
32
+ return parsedSplit.then(function (split) { return getEvaluation(log, key, split, attributes, storage); }).catch(
33
33
  // Exception on async `getSplit` storage. For example, when the storage is redis or
34
34
  // pluggable and there is a connection issue and we can't retrieve the split to be evaluated
35
35
  function () { return treatmentException; });
36
36
  }
37
- return getEvaluation(log, parsedSplit, key, attributes, storage);
37
+ return getEvaluation(log, key, parsedSplit, attributes, storage);
38
38
  }
39
39
  exports.evaluateFeature = evaluateFeature;
40
40
  function evaluateFeatures(log, key, splitNames, attributes, storage) {
@@ -47,13 +47,13 @@ function evaluateFeatures(log, key, splitNames, attributes, storage) {
47
47
  return treatmentsException(splitNames);
48
48
  }
49
49
  return (0, thenable_1.thenable)(parsedSplits) ?
50
- parsedSplits.then(function (splits) { return getEvaluations(log, splitNames, splits, key, attributes, storage); })
50
+ parsedSplits.then(function (splits) { return getEvaluations(log, key, splitNames, splits, attributes, storage); })
51
51
  .catch(function () {
52
52
  // Exception on async `getSplits` storage. For example, when the storage is redis or
53
53
  // pluggable and there is a connection issue and we can't retrieve the split to be evaluated
54
54
  return treatmentsException(splitNames);
55
55
  }) :
56
- getEvaluations(log, splitNames, parsedSplits, key, attributes, storage);
56
+ getEvaluations(log, key, splitNames, parsedSplits, attributes, storage);
57
57
  }
58
58
  exports.evaluateFeatures = evaluateFeatures;
59
59
  function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, method) {
@@ -90,7 +90,7 @@ function evaluateFeaturesByFlagSets(log, key, flagSets, attributes, storage, met
90
90
  evaluate(storedFlagNames);
91
91
  }
92
92
  exports.evaluateFeaturesByFlagSets = evaluateFeaturesByFlagSets;
93
- function getEvaluation(log, splitJSON, key, attributes, storage) {
93
+ function getEvaluation(log, key, splitJSON, attributes, storage) {
94
94
  var evaluation = {
95
95
  treatment: constants_1.CONTROL,
96
96
  label: labels_1.SPLIT_NOT_FOUND,
@@ -116,11 +116,11 @@ function getEvaluation(log, splitJSON, key, attributes, storage) {
116
116
  }
117
117
  return evaluation;
118
118
  }
119
- function getEvaluations(log, splitNames, splits, key, attributes, storage) {
119
+ function getEvaluations(log, key, splitNames, splits, attributes, storage) {
120
120
  var result = {};
121
121
  var thenables = [];
122
122
  splitNames.forEach(function (splitName) {
123
- var evaluation = getEvaluation(log, splits[splitName], key, attributes, storage);
123
+ var evaluation = getEvaluation(log, key, splits[splitName], attributes, storage);
124
124
  if ((0, thenable_1.thenable)(evaluation)) {
125
125
  thenables.push(evaluation.then(function (res) {
126
126
  result[splitName] = res;
@@ -24,6 +24,7 @@ var semver_gte_1 = require("./semver_gte");
24
24
  var semver_lte_1 = require("./semver_lte");
25
25
  var semver_between_1 = require("./semver_between");
26
26
  var semver_inlist_1 = require("./semver_inlist");
27
+ var rbsegment_1 = require("./rbsegment");
27
28
  var matchers = [
28
29
  undefined,
29
30
  all_1.allMatcherContext,
@@ -48,7 +49,8 @@ var matchers = [
48
49
  semver_lte_1.lessThanEqualToSemverMatcherContext,
49
50
  semver_between_1.betweenSemverMatcherContext,
50
51
  semver_inlist_1.inListSemverMatcherContext,
51
- large_segment_1.largeSegmentMatcherContext, // IN_LARGE_SEGMENT: 23
52
+ large_segment_1.largeSegmentMatcherContext,
53
+ rbsegment_1.ruleBasedSegmentMatcherContext // IN_RULE_BASED_SEGMENT: 24
52
54
  ];
53
55
  /**
54
56
  * Matcher factory.
@@ -26,6 +26,7 @@ exports.matcherTypes = {
26
26
  BETWEEN_SEMVER: 21,
27
27
  IN_LIST_SEMVER: 22,
28
28
  IN_LARGE_SEGMENT: 23,
29
+ IN_RULE_BASED_SEGMENT: 24,
29
30
  };
30
31
  exports.matcherDataTypes = {
31
32
  BOOLEAN: 'BOOLEAN',
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ruleBasedSegmentMatcherContext = void 0;
4
+ var thenable_1 = require("../../utils/promise/thenable");
5
+ var key_1 = require("../../utils/key");
6
+ var parser_1 = require("../parser");
7
+ var constants_1 = require("../../utils/constants");
8
+ function ruleBasedSegmentMatcherContext(segmentName, storage, log) {
9
+ return function ruleBasedSegmentMatcher(_a, splitEvaluator) {
10
+ var key = _a.key, attributes = _a.attributes;
11
+ var matchingKey = (0, key_1.getMatching)(key);
12
+ function matchConditions(rbsegment) {
13
+ var conditions = rbsegment.conditions || [];
14
+ if (!conditions.length)
15
+ return false;
16
+ var evaluator = (0, parser_1.parser)(log, conditions, storage);
17
+ var evaluation = evaluator((0, key_1.keyParser)(key), undefined, undefined, undefined, attributes, splitEvaluator);
18
+ return (0, thenable_1.thenable)(evaluation) ?
19
+ evaluation.then(function (evaluation) { return evaluation ? true : false; }) :
20
+ evaluation ? true : false;
21
+ }
22
+ function isInExcludedSegment(_a) {
23
+ var type = _a.type, name = _a.name;
24
+ return type === constants_1.STANDARD_SEGMENT ?
25
+ storage.segments.isInSegment(name, matchingKey) :
26
+ type === constants_1.RULE_BASED_SEGMENT ?
27
+ ruleBasedSegmentMatcherContext(name, storage, log)({ key: key, attributes: attributes }, splitEvaluator) :
28
+ type === constants_1.LARGE_SEGMENT && storage.largeSegments ?
29
+ storage.largeSegments.isInSegment(name, matchingKey) :
30
+ false;
31
+ }
32
+ function isExcluded(rbSegment) {
33
+ var excluded = rbSegment.excluded || {};
34
+ if (excluded.keys && excluded.keys.indexOf(matchingKey) !== -1)
35
+ return true;
36
+ return (excluded.segments || []).reduce(function (result, excludedSegment) {
37
+ return (0, thenable_1.thenable)(result) ?
38
+ result.then(function (result) { return result || isInExcludedSegment(excludedSegment); }) :
39
+ result || isInExcludedSegment(excludedSegment);
40
+ }, false);
41
+ }
42
+ function isInRBSegment(rbSegment) {
43
+ if (!rbSegment)
44
+ return false;
45
+ var excluded = isExcluded(rbSegment);
46
+ return (0, thenable_1.thenable)(excluded) ?
47
+ excluded.then(function (excluded) { return excluded ? false : matchConditions(rbSegment); }) :
48
+ excluded ? false : matchConditions(rbSegment);
49
+ }
50
+ var rbSegment = storage.rbSegments.get(segmentName);
51
+ return (0, thenable_1.thenable)(rbSegment) ?
52
+ rbSegment.then(isInRBSegment) :
53
+ isInRBSegment(rbSegment);
54
+ };
55
+ }
56
+ exports.ruleBasedSegmentMatcherContext = ruleBasedSegmentMatcherContext;
@@ -81,6 +81,10 @@ function matchersTransform(matchers) {
81
81
  type === matcherTypes_1.matcherTypes.LESS_THAN_OR_EQUAL_TO_SEMVER) {
82
82
  value = stringMatcherData;
83
83
  }
84
+ else if (type === matcherTypes_1.matcherTypes.IN_RULE_BASED_SEGMENT) {
85
+ value = (0, segment_1.segmentTransform)(userDefinedSegmentMatcherData);
86
+ dataType = matcherTypes_1.matcherDataTypes.NOT_SPECIFIED;
87
+ }
84
88
  return {
85
89
  attribute: attribute,
86
90
  negate: negate,
@@ -53,9 +53,9 @@ function parser(log, conditions, storage) {
53
53
  // and break the loop
54
54
  break;
55
55
  }
56
- predicates.push((0, condition_1.conditionContext)(log, (0, and_1.andCombinerContext)(log, expressions), treatments_1.Treatments.parse(partitions), label, conditionType));
56
+ predicates.push((0, condition_1.conditionContext)(log, (0, and_1.andCombinerContext)(log, expressions), partitions && treatments_1.Treatments.parse(partitions), label, conditionType));
57
57
  }
58
- // Instanciate evaluator given the set of conditions using if else if logic
58
+ // Instantiate evaluator given the set of conditions using if else if logic
59
59
  return (0, ifelseif_1.ifElseIfCombinerContext)(log, predicates);
60
60
  }
61
61
  exports.parser = parser;
@@ -52,6 +52,7 @@ function getProcessingFunction(matcherTypeID, dataType) {
52
52
  case matcherTypes_1.matcherTypes.BETWEEN:
53
53
  return dataType === 'DATETIME' ? convertions_1.zeroSinceSS : undefined;
54
54
  case matcherTypes_1.matcherTypes.IN_SPLIT_TREATMENT:
55
+ case matcherTypes_1.matcherTypes.IN_RULE_BASED_SEGMENT:
55
56
  return dependencyProcessor;
56
57
  default:
57
58
  return undefined;
@@ -68,11 +68,8 @@ var BrowserSignalListener = /** @class */ (function () {
68
68
  };
69
69
  this._flushData(events + '/testImpressions/beacon', this.storage.impressions, this.serviceApi.postTestImpressionsBulk, this.fromImpressionsCollector, extraMetadata);
70
70
  this._flushData(events + '/events/beacon', this.storage.events, this.serviceApi.postEventsBulk);
71
- if (this.storage.impressionCounts)
72
- this._flushData(events + '/testImpressions/count/beacon', this.storage.impressionCounts, this.serviceApi.postTestImpressionsCount, impressionCountsSubmitter_1.fromImpressionCountsCollector);
73
- // @ts-ignore
74
- if (this.storage.uniqueKeys)
75
- this._flushData(telemetry + '/v1/keys/cs/beacon', this.storage.uniqueKeys, this.serviceApi.postUniqueKeysBulkCs);
71
+ this._flushData(events + '/testImpressions/count/beacon', this.storage.impressionCounts, this.serviceApi.postTestImpressionsCount, impressionCountsSubmitter_1.fromImpressionCountsCollector);
72
+ this._flushData(telemetry + '/v1/keys/cs/beacon', this.storage.uniqueKeys, this.serviceApi.postUniqueKeysBulkCs);
76
73
  }
77
74
  // Flush telemetry data
78
75
  if (this.storage.telemetry)
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CLIENT_NO_LISTENER = exports.ENGINE_VALUE_NO_ATTRIBUTES = exports.ENGINE_VALUE_INVALID = exports.USER_CONSENT_INITIAL = exports.USER_CONSENT_NOT_UPDATED = exports.USER_CONSENT_UPDATED = exports.IMPRESSIONS_TRACKER_SUCCESS = exports.EVENTS_TRACKER_SUCCESS = exports.SYNC_STOP_POLLING = exports.SYNC_CONTINUE_POLLING = exports.SYNC_START_POLLING = exports.SUBMITTERS_PUSH = exports.SUBMITTERS_PUSH_FULL_QUEUE = exports.STREAMING_DISCONNECTING = exports.STREAMING_DISABLED = exports.STREAMING_CONNECTING = exports.STREAMING_RECONNECT = exports.STREAMING_REFRESH_TOKEN = exports.SYNC_SPLITS_FETCH_RETRY = exports.POLLING_STOP = exports.POLLING_START = exports.POLLING_SMART_PAUSING = exports.NEW_FACTORY = exports.NEW_SHARED_CLIENT = exports.IMPRESSION_QUEUEING = exports.IMPRESSION = exports.CLIENT_READY = exports.CLIENT_READY_FROM_CACHE = exports.ENGINE_MATCHER_RESULT = exports.SETTINGS_SPLITS_FILTER = exports.SYNC_TASK_STOP = exports.SYNC_TASK_EXECUTE = exports.SYNC_TASK_START = exports.STREAMING_NEW_MESSAGE = exports.SYNC_SPLITS_UPDATE = exports.SYNC_SPLITS_FETCH = exports.SYNC_OFFLINE_DATA = exports.RETRIEVE_MANAGER = exports.RETRIEVE_CLIENT_EXISTING = exports.RETRIEVE_CLIENT_DEFAULT = exports.CLEANUP_DEREGISTERING = exports.CLEANUP_REGISTERING = exports.ENGINE_SANITIZE = exports.ENGINE_VALUE = exports.ENGINE_MATCHER_DEPENDENCY_PRE = exports.ENGINE_MATCHER_DEPENDENCY = exports.ENGINE_BUCKET = exports.ENGINE_COMBINER_IFELSEIF_NO_TREATMENT = exports.ENGINE_COMBINER_IFELSEIF = exports.ENGINE_COMBINER_AND = void 0;
4
- exports.ERROR_STORAGE_INVALID = exports.ERROR_HTTP = exports.ERROR_INVALID_CONFIG_PARAM = exports.ERROR_EMPTY_ARRAY = exports.ERROR_EMPTY = exports.ERROR_INVALID = exports.ERROR_INVALID_KEY_OBJECT = exports.ERROR_TOO_LONG = exports.ERROR_NULL = exports.ERROR_CLIENT_DESTROYED = exports.ERROR_NOT_FINITE = exports.ERROR_SIZE_EXCEEDED = exports.ERROR_NOT_PLAIN_OBJECT = exports.ERROR_EVENT_TYPE_FORMAT = exports.ERROR_EVENTS_TRACKER = exports.ERROR_IMPRESSIONS_LISTENER = exports.ERROR_IMPRESSIONS_TRACKER = exports.ERROR_STREAMING_AUTH = exports.ERROR_STREAMING_SSE = exports.ERROR_SYNC_OFFLINE_LOADING = exports.ERROR_CLIENT_CANNOT_GET_READY = exports.ERROR_CLIENT_LISTENER = exports.ERROR_LOGLEVEL_INVALID = exports.ERROR_ENGINE_COMBINER_IFELSEIF = exports.WARN_FLAGSET_WITHOUT_FLAGS = exports.WARN_FLAGSET_NOT_CONFIGURED = exports.WARN_LOWERCASE_FLAGSET = exports.WARN_INVALID_FLAGSET = exports.STREAMING_PARSING_SPLIT_UPDATE = exports.STREAMING_PARSING_MEMBERSHIPS_UPDATE = exports.WARN_SDK_KEY = exports.WARN_SPLITS_FILTER_EMPTY = exports.WARN_SPLITS_FILTER_INVALID = exports.WARN_SPLITS_FILTER_IGNORED = exports.WARN_INTEGRATION_INVALID = exports.WARN_NOT_EXISTENT_TT = exports.WARN_LOWERCASE_TRAFFIC_TYPE = exports.WARN_NOT_EXISTENT_SPLIT = exports.WARN_TRIMMING = exports.WARN_CONVERTING = exports.WARN_TRIMMING_PROPERTIES = exports.WARN_SETTING_NULL = exports.SUBMITTERS_PUSH_RETRY = exports.SUBMITTERS_PUSH_FAILS = exports.STREAMING_FALLBACK = exports.STREAMING_PARSING_MESSAGE_FAILS = exports.STREAMING_PARSING_ERROR_FAILS = exports.SYNC_SPLITS_FETCH_FAILS = exports.SYNC_MYSEGMENTS_FETCH_RETRY = exports.CLIENT_NOT_READY = void 0;
5
- exports.LOG_PREFIX_CLEANUP = exports.LOG_PREFIX_UNIQUE_KEYS_TRACKER = exports.LOG_PREFIX_EVENTS_TRACKER = exports.LOG_PREFIX_IMPRESSIONS_TRACKER = exports.LOG_PREFIX_SYNC_SUBMITTERS = exports.LOG_PREFIX_SYNC_POLLING = exports.LOG_PREFIX_SYNC_MYSEGMENTS = exports.LOG_PREFIX_SYNC_SEGMENTS = exports.LOG_PREFIX_SYNC_SPLITS = exports.LOG_PREFIX_SYNC_STREAMING = exports.LOG_PREFIX_SYNC_OFFLINE = exports.LOG_PREFIX_SYNC_MANAGER = exports.LOG_PREFIX_SYNC = exports.LOG_PREFIX_ENGINE_VALUE = exports.LOG_PREFIX_ENGINE_MATCHER = exports.LOG_PREFIX_ENGINE_COMBINER = exports.LOG_PREFIX_ENGINE = exports.LOG_PREFIX_CLIENT_INSTANTIATION = exports.LOG_PREFIX_INSTANTIATION = exports.LOG_PREFIX_SETTINGS = exports.ENGINE_MATCHER_ERROR = exports.ERROR_SETS_FILTER_EXCLUSIVE = exports.ERROR_TOO_MANY_SETS = exports.ERROR_MIN_CONFIG_PARAM = exports.ERROR_NOT_BOOLEAN = void 0;
3
+ exports.ENGINE_VALUE_NO_ATTRIBUTES = exports.ENGINE_VALUE_INVALID = exports.USER_CONSENT_INITIAL = exports.USER_CONSENT_NOT_UPDATED = exports.USER_CONSENT_UPDATED = exports.IMPRESSIONS_TRACKER_SUCCESS = exports.EVENTS_TRACKER_SUCCESS = exports.SYNC_STOP_POLLING = exports.SYNC_CONTINUE_POLLING = exports.SYNC_START_POLLING = exports.SUBMITTERS_PUSH = exports.SUBMITTERS_PUSH_FULL_QUEUE = exports.STREAMING_DISCONNECTING = exports.STREAMING_DISABLED = exports.STREAMING_CONNECTING = exports.STREAMING_RECONNECT = exports.STREAMING_REFRESH_TOKEN = exports.SYNC_SPLITS_FETCH_RETRY = exports.POLLING_STOP = exports.POLLING_START = exports.POLLING_SMART_PAUSING = exports.NEW_FACTORY = exports.NEW_SHARED_CLIENT = exports.IMPRESSION_QUEUEING = exports.IMPRESSION = exports.CLIENT_READY = exports.CLIENT_READY_FROM_CACHE = exports.ENGINE_MATCHER_RESULT = exports.SETTINGS_SPLITS_FILTER = exports.SYNC_TASK_STOP = exports.SYNC_TASK_EXECUTE = exports.SYNC_TASK_START = exports.STREAMING_NEW_MESSAGE = exports.SYNC_RBS_UPDATE = exports.SYNC_SPLITS_UPDATE = exports.SYNC_SPLITS_FETCH = exports.SYNC_OFFLINE_DATA = exports.RETRIEVE_MANAGER = exports.RETRIEVE_CLIENT_EXISTING = exports.RETRIEVE_CLIENT_DEFAULT = exports.CLEANUP_DEREGISTERING = exports.CLEANUP_REGISTERING = exports.ENGINE_SANITIZE = exports.ENGINE_VALUE = exports.ENGINE_MATCHER_DEPENDENCY_PRE = exports.ENGINE_MATCHER_DEPENDENCY = exports.ENGINE_BUCKET = exports.ENGINE_COMBINER_IFELSEIF_NO_TREATMENT = exports.ENGINE_COMBINER_IFELSEIF = exports.ENGINE_COMBINER_AND = void 0;
4
+ exports.ERROR_HTTP = exports.ERROR_INVALID_CONFIG_PARAM = exports.ERROR_EMPTY_ARRAY = exports.ERROR_EMPTY = exports.ERROR_INVALID = exports.ERROR_INVALID_KEY_OBJECT = exports.ERROR_TOO_LONG = exports.ERROR_NULL = exports.ERROR_CLIENT_DESTROYED = exports.ERROR_NOT_FINITE = exports.ERROR_SIZE_EXCEEDED = exports.ERROR_NOT_PLAIN_OBJECT = exports.ERROR_EVENT_TYPE_FORMAT = exports.ERROR_EVENTS_TRACKER = exports.ERROR_IMPRESSIONS_LISTENER = exports.ERROR_IMPRESSIONS_TRACKER = exports.ERROR_STREAMING_AUTH = exports.ERROR_STREAMING_SSE = exports.ERROR_SYNC_OFFLINE_LOADING = exports.ERROR_CLIENT_CANNOT_GET_READY = exports.ERROR_CLIENT_LISTENER = exports.ERROR_LOGLEVEL_INVALID = exports.ERROR_ENGINE_COMBINER_IFELSEIF = exports.WARN_FLAGSET_WITHOUT_FLAGS = exports.WARN_FLAGSET_NOT_CONFIGURED = exports.WARN_LOWERCASE_FLAGSET = exports.WARN_INVALID_FLAGSET = exports.STREAMING_PARSING_SPLIT_UPDATE = exports.STREAMING_PARSING_MEMBERSHIPS_UPDATE = exports.WARN_SDK_KEY = exports.WARN_SPLITS_FILTER_EMPTY = exports.WARN_SPLITS_FILTER_INVALID = exports.WARN_SPLITS_FILTER_IGNORED = exports.WARN_INTEGRATION_INVALID = exports.WARN_NOT_EXISTENT_TT = exports.WARN_LOWERCASE_TRAFFIC_TYPE = exports.WARN_NOT_EXISTENT_SPLIT = exports.WARN_TRIMMING = exports.WARN_CONVERTING = exports.WARN_TRIMMING_PROPERTIES = exports.WARN_SETTING_NULL = exports.SUBMITTERS_PUSH_RETRY = exports.SUBMITTERS_PUSH_FAILS = exports.STREAMING_FALLBACK = exports.STREAMING_PARSING_MESSAGE_FAILS = exports.STREAMING_PARSING_ERROR_FAILS = exports.SYNC_SPLITS_FETCH_FAILS = exports.SYNC_MYSEGMENTS_FETCH_RETRY = exports.CLIENT_NOT_READY = exports.CLIENT_NO_LISTENER = void 0;
5
+ exports.LOG_PREFIX_CLEANUP = exports.LOG_PREFIX_UNIQUE_KEYS_TRACKER = exports.LOG_PREFIX_EVENTS_TRACKER = exports.LOG_PREFIX_IMPRESSIONS_TRACKER = exports.LOG_PREFIX_SYNC_SUBMITTERS = exports.LOG_PREFIX_SYNC_POLLING = exports.LOG_PREFIX_SYNC_MYSEGMENTS = exports.LOG_PREFIX_SYNC_SEGMENTS = exports.LOG_PREFIX_SYNC_SPLITS = exports.LOG_PREFIX_SYNC_STREAMING = exports.LOG_PREFIX_SYNC_OFFLINE = exports.LOG_PREFIX_SYNC_MANAGER = exports.LOG_PREFIX_SYNC = exports.LOG_PREFIX_ENGINE_VALUE = exports.LOG_PREFIX_ENGINE_MATCHER = exports.LOG_PREFIX_ENGINE_COMBINER = exports.LOG_PREFIX_ENGINE = exports.LOG_PREFIX_CLIENT_INSTANTIATION = exports.LOG_PREFIX_INSTANTIATION = exports.LOG_PREFIX_SETTINGS = exports.ENGINE_MATCHER_ERROR = exports.ERROR_SETS_FILTER_EXCLUSIVE = exports.ERROR_TOO_MANY_SETS = exports.ERROR_MIN_CONFIG_PARAM = exports.ERROR_NOT_BOOLEAN = exports.ERROR_STORAGE_INVALID = void 0;
6
6
  /**
7
7
  * Message codes used to trim string log messages from commons and client-side API modules,
8
8
  * in order to reduce the minimal SDK size for Browser and eventually other client-side environments.
@@ -26,6 +26,7 @@ exports.RETRIEVE_MANAGER = 29;
26
26
  exports.SYNC_OFFLINE_DATA = 30;
27
27
  exports.SYNC_SPLITS_FETCH = 31;
28
28
  exports.SYNC_SPLITS_UPDATE = 32;
29
+ exports.SYNC_RBS_UPDATE = 33;
29
30
  exports.STREAMING_NEW_MESSAGE = 35;
30
31
  exports.SYNC_TASK_START = 36;
31
32
  exports.SYNC_TASK_EXECUTE = 37;
@@ -23,8 +23,9 @@ exports.codesDebug = info_1.codesInfo.concat([
23
23
  [c.RETRIEVE_MANAGER, 'Retrieving manager instance.'],
24
24
  // synchronizer
25
25
  [c.SYNC_OFFLINE_DATA, c.LOG_PREFIX_SYNC_OFFLINE + 'Feature flags data: \n%s'],
26
- [c.SYNC_SPLITS_FETCH, c.LOG_PREFIX_SYNC_SPLITS + 'Spin up feature flags update using since = %s'],
27
- [c.SYNC_SPLITS_UPDATE, c.LOG_PREFIX_SYNC_SPLITS + 'New feature flags %s. Removed feature flags %s. Segment names collected %s'],
26
+ [c.SYNC_SPLITS_FETCH, c.LOG_PREFIX_SYNC_SPLITS + 'Spin up feature flags update using since = %s and rbSince = %s.'],
27
+ [c.SYNC_SPLITS_UPDATE, c.LOG_PREFIX_SYNC_SPLITS + 'New feature flags %s. Removed feature flags %s.'],
28
+ [c.SYNC_RBS_UPDATE, c.LOG_PREFIX_SYNC_SPLITS + 'New rule-based segments %s. Removed rule-based segments %s.'],
28
29
  [c.STREAMING_NEW_MESSAGE, c.LOG_PREFIX_SYNC_STREAMING + 'New SSE message received, with data: %s.'],
29
30
  [c.SYNC_TASK_START, c.LOG_PREFIX_SYNC + ': Starting %s. Running each %s millis'],
30
31
  [c.SYNC_TASK_EXECUTE, c.LOG_PREFIX_SYNC + ': Running %s'],
@@ -35,7 +35,7 @@ exports.codesWarn = error_1.codesError.concat([
35
35
  [c.WARN_SPLITS_FILTER_EMPTY, c.LOG_PREFIX_SETTINGS + ': feature flag filter configuration must be a non-empty array of filter objects.'],
36
36
  [c.WARN_SDK_KEY, c.LOG_PREFIX_SETTINGS + ': You already have %s. We recommend keeping only one instance of the factory at all times (Singleton pattern) and reusing it throughout your application'],
37
37
  [c.STREAMING_PARSING_MEMBERSHIPS_UPDATE, c.LOG_PREFIX_SYNC_STREAMING + 'Fetching Memberships due to an error processing %s notification: %s'],
38
- [c.STREAMING_PARSING_SPLIT_UPDATE, c.LOG_PREFIX_SYNC_STREAMING + 'Fetching SplitChanges due to an error processing SPLIT_UPDATE notification: %s'],
38
+ [c.STREAMING_PARSING_SPLIT_UPDATE, c.LOG_PREFIX_SYNC_STREAMING + 'Fetching SplitChanges due to an error processing %s notification: %s'],
39
39
  [c.WARN_INVALID_FLAGSET, '%s: you passed %s, flag set must adhere to the regular expressions %s. This means a flag set must start with a letter or number, be in lowercase, alphanumeric and have a max length of 50 characters. %s was discarded.'],
40
40
  [c.WARN_LOWERCASE_FLAGSET, '%s: flag set %s should be all lowercase - converting string to lowercase.'],
41
41
  [c.WARN_FLAGSET_WITHOUT_FLAGS, '%s: you passed %s flag set that does not contain cached feature flag names. Please double check what flag sets are in use in the Split user interface.'],
@@ -20,7 +20,6 @@ function splitApiFactory(settings, platform, telemetryTracker) {
20
20
  var urls = settings.urls;
21
21
  var filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
22
22
  var SplitSDKImpressionsMode = settings.sync.impressionsMode;
23
- var flagSpecVersion = settings.sync.flagSpecVersion;
24
23
  var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform);
25
24
  return {
26
25
  // @TODO throw errors if health check requests fail, to log them in the Synchronizer
@@ -33,7 +32,7 @@ function splitApiFactory(settings, platform, telemetryTracker) {
33
32
  return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
34
33
  },
35
34
  fetchAuth: function (userMatchingKeys) {
36
- var url = urls.auth + "/v2/auth?s=" + flagSpecVersion;
35
+ var url = urls.auth + "/v2/auth?s=" + settings.sync.flagSpecVersion;
37
36
  if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
38
37
  var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
39
38
  if (queryParams)
@@ -41,8 +40,8 @@ function splitApiFactory(settings, platform, telemetryTracker) {
41
40
  }
42
41
  return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_1.TOKEN));
43
42
  },
44
- fetchSplitChanges: function (since, noCache, till) {
45
- var url = urls.sdk + "/splitChanges?s=" + flagSpecVersion + "&since=" + since + (filterQueryString || '') + (till ? '&till=' + till : '');
43
+ fetchSplitChanges: function (since, noCache, till, rbSince) {
44
+ var url = urls.sdk + "/splitChanges?s=" + settings.sync.flagSpecVersion + "&since=" + since + (rbSince ? '&rbSince=' + rbSince : '') + (filterQueryString || '') + (till ? '&till=' + till : '');
46
45
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SPLITS))
47
46
  .catch(function (err) {
48
47
  if (err.statusCode === 414)
@@ -4,6 +4,7 @@ exports.splitHttpClientFactory = void 0;
4
4
  var objectAssign_1 = require("../utils/lang/objectAssign");
5
5
  var constants_1 = require("../logger/constants");
6
6
  var decorateHeaders_1 = require("./decorateHeaders");
7
+ var timeout_1 = require("../utils/promise/timeout");
7
8
  var messageNoFetch = 'Global fetch API is not available.';
8
9
  /**
9
10
  * Factory of Split HTTP clients, which are HTTP clients with predefined headers for Split endpoints.
@@ -43,7 +44,8 @@ function splitHttpClientFactory(settings, _a) {
43
44
  // https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful
44
45
  .then(function (response) {
45
46
  if (!response.ok) {
46
- return response.text().then(function (message) { return Promise.reject({ response: response, message: message }); });
47
+ // timeout after 100ms because `text()` promise doesn't settle in some implementations and cases (e.g. no content)
48
+ return (0, timeout_1.timeout)(100, response.text()).then(function (message) { return Promise.reject({ response: response, message: message }); }, function () { return Promise.reject({ response: response }); });
47
49
  }
48
50
  latencyTracker();
49
51
  return response;
@@ -53,8 +53,8 @@ exports.AbstractSplitsCacheSync = AbstractSplitsCacheSync;
53
53
  * Given a parsed split, it returns a boolean flagging if its conditions use segments matchers (rules & whitelists).
54
54
  * This util is intended to simplify the implementation of `splitsCache::usesSegments` method
55
55
  */
56
- function usesSegments(split) {
57
- var conditions = split.conditions || [];
56
+ function usesSegments(ruleEntity) {
57
+ var conditions = ruleEntity.conditions || [];
58
58
  for (var i = 0; i < conditions.length; i++) {
59
59
  var matchers = conditions[i].matcherGroup.matchers;
60
60
  for (var j = 0; j < matchers.length; j++) {
@@ -63,6 +63,9 @@ function usesSegments(split) {
63
63
  return true;
64
64
  }
65
65
  }
66
+ var excluded = ruleEntity.excluded;
67
+ if (excluded && excluded.segments && excluded.segments.length > 0)
68
+ return true;
66
69
  return false;
67
70
  }
68
71
  exports.usesSegments = usesSegments;
@@ -28,6 +28,15 @@ var KeyBuilder = /** @class */ (function () {
28
28
  KeyBuilder.prototype.buildSplitKeyPrefix = function () {
29
29
  return this.prefix + ".split.";
30
30
  };
31
+ KeyBuilder.prototype.buildRBSegmentKey = function (rbsegmentName) {
32
+ return this.prefix + ".rbsegment." + rbsegmentName;
33
+ };
34
+ KeyBuilder.prototype.buildRBSegmentsTillKey = function () {
35
+ return this.prefix + ".rbsegments.till";
36
+ };
37
+ KeyBuilder.prototype.buildRBSegmentKeyPrefix = function () {
38
+ return this.prefix + ".rbsegment.";
39
+ };
31
40
  KeyBuilder.prototype.buildSegmentNameKey = function (segmentName) {
32
41
  return this.prefix + ".segment." + segmentName;
33
42
  };
@@ -35,6 +35,9 @@ var KeyBuilderCS = /** @class */ (function (_super) {
35
35
  KeyBuilderCS.prototype.isSplitKey = function (key) {
36
36
  return (0, lang_1.startsWith)(key, this.prefix + ".split.");
37
37
  };
38
+ KeyBuilderCS.prototype.isRBSegmentKey = function (key) {
39
+ return (0, lang_1.startsWith)(key, this.prefix + ".rbsegment.");
40
+ };
38
41
  KeyBuilderCS.prototype.buildSplitsWithSegmentCountKey = function () {
39
42
  return this.prefix + ".splits.usingSegments";
40
43
  };
@@ -42,6 +42,9 @@ var KeyBuilderSS = /** @class */ (function (_super) {
42
42
  KeyBuilderSS.prototype.searchPatternForSplitKeys = function () {
43
43
  return this.buildSplitKeyPrefix() + "*";
44
44
  };
45
+ KeyBuilderSS.prototype.searchPatternForRBSegmentKeys = function () {
46
+ return this.buildRBSegmentKeyPrefix() + "*";
47
+ };
45
48
  /* Telemetry keys */
46
49
  KeyBuilderSS.prototype.buildLatencyKey = function (method, bucket) {
47
50
  return this.latencyPrefix + "::" + this.versionablePrefix + "/" + exports.METHOD_NAMES[method] + "/" + bucket;
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RBSegmentsCacheInLocal = void 0;
4
+ var lang_1 = require("../../utils/lang");
5
+ var sets_1 = require("../../utils/lang/sets");
6
+ var AbstractSplitsCacheSync_1 = require("../AbstractSplitsCacheSync");
7
+ var constants_1 = require("./constants");
8
+ var RBSegmentsCacheInLocal = /** @class */ (function () {
9
+ function RBSegmentsCacheInLocal(settings, keys) {
10
+ this.keys = keys;
11
+ this.log = settings.log;
12
+ }
13
+ RBSegmentsCacheInLocal.prototype.clear = function () {
14
+ var _this = this;
15
+ this.getNames().forEach(function (name) { return _this.remove(name); });
16
+ localStorage.removeItem(this.keys.buildRBSegmentsTillKey());
17
+ };
18
+ RBSegmentsCacheInLocal.prototype.update = function (toAdd, toRemove, changeNumber) {
19
+ var _this = this;
20
+ this.setChangeNumber(changeNumber);
21
+ var updated = toAdd.map(function (toAdd) { return _this.add(toAdd); }).some(function (result) { return result; });
22
+ return toRemove.map(function (toRemove) { return _this.remove(toRemove.name); }).some(function (result) { return result; }) || updated;
23
+ };
24
+ RBSegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
25
+ try {
26
+ localStorage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
27
+ localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
28
+ }
29
+ catch (e) {
30
+ this.log.error(constants_1.LOG_PREFIX + e);
31
+ }
32
+ };
33
+ RBSegmentsCacheInLocal.prototype.updateSegmentCount = function (diff) {
34
+ var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
35
+ var count = (0, lang_1.toNumber)(localStorage.getItem(segmentsCountKey)) + diff;
36
+ // @ts-expect-error
37
+ if (count > 0)
38
+ localStorage.setItem(segmentsCountKey, count);
39
+ else
40
+ localStorage.removeItem(segmentsCountKey);
41
+ };
42
+ RBSegmentsCacheInLocal.prototype.add = function (rbSegment) {
43
+ try {
44
+ var name_1 = rbSegment.name;
45
+ var rbSegmentKey = this.keys.buildRBSegmentKey(name_1);
46
+ var rbSegmentFromLocalStorage = localStorage.getItem(rbSegmentKey);
47
+ var previous = rbSegmentFromLocalStorage ? JSON.parse(rbSegmentFromLocalStorage) : null;
48
+ localStorage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
49
+ var usesSegmentsDiff = 0;
50
+ if (previous && (0, AbstractSplitsCacheSync_1.usesSegments)(previous))
51
+ usesSegmentsDiff--;
52
+ if ((0, AbstractSplitsCacheSync_1.usesSegments)(rbSegment))
53
+ usesSegmentsDiff++;
54
+ if (usesSegmentsDiff !== 0)
55
+ this.updateSegmentCount(usesSegmentsDiff);
56
+ return true;
57
+ }
58
+ catch (e) {
59
+ this.log.error(constants_1.LOG_PREFIX + e);
60
+ return false;
61
+ }
62
+ };
63
+ RBSegmentsCacheInLocal.prototype.remove = function (name) {
64
+ try {
65
+ var rbSegment = this.get(name);
66
+ if (!rbSegment)
67
+ return false;
68
+ localStorage.removeItem(this.keys.buildRBSegmentKey(name));
69
+ if ((0, AbstractSplitsCacheSync_1.usesSegments)(rbSegment))
70
+ this.updateSegmentCount(-1);
71
+ return true;
72
+ }
73
+ catch (e) {
74
+ this.log.error(constants_1.LOG_PREFIX + e);
75
+ return false;
76
+ }
77
+ };
78
+ RBSegmentsCacheInLocal.prototype.getNames = function () {
79
+ var len = localStorage.length;
80
+ var accum = [];
81
+ var cur = 0;
82
+ while (cur < len) {
83
+ var key = localStorage.key(cur);
84
+ if (key != null && this.keys.isRBSegmentKey(key))
85
+ accum.push(this.keys.extractKey(key));
86
+ cur++;
87
+ }
88
+ return accum;
89
+ };
90
+ RBSegmentsCacheInLocal.prototype.get = function (name) {
91
+ var item = localStorage.getItem(this.keys.buildRBSegmentKey(name));
92
+ return item && JSON.parse(item);
93
+ };
94
+ RBSegmentsCacheInLocal.prototype.contains = function (names) {
95
+ var namesArray = (0, sets_1.setToArray)(names);
96
+ var namesInStorage = this.getNames();
97
+ return namesArray.every(function (name) { return namesInStorage.indexOf(name) !== -1; });
98
+ };
99
+ RBSegmentsCacheInLocal.prototype.getChangeNumber = function () {
100
+ var n = -1;
101
+ var value = localStorage.getItem(this.keys.buildRBSegmentsTillKey());
102
+ if (value !== null) {
103
+ value = parseInt(value, 10);
104
+ return (0, lang_1.isNaNNumber)(value) ? n : value;
105
+ }
106
+ return n;
107
+ };
108
+ RBSegmentsCacheInLocal.prototype.usesSegments = function () {
109
+ var storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
110
+ var splitsWithSegmentsCount = storedCount === null ? 0 : (0, lang_1.toNumber)(storedCount);
111
+ return (0, lang_1.isFiniteNumber)(splitsWithSegmentsCount) ?
112
+ splitsWithSegmentsCount > 0 :
113
+ true;
114
+ };
115
+ return RBSegmentsCacheInLocal;
116
+ }());
117
+ exports.RBSegmentsCacheInLocal = RBSegmentsCacheInLocal;
@@ -41,15 +41,13 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
41
41
  };
42
42
  SplitsCacheInLocal.prototype._incrementCounts = function (split) {
43
43
  try {
44
- if (split) {
45
- var ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
44
+ var ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
45
+ // @ts-expect-error
46
+ localStorage.setItem(ttKey, (0, lang_1.toNumber)(localStorage.getItem(ttKey)) + 1);
47
+ if ((0, AbstractSplitsCacheSync_1.usesSegments)(split)) {
48
+ var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
46
49
  // @ts-expect-error
47
- localStorage.setItem(ttKey, (0, lang_1.toNumber)(localStorage.getItem(ttKey)) + 1);
48
- if ((0, AbstractSplitsCacheSync_1.usesSegments)(split)) {
49
- var segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
50
- // @ts-expect-error
51
- localStorage.setItem(segmentsCountKey, (0, lang_1.toNumber)(localStorage.getItem(segmentsCountKey)) + 1);
52
- }
50
+ localStorage.setItem(segmentsCountKey, (0, lang_1.toNumber)(localStorage.getItem(segmentsCountKey)) + 1);
53
51
  }
54
52
  }
55
53
  catch (e) {
@@ -158,12 +156,9 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
158
156
  return true;
159
157
  var storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
160
158
  var splitsWithSegmentsCount = storedCount === null ? 0 : (0, lang_1.toNumber)(storedCount);
161
- if ((0, lang_1.isFiniteNumber)(splitsWithSegmentsCount)) {
162
- return splitsWithSegmentsCount > 0;
163
- }
164
- else {
165
- return true;
166
- }
159
+ return (0, lang_1.isFiniteNumber)(splitsWithSegmentsCount) ?
160
+ splitsWithSegmentsCount > 0 :
161
+ true;
167
162
  };
168
163
  SplitsCacheInLocal.prototype.getNamesByFlagSets = function (flagSets) {
169
164
  var _this = this;