@splitsoftware/splitio-commons 1.10.0 → 1.10.1-rc.1

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 (131) hide show
  1. package/CHANGES.txt +9 -0
  2. package/cjs/evaluator/index.js +18 -1
  3. package/cjs/logger/constants.js +7 -3
  4. package/cjs/logger/messages/error.js +2 -0
  5. package/cjs/logger/messages/warn.js +4 -2
  6. package/cjs/sdkClient/client.js +33 -0
  7. package/cjs/sdkClient/clientAttributesDecoration.js +20 -0
  8. package/cjs/sdkClient/clientCS.js +4 -0
  9. package/cjs/sdkClient/clientInputValidation.js +52 -3
  10. package/cjs/sdkManager/index.js +1 -0
  11. package/cjs/services/splitApi.js +7 -1
  12. package/cjs/storages/KeyBuilder.js +3 -0
  13. package/cjs/storages/KeyBuilderSS.js +4 -0
  14. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +63 -27
  15. package/cjs/storages/inLocalStorage/index.js +2 -2
  16. package/cjs/storages/inMemory/InMemoryStorage.js +2 -2
  17. package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -3
  18. package/cjs/storages/inMemory/SplitsCacheInMemory.js +47 -2
  19. package/cjs/storages/inRedis/SplitsCacheInRedis.js +11 -0
  20. package/cjs/storages/pluggable/SplitsCachePluggable.js +11 -0
  21. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  22. package/cjs/sync/polling/updaters/splitChangesUpdater.js +39 -5
  23. package/cjs/sync/submitters/telemetrySubmitter.js +15 -1
  24. package/cjs/utils/constants/index.js +6 -2
  25. package/cjs/utils/lang/sets.js +9 -1
  26. package/cjs/utils/settingsValidation/index.js +1 -1
  27. package/cjs/utils/settingsValidation/splitFilters.js +78 -15
  28. package/esm/evaluator/index.js +16 -0
  29. package/esm/logger/constants.js +5 -1
  30. package/esm/logger/messages/error.js +2 -0
  31. package/esm/logger/messages/warn.js +4 -2
  32. package/esm/sdkClient/client.js +35 -2
  33. package/esm/sdkClient/clientAttributesDecoration.js +20 -0
  34. package/esm/sdkClient/clientCS.js +4 -0
  35. package/esm/sdkClient/clientInputValidation.js +52 -3
  36. package/esm/sdkManager/index.js +1 -0
  37. package/esm/services/splitApi.js +7 -1
  38. package/esm/storages/KeyBuilder.js +3 -0
  39. package/esm/storages/KeyBuilderSS.js +4 -0
  40. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +63 -27
  41. package/esm/storages/inLocalStorage/index.js +2 -2
  42. package/esm/storages/inMemory/InMemoryStorage.js +2 -2
  43. package/esm/storages/inMemory/InMemoryStorageCS.js +3 -3
  44. package/esm/storages/inMemory/SplitsCacheInMemory.js +47 -2
  45. package/esm/storages/inRedis/SplitsCacheInRedis.js +11 -0
  46. package/esm/storages/pluggable/SplitsCachePluggable.js +11 -0
  47. package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  48. package/esm/sync/polling/updaters/splitChangesUpdater.js +39 -5
  49. package/esm/sync/submitters/telemetrySubmitter.js +15 -1
  50. package/esm/utils/constants/index.js +4 -0
  51. package/esm/utils/lang/sets.js +7 -0
  52. package/esm/utils/settingsValidation/index.js +1 -1
  53. package/esm/utils/settingsValidation/splitFilters.js +72 -10
  54. package/package.json +2 -2
  55. package/src/dtos/types.ts +3 -2
  56. package/src/evaluator/index.ts +24 -0
  57. package/src/logger/constants.ts +5 -1
  58. package/src/logger/messages/error.ts +2 -0
  59. package/src/logger/messages/warn.ts +4 -2
  60. package/src/sdkClient/client.ts +42 -2
  61. package/src/sdkClient/clientAttributesDecoration.ts +24 -0
  62. package/src/sdkClient/clientCS.ts +4 -0
  63. package/src/sdkClient/clientInputValidation.ts +56 -3
  64. package/src/sdkManager/index.ts +1 -0
  65. package/src/services/splitApi.ts +6 -1
  66. package/src/storages/AbstractSplitsCacheAsync.ts +2 -0
  67. package/src/storages/AbstractSplitsCacheSync.ts +3 -0
  68. package/src/storages/KeyBuilder.ts +4 -0
  69. package/src/storages/KeyBuilderSS.ts +4 -0
  70. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +74 -28
  71. package/src/storages/inLocalStorage/index.ts +2 -2
  72. package/src/storages/inMemory/InMemoryStorage.ts +2 -2
  73. package/src/storages/inMemory/InMemoryStorageCS.ts +3 -3
  74. package/src/storages/inMemory/SplitsCacheInMemory.ts +50 -1
  75. package/src/storages/inRedis/SplitsCacheInRedis.ts +12 -0
  76. package/src/storages/pluggable/SplitsCachePluggable.ts +12 -0
  77. package/src/storages/types.ts +7 -3
  78. package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -0
  79. package/src/sync/polling/updaters/splitChangesUpdater.ts +40 -6
  80. package/src/sync/submitters/telemetrySubmitter.ts +19 -2
  81. package/src/sync/submitters/types.ts +7 -1
  82. package/src/types.ts +115 -2
  83. package/src/utils/constants/index.ts +4 -0
  84. package/src/utils/lang/sets.ts +8 -0
  85. package/src/utils/settingsValidation/index.ts +1 -1
  86. package/src/utils/settingsValidation/splitFilters.ts +78 -10
  87. package/types/dtos/types.d.ts +1 -0
  88. package/types/evaluator/index.d.ts +1 -0
  89. package/types/logger/constants.d.ts +5 -1
  90. package/types/myLogger.d.ts +5 -0
  91. package/types/sdkClient/clientAttributesDecoration.d.ts +4 -0
  92. package/types/sdkClient/types.d.ts +18 -0
  93. package/types/storages/AbstractSplitsCacheAsync.d.ts +2 -0
  94. package/types/storages/AbstractSplitsCacheSync.d.ts +2 -0
  95. package/types/storages/KeyBuilder.d.ts +1 -0
  96. package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +6 -1
  97. package/types/storages/inMemory/CountsCacheInMemory.d.ts +20 -0
  98. package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +20 -0
  99. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +9 -1
  100. package/types/storages/inRedis/CountsCacheInRedis.d.ts +9 -0
  101. package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +9 -0
  102. package/types/storages/inRedis/SplitsCacheInRedis.d.ts +8 -0
  103. package/types/storages/metadataBuilder.d.ts +3 -0
  104. package/types/storages/pluggable/SplitsCachePluggable.d.ts +8 -0
  105. package/types/storages/types.d.ts +4 -0
  106. package/types/sync/offline/LocalhostFromFile.d.ts +2 -0
  107. package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +2 -0
  108. package/types/sync/offline/updaters/splitChangesUpdater.d.ts +0 -0
  109. package/types/sync/polling/updaters/splitChangesUpdater.d.ts +3 -3
  110. package/types/sync/submitters/eventsSyncTask.d.ts +8 -0
  111. package/types/sync/submitters/impressionCountsSubmitterInRedis.d.ts +5 -0
  112. package/types/sync/submitters/impressionCountsSyncTask.d.ts +13 -0
  113. package/types/sync/submitters/impressionsSyncTask.d.ts +14 -0
  114. package/types/sync/submitters/metricsSyncTask.d.ts +12 -0
  115. package/types/sync/submitters/submitterSyncTask.d.ts +10 -0
  116. package/types/sync/submitters/types.d.ts +7 -1
  117. package/types/sync/submitters/uniqueKeysSubmitterInRedis.d.ts +5 -0
  118. package/types/sync/syncTaskComposite.d.ts +5 -0
  119. package/types/trackers/filter/bloomFilter.d.ts +10 -0
  120. package/types/trackers/filter/dictionaryFilter.d.ts +8 -0
  121. package/types/trackers/filter/types.d.ts +5 -0
  122. package/types/types.d.ts +114 -1
  123. package/types/utils/constants/index.d.ts +4 -0
  124. package/types/utils/lang/sets.d.ts +1 -0
  125. package/types/utils/settingsValidation/splitFilters.d.ts +2 -2
  126. package/types/utils/timeTracker/index.d.ts +70 -0
  127. package/types/sdkClient/identity.d.ts +0 -6
  128. package/types/utils/inputValidation/sdkKey.d.ts +0 -7
  129. /package/types/storages/inMemory/{UniqueKeysCacheInMemory.d.ts → uniqueKeysCacheInMemory.d.ts} +0 -0
  130. /package/types/storages/inMemory/{UniqueKeysCacheInMemoryCS.d.ts → uniqueKeysCacheInMemoryCS.d.ts} +0 -0
  131. /package/types/storages/inRedis/{UniqueKeysCacheInRedis.d.ts → uniqueKeysCacheInRedis.d.ts} +0 -0
package/src/types.ts CHANGED
@@ -609,7 +609,12 @@ export namespace SplitIO {
609
609
  */
610
610
  configs: {
611
611
  [treatmentName: string]: string
612
- }
612
+ },
613
+ /**
614
+ * List of sets of the feature flag.
615
+ * @property {string[]} sets
616
+ */
617
+ sets: string[],
613
618
  /**
614
619
  * The default treatment of the feature flag.
615
620
  * @property {string} defaultTreatment
@@ -714,7 +719,7 @@ export namespace SplitIO {
714
719
  * SplitFilter type.
715
720
  * @typedef {string} SplitFilterType
716
721
  */
717
- export type SplitFilterType = 'byName' | 'byPrefix';
722
+ export type SplitFilterType = 'byName' | 'byPrefix' | 'bySet';
718
723
  /**
719
724
  * Defines a feature flag filter, described by a type and list of values.
720
725
  */
@@ -1064,6 +1069,42 @@ export namespace SplitIO {
1064
1069
  * @returns {TreatmentsWithConfig} The map with all the TreatmentWithConfig objects
1065
1070
  */
1066
1071
  getTreatmentsWithConfig(key: SplitKey, featureFlagNames: string[], attributes?: Attributes): TreatmentsWithConfig,
1072
+ /**
1073
+ * Returns a Treatments value, which is an object map with the treatments for the feature flags related to the given flagSet.
1074
+ * @function getTreatmentsByFlagSet
1075
+ * @param {string} key - The string key representing the consumer.
1076
+ * @param {string} flagSet - The flagSet name we want to get the treatments.
1077
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1078
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1079
+ */
1080
+ getTreatmentsByFlagSet(key: SplitKey, flagSet: string, attributes?: Attributes): Treatments,
1081
+ /**
1082
+ * Returns a TreatmentsWithConfig value, which is an object map with the TreatmentWithConfig (an object with both treatment and config string) for the feature flags related to the given flagSets.
1083
+ * @function getTreatmentsWithConfigByFlagSet
1084
+ * @param {string} key - The string key representing the consumer.
1085
+ * @param {string} flagSet - The flagSet name we want to get the treatments.
1086
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1087
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1088
+ */
1089
+ getTreatmentsWithConfigByFlagSet(key: SplitKey, flagSet: string, attributes?: Attributes): TreatmentsWithConfig,
1090
+ /**
1091
+ * Returns a Returns a Treatments value, which is an object with both treatment and config string for to the feature flags related to the given flagSets.
1092
+ * @function getTreatmentsByFlagSets
1093
+ * @param {string} key - The string key representing the consumer.
1094
+ * @param {Array<string>} flagSets - An array of the flagSet names we want to get the treatments.
1095
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1096
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1097
+ */
1098
+ getTreatmentsByFlagSets(key: SplitKey, flagSets: string[], attributes?: Attributes): Treatments,
1099
+ /**
1100
+ * Returns a TreatmentsWithConfig value, which is an object map with the TreatmentWithConfig (an object with both treatment and config string) for the feature flags related to the given flagSets.
1101
+ * @function getTreatmentsWithConfigByFlagSets
1102
+ * @param {string} key - The string key representing the consumer.
1103
+ * @param {Array<string>} flagSets - An array of the flagSet names we want to get the treatments.
1104
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1105
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1106
+ */
1107
+ getTreatmentsWithConfigByFlagSets(key: SplitKey, flagSets: string[], attributes?: Attributes): TreatmentsWithConfig,
1067
1108
  /**
1068
1109
  * Tracks an event to be fed to the results product on Split user interface.
1069
1110
  * @function track
@@ -1124,6 +1165,46 @@ export namespace SplitIO {
1124
1165
  * @returns {AsyncTreatmentsWithConfig} TreatmentsWithConfig promise that resolves to the map of TreatmentsWithConfig objects.
1125
1166
  */
1126
1167
  getTreatmentsWithConfig(key: SplitKey, featureFlagNames: string[], attributes?: Attributes): AsyncTreatmentsWithConfig,
1168
+ /**
1169
+ * Returns a Treatments value, which will be (or eventually be) an object map with the treatments for the features related to the given flag set.
1170
+ * For usage on NodeJS as we don't have only one key.
1171
+ * @function getTreatmentsByFlagSet
1172
+ * @param {string} key - The string key representing the consumer.
1173
+ * @param {string} flagSet - The flag set name we want to get the treatments.
1174
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1175
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1176
+ */
1177
+ getTreatmentsByFlagSet(key: SplitKey, flagSet: string, attributes?: Attributes): AsyncTreatments,
1178
+ /**
1179
+ * Returns a TreatmentWithConfig value, which will be (or eventually be) an object with both treatment and config string for features related to the given flag set.
1180
+ * For usage on NodeJS as we don't have only one key.
1181
+ * @function getTreatmentsWithConfigByFlagSet
1182
+ * @param {string} key - The string key representing the consumer.
1183
+ * @param {string} flagSet - The flag set name we want to get the treatments.
1184
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1185
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1186
+ */
1187
+ getTreatmentsWithConfigByFlagSet(key: SplitKey, flagSet: string, attributes?: Attributes): AsyncTreatmentsWithConfig,
1188
+ /**
1189
+ * Returns a Treatments value, which will be (or eventually be) an object map with the treatments for the feature flags related to the given flag sets.
1190
+ * For usage on NodeJS as we don't have only one key.
1191
+ * @function getTreatmentsByFlagSets
1192
+ * @param {string} key - The string key representing the consumer.
1193
+ * @param {Array<string>} flagSets - An array of the flag set names we want to get the treatments.
1194
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1195
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1196
+ */
1197
+ getTreatmentsByFlagSets(key: SplitKey, flagSets: string[], attributes?: Attributes): AsyncTreatments,
1198
+ /**
1199
+ * Returns a TreatmentWithConfig value, which will be (or eventually be) an object with both treatment and config string for the feature flags related to the given flag sets.
1200
+ * For usage on NodeJS as we don't have only one key.
1201
+ * @function getTreatmentsWithConfigByFlagSets
1202
+ * @param {string} key - The string key representing the consumer.
1203
+ * @param {Array<string>} flagSets - An array of the flag set names we want to get the treatments.
1204
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1205
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1206
+ */
1207
+ getTreatmentsWithConfigByFlagSets(key: SplitKey, flagSets: string[], attributes?: Attributes): AsyncTreatmentsWithConfig,
1127
1208
  /**
1128
1209
  * Tracks an event to be fed to the results product on Split user interface, and returns a promise to signal when the event was successfully queued (or not).
1129
1210
  * @function track
@@ -1174,6 +1255,38 @@ export namespace SplitIO {
1174
1255
  * @returns {TreatmentsWithConfig} The map with all the TreatmentWithConfig objects
1175
1256
  */
1176
1257
  getTreatmentsWithConfig(featureFlagNames: string[], attributes?: Attributes): TreatmentsWithConfig,
1258
+ /**
1259
+ * Returns a Treatments value, which is an object map with the treatments for the feature flags related to the given flag set.
1260
+ * @function getTreatmentsByFlagSet
1261
+ * @param {string} flagSet - The flag set name we want to get the treatments.
1262
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1263
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1264
+ */
1265
+ getTreatmentsByFlagSet(flagSet: string, attributes?: Attributes): Treatments,
1266
+ /**
1267
+ * Returns a TreatmentsWithConfig value, which is an object map with the TreatmentWithConfig (an object with both treatment and config string) for the feature flags related to the given flag set.
1268
+ * @function getTreatmentsWithConfigByFlagSet
1269
+ * @param {string} flagSet - The flag set name we want to get the treatments.
1270
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1271
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1272
+ */
1273
+ getTreatmentsWithConfigByFlagSet(flagSet: string, attributes?: Attributes): TreatmentsWithConfig,
1274
+ /**
1275
+ * Returns a Returns a Treatments value, which is an object with both treatment and config string for to the feature flags related to the given flag sets.
1276
+ * @function getTreatmentsByFlagSets
1277
+ * @param {Array<string>} flagSets - An array of the flag set names we want to get the treatments.
1278
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1279
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1280
+ */
1281
+ getTreatmentsByFlagSets(flagSets: string[], attributes?: Attributes): Treatments,
1282
+ /**
1283
+ * Returns a TreatmentsWithConfig value, which is an object map with the TreatmentWithConfig (an object with both treatment and config string) for the feature flags related to the given flag sets.
1284
+ * @function getTreatmentsWithConfigByFlagSets
1285
+ * @param {Array<string>} flagSets - An array of the flag set names we want to get the treatments.
1286
+ * @param {Attributes=} attributes - An object of type Attributes defining the attributes for the given key.
1287
+ * @returns {Treatments} The map with all the TreatmentWithConfig objects
1288
+ */
1289
+ getTreatmentsWithConfigByFlagSets(flagSets: string[], attributes?: Attributes): TreatmentsWithConfig,
1177
1290
  /**
1178
1291
  * Tracks an event to be fed to the results product on Split user interface.
1179
1292
  * @function track
@@ -65,6 +65,10 @@ export const TREATMENT = 't';
65
65
  export const TREATMENTS = 'ts';
66
66
  export const TREATMENT_WITH_CONFIG = 'tc';
67
67
  export const TREATMENTS_WITH_CONFIG = 'tcs';
68
+ export const TREATMENTS_BY_FLAGSET = 'tf';
69
+ export const TREATMENTS_BY_FLAGSETS = 'tfs';
70
+ export const TREATMENTS_WITH_CONFIG_BY_FLAGSET = 'tcf';
71
+ export const TREATMENTS_WITH_CONFIG_BY_FLAGSETS = 'tcfs';
68
72
  export const TRACK = 'tr';
69
73
 
70
74
  export const CONNECTION_ESTABLISHED = 0;
@@ -111,3 +111,11 @@ export function __getSetConstructor(): ISetConstructor {
111
111
  }
112
112
 
113
113
  export const _Set = __getSetConstructor();
114
+
115
+ export function returnSetsUnion<T>(set: ISet<T>, set2: ISet<T>): ISet<T> {
116
+ const result = new _Set(setToArray(set));
117
+ set2.forEach( value => {
118
+ result.add(value);
119
+ });
120
+ return result;
121
+ }
@@ -202,7 +202,7 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
202
202
  }
203
203
 
204
204
  // validate the `splitFilters` settings and parse splits query
205
- const splitFiltersValidation = validateSplitFilters(log, withDefaults.sync.splitFilters, withDefaults.mode);
205
+ const splitFiltersValidation = validateSplitFilters(log, withDefaults.sync.splitFilters);
206
206
  withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
207
207
  withDefaults.sync.__splitFiltersValidation = splitFiltersValidation;
208
208
 
@@ -1,13 +1,19 @@
1
- import { STANDALONE_MODE } from '../constants';
2
1
  import { validateSplits } from '../inputValidation/splits';
3
2
  import { ISplitFiltersValidation } from '../../dtos/types';
4
3
  import { SplitIO } from '../../types';
5
4
  import { ILogger } from '../../logger/types';
6
- import { WARN_SPLITS_FILTER_IGNORED, WARN_SPLITS_FILTER_EMPTY, WARN_SPLITS_FILTER_INVALID, SETTINGS_SPLITS_FILTER, LOG_PREFIX_SETTINGS } from '../../logger/constants';
5
+ 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';
6
+ import { objectAssign } from '../lang/objectAssign';
7
+ import { find, uniq } from '../lang';
7
8
 
8
9
  // Split filters metadata.
9
10
  // Ordered according to their precedency when forming the filter query string: `&names=<values>&prefixes=<values>`
10
11
  const FILTERS_METADATA = [
12
+ {
13
+ type: 'bySet' as SplitIO.SplitFilterType,
14
+ maxLength: 50,
15
+ queryParam: 'sets='
16
+ },
11
17
  {
12
18
  type: 'byName' as SplitIO.SplitFilterType,
13
19
  maxLength: 400,
@@ -20,6 +26,9 @@ const FILTERS_METADATA = [
20
26
  }
21
27
  ];
22
28
 
29
+ const VALID_FLAGSET_REGEX = /^[a-z0-9][_a-z0-9]{0,49}$/;
30
+ const CAPITAL_LETTERS_REGEX = /[A-Z]/;
31
+
23
32
  /**
24
33
  * Validates that the given value is a valid filter type
25
34
  */
@@ -42,6 +51,11 @@ function validateSplitFilter(log: ILogger, type: SplitIO.SplitFilterType, values
42
51
  let result = validateSplits(log, values, LOG_PREFIX_SETTINGS, `${type} filter`, `${type} filter value`);
43
52
 
44
53
  if (result) {
54
+
55
+ if (type === 'bySet') {
56
+ result = sanitizeFlagSets(log, result);
57
+ }
58
+
45
59
  // check max length
46
60
  if (result.length > maxLength) 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.`);
47
61
 
@@ -72,12 +86,48 @@ function queryStringBuilder(groupedFilters: Record<SplitIO.SplitFilterType, stri
72
86
  return queryParams.length > 0 ? '&' + queryParams.join('&') : null;
73
87
  }
74
88
 
89
+ /**
90
+ * Sanitizes set names list taking in account:
91
+ * - It should be lowercase
92
+ * - Must adhere the following regular expression /^[a-z0-9][_a-z0-9]{0,49}$/ that means
93
+ * - must start with a letter or number
94
+ * - Be in lowercase
95
+ * - Be alphanumeric
96
+ * - have a max length of 50 characters
97
+ *
98
+ * @param {ILogger} log
99
+ * @param {string[]} flagSets
100
+ * @returns sanitized list of set names
101
+ */
102
+ function sanitizeFlagSets(log: ILogger, flagSets: string[]) {
103
+ let sanitizedSets = flagSets
104
+ .map(flagSet => {
105
+ if (CAPITAL_LETTERS_REGEX.test(flagSet)){
106
+ log.warn(WARN_SPLITS_FILTER_LOWERCASE_SET,[flagSet]);
107
+ flagSet = flagSet.toLowerCase();
108
+ }
109
+ return flagSet;
110
+ })
111
+ .filter(flagSet => {
112
+ if (!VALID_FLAGSET_REGEX.test(flagSet)){
113
+ log.warn(WARN_SPLITS_FILTER_INVALID_SET, [flagSet,VALID_FLAGSET_REGEX,flagSet]);
114
+ return false;
115
+ }
116
+ if (typeof flagSet !== 'string') return false;
117
+ return true;
118
+ });
119
+ return uniq(sanitizedSets);
120
+ }
121
+
122
+ function configuredFilter(validFilters: SplitIO.SplitFilter[], filterType: SplitIO.SplitFilterType) {
123
+ return find(validFilters, (filter: SplitIO.SplitFilter) => filter.type === filterType && filter.values.length > 0);
124
+ }
125
+
75
126
  /**
76
127
  * Validates `splitFilters` configuration object and parses it into a query string for filtering splits on `/splitChanges` fetch.
77
128
  *
78
129
  * @param {ILogger} log logger
79
130
  * @param {any} maybeSplitFilters split filters configuration param provided by the user
80
- * @param {string} mode settings mode
81
131
  * @returns it returns an object with the following properties:
82
132
  * - `validFilters`: the validated `splitFilters` configuration object defined by the user.
83
133
  * - `queryString`: the parsed split filter query. it is null if all filters are invalid or all values in filters are invalid.
@@ -85,21 +135,16 @@ function queryStringBuilder(groupedFilters: Record<SplitIO.SplitFilterType, stri
85
135
  *
86
136
  * @throws Error if the some of the grouped list of values per filter exceeds the max allowed length
87
137
  */
88
- export function validateSplitFilters(log: ILogger, maybeSplitFilters: any, mode: string): ISplitFiltersValidation {
138
+ export function validateSplitFilters(log: ILogger, maybeSplitFilters: any): ISplitFiltersValidation {
89
139
  // Validation result schema
90
140
  const res = {
91
141
  validFilters: [],
92
142
  queryString: null,
93
- groupedFilters: { byName: [], byPrefix: [] }
143
+ groupedFilters: { bySet: [], byName: [], byPrefix: [] },
94
144
  } as ISplitFiltersValidation;
95
145
 
96
146
  // do nothing if `splitFilters` param is not a non-empty array or mode is not STANDALONE
97
147
  if (!maybeSplitFilters) return res;
98
- // Warn depending on the mode
99
- if (mode !== STANDALONE_MODE) {
100
- log.warn(WARN_SPLITS_FILTER_IGNORED, [STANDALONE_MODE]);
101
- return res;
102
- }
103
148
  // Check collection type
104
149
  if (!Array.isArray(maybeSplitFilters) || maybeSplitFilters.length === 0) {
105
150
  log.warn(WARN_SPLITS_FILTER_EMPTY);
@@ -122,9 +167,32 @@ export function validateSplitFilters(log: ILogger, maybeSplitFilters: any, mode:
122
167
  if (res.groupedFilters[type].length > 0) res.groupedFilters[type] = validateSplitFilter(log, type, res.groupedFilters[type], maxLength);
123
168
  });
124
169
 
170
+ const setFilter = configuredFilter(res.validFilters, 'bySet');
171
+ // Clean all filters if set filter is present
172
+ if (setFilter) {
173
+ if (configuredFilter(res.validFilters, 'byName') || configuredFilter(res.validFilters, 'byPrefix')) log.error(ERROR_SETS_FILTER_EXCLUSIVE);
174
+ objectAssign(res.groupedFilters, { byName: [], byPrefix: [] });
175
+ }
176
+
125
177
  // build query string
126
178
  res.queryString = queryStringBuilder(res.groupedFilters);
127
179
  log.debug(SETTINGS_SPLITS_FILTER, [res.queryString]);
128
180
 
129
181
  return res;
130
182
  }
183
+
184
+ export function flagSetsAreValid(log: ILogger, method: string, flagSets: string[], flagSetsInConfig: string[]): string[] {
185
+ const sets = validateSplits(log, flagSets, method, 'flag sets', 'flag set');
186
+ let toReturn = sets ? sanitizeFlagSets(log, sets) : [];
187
+ if (flagSetsInConfig.length > 0) {
188
+ toReturn = toReturn.filter(flagSet => {
189
+ if (flagSetsInConfig.indexOf(flagSet) > -1) {
190
+ return true;
191
+ }
192
+ log.warn(WARN_FLAGSET_NOT_CONFIGURED, [method, flagSet]);
193
+ return false;
194
+ });
195
+ }
196
+
197
+ return toReturn;
198
+ }
@@ -132,6 +132,7 @@ export interface ISplit {
132
132
  configurations?: {
133
133
  [treatmentName: string]: string;
134
134
  };
135
+ sets?: string[];
135
136
  }
136
137
  export declare type ISplitPartial = Pick<ISplit, 'conditions' | 'configurations' | 'trafficTypeName'>;
137
138
  /** Interface of the parsed JSON response of `/splitChanges` */
@@ -5,3 +5,4 @@ import { SplitIO } from '../types';
5
5
  import { ILogger } from '../logger/types';
6
6
  export declare function evaluateFeature(log: ILogger, key: SplitIO.SplitKey, splitName: string, attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync): MaybeThenable<IEvaluationResult>;
7
7
  export declare function evaluateFeatures(log: ILogger, key: SplitIO.SplitKey, splitNames: string[], attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync): MaybeThenable<Record<string, IEvaluationResult>>;
8
+ export declare function evaluateFeaturesByFlagSets(log: ILogger, key: SplitIO.SplitKey, flagSets: string[], attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync): MaybeThenable<Record<string, IEvaluationResult>>;
@@ -89,12 +89,14 @@ export declare const WARN_NOT_EXISTENT_SPLIT = 215;
89
89
  export declare const WARN_LOWERCASE_TRAFFIC_TYPE = 216;
90
90
  export declare const WARN_NOT_EXISTENT_TT = 217;
91
91
  export declare const WARN_INTEGRATION_INVALID = 218;
92
- export declare const WARN_SPLITS_FILTER_IGNORED = 219;
93
92
  export declare const WARN_SPLITS_FILTER_INVALID = 220;
94
93
  export declare const WARN_SPLITS_FILTER_EMPTY = 221;
95
94
  export declare const WARN_SDK_KEY = 222;
96
95
  export declare const STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2 = 223;
97
96
  export declare const STREAMING_PARSING_SPLIT_UPDATE = 224;
97
+ export declare const WARN_SPLITS_FILTER_INVALID_SET = 225;
98
+ export declare const WARN_SPLITS_FILTER_LOWERCASE_SET = 226;
99
+ export declare const WARN_FLAGSET_NOT_CONFIGURED = 227;
98
100
  export declare const ERROR_ENGINE_COMBINER_IFELSEIF = 300;
99
101
  export declare const ERROR_LOGLEVEL_INVALID = 301;
100
102
  export declare const ERROR_CLIENT_LISTENER = 302;
@@ -122,6 +124,8 @@ export declare const ERROR_LOCALHOST_MODULE_REQUIRED = 323;
122
124
  export declare const ERROR_STORAGE_INVALID = 324;
123
125
  export declare const ERROR_NOT_BOOLEAN = 325;
124
126
  export declare const ERROR_MIN_CONFIG_PARAM = 326;
127
+ export declare const ERROR_TOO_MANY_SETS = 327;
128
+ export declare const ERROR_SETS_FILTER_EXCLUSIVE = 328;
125
129
  export declare const LOG_PREFIX_SETTINGS = "settings";
126
130
  export declare const LOG_PREFIX_INSTANTIATION = "Factory instantiation";
127
131
  export declare const LOG_PREFIX_ENGINE = "engine";
@@ -0,0 +1,5 @@
1
+ export declare const myLogger: {
2
+ log: (msg: any) => void;
3
+ logCsv: (msg: any) => void;
4
+ logToFile: (file: any, msg: any) => void;
5
+ };
@@ -8,6 +8,10 @@ export declare function clientAttributesDecoration<TClient extends SplitIO.IClie
8
8
  getTreatmentWithConfig: (maybeKey: SplitIO.SplitKey, maybeFeatureFlagName: string, maybeAttributes?: SplitIO.Attributes | undefined) => SplitIO.TreatmentWithConfig | SplitIO.AsyncTreatmentWithConfig;
9
9
  getTreatments: (maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes | undefined) => SplitIO.Treatments | SplitIO.AsyncTreatments;
10
10
  getTreatmentsWithConfig: (maybeKey: SplitIO.SplitKey, maybeFeatureFlagNames: string[], maybeAttributes?: SplitIO.Attributes | undefined) => SplitIO.TreatmentsWithConfig | SplitIO.AsyncTreatmentsWithConfig;
11
+ getTreatmentsByFlagSets: (maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes | undefined) => SplitIO.Treatments | SplitIO.AsyncTreatments;
12
+ getTreatmentsWithConfigByFlagSets: (maybeKey: SplitIO.SplitKey, maybeFlagSets: string[], maybeAttributes?: SplitIO.Attributes | undefined) => SplitIO.TreatmentsWithConfig | SplitIO.AsyncTreatmentsWithConfig;
13
+ getTreatmentsByFlagSet: (maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes | undefined) => SplitIO.Treatments | SplitIO.AsyncTreatments;
14
+ getTreatmentsWithConfigByFlagSet: (maybeKey: SplitIO.SplitKey, maybeFlagSet: string, maybeAttributes?: SplitIO.Attributes | undefined) => SplitIO.TreatmentsWithConfig | SplitIO.AsyncTreatmentsWithConfig;
11
15
  track: (maybeKey: SplitIO.SplitKey, maybeTT: string, maybeEvent: string, maybeEventValue?: number | undefined, maybeProperties?: SplitIO.Properties | undefined) => boolean | Promise<boolean>;
12
16
  /**
13
17
  * Add an attribute to client's in memory attributes storage
@@ -0,0 +1,18 @@
1
+ import { ISignalListener } from '../listeners/types';
2
+ import { ISdkReadinessManager } from '../readiness/types';
3
+ import { IStorageAsync, IStorageSync } from '../storages/types';
4
+ import { ISyncManager } from '../sync/types';
5
+ import { IEventTracker, IImpressionsTracker } from '../trackers/types';
6
+ import { ISettings } from '../types';
7
+ export interface IClientFactoryParams {
8
+ storage: IStorageSync | IStorageAsync;
9
+ sdkReadinessManager: ISdkReadinessManager;
10
+ settings: ISettings;
11
+ impressionsTracker: IImpressionsTracker;
12
+ eventTracker: IEventTracker;
13
+ }
14
+ export interface ISdkClientFactoryParams extends IClientFactoryParams {
15
+ signalListener?: ISignalListener;
16
+ syncManager?: ISyncManager;
17
+ sharedClient?: boolean;
18
+ }
@@ -1,5 +1,6 @@
1
1
  import { ISplitsCacheAsync } from './types';
2
2
  import { ISplit } from '../dtos/types';
3
+ import { ISet } from '../utils/lang/sets';
3
4
  /**
4
5
  * This class provides a skeletal implementation of the ISplitsCacheAsync interface
5
6
  * to minimize the effort required to implement this interface.
@@ -14,6 +15,7 @@ export declare abstract class AbstractSplitsCacheAsync implements ISplitsCacheAs
14
15
  abstract getChangeNumber(): Promise<number>;
15
16
  abstract getAll(): Promise<ISplit[]>;
16
17
  abstract getSplitNames(): Promise<string[]>;
18
+ abstract getNamesByFlagSets(flagSets: string[]): Promise<ISet<string>>;
17
19
  abstract trafficTypeExists(trafficType: string): Promise<boolean>;
18
20
  abstract clear(): Promise<boolean | void>;
19
21
  usesSegments(): Promise<boolean>;
@@ -1,5 +1,6 @@
1
1
  import { ISplitsCacheSync } from './types';
2
2
  import { ISplit } from '../dtos/types';
3
+ import { ISet } from '../utils/lang/sets';
3
4
  /**
4
5
  * This class provides a skeletal implementation of the ISplitsCacheSync interface
5
6
  * to minimize the effort required to implement this interface.
@@ -34,6 +35,7 @@ export declare abstract class AbstractSplitsCacheSync implements ISplitsCacheSyn
34
35
  * for instance, if the `changeNumber` is old, or if the split is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
35
36
  */
36
37
  killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean;
38
+ abstract getNamesByFlagSets(flagSets: string[]): ISet<string>;
37
39
  }
38
40
  /**
39
41
  * Given a parsed split, it returns a boolean flagging if its conditions use segments matchers (rules & whitelists).
@@ -3,6 +3,7 @@ export declare class KeyBuilder {
3
3
  protected readonly prefix: string;
4
4
  constructor(prefix?: string);
5
5
  buildTrafficTypeKey(trafficType: string): string;
6
+ buildFlagSetKey(flagSet: string): string;
6
7
  buildSplitKey(splitName: string): string;
7
8
  buildSplitsTillKey(): string;
8
9
  isSplitKey(key: string): boolean;
@@ -2,6 +2,7 @@ import { ISplit, ISplitFiltersValidation } from '../../dtos/types';
2
2
  import { AbstractSplitsCacheSync } from '../AbstractSplitsCacheSync';
3
3
  import { KeyBuilderCS } from '../KeyBuilderCS';
4
4
  import { ILogger } from '../../logger/types';
5
+ import { ISet } from '../../utils/lang/sets';
5
6
  /**
6
7
  * ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
7
8
  */
@@ -9,8 +10,8 @@ export declare class SplitsCacheInLocal extends AbstractSplitsCacheSync {
9
10
  private readonly log;
10
11
  private readonly keys;
11
12
  private readonly splitFiltersValidation;
13
+ private readonly flagSetsFilter;
12
14
  private hasSync?;
13
- private cacheReadyButNeedsToFlush;
14
15
  private updateNewFilter?;
15
16
  /**
16
17
  * @param {KeyBuilderCS} keys
@@ -47,4 +48,8 @@ export declare class SplitsCacheInLocal extends AbstractSplitsCacheSync {
47
48
  */
48
49
  private _checkExpiration;
49
50
  private _checkFilterQuery;
51
+ getNamesByFlagSets(flagSets: string[]): ISet<string>;
52
+ private addToFlagSets;
53
+ private removeFromFlagSets;
54
+ private removeNames;
50
55
  }
@@ -0,0 +1,20 @@
1
+ import { ICountsCacheSync } from '../types';
2
+ export declare class CountsCacheInMemory implements ICountsCacheSync {
3
+ private counters;
4
+ /**
5
+ * Add counts.
6
+ */
7
+ track(metricName: string): boolean;
8
+ /**
9
+ * Clear the collector
10
+ */
11
+ clear(): void;
12
+ /**
13
+ * Get the collected data, used as payload for posting.
14
+ */
15
+ state(): Record<string, number>;
16
+ /**
17
+ * Check if the cache is empty.
18
+ */
19
+ isEmpty(): boolean;
20
+ }
@@ -0,0 +1,20 @@
1
+ import { ILatenciesCacheSync } from '../types';
2
+ export declare class LatenciesCacheInMemory implements ILatenciesCacheSync {
3
+ private counters;
4
+ /**
5
+ * Add latencies.
6
+ */
7
+ track(metricName: string, latency: number): boolean;
8
+ /**
9
+ * Clear the collector
10
+ */
11
+ clear(): void;
12
+ /**
13
+ * Get the collected data, used as payload for posting.
14
+ */
15
+ state(): Record<string, number[]>;
16
+ /**
17
+ * Check if the cache is empty.
18
+ */
19
+ isEmpty(): boolean;
20
+ }
@@ -1,14 +1,18 @@
1
- import { ISplit } from '../../dtos/types';
1
+ import { ISplit, ISplitFiltersValidation } from '../../dtos/types';
2
2
  import { AbstractSplitsCacheSync } from '../AbstractSplitsCacheSync';
3
+ import { ISet } from '../../utils/lang/sets';
3
4
  /**
4
5
  * Default ISplitsCacheSync implementation that stores split definitions in memory.
5
6
  * Supported by all JS runtimes.
6
7
  */
7
8
  export declare class SplitsCacheInMemory extends AbstractSplitsCacheSync {
9
+ private flagSetsFilter;
8
10
  private splitsCache;
9
11
  private ttCache;
10
12
  private changeNumber;
11
13
  private splitsWithSegmentsCount;
14
+ private flagSetsCache;
15
+ constructor(splitFiltersValidation?: ISplitFiltersValidation);
12
16
  clear(): void;
13
17
  addSplit(name: string, split: ISplit): boolean;
14
18
  removeSplit(name: string): boolean;
@@ -18,4 +22,8 @@ export declare class SplitsCacheInMemory extends AbstractSplitsCacheSync {
18
22
  getSplitNames(): string[];
19
23
  trafficTypeExists(trafficType: string): boolean;
20
24
  usesSegments(): boolean;
25
+ getNamesByFlagSets(flagSets: string[]): ISet<string>;
26
+ private addToFlagSets;
27
+ private removeFromFlagSets;
28
+ private removeNames;
21
29
  }
@@ -0,0 +1,9 @@
1
+ import { ICountsCacheAsync } from '../types';
2
+ import { KeyBuilderSS } from '../KeyBuilderSS';
3
+ import { Redis } from 'ioredis';
4
+ export declare class CountsCacheInRedis implements ICountsCacheAsync {
5
+ private readonly redis;
6
+ private readonly keys;
7
+ constructor(keys: KeyBuilderSS, redis: Redis);
8
+ track(metricName: string): Promise<boolean>;
9
+ }
@@ -0,0 +1,9 @@
1
+ import { ILatenciesCacheAsync } from '../types';
2
+ import { KeyBuilderSS } from '../KeyBuilderSS';
3
+ import { Redis } from 'ioredis';
4
+ export declare class LatenciesCacheInRedis implements ILatenciesCacheAsync {
5
+ private readonly redis;
6
+ private readonly keys;
7
+ constructor(keys: KeyBuilderSS, redis: Redis);
8
+ track(metricName: string, latency: number): Promise<boolean>;
9
+ }
@@ -3,6 +3,7 @@ import { Redis } from 'ioredis';
3
3
  import { ILogger } from '../../logger/types';
4
4
  import { ISplit } from '../../dtos/types';
5
5
  import { AbstractSplitsCacheAsync } from '../AbstractSplitsCacheAsync';
6
+ import { ISet } from '../../utils/lang/sets';
6
7
  /**
7
8
  * ISplitsCacheAsync implementation that stores split definitions in Redis.
8
9
  * Supported by Node.
@@ -71,6 +72,13 @@ export declare class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
71
72
  * or rejected if redis operation fails.
72
73
  */
73
74
  getSplitNames(): Promise<string[]>;
75
+ /**
76
+ * Get list of split names related to a given flag set names list.
77
+ * The returned promise is resolved with the list of split names,
78
+ * or rejected if wrapper operation fails.
79
+ * @todo this is a no-op method to be implemented
80
+ */
81
+ getNamesByFlagSets(): Promise<ISet<string>>;
74
82
  /**
75
83
  * Check traffic type existence.
76
84
  * The returned promise is resolved with a boolean indicating whether the TT exist or not.
@@ -0,0 +1,3 @@
1
+ import { IMetadata } from '../dtos/types';
2
+ import { ISettings } from '../types';
3
+ export declare function metadataBuilder(settings: Pick<ISettings, 'version' | 'runtime'>): IMetadata;
@@ -3,6 +3,7 @@ import { IPluggableStorageWrapper } from '../types';
3
3
  import { ILogger } from '../../logger/types';
4
4
  import { ISplit } from '../../dtos/types';
5
5
  import { AbstractSplitsCacheAsync } from '../AbstractSplitsCacheAsync';
6
+ import { ISet } from '../../utils/lang/sets';
6
7
  /**
7
8
  * ISplitsCacheAsync implementation for pluggable storages.
8
9
  */
@@ -67,6 +68,13 @@ export declare class SplitsCachePluggable extends AbstractSplitsCacheAsync {
67
68
  * or rejected if wrapper operation fails.
68
69
  */
69
70
  getSplitNames(): Promise<string[]>;
71
+ /**
72
+ * Get list of split names related to a given flag set names list.
73
+ * The returned promise is resolved with the list of split names,
74
+ * or rejected if wrapper operation fails.
75
+ * @todo this is a no-op method to be implemented
76
+ */
77
+ getNamesByFlagSets(): Promise<ISet<string>>;
70
78
  /**
71
79
  * Check traffic type existence.
72
80
  * The returned promise is resolved with a boolean indicating whether the TT exist or not.