@splitsoftware/splitio-commons 1.12.1-rc.1 → 1.12.1-rc.3

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 (58) hide show
  1. package/CHANGES.txt +11 -9
  2. package/cjs/sdkClient/client.js +4 -4
  3. package/cjs/sdkFactory/index.js +1 -1
  4. package/cjs/sdkManager/index.js +9 -6
  5. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +1 -3
  6. package/cjs/storages/inRedis/RedisAdapter.js +32 -13
  7. package/cjs/storages/inRedis/SegmentsCacheInRedis.js +2 -2
  8. package/cjs/storages/inRedis/SplitsCacheInRedis.js +15 -15
  9. package/cjs/storages/pluggable/SplitsCachePluggable.js +5 -5
  10. package/cjs/utils/inputValidation/index.js +5 -5
  11. package/cjs/utils/inputValidation/{splitExistance.js → splitExistence.js} +3 -3
  12. package/cjs/utils/inputValidation/{trafficTypeExistance.js → trafficTypeExistence.js} +6 -6
  13. package/esm/sdkClient/client.js +4 -4
  14. package/esm/sdkFactory/index.js +1 -1
  15. package/esm/sdkManager/index.js +10 -7
  16. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +1 -3
  17. package/esm/storages/inRedis/RedisAdapter.js +32 -13
  18. package/esm/storages/inRedis/SegmentsCacheInRedis.js +2 -2
  19. package/esm/storages/inRedis/SplitsCacheInRedis.js +15 -15
  20. package/esm/storages/pluggable/SplitsCachePluggable.js +5 -5
  21. package/esm/utils/inputValidation/index.js +2 -2
  22. package/esm/utils/inputValidation/{splitExistance.js → splitExistence.js} +1 -1
  23. package/esm/utils/inputValidation/{trafficTypeExistance.js → trafficTypeExistence.js} +4 -4
  24. package/package.json +1 -1
  25. package/src/sdkClient/client.ts +4 -4
  26. package/src/sdkFactory/index.ts +1 -1
  27. package/src/sdkFactory/types.ts +3 -7
  28. package/src/sdkManager/index.ts +13 -10
  29. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +4 -5
  30. package/src/storages/inRedis/EventsCacheInRedis.ts +3 -3
  31. package/src/storages/inRedis/ImpressionCountsCacheInRedis.ts +3 -3
  32. package/src/storages/inRedis/ImpressionsCacheInRedis.ts +3 -3
  33. package/src/storages/inRedis/RedisAdapter.ts +38 -16
  34. package/src/storages/inRedis/SegmentsCacheInRedis.ts +5 -5
  35. package/src/storages/inRedis/SplitsCacheInRedis.ts +18 -19
  36. package/src/storages/inRedis/TelemetryCacheInRedis.ts +2 -2
  37. package/src/storages/inRedis/UniqueKeysCacheInRedis.ts +3 -3
  38. package/src/storages/pluggable/SplitsCachePluggable.ts +5 -5
  39. package/src/trackers/impressionObserver/utils.ts +1 -1
  40. package/src/utils/inputValidation/index.ts +2 -2
  41. package/src/utils/inputValidation/{splitExistance.ts → splitExistence.ts} +1 -1
  42. package/src/utils/inputValidation/{trafficTypeExistance.ts → trafficTypeExistence.ts} +4 -4
  43. package/src/utils/redis/RedisMock.ts +1 -3
  44. package/types/sdkFactory/types.d.ts +3 -3
  45. package/types/sdkManager/index.d.ts +2 -3
  46. package/types/storages/inRedis/EventsCacheInRedis.d.ts +2 -2
  47. package/types/storages/inRedis/ImpressionCountsCacheInRedis.d.ts +3 -2
  48. package/types/storages/inRedis/ImpressionsCacheInRedis.d.ts +2 -2
  49. package/types/storages/inRedis/RedisAdapter.d.ts +1 -1
  50. package/types/storages/inRedis/SegmentsCacheInRedis.d.ts +3 -3
  51. package/types/storages/inRedis/SplitsCacheInRedis.d.ts +6 -11
  52. package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +2 -2
  53. package/types/storages/inRedis/UniqueKeysCacheInRedis.d.ts +3 -2
  54. package/types/storages/pluggable/SplitsCachePluggable.d.ts +4 -4
  55. package/types/trackers/impressionObserver/utils.d.ts +1 -1
  56. package/types/utils/inputValidation/index.d.ts +2 -2
  57. package/types/utils/inputValidation/splitExistence.d.ts +7 -0
  58. package/types/utils/inputValidation/trafficTypeExistence.d.ts +9 -0
package/CHANGES.txt CHANGED
@@ -1,16 +1,18 @@
1
1
  1.12.0 (December XX, 2023)
2
2
  - Added support for Flag Sets in "consumer" and "partial consumer" modes for Pluggable and Redis storages.
3
3
  - Updated evaluation flow to log a warning when using flag sets that don't contain cached feature flags.
4
+ - Updated Redis adapter to handle timeouts and queueing of some missing commands: 'hincrby', 'popNRaw', and 'pipeline.exec'.
5
+ - Bugfixing - Fixed manager methods in consumer modes to return results in a promise when the SDK is not operational (not ready or destroyed).
4
6
 
5
7
  1.11.0 (November 3, 2023)
6
- - Added support for Flag Sets on the SDK, which enables grouping feature flags and interacting with the group rather than individually (more details in our documentation):
7
- - Added new variations of the get treatment methods to support evaluating flags in given flag set/s.
8
- - getTreatmentsByFlagSet and getTreatmentsByFlagSets
9
- - getTreatmentsWithConfigByFlagSets and getTreatmentsWithConfigByFlagSets
10
- - Added a new optional Split Filter configuration option. This allows the SDK and Split services to only synchronize the flags in the specified flag sets, avoiding unused or unwanted flags from being synced on the SDK instance, bringing all the benefits from a reduced payload.
11
- - Note: Only applicable when the SDK is in charge of the rollout data synchronization. When not applicable, the SDK will log a warning on init.
12
- - Added `sets` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager to expose flag sets on flag views.
13
- - Bugfixing - Fixed SDK key validation in NodeJS to ensure the SDK_READY_TIMED_OUT event is emitted when a client-side type SDK key is provided instead of a server-side one (Related to issue https://github.com/splitio/javascript-client/issues/768).
8
+ - Added support for Flag Sets on the SDK, which enables grouping feature flags and interacting with the group rather than individually (more details in our documentation):
9
+ - Added new variations of the get treatment methods to support evaluating flags in given flag set/s.
10
+ - getTreatmentsByFlagSet and getTreatmentsByFlagSets
11
+ - getTreatmentsWithConfigByFlagSets and getTreatmentsWithConfigByFlagSets
12
+ - Added a new optional Split Filter configuration option. This allows the SDK and Split services to only synchronize the flags in the specified flag sets, avoiding unused or unwanted flags from being synced on the SDK instance, bringing all the benefits from a reduced payload.
13
+ - Note: Only applicable when the SDK is in charge of the rollout data synchronization. When not applicable, the SDK will log a warning on init.
14
+ - Added `sets` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager to expose flag sets on flag views.
15
+ - Bugfixing - Fixed SDK key validation in NodeJS to ensure the SDK_READY_TIMED_OUT event is emitted when a client-side type SDK key is provided instead of a server-side one (Related to issue https://github.com/splitio/javascript-client/issues/768).
14
16
 
15
17
  1.10.0 (October 20, 2023)
16
18
  - Added `defaultTreatment` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager (Related to issue https://github.com/splitio/javascript-commons/issues/225).
@@ -57,7 +59,7 @@
57
59
  - Added a new impressions mode for the SDK called NONE, to be used in factory when there is no desire to capture impressions on an SDK factory to feed Split's analytics engine. Running NONE mode, the SDK will only capture unique keys evaluated for a particular feature flag instead of full blown impressions.
58
60
  - Updated SDK telemetry to support pluggable storage, partial consumer mode, and synchronizer.
59
61
  - Updated storage implementations to improve the performance of feature flag evaluations (i.e., `getTreatment(s)` method calls) when using the default storage in memory.
60
- - Updated evaluation flow to avoid unnecessarily storage calls when the SDK is not ready.
62
+ - Updated evaluation flow (i.e., `getTreatment(s)` method calls) to avoid calling the storage for cached feature flags when the SDK is not ready or ready from cache. It applies to all SDK modes.
61
63
 
62
64
  1.6.1 (July 22, 2022)
63
65
  - Updated GoogleAnalyticsToSplit integration to validate `autoRequire` config parameter and avoid some wrong warning logs when mapping GA hit fields to Split event properties.
@@ -4,8 +4,8 @@ exports.clientFactory = void 0;
4
4
  var evaluator_1 = require("../evaluator");
5
5
  var thenable_1 = require("../utils/promise/thenable");
6
6
  var key_1 = require("../utils/key");
7
- var splitExistance_1 = require("../utils/inputValidation/splitExistance");
8
- var trafficTypeExistance_1 = require("../utils/inputValidation/trafficTypeExistance");
7
+ var splitExistence_1 = require("../utils/inputValidation/splitExistence");
8
+ var trafficTypeExistence_1 = require("../utils/inputValidation/trafficTypeExistence");
9
9
  var labels_1 = require("../utils/labels");
10
10
  var constants_1 = require("../utils/constants");
11
11
  var constants_2 = require("../logger/constants");
@@ -102,7 +102,7 @@ function clientFactory(params) {
102
102
  var bucketingKey = (0, key_1.getBucketing)(key);
103
103
  var treatment = evaluation.treatment, label = evaluation.label, changeNumber = evaluation.changeNumber, _a = evaluation.config, config = _a === void 0 ? null : _a;
104
104
  log.info(constants_2.IMPRESSION, [featureFlagName, matchingKey, treatment, label]);
105
- if ((0, splitExistance_1.validateSplitExistance)(log, readinessManager, featureFlagName, label, invokingMethodName)) {
105
+ if ((0, splitExistence_1.validateSplitExistence)(log, readinessManager, featureFlagName, label, invokingMethodName)) {
106
106
  log.info(constants_2.IMPRESSION_QUEUEING);
107
107
  queue.push({
108
108
  feature: featureFlagName,
@@ -136,7 +136,7 @@ function clientFactory(params) {
136
136
  properties: properties
137
137
  };
138
138
  // This may be async but we only warn, we don't actually care if it is valid or not in terms of queueing the event.
139
- (0, trafficTypeExistance_1.validateTrafficTypeExistance)(log, readinessManager, storage.splits, mode, trafficTypeName, 'track');
139
+ (0, trafficTypeExistence_1.validateTrafficTypeExistence)(log, readinessManager, storage.splits, mode, trafficTypeName, 'track');
140
140
  var result = eventTracker.track(eventData, size);
141
141
  if ((0, thenable_1.thenable)(result)) {
142
142
  return result.then(function (result) {
@@ -66,7 +66,7 @@ function sdkFactory(params) {
66
66
  ctx.signalListener = signalListener;
67
67
  // SDK client and manager
68
68
  var clientMethod = sdkClientMethodFactory(ctx);
69
- var managerInstance = sdkManagerFactory(log, storage.splits, sdkReadinessManager);
69
+ var managerInstance = sdkManagerFactory(settings, storage.splits, sdkReadinessManager);
70
70
  syncManager && syncManager.start();
71
71
  signalListener && signalListener.start();
72
72
  log.info(constants_1.NEW_FACTORY);
@@ -5,6 +5,7 @@ var objectAssign_1 = require("../utils/lang/objectAssign");
5
5
  var thenable_1 = require("../utils/promise/thenable");
6
6
  var lang_1 = require("../utils/lang");
7
7
  var inputValidation_1 = require("../utils/inputValidation");
8
+ var utils_1 = require("../trackers/impressionObserver/utils");
8
9
  var SPLIT_FN_LABEL = 'split';
9
10
  var SPLITS_FN_LABEL = 'splits';
10
11
  var NAMES_FN_LABEL = 'names';
@@ -41,8 +42,10 @@ function objectsToViews(splitObjects) {
41
42
  });
42
43
  return views;
43
44
  }
44
- function sdkManagerFactory(log, splits, _a) {
45
+ function sdkManagerFactory(settings, splits, _a) {
45
46
  var readinessManager = _a.readinessManager, sdkStatus = _a.sdkStatus;
47
+ var log = settings.log;
48
+ var isSync = (0, utils_1.isStorageSync)(settings);
46
49
  return (0, objectAssign_1.objectAssign)(
47
50
  // Proto-linkage of the readiness Event Emitter
48
51
  Object.create(sdkStatus), {
@@ -52,16 +55,16 @@ function sdkManagerFactory(log, splits, _a) {
52
55
  split: function (featureFlagName) {
53
56
  var splitName = (0, inputValidation_1.validateSplit)(log, featureFlagName, SPLIT_FN_LABEL);
54
57
  if (!(0, inputValidation_1.validateIfNotDestroyed)(log, readinessManager, SPLIT_FN_LABEL) || !(0, inputValidation_1.validateIfOperational)(log, readinessManager, SPLIT_FN_LABEL) || !splitName) {
55
- return null;
58
+ return isSync ? null : Promise.resolve(null);
56
59
  }
57
60
  var split = splits.getSplit(splitName);
58
61
  if ((0, thenable_1.thenable)(split)) {
59
62
  return split.catch(function () { return null; }).then(function (result) {
60
- (0, inputValidation_1.validateSplitExistance)(log, readinessManager, splitName, result, SPLIT_FN_LABEL);
63
+ (0, inputValidation_1.validateSplitExistence)(log, readinessManager, splitName, result, SPLIT_FN_LABEL);
61
64
  return objectToView(result);
62
65
  });
63
66
  }
64
- (0, inputValidation_1.validateSplitExistance)(log, readinessManager, splitName, split, SPLIT_FN_LABEL);
67
+ (0, inputValidation_1.validateSplitExistence)(log, readinessManager, splitName, split, SPLIT_FN_LABEL);
65
68
  return objectToView(split);
66
69
  },
67
70
  /**
@@ -69,7 +72,7 @@ function sdkManagerFactory(log, splits, _a) {
69
72
  */
70
73
  splits: function () {
71
74
  if (!(0, inputValidation_1.validateIfNotDestroyed)(log, readinessManager, SPLITS_FN_LABEL) || !(0, inputValidation_1.validateIfOperational)(log, readinessManager, SPLITS_FN_LABEL)) {
72
- return [];
75
+ return isSync ? [] : Promise.resolve([]);
73
76
  }
74
77
  var currentSplits = splits.getAll();
75
78
  return (0, thenable_1.thenable)(currentSplits) ?
@@ -81,7 +84,7 @@ function sdkManagerFactory(log, splits, _a) {
81
84
  */
82
85
  names: function () {
83
86
  if (!(0, inputValidation_1.validateIfNotDestroyed)(log, readinessManager, NAMES_FN_LABEL) || !(0, inputValidation_1.validateIfOperational)(log, readinessManager, NAMES_FN_LABEL)) {
84
- return [];
87
+ return isSync ? [] : Promise.resolve([]);
85
88
  }
86
89
  var splitNames = splits.getSplitNames();
87
90
  return (0, thenable_1.thenable)(splitNames) ?
@@ -246,9 +246,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
246
246
  return;
247
247
  var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
248
248
  var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
249
- if (!flagSetFromLocalStorage)
250
- flagSetFromLocalStorage = '[]';
251
- var flagSetCache = new sets_1._Set(JSON.parse(flagSetFromLocalStorage));
249
+ var flagSetCache = new sets_1._Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
252
250
  flagSetCache.add(featureFlag.name);
253
251
  localStorage.setItem(flagSetKey, JSON.stringify((0, sets_1.setToArray)(flagSetCache)));
254
252
  });
@@ -9,7 +9,8 @@ var thenable_1 = require("../../utils/promise/thenable");
9
9
  var timeout_1 = require("../../utils/promise/timeout");
10
10
  var LOG_PREFIX = 'storage:redis-adapter: ';
11
11
  // If we ever decide to fully wrap every method, there's a Commander.getBuiltinCommands from ioredis.
12
- var METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'pipeline', 'expire', 'mget', 'lrange', 'ltrim', 'hset'];
12
+ var METHODS_TO_PROMISE_WRAP = ['set', 'exec', 'del', 'get', 'keys', 'sadd', 'srem', 'sismember', 'smembers', 'incr', 'rpush', 'expire', 'mget', 'lrange', 'ltrim', 'hset', 'hincrby', 'popNRaw'];
13
+ var METHODS_TO_PROMISE_WRAP_EXEC = ['pipeline'];
13
14
  // Not part of the settings since it'll vary on each storage. We should be removing storage specific logic from elsewhere.
14
15
  var DEFAULT_OPTIONS = {
15
16
  connectionTimeout: 10000,
@@ -27,6 +28,7 @@ var DEFAULT_LIBRARY_OPTIONS = {
27
28
  var RedisAdapter = /** @class */ (function (_super) {
28
29
  (0, tslib_1.__extends)(RedisAdapter, _super);
29
30
  function RedisAdapter(log, storageSettings) {
31
+ if (storageSettings === void 0) { storageSettings = {}; }
30
32
  var _this = this;
31
33
  var options = RedisAdapter._defineOptions(storageSettings);
32
34
  // Call the ioredis constructor
@@ -58,14 +60,15 @@ var RedisAdapter = /** @class */ (function (_super) {
58
60
  };
59
61
  RedisAdapter.prototype._setTimeoutWrappers = function () {
60
62
  var instance = this;
61
- METHODS_TO_PROMISE_WRAP.forEach(function (method) {
62
- var originalMethod = instance[method];
63
- instance[method] = function () {
63
+ var wrapCommand = function (originalMethod, methodName) {
64
+ // The value of "this" in this function should be the instance actually executing the method. It might be the instance referred (the base one)
65
+ // or it can be the instance of a Pipeline object.
66
+ return function () {
64
67
  var params = arguments;
68
+ var caller = this;
65
69
  function commandWrapper() {
66
- instance.log.debug(LOG_PREFIX + ("Executing " + method + "."));
67
- // Return original method
68
- var result = originalMethod.apply(instance, params);
70
+ instance.log.debug(LOG_PREFIX + "Executing " + methodName + ".");
71
+ var result = originalMethod.apply(caller, params);
69
72
  if ((0, thenable_1.thenable)(result)) {
70
73
  // For handling pending commands on disconnect, add to the set and remove once finished.
71
74
  // On sync commands there's no need, only thenables.
@@ -76,7 +79,7 @@ var RedisAdapter = /** @class */ (function (_super) {
76
79
  // Both success and error remove from queue.
77
80
  result.then(cleanUpRunningCommandsCb, cleanUpRunningCommandsCb);
78
81
  return (0, timeout_1.timeout)(instance._options.operationTimeout, result).catch(function (err) {
79
- instance.log.error(LOG_PREFIX + (method + " operation threw an error or exceeded configured timeout of " + instance._options.operationTimeout + "ms. Message: " + err));
82
+ instance.log.error("" + LOG_PREFIX + methodName + " operation threw an error or exceeded configured timeout of " + instance._options.operationTimeout + "ms. Message: " + err);
80
83
  // Handling is not the adapter responsibility.
81
84
  throw err;
82
85
  });
@@ -84,12 +87,12 @@ var RedisAdapter = /** @class */ (function (_super) {
84
87
  return result;
85
88
  }
86
89
  if (instance._notReadyCommandsQueue) {
87
- return new Promise(function (res, rej) {
90
+ return new Promise(function (resolve, reject) {
88
91
  instance._notReadyCommandsQueue.unshift({
89
- resolve: res,
90
- reject: rej,
92
+ resolve: resolve,
93
+ reject: reject,
91
94
  command: commandWrapper,
92
- name: method.toUpperCase()
95
+ name: methodName.toUpperCase()
93
96
  });
94
97
  });
95
98
  }
@@ -97,6 +100,22 @@ var RedisAdapter = /** @class */ (function (_super) {
97
100
  return commandWrapper();
98
101
  }
99
102
  };
103
+ };
104
+ // Wrap regular async methods to track timeouts and queue when Redis is not yet executing commands.
105
+ METHODS_TO_PROMISE_WRAP.forEach(function (methodName) {
106
+ var originalFn = instance[methodName];
107
+ instance[methodName] = wrapCommand(originalFn, methodName);
108
+ });
109
+ // Special handling for pipeline~like methods. We need to wrap the async trigger, which is exec, but return the Pipeline right away.
110
+ METHODS_TO_PROMISE_WRAP_EXEC.forEach(function (methodName) {
111
+ var originalFn = instance[methodName];
112
+ // "First level wrapper" to handle the sync execution and wrap async, queueing later if applicable.
113
+ instance[methodName] = function () {
114
+ var res = originalFn.apply(instance, arguments);
115
+ var originalExec = res.exec;
116
+ res.exec = wrapCommand(originalExec, methodName + '.exec').bind(res);
117
+ return res;
118
+ };
100
119
  });
101
120
  };
102
121
  RedisAdapter.prototype._setDisconnectWrapper = function () {
@@ -107,7 +126,7 @@ var RedisAdapter = /** @class */ (function (_super) {
107
126
  for (var _i = 0; _i < arguments.length; _i++) {
108
127
  params[_i] = arguments[_i];
109
128
  }
110
- setTimeout(function deferedDisconnect() {
129
+ setTimeout(function deferredDisconnect() {
111
130
  if (instance._runningCommands.size > 0) {
112
131
  instance.log.info(LOG_PREFIX + ("Attempting to disconnect but there are " + instance._runningCommands.size + " commands still waiting for resolution. Defering disconnection until those finish."));
113
132
  Promise.all((0, sets_1.setToArray)(instance._runningCommands))
@@ -54,9 +54,9 @@ var SegmentsCacheInRedis = /** @class */ (function () {
54
54
  SegmentsCacheInRedis.prototype.getRegisteredSegments = function () {
55
55
  return this.redis.smembers(this.keys.buildRegisteredSegmentsKey());
56
56
  };
57
- // @TODO remove/review. It is not being used.
57
+ // @TODO remove or implement. It is not being used.
58
58
  SegmentsCacheInRedis.prototype.clear = function () {
59
- return this.redis.flushdb().then(function (status) { return status === 'OK'; });
59
+ return Promise.resolve();
60
60
  };
61
61
  return SegmentsCacheInRedis;
62
62
  }());
@@ -187,16 +187,20 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
187
187
  return this.redis.keys(this.keys.searchPatternForSplitKeys()).then(function (listOfKeys) { return listOfKeys.map(_this.keys.extractKey); });
188
188
  };
189
189
  /**
190
- * Get list of split names related to a given flag set names list.
191
- * The returned promise is resolved with the list of split names,
192
- * or rejected if any wrapper operation fails.
190
+ * Get list of feature flag names related to a given list of flag set names.
191
+ * The returned promise is resolved with the list of feature flag names per flag set,
192
+ * or rejected if the pipelined redis operation fails (e.g., timeout).
193
193
  */
194
194
  SplitsCacheInRedis.prototype.getNamesByFlagSets = function (flagSets) {
195
195
  var _this = this;
196
- return Promise.all(flagSets.map(function (flagSet) {
197
- var flagSetKey = _this.keys.buildFlagSetKey(flagSet);
198
- return _this.redis.smembers(flagSetKey);
199
- })).then(function (namesByFlagSets) { return namesByFlagSets.map(function (namesByFlagSet) { return new sets_1._Set(namesByFlagSet); }); });
196
+ return this.redis.pipeline(flagSets.map(function (flagSet) { return ['smembers', _this.keys.buildFlagSetKey(flagSet)]; })).exec()
197
+ .then(function (results) { return results.map(function (_a, index) {
198
+ var e = _a[0], value = _a[1];
199
+ if (e === null)
200
+ return value;
201
+ _this.log.error(constants_1.LOG_PREFIX + ("Could not read result from get members of flag set " + flagSets[index] + " due to an error: " + e));
202
+ }); })
203
+ .then(function (namesByFlagSets) { return namesByFlagSets.map(function (namesByFlagSet) { return new sets_1._Set(namesByFlagSet); }); });
200
204
  };
201
205
  /**
202
206
  * Check traffic type existence.
@@ -213,24 +217,20 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
213
217
  return false; // if entry doesn't exist, means that TT doesn't exist
214
218
  ttCount = parseInt(ttCount, 10);
215
219
  if (!(0, lang_1.isFiniteNumber)(ttCount) || ttCount < 0) {
216
- _this.log.info(constants_1.LOG_PREFIX + ("Could not validate traffic type existance of " + trafficType + " due to data corruption of some sorts."));
220
+ _this.log.info(constants_1.LOG_PREFIX + ("Could not validate traffic type existence of " + trafficType + " due to data corruption of some sorts."));
217
221
  return false;
218
222
  }
219
223
  return ttCount > 0;
220
224
  })
221
225
  .catch(function (e) {
222
- _this.log.error(constants_1.LOG_PREFIX + ("Could not validate traffic type existance of " + trafficType + " due to an error: " + e + "."));
226
+ _this.log.error(constants_1.LOG_PREFIX + ("Could not validate traffic type existence of " + trafficType + " due to an error: " + e + "."));
223
227
  // If there is an error, bypass the validation so the event can get tracked.
224
228
  return true;
225
229
  });
226
230
  };
227
- /**
228
- * Delete everything in the current database.
229
- *
230
- * @NOTE documentation says it never fails.
231
- */
231
+ // @TODO remove or implement. It is not being used.
232
232
  SplitsCacheInRedis.prototype.clear = function () {
233
- return this.redis.flushdb().then(function (status) { return status === 'OK'; });
233
+ return Promise.resolve();
234
234
  };
235
235
  /**
236
236
  * Fetches multiple splits definitions.
@@ -161,15 +161,15 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
161
161
  return this.wrapper.getKeysByPrefix(this.keys.buildSplitKeyPrefix()).then(function (listOfKeys) { return listOfKeys.map(_this.keys.extractKey); });
162
162
  };
163
163
  /**
164
- * Get list of split names related to a given flag set names list.
165
- * The returned promise is resolved with the list of split names,
166
- * or rejected if any wrapper operation fails.
167
- */
164
+ * Get list of feature flag names related to a given list of flag set names.
165
+ * The returned promise is resolved with the list of feature flag names per flag set.
166
+ * It never rejects (If there is a wrapper error for some flag set, an empty set is returned for it).
167
+ */
168
168
  SplitsCachePluggable.prototype.getNamesByFlagSets = function (flagSets) {
169
169
  var _this = this;
170
170
  return Promise.all(flagSets.map(function (flagSet) {
171
171
  var flagSetKey = _this.keys.buildFlagSetKey(flagSet);
172
- return _this.wrapper.getItems(flagSetKey);
172
+ return _this.wrapper.getItems(flagSetKey).catch(function () { return []; });
173
173
  })).then(function (namesByFlagSets) { return namesByFlagSets.map(function (namesByFlagSet) { return new sets_1._Set(namesByFlagSet); }); });
174
174
  };
175
175
  /**
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validatePreloadedData = exports.validateTrafficTypeExistance = exports.validateSplitExistance = exports.validateIfOperational = exports.validateIfNotDestroyed = exports.validateTrafficType = exports.validateSplits = exports.validateSplit = exports.validateKey = exports.validateEventProperties = exports.validateEventValue = exports.validateEvent = exports.validateAttributes = exports.releaseApiKey = exports.validateAndTrackApiKey = exports.validateApiKey = void 0;
3
+ exports.validatePreloadedData = exports.validateTrafficTypeExistence = exports.validateSplitExistence = exports.validateIfOperational = exports.validateIfNotDestroyed = exports.validateTrafficType = exports.validateSplits = exports.validateSplit = exports.validateKey = exports.validateEventProperties = exports.validateEventValue = exports.validateEvent = exports.validateAttributes = exports.releaseApiKey = exports.validateAndTrackApiKey = exports.validateApiKey = void 0;
4
4
  var apiKey_1 = require("./apiKey");
5
5
  Object.defineProperty(exports, "validateApiKey", { enumerable: true, get: function () { return apiKey_1.validateApiKey; } });
6
6
  Object.defineProperty(exports, "validateAndTrackApiKey", { enumerable: true, get: function () { return apiKey_1.validateAndTrackApiKey; } });
@@ -24,9 +24,9 @@ Object.defineProperty(exports, "validateTrafficType", { enumerable: true, get: f
24
24
  var isOperational_1 = require("./isOperational");
25
25
  Object.defineProperty(exports, "validateIfNotDestroyed", { enumerable: true, get: function () { return isOperational_1.validateIfNotDestroyed; } });
26
26
  Object.defineProperty(exports, "validateIfOperational", { enumerable: true, get: function () { return isOperational_1.validateIfOperational; } });
27
- var splitExistance_1 = require("./splitExistance");
28
- Object.defineProperty(exports, "validateSplitExistance", { enumerable: true, get: function () { return splitExistance_1.validateSplitExistance; } });
29
- var trafficTypeExistance_1 = require("./trafficTypeExistance");
30
- Object.defineProperty(exports, "validateTrafficTypeExistance", { enumerable: true, get: function () { return trafficTypeExistance_1.validateTrafficTypeExistance; } });
27
+ var splitExistence_1 = require("./splitExistence");
28
+ Object.defineProperty(exports, "validateSplitExistence", { enumerable: true, get: function () { return splitExistence_1.validateSplitExistence; } });
29
+ var trafficTypeExistence_1 = require("./trafficTypeExistence");
30
+ Object.defineProperty(exports, "validateTrafficTypeExistence", { enumerable: true, get: function () { return trafficTypeExistence_1.validateTrafficTypeExistence; } });
31
31
  var preloadedData_1 = require("./preloadedData");
32
32
  Object.defineProperty(exports, "validatePreloadedData", { enumerable: true, get: function () { return preloadedData_1.validatePreloadedData; } });
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateSplitExistance = void 0;
3
+ exports.validateSplitExistence = void 0;
4
4
  var labels_1 = require("../labels");
5
5
  var constants_1 = require("../../logger/constants");
6
6
  /**
7
7
  * This is defined here and in this format mostly because of the logger and the fact that it's considered a validation at product level.
8
8
  * But it's not going to run on the input validation layer. In any case, the most compeling reason to use it as we do is to avoid going to Redis and get a split twice.
9
9
  */
10
- function validateSplitExistance(log, readinessManager, splitName, labelOrSplitObj, method) {
10
+ function validateSplitExistence(log, readinessManager, splitName, labelOrSplitObj, method) {
11
11
  if (readinessManager.isReady()) { // Only if it's ready we validate this, otherwise it may just be that the SDK is not ready yet.
12
12
  if (labelOrSplitObj === labels_1.SPLIT_NOT_FOUND || labelOrSplitObj == null) {
13
13
  log.warn(constants_1.WARN_NOT_EXISTENT_SPLIT, [method, splitName]);
@@ -16,4 +16,4 @@ function validateSplitExistance(log, readinessManager, splitName, labelOrSplitOb
16
16
  }
17
17
  return true;
18
18
  }
19
- exports.validateSplitExistance = validateSplitExistance;
19
+ exports.validateSplitExistence = validateSplitExistence;
@@ -1,16 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateTrafficTypeExistance = void 0;
3
+ exports.validateTrafficTypeExistence = void 0;
4
4
  var thenable_1 = require("../promise/thenable");
5
5
  var constants_1 = require("../constants");
6
6
  var constants_2 = require("../../logger/constants");
7
- function logTTExistanceWarning(log, maybeTT, method) {
7
+ function logTTExistenceWarning(log, maybeTT, method) {
8
8
  log.warn(constants_2.WARN_NOT_EXISTENT_TT, [method, maybeTT]);
9
9
  }
10
10
  /**
11
11
  * Separated from the previous method since on some cases it'll be async.
12
12
  */
13
- function validateTrafficTypeExistance(log, readinessManager, splitsCache, mode, maybeTT, method) {
13
+ function validateTrafficTypeExistence(log, readinessManager, splitsCache, mode, maybeTT, method) {
14
14
  // If not ready or in localhost mode, we won't run the validation
15
15
  if (!readinessManager.isReady() || mode === constants_1.LOCALHOST_MODE)
16
16
  return true;
@@ -18,14 +18,14 @@ function validateTrafficTypeExistance(log, readinessManager, splitsCache, mode,
18
18
  if ((0, thenable_1.thenable)(res)) {
19
19
  return res.then(function (isValid) {
20
20
  if (!isValid)
21
- logTTExistanceWarning(log, maybeTT, method);
21
+ logTTExistenceWarning(log, maybeTT, method);
22
22
  return isValid; // propagate result
23
23
  });
24
24
  }
25
25
  else {
26
26
  if (!res)
27
- logTTExistanceWarning(log, maybeTT, method);
27
+ logTTExistenceWarning(log, maybeTT, method);
28
28
  return res;
29
29
  }
30
30
  }
31
- exports.validateTrafficTypeExistance = validateTrafficTypeExistance;
31
+ exports.validateTrafficTypeExistence = validateTrafficTypeExistence;
@@ -1,8 +1,8 @@
1
1
  import { evaluateFeature, evaluateFeatures, evaluateFeaturesByFlagSets } from '../evaluator';
2
2
  import { thenable } from '../utils/promise/thenable';
3
3
  import { getMatching, getBucketing } from '../utils/key';
4
- import { validateSplitExistance } from '../utils/inputValidation/splitExistance';
5
- import { validateTrafficTypeExistance } from '../utils/inputValidation/trafficTypeExistance';
4
+ import { validateSplitExistence } from '../utils/inputValidation/splitExistence';
5
+ import { validateTrafficTypeExistence } from '../utils/inputValidation/trafficTypeExistence';
6
6
  import { SDK_NOT_READY } from '../utils/labels';
7
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 { IMPRESSION, IMPRESSION_QUEUEING } from '../logger/constants';
@@ -99,7 +99,7 @@ export function clientFactory(params) {
99
99
  var bucketingKey = getBucketing(key);
100
100
  var treatment = evaluation.treatment, label = evaluation.label, changeNumber = evaluation.changeNumber, _a = evaluation.config, config = _a === void 0 ? null : _a;
101
101
  log.info(IMPRESSION, [featureFlagName, matchingKey, treatment, label]);
102
- if (validateSplitExistance(log, readinessManager, featureFlagName, label, invokingMethodName)) {
102
+ if (validateSplitExistence(log, readinessManager, featureFlagName, label, invokingMethodName)) {
103
103
  log.info(IMPRESSION_QUEUEING);
104
104
  queue.push({
105
105
  feature: featureFlagName,
@@ -133,7 +133,7 @@ export function clientFactory(params) {
133
133
  properties: properties
134
134
  };
135
135
  // This may be async but we only warn, we don't actually care if it is valid or not in terms of queueing the event.
136
- validateTrafficTypeExistance(log, readinessManager, storage.splits, mode, trafficTypeName, 'track');
136
+ validateTrafficTypeExistence(log, readinessManager, storage.splits, mode, trafficTypeName, 'track');
137
137
  var result = eventTracker.track(eventData, size);
138
138
  if (thenable(result)) {
139
139
  return result.then(function (result) {
@@ -63,7 +63,7 @@ export function sdkFactory(params) {
63
63
  ctx.signalListener = signalListener;
64
64
  // SDK client and manager
65
65
  var clientMethod = sdkClientMethodFactory(ctx);
66
- var managerInstance = sdkManagerFactory(log, storage.splits, sdkReadinessManager);
66
+ var managerInstance = sdkManagerFactory(settings, storage.splits, sdkReadinessManager);
67
67
  syncManager && syncManager.start();
68
68
  signalListener && signalListener.start();
69
69
  log.info(NEW_FACTORY);
@@ -1,7 +1,8 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
2
  import { thenable } from '../utils/promise/thenable';
3
3
  import { find } from '../utils/lang';
4
- import { validateSplit, validateSplitExistance, validateIfNotDestroyed, validateIfOperational } from '../utils/inputValidation';
4
+ import { validateSplit, validateSplitExistence, validateIfNotDestroyed, validateIfOperational } from '../utils/inputValidation';
5
+ import { isStorageSync } from '../trackers/impressionObserver/utils';
5
6
  var SPLIT_FN_LABEL = 'split';
6
7
  var SPLITS_FN_LABEL = 'splits';
7
8
  var NAMES_FN_LABEL = 'names';
@@ -38,8 +39,10 @@ function objectsToViews(splitObjects) {
38
39
  });
39
40
  return views;
40
41
  }
41
- export function sdkManagerFactory(log, splits, _a) {
42
+ export function sdkManagerFactory(settings, splits, _a) {
42
43
  var readinessManager = _a.readinessManager, sdkStatus = _a.sdkStatus;
44
+ var log = settings.log;
45
+ var isSync = isStorageSync(settings);
43
46
  return objectAssign(
44
47
  // Proto-linkage of the readiness Event Emitter
45
48
  Object.create(sdkStatus), {
@@ -49,16 +52,16 @@ export function sdkManagerFactory(log, splits, _a) {
49
52
  split: function (featureFlagName) {
50
53
  var splitName = validateSplit(log, featureFlagName, SPLIT_FN_LABEL);
51
54
  if (!validateIfNotDestroyed(log, readinessManager, SPLIT_FN_LABEL) || !validateIfOperational(log, readinessManager, SPLIT_FN_LABEL) || !splitName) {
52
- return null;
55
+ return isSync ? null : Promise.resolve(null);
53
56
  }
54
57
  var split = splits.getSplit(splitName);
55
58
  if (thenable(split)) {
56
59
  return split.catch(function () { return null; }).then(function (result) {
57
- validateSplitExistance(log, readinessManager, splitName, result, SPLIT_FN_LABEL);
60
+ validateSplitExistence(log, readinessManager, splitName, result, SPLIT_FN_LABEL);
58
61
  return objectToView(result);
59
62
  });
60
63
  }
61
- validateSplitExistance(log, readinessManager, splitName, split, SPLIT_FN_LABEL);
64
+ validateSplitExistence(log, readinessManager, splitName, split, SPLIT_FN_LABEL);
62
65
  return objectToView(split);
63
66
  },
64
67
  /**
@@ -66,7 +69,7 @@ export function sdkManagerFactory(log, splits, _a) {
66
69
  */
67
70
  splits: function () {
68
71
  if (!validateIfNotDestroyed(log, readinessManager, SPLITS_FN_LABEL) || !validateIfOperational(log, readinessManager, SPLITS_FN_LABEL)) {
69
- return [];
72
+ return isSync ? [] : Promise.resolve([]);
70
73
  }
71
74
  var currentSplits = splits.getAll();
72
75
  return thenable(currentSplits) ?
@@ -78,7 +81,7 @@ export function sdkManagerFactory(log, splits, _a) {
78
81
  */
79
82
  names: function () {
80
83
  if (!validateIfNotDestroyed(log, readinessManager, NAMES_FN_LABEL) || !validateIfOperational(log, readinessManager, NAMES_FN_LABEL)) {
81
- return [];
84
+ return isSync ? [] : Promise.resolve([]);
82
85
  }
83
86
  var splitNames = splits.getSplitNames();
84
87
  return thenable(splitNames) ?
@@ -243,9 +243,7 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
243
243
  return;
244
244
  var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
245
245
  var flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
246
- if (!flagSetFromLocalStorage)
247
- flagSetFromLocalStorage = '[]';
248
- var flagSetCache = new _Set(JSON.parse(flagSetFromLocalStorage));
246
+ var flagSetCache = new _Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
249
247
  flagSetCache.add(featureFlag.name);
250
248
  localStorage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
251
249
  });