@splitsoftware/splitio-commons 2.1.0 → 2.1.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 (77) hide show
  1. package/CHANGES.txt +3 -0
  2. package/cjs/logger/constants.js +4 -6
  3. package/cjs/logger/messages/debug.js +1 -3
  4. package/cjs/logger/messages/error.js +1 -1
  5. package/cjs/logger/messages/warn.js +1 -1
  6. package/cjs/sdkClient/client.js +29 -19
  7. package/cjs/sdkClient/clientAttributesDecoration.js +19 -25
  8. package/cjs/sdkClient/clientInputValidation.js +28 -26
  9. package/cjs/storages/AbstractSplitsCacheAsync.js +12 -1
  10. package/cjs/storages/AbstractSplitsCacheSync.js +5 -7
  11. package/cjs/storages/KeyBuilder.js +0 -16
  12. package/cjs/storages/KeyBuilderCS.js +8 -2
  13. package/cjs/storages/dataLoader.js +1 -2
  14. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +5 -2
  15. package/cjs/storages/inMemory/SplitsCacheInMemory.js +24 -31
  16. package/cjs/storages/inRedis/SplitsCacheInRedis.js +4 -21
  17. package/cjs/storages/pluggable/SplitsCachePluggable.js +2 -19
  18. package/cjs/storages/utils.js +1 -0
  19. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +12 -13
  20. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  21. package/cjs/sync/polling/updaters/splitChangesUpdater.js +9 -23
  22. package/cjs/sync/submitters/impressionsSubmitter.js +3 -2
  23. package/cjs/trackers/strategy/strategyOptimized.js +3 -0
  24. package/cjs/utils/inputValidation/eventProperties.js +12 -1
  25. package/cjs/utils/inputValidation/index.js +3 -1
  26. package/esm/logger/constants.js +1 -3
  27. package/esm/logger/messages/debug.js +1 -3
  28. package/esm/logger/messages/error.js +1 -1
  29. package/esm/logger/messages/warn.js +1 -1
  30. package/esm/sdkClient/client.js +29 -19
  31. package/esm/sdkClient/clientAttributesDecoration.js +19 -25
  32. package/esm/sdkClient/clientInputValidation.js +29 -27
  33. package/esm/storages/AbstractSplitsCacheAsync.js +12 -1
  34. package/esm/storages/AbstractSplitsCacheSync.js +5 -7
  35. package/esm/storages/KeyBuilder.js +0 -16
  36. package/esm/storages/KeyBuilderCS.js +8 -2
  37. package/esm/storages/dataLoader.js +1 -2
  38. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +5 -2
  39. package/esm/storages/inMemory/SplitsCacheInMemory.js +24 -31
  40. package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -21
  41. package/esm/storages/pluggable/SplitsCachePluggable.js +2 -19
  42. package/esm/storages/utils.js +1 -0
  43. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +12 -13
  44. package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  45. package/esm/sync/polling/updaters/splitChangesUpdater.js +10 -24
  46. package/esm/sync/submitters/impressionsSubmitter.js +3 -2
  47. package/esm/trackers/strategy/strategyOptimized.js +3 -0
  48. package/esm/utils/inputValidation/eventProperties.js +10 -0
  49. package/esm/utils/inputValidation/index.js +1 -0
  50. package/package.json +1 -1
  51. package/src/logger/constants.ts +1 -3
  52. package/src/logger/messages/debug.ts +1 -3
  53. package/src/logger/messages/error.ts +1 -1
  54. package/src/logger/messages/warn.ts +1 -1
  55. package/src/sdkClient/client.ts +31 -21
  56. package/src/sdkClient/clientAttributesDecoration.ts +20 -27
  57. package/src/sdkClient/clientInputValidation.ts +30 -27
  58. package/src/storages/AbstractSplitsCacheAsync.ts +15 -5
  59. package/src/storages/AbstractSplitsCacheSync.ts +9 -13
  60. package/src/storages/KeyBuilder.ts +0 -20
  61. package/src/storages/KeyBuilderCS.ts +10 -3
  62. package/src/storages/dataLoader.ts +1 -2
  63. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +5 -2
  64. package/src/storages/inMemory/SplitsCacheInMemory.ts +22 -27
  65. package/src/storages/inRedis/SplitsCacheInRedis.ts +4 -21
  66. package/src/storages/pluggable/SplitsCachePluggable.ts +2 -19
  67. package/src/storages/types.ts +10 -16
  68. package/src/storages/utils.ts +1 -0
  69. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +14 -15
  70. package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -2
  71. package/src/sync/polling/updaters/splitChangesUpdater.ts +12 -27
  72. package/src/sync/submitters/impressionsSubmitter.ts +3 -2
  73. package/src/sync/submitters/types.ts +23 -33
  74. package/src/trackers/strategy/strategyOptimized.ts +3 -0
  75. package/src/utils/inputValidation/eventProperties.ts +10 -0
  76. package/src/utils/inputValidation/index.ts +1 -0
  77. package/types/splitio.d.ts +100 -35
@@ -1,5 +1,5 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
- import { validateAttributes, validateEvent, validateEventValue, validateEventProperties, validateKey, validateSplit, validateSplits, validateTrafficType, validateIfNotDestroyed, validateIfOperational } from '../utils/inputValidation';
2
+ import { validateAttributes, validateEvent, validateEventValue, validateEventProperties, validateKey, validateSplit, validateSplits, validateTrafficType, validateIfNotDestroyed, validateIfOperational, validateEvaluationOptions } from '../utils/inputValidation';
3
3
  import { startsWith } from '../utils/lang';
4
4
  import { CONTROL, CONTROL_WITH_CONFIG, GET_TREATMENT, GET_TREATMENTS, GET_TREATMENTS_BY_FLAG_SET, GET_TREATMENTS_BY_FLAG_SETS, GET_TREATMENTS_WITH_CONFIG, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, GET_TREATMENT_WITH_CONFIG, TRACK_FN_LABEL } from '../utils/constants';
5
5
  import { isConsumerMode } from '../utils/settingsValidation/mode';
@@ -14,7 +14,7 @@ export function clientInputValidationDecorator(settings, client, readinessManage
14
14
  /**
15
15
  * Avoid repeating this validations code
16
16
  */
17
- function validateEvaluationParams(maybeKey, maybeNameOrNames, maybeAttributes, methodName) {
17
+ function validateEvaluationParams(methodName, maybeKey, maybeNameOrNames, maybeAttributes, maybeOptions) {
18
18
  var key = validateKey(log, maybeKey, methodName);
19
19
  var nameOrNames = methodName.indexOf('ByFlagSet') > -1 ?
20
20
  validateFlagSets(log, methodName, maybeNameOrNames, settings.sync.__splitFiltersValidation.groupedFilters.bySet) :
@@ -23,40 +23,42 @@ export function clientInputValidationDecorator(settings, client, readinessManage
23
23
  validateSplit(log, maybeNameOrNames, methodName);
24
24
  var attributes = validateAttributes(log, maybeAttributes, methodName);
25
25
  var isNotDestroyed = validateIfNotDestroyed(log, readinessManager, methodName);
26
+ var options = validateEvaluationOptions(log, maybeOptions, methodName);
26
27
  validateIfOperational(log, readinessManager, methodName, nameOrNames);
27
28
  var valid = isNotDestroyed && key && nameOrNames && attributes !== false;
28
29
  return {
29
30
  valid: valid,
30
31
  key: key,
31
32
  nameOrNames: nameOrNames,
32
- attributes: attributes
33
+ attributes: attributes,
34
+ options: options
33
35
  };
34
36
  }
35
37
  function wrapResult(value) {
36
38
  return isAsync ? Promise.resolve(value) : value;
37
39
  }
38
- function getTreatment(maybeKey, maybeFeatureFlagName, maybeAttributes) {
39
- var params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes, GET_TREATMENT);
40
+ function getTreatment(maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions) {
41
+ var params = validateEvaluationParams(GET_TREATMENT, maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions);
40
42
  if (params.valid) {
41
- return client.getTreatment(params.key, params.nameOrNames, params.attributes);
43
+ return client.getTreatment(params.key, params.nameOrNames, params.attributes, params.options);
42
44
  }
43
45
  else {
44
46
  return wrapResult(CONTROL);
45
47
  }
46
48
  }
47
- function getTreatmentWithConfig(maybeKey, maybeFeatureFlagName, maybeAttributes) {
48
- var params = validateEvaluationParams(maybeKey, maybeFeatureFlagName, maybeAttributes, GET_TREATMENT_WITH_CONFIG);
49
+ function getTreatmentWithConfig(maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions) {
50
+ var params = validateEvaluationParams(GET_TREATMENT_WITH_CONFIG, maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions);
49
51
  if (params.valid) {
50
- return client.getTreatmentWithConfig(params.key, params.nameOrNames, params.attributes);
52
+ return client.getTreatmentWithConfig(params.key, params.nameOrNames, params.attributes, params.options);
51
53
  }
52
54
  else {
53
55
  return wrapResult(objectAssign({}, CONTROL_WITH_CONFIG));
54
56
  }
55
57
  }
56
- function getTreatments(maybeKey, maybeFeatureFlagNames, maybeAttributes) {
57
- var params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes, GET_TREATMENTS);
58
+ function getTreatments(maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions) {
59
+ var params = validateEvaluationParams(GET_TREATMENTS, maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions);
58
60
  if (params.valid) {
59
- return client.getTreatments(params.key, params.nameOrNames, params.attributes);
61
+ return client.getTreatments(params.key, params.nameOrNames, params.attributes, params.options);
60
62
  }
61
63
  else {
62
64
  var res_1 = {};
@@ -65,10 +67,10 @@ export function clientInputValidationDecorator(settings, client, readinessManage
65
67
  return wrapResult(res_1);
66
68
  }
67
69
  }
68
- function getTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, maybeAttributes) {
69
- var params = validateEvaluationParams(maybeKey, maybeFeatureFlagNames, maybeAttributes, GET_TREATMENTS_WITH_CONFIG);
70
+ function getTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions) {
71
+ var params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG, maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions);
70
72
  if (params.valid) {
71
- return client.getTreatmentsWithConfig(params.key, params.nameOrNames, params.attributes);
73
+ return client.getTreatmentsWithConfig(params.key, params.nameOrNames, params.attributes, params.options);
72
74
  }
73
75
  else {
74
76
  var res_2 = {};
@@ -77,37 +79,37 @@ export function clientInputValidationDecorator(settings, client, readinessManage
77
79
  return wrapResult(res_2);
78
80
  }
79
81
  }
80
- function getTreatmentsByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
81
- var params = validateEvaluationParams(maybeKey, maybeFlagSets, maybeAttributes, GET_TREATMENTS_BY_FLAG_SETS);
82
+ function getTreatmentsByFlagSets(maybeKey, maybeFlagSets, maybeAttributes, maybeOptions) {
83
+ var params = validateEvaluationParams(GET_TREATMENTS_BY_FLAG_SETS, maybeKey, maybeFlagSets, maybeAttributes, maybeOptions);
82
84
  if (params.valid) {
83
- return client.getTreatmentsByFlagSets(params.key, params.nameOrNames, params.attributes);
85
+ return client.getTreatmentsByFlagSets(params.key, params.nameOrNames, params.attributes, params.options);
84
86
  }
85
87
  else {
86
88
  return wrapResult({});
87
89
  }
88
90
  }
89
- function getTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
90
- var params = validateEvaluationParams(maybeKey, maybeFlagSets, maybeAttributes, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS);
91
+ function getTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, maybeAttributes, maybeOptions) {
92
+ var params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, maybeKey, maybeFlagSets, maybeAttributes, maybeOptions);
91
93
  if (params.valid) {
92
- return client.getTreatmentsWithConfigByFlagSets(params.key, params.nameOrNames, params.attributes);
94
+ return client.getTreatmentsWithConfigByFlagSets(params.key, params.nameOrNames, params.attributes, params.options);
93
95
  }
94
96
  else {
95
97
  return wrapResult({});
96
98
  }
97
99
  }
98
- function getTreatmentsByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
99
- var params = validateEvaluationParams(maybeKey, [maybeFlagSet], maybeAttributes, GET_TREATMENTS_BY_FLAG_SET);
100
+ function getTreatmentsByFlagSet(maybeKey, maybeFlagSet, maybeAttributes, maybeOptions) {
101
+ var params = validateEvaluationParams(GET_TREATMENTS_BY_FLAG_SET, maybeKey, [maybeFlagSet], maybeAttributes, maybeOptions);
100
102
  if (params.valid) {
101
- return client.getTreatmentsByFlagSet(params.key, params.nameOrNames[0], params.attributes);
103
+ return client.getTreatmentsByFlagSet(params.key, params.nameOrNames[0], params.attributes, params.options);
102
104
  }
103
105
  else {
104
106
  return wrapResult({});
105
107
  }
106
108
  }
107
- function getTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
108
- var params = validateEvaluationParams(maybeKey, [maybeFlagSet], maybeAttributes, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
109
+ function getTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, maybeAttributes, maybeOptions) {
110
+ var params = validateEvaluationParams(GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, maybeKey, [maybeFlagSet], maybeAttributes, maybeOptions);
109
111
  if (params.valid) {
110
- return client.getTreatmentsWithConfigByFlagSet(params.key, params.nameOrNames[0], params.attributes);
112
+ return client.getTreatmentsWithConfigByFlagSet(params.key, params.nameOrNames[0], params.attributes, params.options);
111
113
  }
112
114
  else {
113
115
  return wrapResult({});
@@ -6,6 +6,17 @@ import { objectAssign } from '../utils/lang/objectAssign';
6
6
  var AbstractSplitsCacheAsync = /** @class */ (function () {
7
7
  function AbstractSplitsCacheAsync() {
8
8
  }
9
+ AbstractSplitsCacheAsync.prototype.update = function (toAdd, toRemove, changeNumber) {
10
+ var _this = this;
11
+ return Promise.all([
12
+ this.setChangeNumber(changeNumber),
13
+ Promise.all(toAdd.map(function (addedFF) { return _this.addSplit(addedFF); })),
14
+ Promise.all(toRemove.map(function (removedFF) { return _this.removeSplit(removedFF.name); }))
15
+ ]).then(function (_a) {
16
+ var added = _a[1], removed = _a[2];
17
+ return added.some(function (result) { return result; }) || removed.some(function (result) { return result; });
18
+ });
19
+ };
9
20
  // @TODO revisit segment-related methods ('usesSegments', 'getRegisteredSegments', 'registerSegments')
10
21
  // noop, just keeping the interface. This is used by standalone client-side API only, and so only implemented by InMemory and InLocalStorage.
11
22
  AbstractSplitsCacheAsync.prototype.usesSegments = function () {
@@ -34,7 +45,7 @@ var AbstractSplitsCacheAsync = /** @class */ (function () {
34
45
  newSplit.killed = true;
35
46
  newSplit.defaultTreatment = defaultTreatment;
36
47
  newSplit.changeNumber = changeNumber;
37
- return _this.addSplit(name, newSplit);
48
+ return _this.addSplit(newSplit);
38
49
  }
39
50
  return false;
40
51
  }).catch(function () { return false; });
@@ -7,13 +7,11 @@ import { IN_SEGMENT, IN_LARGE_SEGMENT } from '../utils/constants';
7
7
  var AbstractSplitsCacheSync = /** @class */ (function () {
8
8
  function AbstractSplitsCacheSync() {
9
9
  }
10
- AbstractSplitsCacheSync.prototype.addSplits = function (entries) {
10
+ AbstractSplitsCacheSync.prototype.update = function (toAdd, toRemove, changeNumber) {
11
11
  var _this = this;
12
- return entries.map(function (keyValuePair) { return _this.addSplit(keyValuePair[0], keyValuePair[1]); });
13
- };
14
- AbstractSplitsCacheSync.prototype.removeSplits = function (names) {
15
- var _this = this;
16
- return names.map(function (name) { return _this.removeSplit(name); });
12
+ this.setChangeNumber(changeNumber);
13
+ var updated = toAdd.map(function (addedFF) { return _this.addSplit(addedFF); }).some(function (result) { return result; });
14
+ return toRemove.map(function (removedFF) { return _this.removeSplit(removedFF.name); }).some(function (result) { return result; }) || updated;
17
15
  };
18
16
  AbstractSplitsCacheSync.prototype.getSplits = function (names) {
19
17
  var _this = this;
@@ -48,7 +46,7 @@ var AbstractSplitsCacheSync = /** @class */ (function () {
48
46
  newSplit.killed = true;
49
47
  newSplit.defaultTreatment = defaultTreatment;
50
48
  newSplit.changeNumber = changeNumber;
51
- return this.addSplit(name, newSplit);
49
+ return this.addSplit(newSplit);
52
50
  }
53
51
  return false;
54
52
  };
@@ -1,4 +1,3 @@
1
- import { startsWith } from '../utils/lang';
2
1
  import { hash } from '../utils/murmur3/murmur3';
3
2
  var everythingAtTheEnd = /[^.]+$/;
4
3
  var DEFAULT_PREFIX = 'SPLITIO';
@@ -22,30 +21,15 @@ var KeyBuilder = /** @class */ (function () {
22
21
  KeyBuilder.prototype.buildSplitsTillKey = function () {
23
22
  return this.prefix + ".splits.till";
24
23
  };
25
- // NOT USED
26
- // buildSplitsReady() {
27
- // return `${this.prefix}.splits.ready`;
28
- // }
29
- KeyBuilder.prototype.isSplitKey = function (key) {
30
- return startsWith(key, this.prefix + ".split.");
31
- };
32
24
  KeyBuilder.prototype.buildSplitKeyPrefix = function () {
33
25
  return this.prefix + ".split.";
34
26
  };
35
- // Only used by InLocalStorage.
36
- KeyBuilder.prototype.buildSplitsWithSegmentCountKey = function () {
37
- return this.prefix + ".splits.usingSegments";
38
- };
39
27
  KeyBuilder.prototype.buildSegmentNameKey = function (segmentName) {
40
28
  return this.prefix + ".segment." + segmentName;
41
29
  };
42
30
  KeyBuilder.prototype.buildSegmentTillKey = function (segmentName) {
43
31
  return this.prefix + ".segment." + segmentName + ".till";
44
32
  };
45
- // NOT USED
46
- // buildSegmentsReady() {
47
- // return `${this.prefix}.segments.ready`;
48
- // }
49
33
  KeyBuilder.prototype.extractKey = function (builtKey) {
50
34
  var s = builtKey.match(everythingAtTheEnd);
51
35
  if (s && s.length) {
@@ -18,7 +18,7 @@ var KeyBuilderCS = /** @class */ (function (_super) {
18
18
  KeyBuilderCS.prototype.extractSegmentName = function (builtSegmentKeyName) {
19
19
  var prefix = this.prefix + "." + this.matchingKey + ".segment.";
20
20
  if (startsWith(builtSegmentKeyName, prefix))
21
- return builtSegmentKeyName.substr(prefix.length);
21
+ return builtSegmentKeyName.slice(prefix.length);
22
22
  };
23
23
  KeyBuilderCS.prototype.buildLastUpdatedKey = function () {
24
24
  return this.prefix + ".splits.lastUpdated";
@@ -29,6 +29,12 @@ var KeyBuilderCS = /** @class */ (function (_super) {
29
29
  KeyBuilderCS.prototype.buildTillKey = function () {
30
30
  return this.prefix + "." + this.matchingKey + ".segments.till";
31
31
  };
32
+ KeyBuilderCS.prototype.isSplitKey = function (key) {
33
+ return startsWith(key, this.prefix + ".split.");
34
+ };
35
+ KeyBuilderCS.prototype.buildSplitsWithSegmentCountKey = function () {
36
+ return this.prefix + ".splits.usingSegments";
37
+ };
32
38
  return KeyBuilderCS;
33
39
  }(KeyBuilder));
34
40
  export { KeyBuilderCS };
@@ -40,7 +46,7 @@ export function myLargeSegmentsKeyBuilder(prefix, matchingKey) {
40
46
  extractSegmentName: function (builtSegmentKeyName) {
41
47
  var p = prefix + "." + matchingKey + ".largeSegment.";
42
48
  if (startsWith(builtSegmentKeyName, p))
43
- return builtSegmentKeyName.substr(p.length);
49
+ return builtSegmentKeyName.slice(p.length);
44
50
  },
45
51
  buildTillKey: function () {
46
52
  return prefix + "." + matchingKey + ".largeSegments.till";
@@ -29,9 +29,8 @@ export function dataLoaderFactory(preloadedData) {
29
29
  return;
30
30
  // cleaning up the localStorage data, since some cached splits might need be part of the preloaded data
31
31
  storage.splits.clear();
32
- storage.splits.setChangeNumber(since);
33
32
  // splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
34
- storage.splits.addSplits(Object.keys(splitsData).map(function (splitName) { return JSON.parse(splitsData[splitName]); }));
33
+ storage.splits.update(Object.keys(splitsData).map(function (splitName) { return JSON.parse(splitsData[splitName]); }), [], since);
35
34
  // add mySegments data
36
35
  var mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userId];
37
36
  if (!mySegmentsData) {
@@ -79,9 +79,10 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
79
79
  });
80
80
  this.hasSync = false;
81
81
  };
82
- SplitsCacheInLocal.prototype.addSplit = function (name, split) {
82
+ SplitsCacheInLocal.prototype.addSplit = function (split) {
83
83
  try {
84
- var splitKey = this.keys.buildSplitKey(name);
84
+ var name_1 = split.name;
85
+ var splitKey = this.keys.buildSplitKey(name_1);
85
86
  var splitFromLocalStorage = localStorage.getItem(splitKey);
86
87
  var previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
87
88
  localStorage.setItem(splitKey, JSON.stringify(split));
@@ -100,6 +101,8 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
100
101
  SplitsCacheInLocal.prototype.removeSplit = function (name) {
101
102
  try {
102
103
  var split = this.getSplit(name);
104
+ if (!split)
105
+ return false;
103
106
  localStorage.removeItem(this.keys.buildSplitKey(name));
104
107
  this._decrementCounts(split);
105
108
  if (split)
@@ -22,7 +22,8 @@ var SplitsCacheInMemory = /** @class */ (function (_super) {
22
22
  this.changeNumber = -1;
23
23
  this.segmentsCount = 0;
24
24
  };
25
- SplitsCacheInMemory.prototype.addSplit = function (name, split) {
25
+ SplitsCacheInMemory.prototype.addSplit = function (split) {
26
+ var name = split.name;
26
27
  var previousSplit = this.getSplit(name);
27
28
  if (previousSplit) { // We had this Split already
28
29
  var previousTtName = previousSplit.trafficTypeName;
@@ -34,40 +35,32 @@ var SplitsCacheInMemory = /** @class */ (function (_super) {
34
35
  if (usesSegments(previousSplit))
35
36
  this.segmentsCount--;
36
37
  }
37
- if (split) {
38
- // Store the Split.
39
- this.splitsCache[name] = split;
40
- // Update TT cache
41
- var ttName = split.trafficTypeName;
42
- this.ttCache[ttName] = (this.ttCache[ttName] || 0) + 1;
43
- this.addToFlagSets(split);
44
- // Add to segments count for the new version of the Split
45
- if (usesSegments(split))
46
- this.segmentsCount++;
47
- return true;
48
- }
49
- else {
50
- return false;
51
- }
38
+ // Store the Split.
39
+ this.splitsCache[name] = split;
40
+ // Update TT cache
41
+ var ttName = split.trafficTypeName;
42
+ this.ttCache[ttName] = (this.ttCache[ttName] || 0) + 1;
43
+ this.addToFlagSets(split);
44
+ // Add to segments count for the new version of the Split
45
+ if (usesSegments(split))
46
+ this.segmentsCount++;
47
+ return true;
52
48
  };
53
49
  SplitsCacheInMemory.prototype.removeSplit = function (name) {
54
50
  var split = this.getSplit(name);
55
- if (split) {
56
- // Delete the Split
57
- delete this.splitsCache[name];
58
- var ttName = split.trafficTypeName;
59
- this.ttCache[ttName]--; // Update tt cache
60
- if (!this.ttCache[ttName])
61
- delete this.ttCache[ttName];
62
- this.removeFromFlagSets(split.name, split.sets);
63
- // Update the segments count.
64
- if (usesSegments(split))
65
- this.segmentsCount--;
66
- return true;
67
- }
68
- else {
51
+ if (!split)
69
52
  return false;
70
- }
53
+ // Delete the Split
54
+ delete this.splitsCache[name];
55
+ var ttName = split.trafficTypeName;
56
+ this.ttCache[ttName]--; // Update tt cache
57
+ if (!this.ttCache[ttName])
58
+ delete this.ttCache[ttName];
59
+ this.removeFromFlagSets(split.name, split.sets);
60
+ // Update the segments count.
61
+ if (usesSegments(split))
62
+ this.segmentsCount--;
63
+ return true;
71
64
  };
72
65
  SplitsCacheInMemory.prototype.getSplit = function (name) {
73
66
  return this.splitsCache[name] || null;
@@ -64,8 +64,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
64
64
  * The returned promise is resolved when the operation success
65
65
  * or rejected if it fails (e.g., redis operation fails)
66
66
  */
67
- SplitsCacheInRedis.prototype.addSplit = function (name, split) {
67
+ SplitsCacheInRedis.prototype.addSplit = function (split) {
68
68
  var _this = this;
69
+ var name = split.name;
69
70
  var splitKey = this.keys.buildSplitKey(name);
70
71
  return this.redis.get(splitKey).then(function (splitFromStorage) {
71
72
  // handling parsing error
@@ -89,18 +90,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
89
90
  }).then(function () { return _this._updateFlagSets(name, parsedPreviousSplit && parsedPreviousSplit.sets, split.sets); });
90
91
  }).then(function () { return true; });
91
92
  };
92
- /**
93
- * Add a list of splits.
94
- * The returned promise is resolved when the operation success
95
- * or rejected if it fails (e.g., redis operation fails)
96
- */
97
- SplitsCacheInRedis.prototype.addSplits = function (entries) {
98
- var _this = this;
99
- return Promise.all(entries.map(function (keyValuePair) { return _this.addSplit(keyValuePair[0], keyValuePair[1]); }));
100
- };
101
93
  /**
102
94
  * Remove a given split.
103
- * The returned promise is resolved when the operation success, with 1 or 0 indicating if the split existed or not.
95
+ * The returned promise is resolved when the operation success, with true or false indicating if the split existed (and was removed) or not.
104
96
  * or rejected if it fails (e.g., redis operation fails).
105
97
  */
106
98
  SplitsCacheInRedis.prototype.removeSplit = function (name) {
@@ -110,18 +102,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
110
102
  return _this._decrementCounts(split).then(function () { return _this._updateFlagSets(name, split.sets); });
111
103
  }
112
104
  }).then(function () {
113
- return _this.redis.del(_this.keys.buildSplitKey(name));
105
+ return _this.redis.del(_this.keys.buildSplitKey(name)).then(function (status) { return status === 1; });
114
106
  });
115
107
  };
116
- /**
117
- * Remove a list of splits.
118
- * The returned promise is resolved when the operation success,
119
- * or rejected if it fails (e.g., redis operation fails).
120
- */
121
- SplitsCacheInRedis.prototype.removeSplits = function (names) {
122
- var _this = this;
123
- return Promise.all(names.map(function (name) { return _this.removeSplit(name); }));
124
- };
125
108
  /**
126
109
  * Get split definition or null if it's not defined.
127
110
  * Returned promise is rejected if redis operation fails.
@@ -51,8 +51,9 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
51
51
  * The returned promise is resolved when the operation success
52
52
  * or rejected if it fails (e.g., wrapper operation fails)
53
53
  */
54
- SplitsCachePluggable.prototype.addSplit = function (name, split) {
54
+ SplitsCachePluggable.prototype.addSplit = function (split) {
55
55
  var _this = this;
56
+ var name = split.name;
56
57
  var splitKey = this.keys.buildSplitKey(name);
57
58
  return this.wrapper.get(splitKey).then(function (splitFromStorage) {
58
59
  // handling parsing error
@@ -76,15 +77,6 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
76
77
  }).then(function () { return _this._updateFlagSets(name, parsedPreviousSplit && parsedPreviousSplit.sets, split.sets); });
77
78
  }).then(function () { return true; });
78
79
  };
79
- /**
80
- * Add a list of splits.
81
- * The returned promise is resolved when the operation success
82
- * or rejected if it fails (e.g., wrapper operation fails)
83
- */
84
- SplitsCachePluggable.prototype.addSplits = function (entries) {
85
- var _this = this;
86
- return Promise.all(entries.map(function (keyValuePair) { return _this.addSplit(keyValuePair[0], keyValuePair[1]); }));
87
- };
88
80
  /**
89
81
  * Remove a given split.
90
82
  * The returned promise is resolved when the operation success, with a boolean indicating if the split existed or not.
@@ -100,15 +92,6 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
100
92
  return _this.wrapper.del(_this.keys.buildSplitKey(name));
101
93
  });
102
94
  };
103
- /**
104
- * Remove a list of splits.
105
- * The returned promise is resolved when the operation success, with a boolean array indicating if the splits existed or not.
106
- * or rejected if it fails (e.g., wrapper operation fails).
107
- */
108
- SplitsCachePluggable.prototype.removeSplits = function (names) {
109
- var _this = this;
110
- return Promise.all(names.map(function (name) { return _this.removeSplit(name); }));
111
- };
112
95
  /**
113
96
  * Get split.
114
97
  * The returned promise is resolved with the split definition or null if it's not defined,
@@ -23,6 +23,7 @@ export function impressionsToJSON(impressions, metadata) {
23
23
  c: impression.changeNumber,
24
24
  m: impression.time,
25
25
  pt: impression.pt,
26
+ properties: impression.properties
26
27
  }
27
28
  };
28
29
  return JSON.stringify(impressionWithMetadata);
@@ -23,22 +23,21 @@ export function fromObjectUpdaterFactory(splitsParser, storage, readiness, setti
23
23
  if (!loadError && splitsMock) {
24
24
  log.debug(SYNC_OFFLINE_DATA, [JSON.stringify(splitsMock)]);
25
25
  forOwn(splitsMock, function (val, name) {
26
- splits.push([
27
- name, {
28
- name: name,
29
- status: 'ACTIVE',
30
- killed: false,
31
- trafficAllocation: 100,
32
- defaultTreatment: CONTROL,
33
- conditions: val.conditions || [],
34
- configurations: val.configurations,
35
- trafficTypeName: val.trafficTypeName
36
- }
37
- ]);
26
+ // @ts-ignore Split changeNumber and seed is undefined in localhost mode
27
+ splits.push({
28
+ name: name,
29
+ status: 'ACTIVE',
30
+ killed: false,
31
+ trafficAllocation: 100,
32
+ defaultTreatment: CONTROL,
33
+ conditions: val.conditions || [],
34
+ configurations: val.configurations,
35
+ trafficTypeName: val.trafficTypeName
36
+ });
38
37
  });
39
38
  return Promise.all([
40
39
  splitsCache.clear(),
41
- splitsCache.addSplits(splits)
40
+ splitsCache.update(splits, [], Date.now())
42
41
  ]).then(function () {
43
42
  readiness.splits.emit(SDK_SPLITS_ARRIVED);
44
43
  if (startingUp) {
@@ -5,5 +5,5 @@ import { splitChangesUpdaterFactory } from '../updaters/splitChangesUpdater';
5
5
  * Creates a sync task that periodically executes a `splitChangesUpdater` task
6
6
  */
7
7
  export function splitsSyncTaskFactory(fetchSplitChanges, storage, readiness, settings, isClientSide) {
8
- return syncTaskFactory(settings.log, splitChangesUpdaterFactory(settings.log, splitChangesFetcherFactory(fetchSplitChanges), storage.splits, storage.segments, settings.sync.__splitFiltersValidation, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
8
+ return syncTaskFactory(settings.log, splitChangesUpdaterFactory(settings.log, splitChangesFetcherFactory(fetchSplitChanges), storage, settings.sync.__splitFiltersValidation, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
9
9
  }
@@ -1,6 +1,6 @@
1
1
  import { timeout } from '../../../utils/promise/timeout';
2
2
  import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
3
- import { SYNC_SPLITS_FETCH, SYNC_SPLITS_NEW, SYNC_SPLITS_REMOVED, SYNC_SPLITS_SEGMENTS, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
3
+ import { SYNC_SPLITS_FETCH, SYNC_SPLITS_UPDATE, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
4
4
  import { startsWith } from '../../../utils/lang';
5
5
  import { IN_SEGMENT } from '../../../utils/constants';
6
6
  import { setToArray } from '../../../utils/lang/sets';
@@ -58,13 +58,13 @@ export function computeSplitsMutation(entries, filters) {
58
58
  var segments = new Set();
59
59
  var computed = entries.reduce(function (accum, split) {
60
60
  if (split.status === 'ACTIVE' && matchFilters(split, filters)) {
61
- accum.added.push([split.name, split]);
61
+ accum.added.push(split);
62
62
  parseSegments(split).forEach(function (segmentName) {
63
63
  segments.add(segmentName);
64
64
  });
65
65
  }
66
66
  else {
67
- accum.removed.push(split.name);
67
+ accum.removed.push(split);
68
68
  }
69
69
  return accum;
70
70
  }, { added: [], removed: [], segments: [] });
@@ -85,9 +85,10 @@ export function computeSplitsMutation(entries, filters) {
85
85
  * @param requestTimeoutBeforeReady - How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
86
86
  * @param retriesOnFailureBeforeReady - How many retries on `/splitChanges` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
87
87
  */
88
- export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments, splitFiltersValidation, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
88
+ export function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFiltersValidation, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
89
89
  if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
90
90
  if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
91
+ var splits = storage.splits, segments = storage.segments;
91
92
  var startingUp = true;
92
93
  /** timeout decorator for `splitChangesFetcher` promise */
93
94
  function _promiseDecorator(promise) {
@@ -95,17 +96,6 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
95
96
  promise = timeout(requestTimeoutBeforeReady, promise);
96
97
  return promise;
97
98
  }
98
- /** Returns true if at least one split was updated */
99
- function isThereUpdate(flagsChange) {
100
- var added = flagsChange[1], removed = flagsChange[2];
101
- // There is at least one added or modified feature flag
102
- if (added && added.some(function (update) { return update; }))
103
- return true;
104
- // There is at least one removed feature flag
105
- if (removed && removed.some(function (update) { return update; }))
106
- return true;
107
- return false;
108
- }
109
99
  /**
110
100
  * SplitChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch splits or synchronize them with the storage.
111
101
  * Returned promise will not be rejected.
@@ -127,21 +117,17 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
127
117
  .then(function (splitChanges) {
128
118
  startingUp = false;
129
119
  var mutation = computeSplitsMutation(splitChanges.splits, splitFiltersValidation);
130
- log.debug(SYNC_SPLITS_NEW, [mutation.added.length]);
131
- log.debug(SYNC_SPLITS_REMOVED, [mutation.removed.length]);
132
- log.debug(SYNC_SPLITS_SEGMENTS, [mutation.segments.length]);
120
+ log.debug(SYNC_SPLITS_UPDATE, [mutation.added.length, mutation.removed.length, mutation.segments.length]);
133
121
  // Write into storage
134
122
  // @TODO call `setChangeNumber` only if the other storage operations have succeeded, in order to keep storage consistency
135
123
  return Promise.all([
136
- // calling first `setChangenumber` method, to perform cache flush if split filter queryString changed
137
- splits.setChangeNumber(splitChanges.till),
138
- splits.addSplits(mutation.added),
139
- splits.removeSplits(mutation.removed),
124
+ splits.update(mutation.added, mutation.removed, splitChanges.till),
140
125
  segments.registerSegments(mutation.segments)
141
- ]).then(function (flagsChange) {
126
+ ]).then(function (_a) {
127
+ var isThereUpdate = _a[0];
142
128
  if (splitsEventEmitter) {
143
129
  // To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
144
- return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate(flagsChange) && (isClientSide || checkAllSegmentsExist(segments))))
130
+ return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate && (isClientSide || checkAllSegmentsExist(segments))))
145
131
  .catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
146
132
  .then(function (emitSplitsArrivedEvent) {
147
133
  // emit SDK events
@@ -19,8 +19,9 @@ export function fromImpressionsCollector(sendLabels, data) {
19
19
  m: entry.time,
20
20
  c: entry.changeNumber,
21
21
  r: sendLabels ? entry.label : undefined,
22
- b: entry.bucketingKey ? entry.bucketingKey : undefined,
23
- pt: entry.pt ? entry.pt : undefined // Previous time
22
+ b: entry.bucketingKey,
23
+ pt: entry.pt,
24
+ properties: entry.properties // Properties
24
25
  };
25
26
  return keyImpression;
26
27
  })
@@ -9,6 +9,9 @@ import { truncateTimeFrame } from '../../utils/time';
9
9
  export function strategyOptimizedFactory(impressionsObserver, impressionCounts) {
10
10
  return {
11
11
  process: function (impression) {
12
+ // DEBUG mode without previous time, for impressions with properties
13
+ if (impression.properties)
14
+ return true;
12
15
  impression.pt = impressionsObserver.testAndSet(impression);
13
16
  var now = Date.now();
14
17
  // Increments impression counter per featureName
@@ -57,3 +57,13 @@ export function validateEventProperties(log, maybeProperties, method) {
57
57
  }
58
58
  return output;
59
59
  }
60
+ export function validateEvaluationOptions(log, maybeOptions, method) {
61
+ if (isObject(maybeOptions)) {
62
+ var properties = validateEventProperties(log, maybeOptions.properties, method).properties;
63
+ return properties && Object.keys(properties).length > 0 ? { properties: properties } : undefined;
64
+ }
65
+ else if (maybeOptions) {
66
+ log.error(ERROR_NOT_PLAIN_OBJECT, [method, 'evaluation options']);
67
+ }
68
+ return undefined;
69
+ }
@@ -11,3 +11,4 @@ export { validateIfNotDestroyed, validateIfOperational } from './isOperational';
11
11
  export { validateSplitExistence } from './splitExistence';
12
12
  export { validateTrafficTypeExistence } from './trafficTypeExistence';
13
13
  export { validatePreloadedData } from './preloadedData';
14
+ export { validateEvaluationOptions } from './eventProperties';