@splitsoftware/splitio-commons 1.10.0 → 1.10.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 (130) hide show
  1. package/cjs/evaluator/index.js +18 -1
  2. package/cjs/logger/constants.js +7 -2
  3. package/cjs/logger/messages/error.js +2 -0
  4. package/cjs/logger/messages/warn.js +4 -1
  5. package/cjs/sdkClient/client.js +33 -0
  6. package/cjs/sdkClient/clientAttributesDecoration.js +20 -0
  7. package/cjs/sdkClient/clientCS.js +4 -0
  8. package/cjs/sdkClient/clientInputValidation.js +52 -3
  9. package/cjs/sdkManager/index.js +1 -0
  10. package/cjs/services/splitApi.js +7 -1
  11. package/cjs/storages/KeyBuilder.js +3 -0
  12. package/cjs/storages/KeyBuilderSS.js +4 -0
  13. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +63 -27
  14. package/cjs/storages/inLocalStorage/index.js +2 -2
  15. package/cjs/storages/inMemory/InMemoryStorage.js +2 -2
  16. package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -3
  17. package/cjs/storages/inMemory/SplitsCacheInMemory.js +47 -2
  18. package/cjs/storages/inRedis/SplitsCacheInRedis.js +11 -0
  19. package/cjs/storages/pluggable/SplitsCachePluggable.js +11 -0
  20. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  21. package/cjs/sync/polling/updaters/splitChangesUpdater.js +24 -4
  22. package/cjs/sync/submitters/telemetrySubmitter.js +15 -1
  23. package/cjs/utils/constants/index.js +6 -2
  24. package/cjs/utils/lang/sets.js +9 -1
  25. package/cjs/utils/settingsValidation/index.js +1 -1
  26. package/cjs/utils/settingsValidation/splitFilters.js +78 -15
  27. package/esm/evaluator/index.js +16 -0
  28. package/esm/logger/constants.js +5 -0
  29. package/esm/logger/messages/error.js +2 -0
  30. package/esm/logger/messages/warn.js +4 -1
  31. package/esm/sdkClient/client.js +35 -2
  32. package/esm/sdkClient/clientAttributesDecoration.js +20 -0
  33. package/esm/sdkClient/clientCS.js +4 -0
  34. package/esm/sdkClient/clientInputValidation.js +52 -3
  35. package/esm/sdkManager/index.js +1 -0
  36. package/esm/services/splitApi.js +7 -1
  37. package/esm/storages/KeyBuilder.js +3 -0
  38. package/esm/storages/KeyBuilderSS.js +4 -0
  39. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +63 -27
  40. package/esm/storages/inLocalStorage/index.js +2 -2
  41. package/esm/storages/inMemory/InMemoryStorage.js +2 -2
  42. package/esm/storages/inMemory/InMemoryStorageCS.js +3 -3
  43. package/esm/storages/inMemory/SplitsCacheInMemory.js +47 -2
  44. package/esm/storages/inRedis/SplitsCacheInRedis.js +11 -0
  45. package/esm/storages/pluggable/SplitsCachePluggable.js +11 -0
  46. package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  47. package/esm/sync/polling/updaters/splitChangesUpdater.js +24 -4
  48. package/esm/sync/submitters/telemetrySubmitter.js +15 -1
  49. package/esm/utils/constants/index.js +4 -0
  50. package/esm/utils/lang/sets.js +7 -0
  51. package/esm/utils/settingsValidation/index.js +1 -1
  52. package/esm/utils/settingsValidation/splitFilters.js +72 -10
  53. package/package.json +2 -2
  54. package/src/dtos/types.ts +3 -2
  55. package/src/evaluator/index.ts +24 -0
  56. package/src/logger/constants.ts +5 -0
  57. package/src/logger/messages/error.ts +2 -0
  58. package/src/logger/messages/warn.ts +4 -1
  59. package/src/sdkClient/client.ts +42 -2
  60. package/src/sdkClient/clientAttributesDecoration.ts +24 -0
  61. package/src/sdkClient/clientCS.ts +4 -0
  62. package/src/sdkClient/clientInputValidation.ts +56 -3
  63. package/src/sdkManager/index.ts +1 -0
  64. package/src/services/splitApi.ts +6 -1
  65. package/src/storages/AbstractSplitsCacheAsync.ts +2 -0
  66. package/src/storages/AbstractSplitsCacheSync.ts +3 -0
  67. package/src/storages/KeyBuilder.ts +4 -0
  68. package/src/storages/KeyBuilderSS.ts +4 -0
  69. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +74 -28
  70. package/src/storages/inLocalStorage/index.ts +2 -2
  71. package/src/storages/inMemory/InMemoryStorage.ts +2 -2
  72. package/src/storages/inMemory/InMemoryStorageCS.ts +3 -3
  73. package/src/storages/inMemory/SplitsCacheInMemory.ts +50 -1
  74. package/src/storages/inRedis/SplitsCacheInRedis.ts +12 -0
  75. package/src/storages/pluggable/SplitsCachePluggable.ts +12 -0
  76. package/src/storages/types.ts +7 -3
  77. package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -0
  78. package/src/sync/polling/updaters/splitChangesUpdater.ts +27 -4
  79. package/src/sync/submitters/telemetrySubmitter.ts +19 -2
  80. package/src/sync/submitters/types.ts +7 -1
  81. package/src/types.ts +114 -1
  82. package/src/utils/constants/index.ts +4 -0
  83. package/src/utils/lang/sets.ts +8 -0
  84. package/src/utils/settingsValidation/index.ts +1 -1
  85. package/src/utils/settingsValidation/splitFilters.ts +78 -10
  86. package/types/dtos/types.d.ts +1 -0
  87. package/types/evaluator/index.d.ts +1 -0
  88. package/types/logger/constants.d.ts +5 -0
  89. package/types/myLogger.d.ts +5 -0
  90. package/types/sdkClient/clientAttributesDecoration.d.ts +4 -0
  91. package/types/sdkClient/types.d.ts +18 -0
  92. package/types/storages/AbstractSplitsCacheAsync.d.ts +2 -0
  93. package/types/storages/AbstractSplitsCacheSync.d.ts +2 -0
  94. package/types/storages/KeyBuilder.d.ts +1 -0
  95. package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +6 -1
  96. package/types/storages/inMemory/CountsCacheInMemory.d.ts +20 -0
  97. package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +20 -0
  98. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +9 -1
  99. package/types/storages/inRedis/CountsCacheInRedis.d.ts +9 -0
  100. package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +9 -0
  101. package/types/storages/inRedis/SplitsCacheInRedis.d.ts +8 -0
  102. package/types/storages/metadataBuilder.d.ts +3 -0
  103. package/types/storages/pluggable/SplitsCachePluggable.d.ts +8 -0
  104. package/types/storages/types.d.ts +4 -0
  105. package/types/sync/offline/LocalhostFromFile.d.ts +2 -0
  106. package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +2 -0
  107. package/types/sync/offline/updaters/splitChangesUpdater.d.ts +0 -0
  108. package/types/sync/polling/updaters/splitChangesUpdater.d.ts +3 -3
  109. package/types/sync/submitters/eventsSyncTask.d.ts +8 -0
  110. package/types/sync/submitters/impressionCountsSubmitterInRedis.d.ts +5 -0
  111. package/types/sync/submitters/impressionCountsSyncTask.d.ts +13 -0
  112. package/types/sync/submitters/impressionsSyncTask.d.ts +14 -0
  113. package/types/sync/submitters/metricsSyncTask.d.ts +12 -0
  114. package/types/sync/submitters/submitterSyncTask.d.ts +10 -0
  115. package/types/sync/submitters/types.d.ts +7 -1
  116. package/types/sync/submitters/uniqueKeysSubmitterInRedis.d.ts +5 -0
  117. package/types/sync/syncTaskComposite.d.ts +5 -0
  118. package/types/trackers/filter/bloomFilter.d.ts +10 -0
  119. package/types/trackers/filter/dictionaryFilter.d.ts +8 -0
  120. package/types/trackers/filter/types.d.ts +5 -0
  121. package/types/types.d.ts +114 -1
  122. package/types/utils/constants/index.d.ts +4 -0
  123. package/types/utils/lang/sets.d.ts +1 -0
  124. package/types/utils/settingsValidation/splitFilters.d.ts +2 -2
  125. package/types/utils/timeTracker/index.d.ts +70 -0
  126. package/types/sdkClient/identity.d.ts +0 -6
  127. package/types/utils/inputValidation/sdkKey.d.ts +0 -7
  128. /package/types/storages/inMemory/{UniqueKeysCacheInMemory.d.ts → uniqueKeysCacheInMemory.d.ts} +0 -0
  129. /package/types/storages/inMemory/{UniqueKeysCacheInMemoryCS.d.ts → uniqueKeysCacheInMemoryCS.d.ts} +0 -0
  130. /package/types/storages/inRedis/{UniqueKeysCacheInRedis.d.ts → uniqueKeysCacheInRedis.d.ts} +0 -0
@@ -29,6 +29,17 @@ function getRedundantActiveFactories() {
29
29
  return acum + usedKeysMap[sdkKey] - 1;
30
30
  }, 0);
31
31
  }
32
+ function getTelemetryFlagSetsStats(splitFiltersValidation) {
33
+ // Group every configured flag set in an unique array called originalSets
34
+ var flagSetsTotal = 0;
35
+ splitFiltersValidation.validFilters.forEach(function (filter) {
36
+ if (filter.type === 'bySet')
37
+ flagSetsTotal += filter.values.length;
38
+ });
39
+ var flagSetsValid = splitFiltersValidation.groupedFilters.bySet.length;
40
+ var flagSetsIgnored = flagSetsTotal - flagSetsValid;
41
+ return { flagSetsTotal: flagSetsTotal, flagSetsIgnored: flagSetsIgnored };
42
+ }
32
43
  export function getTelemetryConfigStats(mode, storageType) {
33
44
  return {
34
45
  oM: OPERATION_MODE_MAP[mode],
@@ -47,6 +58,7 @@ export function telemetryCacheConfigAdapter(telemetry, settings) {
47
58
  pop: function () {
48
59
  var urls = settings.urls, scheduler = settings.scheduler;
49
60
  var isClientSide = settings.core.key !== undefined;
61
+ var _a = getTelemetryFlagSetsStats(settings.sync.__splitFiltersValidation), flagSetsTotal = _a.flagSetsTotal, flagSetsIgnored = _a.flagSetsIgnored;
50
62
  return objectAssign(getTelemetryConfigStats(settings.mode, settings.storage.type), {
51
63
  sE: settings.streamingEnabled,
52
64
  rR: {
@@ -74,7 +86,9 @@ export function telemetryCacheConfigAdapter(telemetry, settings) {
74
86
  nR: telemetry.getNonReadyUsage(),
75
87
  t: telemetry.popTags(),
76
88
  i: settings.integrations && settings.integrations.map(function (int) { return int.type; }),
77
- uC: settings.userConsent ? USER_CONSENT_MAP[settings.userConsent] : 0
89
+ uC: settings.userConsent ? USER_CONSENT_MAP[settings.userConsent] : 0,
90
+ fsT: flagSetsTotal,
91
+ fsI: flagSetsIgnored
78
92
  });
79
93
  }
80
94
  };
@@ -51,6 +51,10 @@ export var TREATMENT = 't';
51
51
  export var TREATMENTS = 'ts';
52
52
  export var TREATMENT_WITH_CONFIG = 'tc';
53
53
  export var TREATMENTS_WITH_CONFIG = 'tcs';
54
+ export var TREATMENTS_BY_FLAGSET = 'tf';
55
+ export var TREATMENTS_BY_FLAGSETS = 'tfs';
56
+ export var TREATMENTS_WITH_CONFIG_BY_FLAGSET = 'tcf';
57
+ export var TREATMENTS_WITH_CONFIG_BY_FLAGSETS = 'tcfs';
54
58
  export var TRACK = 'tr';
55
59
  export var CONNECTION_ESTABLISHED = 0;
56
60
  export var OCCUPANCY_PRI = 10;
@@ -95,3 +95,10 @@ export function __getSetConstructor() {
95
95
  return SetPoly;
96
96
  }
97
97
  export var _Set = __getSetConstructor();
98
+ export function returnSetsUnion(set, set2) {
99
+ var result = new _Set(setToArray(set));
100
+ set2.forEach(function (value) {
101
+ result.add(value);
102
+ });
103
+ return result;
104
+ }
@@ -176,7 +176,7 @@ export function settingsValidation(config, validationParams) {
176
176
  withDefaults.sync.enabled = true;
177
177
  }
178
178
  // validate the `splitFilters` settings and parse splits query
179
- var splitFiltersValidation = validateSplitFilters(log, withDefaults.sync.splitFilters, withDefaults.mode);
179
+ var splitFiltersValidation = validateSplitFilters(log, withDefaults.sync.splitFilters);
180
180
  withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
181
181
  withDefaults.sync.__splitFiltersValidation = splitFiltersValidation;
182
182
  // ensure a valid user consent value
@@ -1,9 +1,15 @@
1
- import { STANDALONE_MODE } from '../constants';
2
1
  import { validateSplits } from '../inputValidation/splits';
3
- import { WARN_SPLITS_FILTER_IGNORED, WARN_SPLITS_FILTER_EMPTY, WARN_SPLITS_FILTER_INVALID, SETTINGS_SPLITS_FILTER, LOG_PREFIX_SETTINGS } from '../../logger/constants';
2
+ import { WARN_SPLITS_FILTER_EMPTY, WARN_SPLITS_FILTER_INVALID, SETTINGS_SPLITS_FILTER, LOG_PREFIX_SETTINGS, ERROR_SETS_FILTER_EXCLUSIVE, WARN_SPLITS_FILTER_LOWERCASE_SET, WARN_SPLITS_FILTER_INVALID_SET, WARN_FLAGSET_NOT_CONFIGURED } from '../../logger/constants';
3
+ import { objectAssign } from '../lang/objectAssign';
4
+ import { find, uniq } from '../lang';
4
5
  // Split filters metadata.
5
6
  // Ordered according to their precedency when forming the filter query string: `&names=<values>&prefixes=<values>`
6
7
  var FILTERS_METADATA = [
8
+ {
9
+ type: 'bySet',
10
+ maxLength: 50,
11
+ queryParam: 'sets='
12
+ },
7
13
  {
8
14
  type: 'byName',
9
15
  maxLength: 400,
@@ -15,6 +21,8 @@ var FILTERS_METADATA = [
15
21
  queryParam: 'prefixes='
16
22
  }
17
23
  ];
24
+ var VALID_FLAGSET_REGEX = /^[a-z0-9][_a-z0-9]{0,49}$/;
25
+ var CAPITAL_LETTERS_REGEX = /[A-Z]/;
18
26
  /**
19
27
  * Validates that the given value is a valid filter type
20
28
  */
@@ -35,6 +43,9 @@ function validateSplitFilter(log, type, values, maxLength) {
35
43
  // validate and remove invalid and duplicated values
36
44
  var result = validateSplits(log, values, LOG_PREFIX_SETTINGS, type + " filter", type + " filter value");
37
45
  if (result) {
46
+ if (type === 'bySet') {
47
+ result = sanitizeFlagSets(log, result);
48
+ }
38
49
  // check max length
39
50
  if (result.length > maxLength)
40
51
  throw new Error(maxLength + " unique values can be specified at most for '" + type + "' filter. You passed " + result.length + ". Please consider reducing the amount or using other filter.");
@@ -65,12 +76,47 @@ function queryStringBuilder(groupedFilters) {
65
76
  });
66
77
  return queryParams.length > 0 ? '&' + queryParams.join('&') : null;
67
78
  }
79
+ /**
80
+ * Sanitizes set names list taking in account:
81
+ * - It should be lowercase
82
+ * - Must adhere the following regular expression /^[a-z0-9][_a-z0-9]{0,49}$/ that means
83
+ * - must start with a letter or number
84
+ * - Be in lowercase
85
+ * - Be alphanumeric
86
+ * - have a max length of 50 characters
87
+ *
88
+ * @param {ILogger} log
89
+ * @param {string[]} flagSets
90
+ * @returns sanitized list of set names
91
+ */
92
+ function sanitizeFlagSets(log, flagSets) {
93
+ var sanitizedSets = flagSets
94
+ .map(function (flagSet) {
95
+ if (CAPITAL_LETTERS_REGEX.test(flagSet)) {
96
+ log.warn(WARN_SPLITS_FILTER_LOWERCASE_SET, [flagSet]);
97
+ flagSet = flagSet.toLowerCase();
98
+ }
99
+ return flagSet;
100
+ })
101
+ .filter(function (flagSet) {
102
+ if (!VALID_FLAGSET_REGEX.test(flagSet)) {
103
+ log.warn(WARN_SPLITS_FILTER_INVALID_SET, [flagSet, VALID_FLAGSET_REGEX, flagSet]);
104
+ return false;
105
+ }
106
+ if (typeof flagSet !== 'string')
107
+ return false;
108
+ return true;
109
+ });
110
+ return uniq(sanitizedSets);
111
+ }
112
+ function configuredFilter(validFilters, filterType) {
113
+ return find(validFilters, function (filter) { return filter.type === filterType && filter.values.length > 0; });
114
+ }
68
115
  /**
69
116
  * Validates `splitFilters` configuration object and parses it into a query string for filtering splits on `/splitChanges` fetch.
70
117
  *
71
118
  * @param {ILogger} log logger
72
119
  * @param {any} maybeSplitFilters split filters configuration param provided by the user
73
- * @param {string} mode settings mode
74
120
  * @returns it returns an object with the following properties:
75
121
  * - `validFilters`: the validated `splitFilters` configuration object defined by the user.
76
122
  * - `queryString`: the parsed split filter query. it is null if all filters are invalid or all values in filters are invalid.
@@ -78,21 +124,16 @@ function queryStringBuilder(groupedFilters) {
78
124
  *
79
125
  * @throws Error if the some of the grouped list of values per filter exceeds the max allowed length
80
126
  */
81
- export function validateSplitFilters(log, maybeSplitFilters, mode) {
127
+ export function validateSplitFilters(log, maybeSplitFilters) {
82
128
  // Validation result schema
83
129
  var res = {
84
130
  validFilters: [],
85
131
  queryString: null,
86
- groupedFilters: { byName: [], byPrefix: [] }
132
+ groupedFilters: { bySet: [], byName: [], byPrefix: [] },
87
133
  };
88
134
  // do nothing if `splitFilters` param is not a non-empty array or mode is not STANDALONE
89
135
  if (!maybeSplitFilters)
90
136
  return res;
91
- // Warn depending on the mode
92
- if (mode !== STANDALONE_MODE) {
93
- log.warn(WARN_SPLITS_FILTER_IGNORED, [STANDALONE_MODE]);
94
- return res;
95
- }
96
137
  // Check collection type
97
138
  if (!Array.isArray(maybeSplitFilters) || maybeSplitFilters.length === 0) {
98
139
  log.warn(WARN_SPLITS_FILTER_EMPTY);
@@ -115,8 +156,29 @@ export function validateSplitFilters(log, maybeSplitFilters, mode) {
115
156
  if (res.groupedFilters[type].length > 0)
116
157
  res.groupedFilters[type] = validateSplitFilter(log, type, res.groupedFilters[type], maxLength);
117
158
  });
159
+ var setFilter = configuredFilter(res.validFilters, 'bySet');
160
+ // Clean all filters if set filter is present
161
+ if (setFilter) {
162
+ if (configuredFilter(res.validFilters, 'byName') || configuredFilter(res.validFilters, 'byPrefix'))
163
+ log.error(ERROR_SETS_FILTER_EXCLUSIVE);
164
+ objectAssign(res.groupedFilters, { byName: [], byPrefix: [] });
165
+ }
118
166
  // build query string
119
167
  res.queryString = queryStringBuilder(res.groupedFilters);
120
168
  log.debug(SETTINGS_SPLITS_FILTER, [res.queryString]);
121
169
  return res;
122
170
  }
171
+ export function flagSetsAreValid(log, method, flagSets, flagSetsInConfig) {
172
+ var sets = validateSplits(log, flagSets, method, 'flag sets', 'flag set');
173
+ var toReturn = sets ? sanitizeFlagSets(log, sets) : [];
174
+ if (flagSetsInConfig.length > 0) {
175
+ toReturn = toReturn.filter(function (flagSet) {
176
+ if (flagSetsInConfig.indexOf(flagSet) > -1) {
177
+ return true;
178
+ }
179
+ log.warn(WARN_FLAGSET_NOT_CONFIGURED, [method, flagSet]);
180
+ return false;
181
+ });
182
+ }
183
+ return toReturn;
184
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "1.10.0",
3
+ "version": "1.10.1-rc.0",
4
4
  "description": "Split Javascript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -22,7 +22,7 @@
22
22
  "build": "npm run build:cjs && npm run build:esm",
23
23
  "build:esm": "rimraf esm && tsc -m es2015 --outDir esm -d true --declarationDir types",
24
24
  "build:cjs": "rimraf cjs && tsc -m CommonJS --outDir cjs",
25
- "test": "jest --runInBand",
25
+ "test": "jest",
26
26
  "test:coverage": "jest --coverage",
27
27
  "all": "npm run check && npm run build && npm run test",
28
28
  "publish:rc": "npm run check && npm run test && npm run build && npm publish --tag rc",
package/src/dtos/types.ts CHANGED
@@ -163,7 +163,8 @@ export interface ISplit {
163
163
  trafficAllocationSeed?: number
164
164
  configurations?: {
165
165
  [treatmentName: string]: string
166
- }
166
+ },
167
+ sets?: string[]
167
168
  }
168
169
 
169
170
  // Split definition used in offline mode
@@ -208,5 +209,5 @@ export interface IMetadata {
208
209
  export type ISplitFiltersValidation = {
209
210
  queryString: string | null,
210
211
  groupedFilters: Record<SplitIO.SplitFilterType, string[]>,
211
- validFilters: SplitIO.SplitFilter[]
212
+ validFilters: SplitIO.SplitFilter[],
212
213
  };
@@ -7,6 +7,7 @@ import { IStorageAsync, IStorageSync } from '../storages/types';
7
7
  import { IEvaluationResult } from './types';
8
8
  import { SplitIO } from '../types';
9
9
  import { ILogger } from '../logger/types';
10
+ import { ISet, setToArray } from '../utils/lang/sets';
10
11
 
11
12
  const treatmentException = {
12
13
  treatment: CONTROL,
@@ -87,6 +88,29 @@ export function evaluateFeatures(
87
88
  getEvaluations(log, splitNames, parsedSplits, key, attributes, storage);
88
89
  }
89
90
 
91
+ export function evaluateFeaturesByFlagSets(
92
+ log: ILogger,
93
+ key: SplitIO.SplitKey,
94
+ flagSets: string[],
95
+ attributes: SplitIO.Attributes | undefined,
96
+ storage: IStorageSync | IStorageAsync,
97
+ ): MaybeThenable<Record<string,IEvaluationResult>> {
98
+ let storedFlagNames: MaybeThenable<ISet<string>>;
99
+
100
+ // get features by flag sets
101
+ try {
102
+ storedFlagNames = storage.splits.getNamesByFlagSets(flagSets);
103
+ } catch (e) {
104
+ // return empty evaluations
105
+ return {};
106
+ }
107
+
108
+ // evaluate related features
109
+ return thenable(storedFlagNames) ?
110
+ storedFlagNames.then((splitNames) => evaluateFeatures(log, key, setToArray(splitNames), attributes, storage)) :
111
+ evaluateFeatures(log, key, setToArray(storedFlagNames), attributes, storage);
112
+ }
113
+
90
114
  function getEvaluation(
91
115
  log: ILogger,
92
116
  splitJSON: ISplit | null,
@@ -97,6 +97,9 @@ export const WARN_SPLITS_FILTER_EMPTY = 221;
97
97
  export const WARN_SDK_KEY = 222;
98
98
  export const STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2 = 223;
99
99
  export const STREAMING_PARSING_SPLIT_UPDATE = 224;
100
+ export const WARN_SPLITS_FILTER_INVALID_SET = 225;
101
+ export const WARN_SPLITS_FILTER_LOWERCASE_SET = 226;
102
+ export const WARN_FLAGSET_NOT_CONFIGURED = 227;
100
103
 
101
104
  export const ERROR_ENGINE_COMBINER_IFELSEIF = 300;
102
105
  export const ERROR_LOGLEVEL_INVALID = 301;
@@ -125,6 +128,8 @@ export const ERROR_LOCALHOST_MODULE_REQUIRED = 323;
125
128
  export const ERROR_STORAGE_INVALID = 324;
126
129
  export const ERROR_NOT_BOOLEAN = 325;
127
130
  export const ERROR_MIN_CONFIG_PARAM = 326;
131
+ export const ERROR_TOO_MANY_SETS = 327;
132
+ export const ERROR_SETS_FILTER_EXCLUSIVE = 328;
128
133
 
129
134
  // Log prefixes (a.k.a. tags or categories)
130
135
  export const LOG_PREFIX_SETTINGS = 'settings';
@@ -34,4 +34,6 @@ export const codesError: [number, string][] = [
34
34
  [c.ERROR_LOCALHOST_MODULE_REQUIRED, c.LOG_PREFIX_SETTINGS + ': an invalid value was received for "sync.localhostMode" config. A valid entity should be provided for localhost mode.'],
35
35
  [c.ERROR_STORAGE_INVALID, c.LOG_PREFIX_SETTINGS+': the provided storage is invalid.%s Falling back into default MEMORY storage'],
36
36
  [c.ERROR_MIN_CONFIG_PARAM, c.LOG_PREFIX_SETTINGS + ': the provided "%s" config param is lower than allowed. Setting to the minimum value %s seconds'],
37
+ [c.ERROR_TOO_MANY_SETS, c.LOG_PREFIX_SETTINGS + ': the amount of flag sets provided are big causing uri length error.'],
38
+ [c.ERROR_SETS_FILTER_EXCLUSIVE, c.LOG_PREFIX_SETTINGS+': the Set filter is exclusive and cannot be used simultaneously with names or prefix filters. Ignoring names and prefixes.'],
37
39
  ];
@@ -24,13 +24,16 @@ export const codesWarn: [number, string][] = codesError.concat([
24
24
  [c.WARN_NOT_EXISTENT_SPLIT, '%s: feature flag "%s" does not exist in this environment. Please double check what feature flags exist in the Split user interface.'],
25
25
  [c.WARN_LOWERCASE_TRAFFIC_TYPE, '%s: traffic_type_name should be all lowercase - converting string to lowercase.'],
26
26
  [c.WARN_NOT_EXISTENT_TT, '%s: traffic type "%s" does not have any corresponding feature flag in this environment, make sure you\'re tracking your events to a valid traffic type defined in the Split user interface.'],
27
+ [c.WARN_FLAGSET_NOT_CONFIGURED, '%s: : you passed %s wich is not part of the configured FlagSetsFilter, ignoring Flag Set.'],
27
28
  // initialization / settings validation
28
29
  [c.WARN_INTEGRATION_INVALID, c.LOG_PREFIX_SETTINGS+': %s integration item(s) at settings is invalid. %s'],
29
30
  [c.WARN_SPLITS_FILTER_IGNORED, c.LOG_PREFIX_SETTINGS+': feature flag filters have been configured but will have no effect if mode is not "%s", since synchronization is being deferred to an external tool.'],
30
- [c.WARN_SPLITS_FILTER_INVALID, c.LOG_PREFIX_SETTINGS+': feature flag filter at position %s is invalid. It must be an object with a valid filter type ("byName" or "byPrefix") and a list of "values".'],
31
+ [c.WARN_SPLITS_FILTER_INVALID, c.LOG_PREFIX_SETTINGS+': feature flag filter at position %s is invalid. It must be an object with a valid filter type ("bySet", "byName" or "byPrefix") and a list of "values".'],
31
32
  [c.WARN_SPLITS_FILTER_EMPTY, c.LOG_PREFIX_SETTINGS+': feature flag filter configuration must be a non-empty array of filter objects.'],
32
33
  [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'],
33
34
 
34
35
  [c.STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, c.LOG_PREFIX_SYNC_STREAMING + 'Fetching MySegments due to an error processing %s notification: %s'],
35
36
  [c.STREAMING_PARSING_SPLIT_UPDATE, c.LOG_PREFIX_SYNC_STREAMING + 'Fetching SplitChanges due to an error processing SPLIT_UPDATE notification: %s'],
37
+ [c.WARN_SPLITS_FILTER_INVALID_SET, c.LOG_PREFIX_SETTINGS+': 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.'],
38
+ [c.WARN_SPLITS_FILTER_LOWERCASE_SET, c.LOG_PREFIX_SETTINGS+': flag set %s should be all lowercase - converting string to lowercase.'],
36
39
  ]);
@@ -1,15 +1,16 @@
1
- import { evaluateFeature, evaluateFeatures } from '../evaluator';
1
+ import { evaluateFeature, evaluateFeatures, evaluateFeaturesByFlagSets } from '../evaluator';
2
2
  import { thenable } from '../utils/promise/thenable';
3
3
  import { getMatching, getBucketing } from '../utils/key';
4
4
  import { validateSplitExistance } from '../utils/inputValidation/splitExistance';
5
5
  import { validateTrafficTypeExistance } from '../utils/inputValidation/trafficTypeExistance';
6
6
  import { SDK_NOT_READY } from '../utils/labels';
7
- import { CONTROL, TREATMENT, TREATMENTS, TREATMENT_WITH_CONFIG, TREATMENTS_WITH_CONFIG, TRACK } from '../utils/constants';
7
+ import { CONTROL, TREATMENT, TREATMENTS, TREATMENT_WITH_CONFIG, TREATMENTS_WITH_CONFIG, TRACK, TREATMENTS_WITH_CONFIG_BY_FLAGSETS, TREATMENTS_BY_FLAGSETS, TREATMENTS_BY_FLAGSET, TREATMENTS_WITH_CONFIG_BY_FLAGSET } from '../utils/constants';
8
8
  import { IEvaluationResult } from '../evaluator/types';
9
9
  import { SplitIO, ImpressionDTO } from '../types';
10
10
  import { IMPRESSION, IMPRESSION_QUEUEING } from '../logger/constants';
11
11
  import { ISdkFactoryContext } from '../sdkFactory/types';
12
12
  import { isStorageSync } from '../trackers/impressionObserver/utils';
13
+ import { Method } from '../sync/submitters/types';
13
14
 
14
15
  const treatmentNotReady = { treatment: CONTROL, label: SDK_NOT_READY };
15
16
 
@@ -81,6 +82,41 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
81
82
  return getTreatments(key, featureFlagNames, attributes, true);
82
83
  }
83
84
 
85
+ function getTreatmentsByFlagSets(key: SplitIO.SplitKey, flagSetNames: string[], attributes: SplitIO.Attributes | undefined, withConfig = false, method: Method = TREATMENTS_BY_FLAGSETS) {
86
+ const stopTelemetryTracker = telemetryTracker.trackEval(method);
87
+
88
+ const wrapUp = (evaluationResults: Record<string,IEvaluationResult>) => {
89
+ const queue: ImpressionDTO[] = [];
90
+ const treatments: Record<string, SplitIO.Treatment | SplitIO.TreatmentWithConfig> = {};
91
+ const evaluations = evaluationResults;
92
+ Object.keys(evaluations).forEach(featureFlagName => {
93
+ treatments[featureFlagName] = processEvaluation(evaluations[featureFlagName], featureFlagName, key, attributes, withConfig, `getTreatmentsByFlagSets${withConfig ? 'WithConfig' : ''}`, queue);
94
+ });
95
+ impressionsTracker.track(queue, attributes);
96
+
97
+ stopTelemetryTracker(queue[0] && queue[0].label);
98
+ return treatments;
99
+ };
100
+
101
+ const evaluations = readinessManager.isReady() || readinessManager.isReadyFromCache() ?
102
+ evaluateFeaturesByFlagSets(log, key, flagSetNames, attributes, storage) :
103
+ isStorageSync(settings) ? {} : Promise.resolve({}); // Promisify if async
104
+
105
+ return thenable(evaluations) ? evaluations.then((res) => wrapUp(res)) : wrapUp(evaluations);
106
+ }
107
+
108
+ function getTreatmentsWithConfigByFlagSets(key: SplitIO.SplitKey, flagSetNames: string[], attributes: SplitIO.Attributes | undefined) {
109
+ return getTreatmentsByFlagSets(key, flagSetNames, attributes, true, TREATMENTS_WITH_CONFIG_BY_FLAGSETS);
110
+ }
111
+
112
+ function getTreatmentsByFlagSet(key: SplitIO.SplitKey, flagSetName: string, attributes: SplitIO.Attributes | undefined) {
113
+ return getTreatmentsByFlagSets(key, [flagSetName], attributes, false, TREATMENTS_BY_FLAGSET);
114
+ }
115
+
116
+ function getTreatmentsWithConfigByFlagSet(key: SplitIO.SplitKey, flagSetName: string, attributes: SplitIO.Attributes | undefined) {
117
+ return getTreatmentsByFlagSets(key, [flagSetName], attributes, true, TREATMENTS_WITH_CONFIG_BY_FLAGSET);
118
+ }
119
+
84
120
  // Internal function
85
121
  function processEvaluation(
86
122
  evaluation: IEvaluationResult,
@@ -155,6 +191,10 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
155
191
  getTreatmentWithConfig,
156
192
  getTreatments,
157
193
  getTreatmentsWithConfig,
194
+ getTreatmentsByFlagSets,
195
+ getTreatmentsWithConfigByFlagSets,
196
+ getTreatmentsByFlagSet,
197
+ getTreatmentsWithConfigByFlagSet,
158
198
  track,
159
199
  isClientSide: false
160
200
  } as SplitIO.IClient | SplitIO.IAsyncClient;
@@ -16,6 +16,10 @@ export function clientAttributesDecoration<TClient extends SplitIO.IClient | Spl
16
16
  const clientGetTreatmentWithConfig = client.getTreatmentWithConfig;
17
17
  const clientGetTreatments = client.getTreatments;
18
18
  const clientGetTreatmentsWithConfig = client.getTreatmentsWithConfig;
19
+ const clientGetTreatmentsByFlagSets = client.getTreatmentsByFlagSets;
20
+ const clientGetTreatmentsWithConfigByFlagSets = client.getTreatmentsWithConfigByFlagSets;
21
+ const clientGetTreatmentsByFlagSet = client.getTreatmentsByFlagSet;
22
+ const clientGetTreatmentsWithConfigByFlagSet = client.getTreatmentsWithConfigByFlagSet;
19
23
  const clientTrack = client.track;
20
24
 
21
25
  function getTreatment(maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes) {
@@ -34,6 +38,22 @@ export function clientAttributesDecoration<TClient extends SplitIO.IClient | Spl
34
38
  return clientGetTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes));
35
39
  }
36
40
 
41
+ function getTreatmentsByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
42
+ return clientGetTreatmentsByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes));
43
+ }
44
+
45
+ function getTreatmentsWithConfigByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
46
+ return clientGetTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes));
47
+ }
48
+
49
+ function getTreatmentsByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
50
+ return clientGetTreatmentsByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes));
51
+ }
52
+
53
+ function getTreatmentsWithConfigByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
54
+ return clientGetTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes));
55
+ }
56
+
37
57
  function track(maybeKey: SplitIO.SplitKey, maybeTT: string, maybeEvent: string, maybeEventValue?: number, maybeProperties?: SplitIO.Properties) {
38
58
  return clientTrack(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties);
39
59
  }
@@ -51,6 +71,10 @@ export function clientAttributesDecoration<TClient extends SplitIO.IClient | Spl
51
71
  getTreatmentWithConfig: getTreatmentWithConfig,
52
72
  getTreatments: getTreatments,
53
73
  getTreatmentsWithConfig: getTreatmentsWithConfig,
74
+ getTreatmentsByFlagSets: getTreatmentsByFlagSets,
75
+ getTreatmentsWithConfigByFlagSets: getTreatmentsWithConfigByFlagSets,
76
+ getTreatmentsByFlagSet: getTreatmentsByFlagSet,
77
+ getTreatmentsWithConfigByFlagSet: getTreatmentsWithConfigByFlagSet,
54
78
  track: track,
55
79
 
56
80
  /**
@@ -21,6 +21,10 @@ export function clientCSDecorator(log: ILogger, client: SplitIO.IClient, key: Sp
21
21
  getTreatmentWithConfig: clientCS.getTreatmentWithConfig.bind(clientCS, key),
22
22
  getTreatments: clientCS.getTreatments.bind(clientCS, key),
23
23
  getTreatmentsWithConfig: clientCS.getTreatmentsWithConfig.bind(clientCS, key),
24
+ getTreatmentsByFlagSets: clientCS.getTreatmentsByFlagSets.bind(clientCS, key),
25
+ getTreatmentsWithConfigByFlagSets: clientCS.getTreatmentsWithConfigByFlagSets.bind(clientCS, key),
26
+ getTreatmentsByFlagSet: clientCS.getTreatmentsByFlagSet.bind(clientCS, key),
27
+ getTreatmentsWithConfigByFlagSet: clientCS.getTreatmentsWithConfigByFlagSet.bind(clientCS, key),
24
28
 
25
29
  // Key is bound to the `track` method. Same thing happens with trafficType but only if provided
26
30
  track: trafficType ? clientCS.track.bind(clientCS, key, trafficType) : clientCS.track.bind(clientCS, key),
@@ -17,6 +17,7 @@ import { IReadinessManager } from '../readiness/types';
17
17
  import { MaybeThenable } from '../dtos/types';
18
18
  import { ISettings, SplitIO } from '../types';
19
19
  import { isStorageSync } from '../trackers/impressionObserver/utils';
20
+ import { flagSetsAreValid } from '../utils/settingsValidation/splitFilters';
20
21
 
21
22
  /**
22
23
  * Decorator that validates the input before actually executing the client methods.
@@ -30,21 +31,29 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
30
31
  /**
31
32
  * Avoid repeating this validations code
32
33
  */
33
- function validateEvaluationParams(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNameOrNames: string | string[], maybeAttributes: SplitIO.Attributes | undefined, methodName: string) {
34
+ function validateEvaluationParams(maybeKey: SplitIO.SplitKey, maybeFeatureFlagNameOrNames: string | string[] | undefined, maybeAttributes: SplitIO.Attributes | undefined, methodName: string, maybeFlagSetNameOrNames?: string[]) {
34
35
  const multi = startsWith(methodName, 'getTreatments');
35
36
  const key = validateKey(log, maybeKey, methodName);
36
- const splitOrSplits = multi ? validateSplits(log, maybeFeatureFlagNameOrNames, methodName) : validateSplit(log, maybeFeatureFlagNameOrNames, methodName);
37
+ let splitOrSplits: string | string[] | false = false;
38
+ let flagSetOrFlagSets: string[] = [];
39
+ if (maybeFeatureFlagNameOrNames) {
40
+ splitOrSplits = multi ? validateSplits(log, maybeFeatureFlagNameOrNames, methodName) : validateSplit(log, maybeFeatureFlagNameOrNames, methodName);
41
+ }
37
42
  const attributes = validateAttributes(log, maybeAttributes, methodName);
38
43
  const isNotDestroyed = validateIfNotDestroyed(log, readinessManager, methodName);
44
+ if (maybeFlagSetNameOrNames) {
45
+ flagSetOrFlagSets = flagSetsAreValid(log, methodName, maybeFlagSetNameOrNames, settings.sync.__splitFiltersValidation.groupedFilters.bySet);
46
+ }
39
47
 
40
48
  validateIfOperational(log, readinessManager, methodName, splitOrSplits);
41
49
 
42
- const valid = isNotDestroyed && key && splitOrSplits && attributes !== false;
50
+ const valid = isNotDestroyed && key && (splitOrSplits || flagSetOrFlagSets.length > 0) && attributes !== false;
43
51
 
44
52
  return {
45
53
  valid,
46
54
  key,
47
55
  splitOrSplits,
56
+ flagSetOrFlagSets,
48
57
  attributes
49
58
  };
50
59
  }
@@ -99,6 +108,46 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
99
108
  }
100
109
  }
101
110
 
111
+ function getTreatmentsByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
112
+ const params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, 'getTreatmentsByFlagSets', maybeFlagSets);
113
+
114
+ if (params.valid) {
115
+ return client.getTreatmentsByFlagSets(params.key as SplitIO.SplitKey, params.flagSetOrFlagSets as string[], params.attributes as SplitIO.Attributes | undefined);
116
+ } else {
117
+ return wrapResult({});
118
+ }
119
+ }
120
+
121
+ function getTreatmentsWithConfigByFlagSets(maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes) {
122
+ const params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, 'getTreatmentsWithConfigByFlagSets', maybeFlagSets);
123
+
124
+ if (params.valid) {
125
+ return client.getTreatmentsWithConfigByFlagSets(params.key as SplitIO.SplitKey, params.flagSetOrFlagSets as string[], params.attributes as SplitIO.Attributes | undefined);
126
+ } else {
127
+ return wrapResult({});
128
+ }
129
+ }
130
+
131
+ function getTreatmentsByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
132
+ const params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, 'getTreatmentsByFlagSet', [maybeFlagSet]);
133
+
134
+ if (params.valid) {
135
+ return client.getTreatmentsByFlagSet(params.key as SplitIO.SplitKey, params.flagSetOrFlagSets[0] as string, params.attributes as SplitIO.Attributes | undefined);
136
+ } else {
137
+ return wrapResult({});
138
+ }
139
+ }
140
+
141
+ function getTreatmentsWithConfigByFlagSet(maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes) {
142
+ const params = validateEvaluationParams(maybeKey, undefined, maybeAttributes, 'getTreatmentsWithConfigByFlagSet', [maybeFlagSet]);
143
+
144
+ if (params.valid) {
145
+ return client.getTreatmentsWithConfigByFlagSet(params.key as SplitIO.SplitKey, params.flagSetOrFlagSets[0] as string, params.attributes as SplitIO.Attributes | undefined);
146
+ } else {
147
+ return wrapResult({});
148
+ }
149
+ }
150
+
102
151
  function track(maybeKey: SplitIO.SplitKey, maybeTT: string, maybeEvent: string, maybeEventValue?: number, maybeProperties?: SplitIO.Properties) {
103
152
  const key = validateKey(log, maybeKey, 'track');
104
153
  const tt = validateTrafficType(log, maybeTT, 'track');
@@ -119,6 +168,10 @@ export function clientInputValidationDecorator<TClient extends SplitIO.IClient |
119
168
  getTreatmentWithConfig,
120
169
  getTreatments,
121
170
  getTreatmentsWithConfig,
171
+ getTreatmentsByFlagSets,
172
+ getTreatmentsWithConfigByFlagSets,
173
+ getTreatmentsByFlagSet,
174
+ getTreatmentsWithConfigByFlagSet,
122
175
  track
123
176
  } as TClient;
124
177
  }
@@ -32,6 +32,7 @@ function objectToView(splitObject: ISplit | null): SplitIO.SplitView | null {
32
32
  changeNumber: splitObject.changeNumber || 0,
33
33
  treatments: collectTreatments(splitObject),
34
34
  configs: splitObject.configurations || {},
35
+ sets: splitObject.sets || [],
35
36
  defaultTreatment: splitObject.defaultTreatment
36
37
  };
37
38
  }
@@ -5,6 +5,7 @@ import { ISplitApi } from './types';
5
5
  import { objectAssign } from '../utils/lang/objectAssign';
6
6
  import { ITelemetryTracker } from '../trackers/types';
7
7
  import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT } from '../utils/constants';
8
+ import { ERROR_TOO_MANY_SETS } from '../logger/constants';
8
9
 
9
10
  const noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
10
11
 
@@ -53,7 +54,11 @@ export function splitApiFactory(
53
54
 
54
55
  fetchSplitChanges(since: number, noCache?: boolean, till?: number) {
55
56
  const url = `${urls.sdk}/splitChanges?since=${since}${till ? '&till=' + till : ''}${filterQueryString || ''}`;
56
- return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SPLITS));
57
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SPLITS))
58
+ .catch((err) => {
59
+ if (err.statusCode === 414) settings.log.error(ERROR_TOO_MANY_SETS);
60
+ throw err;
61
+ });
57
62
  },
58
63
 
59
64
  fetchSegmentChanges(since: number, segmentName: string, noCache?: boolean, till?: number) {
@@ -1,6 +1,7 @@
1
1
  import { ISplitsCacheAsync } from './types';
2
2
  import { ISplit } from '../dtos/types';
3
3
  import { objectAssign } from '../utils/lang/objectAssign';
4
+ import { ISet } from '../utils/lang/sets';
4
5
 
5
6
  /**
6
7
  * This class provides a skeletal implementation of the ISplitsCacheAsync interface
@@ -17,6 +18,7 @@ export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
17
18
  abstract getChangeNumber(): Promise<number>
18
19
  abstract getAll(): Promise<ISplit[]>
19
20
  abstract getSplitNames(): Promise<string[]>
21
+ abstract getNamesByFlagSets(flagSets: string[]): Promise<ISet<string>>
20
22
  abstract trafficTypeExists(trafficType: string): Promise<boolean>
21
23
  abstract clear(): Promise<boolean | void>
22
24
 
@@ -1,6 +1,7 @@
1
1
  import { ISplitsCacheSync } from './types';
2
2
  import { ISplit } from '../dtos/types';
3
3
  import { objectAssign } from '../utils/lang/objectAssign';
4
+ import { ISet } from '../utils/lang/sets';
4
5
 
5
6
  /**
6
7
  * This class provides a skeletal implementation of the ISplitsCacheSync interface
@@ -78,6 +79,8 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
78
79
  return false;
79
80
  }
80
81
 
82
+ abstract getNamesByFlagSets(flagSets: string[]): ISet<string>
83
+
81
84
  }
82
85
 
83
86
  /**
@@ -20,6 +20,10 @@ export class KeyBuilder {
20
20
  return `${this.prefix}.trafficType.${trafficType}`;
21
21
  }
22
22
 
23
+ buildFlagSetKey(flagSet: string) {
24
+ return `${this.prefix}.flagset.${flagSet}`;
25
+ }
26
+
23
27
  buildSplitKey(splitName: string) {
24
28
  return `${this.prefix}.split.${splitName}`;
25
29
  }
@@ -7,6 +7,10 @@ export const METHOD_NAMES: Record<Method, string> = {
7
7
  ts: 'treatments',
8
8
  tc: 'treatmentWithConfig',
9
9
  tcs: 'treatmentsWithConfig',
10
+ tf: 'treatmentsByFlagSet',
11
+ tfs: 'treatmentsByFlagSets',
12
+ tcf: 'treatmentsWithConfigByFlagSet',
13
+ tcfs: 'treatmentsWithConfigByFlagSets',
10
14
  tr: 'track'
11
15
  };
12
16