@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
@@ -67,8 +67,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
67
67
  * The returned promise is resolved when the operation success
68
68
  * or rejected if it fails (e.g., redis operation fails)
69
69
  */
70
- SplitsCacheInRedis.prototype.addSplit = function (name, split) {
70
+ SplitsCacheInRedis.prototype.addSplit = function (split) {
71
71
  var _this = this;
72
+ var name = split.name;
72
73
  var splitKey = this.keys.buildSplitKey(name);
73
74
  return this.redis.get(splitKey).then(function (splitFromStorage) {
74
75
  // handling parsing error
@@ -92,18 +93,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
92
93
  }).then(function () { return _this._updateFlagSets(name, parsedPreviousSplit && parsedPreviousSplit.sets, split.sets); });
93
94
  }).then(function () { return true; });
94
95
  };
95
- /**
96
- * Add a list of splits.
97
- * The returned promise is resolved when the operation success
98
- * or rejected if it fails (e.g., redis operation fails)
99
- */
100
- SplitsCacheInRedis.prototype.addSplits = function (entries) {
101
- var _this = this;
102
- return Promise.all(entries.map(function (keyValuePair) { return _this.addSplit(keyValuePair[0], keyValuePair[1]); }));
103
- };
104
96
  /**
105
97
  * Remove a given split.
106
- * The returned promise is resolved when the operation success, with 1 or 0 indicating if the split existed or not.
98
+ * The returned promise is resolved when the operation success, with true or false indicating if the split existed (and was removed) or not.
107
99
  * or rejected if it fails (e.g., redis operation fails).
108
100
  */
109
101
  SplitsCacheInRedis.prototype.removeSplit = function (name) {
@@ -113,18 +105,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
113
105
  return _this._decrementCounts(split).then(function () { return _this._updateFlagSets(name, split.sets); });
114
106
  }
115
107
  }).then(function () {
116
- return _this.redis.del(_this.keys.buildSplitKey(name));
108
+ return _this.redis.del(_this.keys.buildSplitKey(name)).then(function (status) { return status === 1; });
117
109
  });
118
110
  };
119
- /**
120
- * Remove a list of splits.
121
- * The returned promise is resolved when the operation success,
122
- * or rejected if it fails (e.g., redis operation fails).
123
- */
124
- SplitsCacheInRedis.prototype.removeSplits = function (names) {
125
- var _this = this;
126
- return Promise.all(names.map(function (name) { return _this.removeSplit(name); }));
127
- };
128
111
  /**
129
112
  * Get split definition or null if it's not defined.
130
113
  * Returned promise is rejected if redis operation fails.
@@ -54,8 +54,9 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
54
54
  * The returned promise is resolved when the operation success
55
55
  * or rejected if it fails (e.g., wrapper operation fails)
56
56
  */
57
- SplitsCachePluggable.prototype.addSplit = function (name, split) {
57
+ SplitsCachePluggable.prototype.addSplit = function (split) {
58
58
  var _this = this;
59
+ var name = split.name;
59
60
  var splitKey = this.keys.buildSplitKey(name);
60
61
  return this.wrapper.get(splitKey).then(function (splitFromStorage) {
61
62
  // handling parsing error
@@ -79,15 +80,6 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
79
80
  }).then(function () { return _this._updateFlagSets(name, parsedPreviousSplit && parsedPreviousSplit.sets, split.sets); });
80
81
  }).then(function () { return true; });
81
82
  };
82
- /**
83
- * Add a list of splits.
84
- * The returned promise is resolved when the operation success
85
- * or rejected if it fails (e.g., wrapper operation fails)
86
- */
87
- SplitsCachePluggable.prototype.addSplits = function (entries) {
88
- var _this = this;
89
- return Promise.all(entries.map(function (keyValuePair) { return _this.addSplit(keyValuePair[0], keyValuePair[1]); }));
90
- };
91
83
  /**
92
84
  * Remove a given split.
93
85
  * The returned promise is resolved when the operation success, with a boolean indicating if the split existed or not.
@@ -103,15 +95,6 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
103
95
  return _this.wrapper.del(_this.keys.buildSplitKey(name));
104
96
  });
105
97
  };
106
- /**
107
- * Remove a list of splits.
108
- * The returned promise is resolved when the operation success, with a boolean array indicating if the splits existed or not.
109
- * or rejected if it fails (e.g., wrapper operation fails).
110
- */
111
- SplitsCachePluggable.prototype.removeSplits = function (names) {
112
- var _this = this;
113
- return Promise.all(names.map(function (name) { return _this.removeSplit(name); }));
114
- };
115
98
  /**
116
99
  * Get split.
117
100
  * The returned promise is resolved with the split definition or null if it's not defined,
@@ -27,6 +27,7 @@ function impressionsToJSON(impressions, metadata) {
27
27
  c: impression.changeNumber,
28
28
  m: impression.time,
29
29
  pt: impression.pt,
30
+ properties: impression.properties
30
31
  }
31
32
  };
32
33
  return JSON.stringify(impressionWithMetadata);
@@ -26,22 +26,21 @@ function fromObjectUpdaterFactory(splitsParser, storage, readiness, settings) {
26
26
  if (!loadError && splitsMock) {
27
27
  log.debug(constants_3.SYNC_OFFLINE_DATA, [JSON.stringify(splitsMock)]);
28
28
  (0, lang_1.forOwn)(splitsMock, function (val, name) {
29
- splits.push([
30
- name, {
31
- name: name,
32
- status: 'ACTIVE',
33
- killed: false,
34
- trafficAllocation: 100,
35
- defaultTreatment: constants_1.CONTROL,
36
- conditions: val.conditions || [],
37
- configurations: val.configurations,
38
- trafficTypeName: val.trafficTypeName
39
- }
40
- ]);
29
+ // @ts-ignore Split changeNumber and seed is undefined in localhost mode
30
+ splits.push({
31
+ name: name,
32
+ status: 'ACTIVE',
33
+ killed: false,
34
+ trafficAllocation: 100,
35
+ defaultTreatment: constants_1.CONTROL,
36
+ conditions: val.conditions || [],
37
+ configurations: val.configurations,
38
+ trafficTypeName: val.trafficTypeName
39
+ });
41
40
  });
42
41
  return Promise.all([
43
42
  splitsCache.clear(),
44
- splitsCache.addSplits(splits)
43
+ splitsCache.update(splits, [], Date.now())
45
44
  ]).then(function () {
46
45
  readiness.splits.emit(constants_2.SDK_SPLITS_ARRIVED);
47
46
  if (startingUp) {
@@ -8,6 +8,6 @@ var splitChangesUpdater_1 = require("../updaters/splitChangesUpdater");
8
8
  * Creates a sync task that periodically executes a `splitChangesUpdater` task
9
9
  */
10
10
  function splitsSyncTaskFactory(fetchSplitChanges, storage, readiness, settings, isClientSide) {
11
- return (0, syncTask_1.syncTaskFactory)(settings.log, (0, splitChangesUpdater_1.splitChangesUpdaterFactory)(settings.log, (0, splitChangesFetcher_1.splitChangesFetcherFactory)(fetchSplitChanges), storage.splits, storage.segments, settings.sync.__splitFiltersValidation, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
11
+ return (0, syncTask_1.syncTaskFactory)(settings.log, (0, splitChangesUpdater_1.splitChangesUpdaterFactory)(settings.log, (0, splitChangesFetcher_1.splitChangesFetcherFactory)(fetchSplitChanges), storage, settings.sync.__splitFiltersValidation, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
12
12
  }
13
13
  exports.splitsSyncTaskFactory = splitsSyncTaskFactory;
@@ -62,13 +62,13 @@ function computeSplitsMutation(entries, filters) {
62
62
  var segments = new Set();
63
63
  var computed = entries.reduce(function (accum, split) {
64
64
  if (split.status === 'ACTIVE' && matchFilters(split, filters)) {
65
- accum.added.push([split.name, split]);
65
+ accum.added.push(split);
66
66
  parseSegments(split).forEach(function (segmentName) {
67
67
  segments.add(segmentName);
68
68
  });
69
69
  }
70
70
  else {
71
- accum.removed.push(split.name);
71
+ accum.removed.push(split);
72
72
  }
73
73
  return accum;
74
74
  }, { added: [], removed: [], segments: [] });
@@ -90,9 +90,10 @@ exports.computeSplitsMutation = computeSplitsMutation;
90
90
  * @param requestTimeoutBeforeReady - How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
91
91
  * @param retriesOnFailureBeforeReady - How many retries on `/splitChanges` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
92
92
  */
93
- function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments, splitFiltersValidation, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
93
+ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFiltersValidation, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
94
94
  if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
95
95
  if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
96
+ var splits = storage.splits, segments = storage.segments;
96
97
  var startingUp = true;
97
98
  /** timeout decorator for `splitChangesFetcher` promise */
98
99
  function _promiseDecorator(promise) {
@@ -100,17 +101,6 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
100
101
  promise = (0, timeout_1.timeout)(requestTimeoutBeforeReady, promise);
101
102
  return promise;
102
103
  }
103
- /** Returns true if at least one split was updated */
104
- function isThereUpdate(flagsChange) {
105
- var added = flagsChange[1], removed = flagsChange[2];
106
- // There is at least one added or modified feature flag
107
- if (added && added.some(function (update) { return update; }))
108
- return true;
109
- // There is at least one removed feature flag
110
- if (removed && removed.some(function (update) { return update; }))
111
- return true;
112
- return false;
113
- }
114
104
  /**
115
105
  * SplitChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch splits or synchronize them with the storage.
116
106
  * Returned promise will not be rejected.
@@ -132,21 +122,17 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
132
122
  .then(function (splitChanges) {
133
123
  startingUp = false;
134
124
  var mutation = computeSplitsMutation(splitChanges.splits, splitFiltersValidation);
135
- log.debug(constants_2.SYNC_SPLITS_NEW, [mutation.added.length]);
136
- log.debug(constants_2.SYNC_SPLITS_REMOVED, [mutation.removed.length]);
137
- log.debug(constants_2.SYNC_SPLITS_SEGMENTS, [mutation.segments.length]);
125
+ log.debug(constants_2.SYNC_SPLITS_UPDATE, [mutation.added.length, mutation.removed.length, mutation.segments.length]);
138
126
  // Write into storage
139
127
  // @TODO call `setChangeNumber` only if the other storage operations have succeeded, in order to keep storage consistency
140
128
  return Promise.all([
141
- // calling first `setChangenumber` method, to perform cache flush if split filter queryString changed
142
- splits.setChangeNumber(splitChanges.till),
143
- splits.addSplits(mutation.added),
144
- splits.removeSplits(mutation.removed),
129
+ splits.update(mutation.added, mutation.removed, splitChanges.till),
145
130
  segments.registerSegments(mutation.segments)
146
- ]).then(function (flagsChange) {
131
+ ]).then(function (_a) {
132
+ var isThereUpdate = _a[0];
147
133
  if (splitsEventEmitter) {
148
134
  // To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
149
- return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate(flagsChange) && (isClientSide || checkAllSegmentsExist(segments))))
135
+ return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate && (isClientSide || checkAllSegmentsExist(segments))))
150
136
  .catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
151
137
  .then(function (emitSplitsArrivedEvent) {
152
138
  // emit SDK events
@@ -22,8 +22,9 @@ function fromImpressionsCollector(sendLabels, data) {
22
22
  m: entry.time,
23
23
  c: entry.changeNumber,
24
24
  r: sendLabels ? entry.label : undefined,
25
- b: entry.bucketingKey ? entry.bucketingKey : undefined,
26
- pt: entry.pt ? entry.pt : undefined // Previous time
25
+ b: entry.bucketingKey,
26
+ pt: entry.pt,
27
+ properties: entry.properties // Properties
27
28
  };
28
29
  return keyImpression;
29
30
  })
@@ -12,6 +12,9 @@ var time_1 = require("../../utils/time");
12
12
  function strategyOptimizedFactory(impressionsObserver, impressionCounts) {
13
13
  return {
14
14
  process: function (impression) {
15
+ // DEBUG mode without previous time, for impressions with properties
16
+ if (impression.properties)
17
+ return true;
15
18
  impression.pt = impressionsObserver.testAndSet(impression);
16
19
  var now = Date.now();
17
20
  // Increments impression counter per featureName
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateEventProperties = void 0;
3
+ exports.validateEvaluationOptions = exports.validateEventProperties = void 0;
4
4
  var lang_1 = require("../lang");
5
5
  var objectAssign_1 = require("../lang/objectAssign");
6
6
  var constants_1 = require("../../logger/constants");
@@ -61,3 +61,14 @@ function validateEventProperties(log, maybeProperties, method) {
61
61
  return output;
62
62
  }
63
63
  exports.validateEventProperties = validateEventProperties;
64
+ function validateEvaluationOptions(log, maybeOptions, method) {
65
+ if ((0, lang_1.isObject)(maybeOptions)) {
66
+ var properties = validateEventProperties(log, maybeOptions.properties, method).properties;
67
+ return properties && Object.keys(properties).length > 0 ? { properties: properties } : undefined;
68
+ }
69
+ else if (maybeOptions) {
70
+ log.error(constants_1.ERROR_NOT_PLAIN_OBJECT, [method, 'evaluation options']);
71
+ }
72
+ return undefined;
73
+ }
74
+ exports.validateEvaluationOptions = validateEvaluationOptions;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
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;
3
+ exports.validateEvaluationOptions = 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; } });
@@ -30,3 +30,5 @@ var trafficTypeExistence_1 = require("./trafficTypeExistence");
30
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; } });
33
+ var eventProperties_2 = require("./eventProperties");
34
+ Object.defineProperty(exports, "validateEvaluationOptions", { enumerable: true, get: function () { return eventProperties_2.validateEvaluationOptions; } });
@@ -20,9 +20,7 @@ export var RETRIEVE_CLIENT_EXISTING = 28;
20
20
  export var RETRIEVE_MANAGER = 29;
21
21
  export var SYNC_OFFLINE_DATA = 30;
22
22
  export var SYNC_SPLITS_FETCH = 31;
23
- export var SYNC_SPLITS_NEW = 32;
24
- export var SYNC_SPLITS_REMOVED = 33;
25
- export var SYNC_SPLITS_SEGMENTS = 34;
23
+ export var SYNC_SPLITS_UPDATE = 32;
26
24
  export var STREAMING_NEW_MESSAGE = 35;
27
25
  export var SYNC_TASK_START = 36;
28
26
  export var SYNC_TASK_EXECUTE = 37;
@@ -20,9 +20,7 @@ export var codesDebug = codesInfo.concat([
20
20
  // synchronizer
21
21
  [c.SYNC_OFFLINE_DATA, c.LOG_PREFIX_SYNC_OFFLINE + 'Feature flags data: \n%s'],
22
22
  [c.SYNC_SPLITS_FETCH, c.LOG_PREFIX_SYNC_SPLITS + 'Spin up feature flags update using since = %s'],
23
- [c.SYNC_SPLITS_NEW, c.LOG_PREFIX_SYNC_SPLITS + 'New feature flags %s'],
24
- [c.SYNC_SPLITS_REMOVED, c.LOG_PREFIX_SYNC_SPLITS + 'Removed feature flags %s'],
25
- [c.SYNC_SPLITS_SEGMENTS, c.LOG_PREFIX_SYNC_SPLITS + 'Segment names collected %s'],
23
+ [c.SYNC_SPLITS_UPDATE, c.LOG_PREFIX_SYNC_SPLITS + 'New feature flags %s. Removed feature flags %s. Segment names collected %s'],
26
24
  [c.STREAMING_NEW_MESSAGE, c.LOG_PREFIX_SYNC_STREAMING + 'New SSE message received, with data: %s.'],
27
25
  [c.SYNC_TASK_START, c.LOG_PREFIX_SYNC + ': Starting %s. Running each %s millis'],
28
26
  [c.SYNC_TASK_EXECUTE, c.LOG_PREFIX_SYNC + ': Running %s'],
@@ -20,7 +20,7 @@ export var codesError = [
20
20
  // input validation
21
21
  [c.ERROR_EVENT_TYPE_FORMAT, '%s: you passed "%s", event_type must adhere to the regular expression /^[a-zA-Z0-9][-_.:a-zA-Z0-9]{0,79}$/g. This means an event_type must be alphanumeric, cannot be more than 80 characters long, and can only include a dash, underscore, period, or colon as separators of alphanumeric characters.'],
22
22
  [c.ERROR_NOT_PLAIN_OBJECT, '%s: %s must be a plain object.'],
23
- [c.ERROR_SIZE_EXCEEDED, '%s: the maximum size allowed for the properties is 32768 bytes, which was exceeded. Event not queued.'],
23
+ [c.ERROR_SIZE_EXCEEDED, '%s: the maximum size allowed for the properties is 32768 bytes, which was exceeded.'],
24
24
  [c.ERROR_NOT_FINITE, '%s: value must be a finite number.'],
25
25
  [c.ERROR_NULL, '%s: you passed a null or undefined %s. It must be a non-empty string.'],
26
26
  [c.ERROR_TOO_LONG, '%s: %s too long. It must have 250 characters or less.'],
@@ -17,7 +17,7 @@ export var codesWarn = codesError.concat([
17
17
  [c.CLIENT_NO_LISTENER, 'No listeners for SDK Readiness detected. Incorrect control treatments could have been logged if you called getTreatment/s while the SDK was not yet ready.'],
18
18
  // input validation
19
19
  [c.WARN_SETTING_NULL, '%s: Property "%s" is of invalid type. Setting value to null.'],
20
- [c.WARN_TRIMMING_PROPERTIES, '%s: Event has more than 300 properties. Some of them will be trimmed when processed.'],
20
+ [c.WARN_TRIMMING_PROPERTIES, '%s: more than 300 properties were provided. Some of them will be trimmed when processed.'],
21
21
  [c.WARN_CONVERTING, '%s: %s "%s" is not of type string, converting.'],
22
22
  [c.WARN_TRIMMING, '%s: %s "%s" has extra whitespace, trimming.'],
23
23
  [c.WARN_NOT_EXISTENT_SPLIT, '%s: feature flag "%s" does not exist in this environment. Please double check what feature flags exist in the Split user interface.'],
@@ -15,6 +15,14 @@ function treatmentsNotReady(featureFlagNames) {
15
15
  });
16
16
  return evaluations;
17
17
  }
18
+ function stringify(options) {
19
+ if (options && options.properties) {
20
+ try {
21
+ return JSON.stringify(options.properties);
22
+ }
23
+ catch ( /* JSON.stringify should never throw with validated options, but handling just in case */_a) { /* JSON.stringify should never throw with validated options, but handling just in case */ }
24
+ }
25
+ }
18
26
  /**
19
27
  * Creator of base client with getTreatments and track methods.
20
28
  */
@@ -22,13 +30,13 @@ export function clientFactory(params) {
22
30
  var readinessManager = params.sdkReadinessManager.readinessManager, storage = params.storage, settings = params.settings, impressionsTracker = params.impressionsTracker, eventTracker = params.eventTracker, telemetryTracker = params.telemetryTracker;
23
31
  var log = settings.log, mode = settings.mode;
24
32
  var isAsync = isConsumerMode(mode);
25
- function getTreatment(key, featureFlagName, attributes, withConfig, methodName) {
33
+ function getTreatment(key, featureFlagName, attributes, options, withConfig, methodName) {
26
34
  if (withConfig === void 0) { withConfig = false; }
27
35
  if (methodName === void 0) { methodName = GET_TREATMENT; }
28
36
  var stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENT_WITH_CONFIG : TREATMENT);
29
37
  var wrapUp = function (evaluationResult) {
30
38
  var queue = [];
31
- var treatment = processEvaluation(evaluationResult, featureFlagName, key, attributes, withConfig, methodName, queue);
39
+ var treatment = processEvaluation(evaluationResult, featureFlagName, key, stringify(options), withConfig, methodName, queue);
32
40
  impressionsTracker.track(queue, attributes);
33
41
  stopTelemetryTracker(queue[0] && queue[0].imp.label);
34
42
  return treatment;
@@ -40,18 +48,19 @@ export function clientFactory(params) {
40
48
  treatmentNotReady;
41
49
  return thenable(evaluation) ? evaluation.then(function (res) { return wrapUp(res); }) : wrapUp(evaluation);
42
50
  }
43
- function getTreatmentWithConfig(key, featureFlagName, attributes) {
44
- return getTreatment(key, featureFlagName, attributes, true, GET_TREATMENT_WITH_CONFIG);
51
+ function getTreatmentWithConfig(key, featureFlagName, attributes, options) {
52
+ return getTreatment(key, featureFlagName, attributes, options, true, GET_TREATMENT_WITH_CONFIG);
45
53
  }
46
- function getTreatments(key, featureFlagNames, attributes, withConfig, methodName) {
54
+ function getTreatments(key, featureFlagNames, attributes, options, withConfig, methodName) {
47
55
  if (withConfig === void 0) { withConfig = false; }
48
56
  if (methodName === void 0) { methodName = GET_TREATMENTS; }
49
57
  var stopTelemetryTracker = telemetryTracker.trackEval(withConfig ? TREATMENTS_WITH_CONFIG : TREATMENTS);
50
58
  var wrapUp = function (evaluationResults) {
51
59
  var queue = [];
52
60
  var treatments = {};
61
+ var properties = stringify(options);
53
62
  Object.keys(evaluationResults).forEach(function (featureFlagName) {
54
- treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, attributes, withConfig, methodName, queue);
63
+ treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, properties, withConfig, methodName, queue);
55
64
  });
56
65
  impressionsTracker.track(queue, attributes);
57
66
  stopTelemetryTracker(queue[0] && queue[0].imp.label);
@@ -64,10 +73,10 @@ export function clientFactory(params) {
64
73
  treatmentsNotReady(featureFlagNames);
65
74
  return thenable(evaluations) ? evaluations.then(function (res) { return wrapUp(res); }) : wrapUp(evaluations);
66
75
  }
67
- function getTreatmentsWithConfig(key, featureFlagNames, attributes) {
68
- return getTreatments(key, featureFlagNames, attributes, true, GET_TREATMENTS_WITH_CONFIG);
76
+ function getTreatmentsWithConfig(key, featureFlagNames, attributes, options) {
77
+ return getTreatments(key, featureFlagNames, attributes, options, true, GET_TREATMENTS_WITH_CONFIG);
69
78
  }
70
- function getTreatmentsByFlagSets(key, flagSetNames, attributes, withConfig, method, methodName) {
79
+ function getTreatmentsByFlagSets(key, flagSetNames, attributes, options, withConfig, method, methodName) {
71
80
  if (withConfig === void 0) { withConfig = false; }
72
81
  if (method === void 0) { method = TREATMENTS_BY_FLAGSETS; }
73
82
  if (methodName === void 0) { methodName = GET_TREATMENTS_BY_FLAG_SETS; }
@@ -75,9 +84,9 @@ export function clientFactory(params) {
75
84
  var wrapUp = function (evaluationResults) {
76
85
  var queue = [];
77
86
  var treatments = {};
78
- var evaluations = evaluationResults;
79
- Object.keys(evaluations).forEach(function (featureFlagName) {
80
- treatments[featureFlagName] = processEvaluation(evaluations[featureFlagName], featureFlagName, key, attributes, withConfig, methodName, queue);
87
+ var properties = stringify(options);
88
+ Object.keys(evaluationResults).forEach(function (featureFlagName) {
89
+ treatments[featureFlagName] = processEvaluation(evaluationResults[featureFlagName], featureFlagName, key, properties, withConfig, methodName, queue);
81
90
  });
82
91
  impressionsTracker.track(queue, attributes);
83
92
  stopTelemetryTracker(queue[0] && queue[0].imp.label);
@@ -90,17 +99,17 @@ export function clientFactory(params) {
90
99
  {};
91
100
  return thenable(evaluations) ? evaluations.then(function (res) { return wrapUp(res); }) : wrapUp(evaluations);
92
101
  }
93
- function getTreatmentsWithConfigByFlagSets(key, flagSetNames, attributes) {
94
- return getTreatmentsByFlagSets(key, flagSetNames, attributes, true, TREATMENTS_WITH_CONFIG_BY_FLAGSETS, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS);
102
+ function getTreatmentsWithConfigByFlagSets(key, flagSetNames, attributes, options) {
103
+ return getTreatmentsByFlagSets(key, flagSetNames, attributes, options, true, TREATMENTS_WITH_CONFIG_BY_FLAGSETS, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS);
95
104
  }
96
- function getTreatmentsByFlagSet(key, flagSetName, attributes) {
97
- return getTreatmentsByFlagSets(key, [flagSetName], attributes, false, TREATMENTS_BY_FLAGSET, GET_TREATMENTS_BY_FLAG_SET);
105
+ function getTreatmentsByFlagSet(key, flagSetName, attributes, options) {
106
+ return getTreatmentsByFlagSets(key, [flagSetName], attributes, options, false, TREATMENTS_BY_FLAGSET, GET_TREATMENTS_BY_FLAG_SET);
98
107
  }
99
- function getTreatmentsWithConfigByFlagSet(key, flagSetName, attributes) {
100
- return getTreatmentsByFlagSets(key, [flagSetName], attributes, true, TREATMENTS_WITH_CONFIG_BY_FLAGSET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
108
+ function getTreatmentsWithConfigByFlagSet(key, flagSetName, attributes, options) {
109
+ return getTreatmentsByFlagSets(key, [flagSetName], attributes, options, true, TREATMENTS_WITH_CONFIG_BY_FLAGSET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
101
110
  }
102
111
  // Internal function
103
- function processEvaluation(evaluation, featureFlagName, key, attributes, withConfig, invokingMethodName, queue) {
112
+ function processEvaluation(evaluation, featureFlagName, key, properties, withConfig, invokingMethodName, queue) {
104
113
  var matchingKey = getMatching(key);
105
114
  var bucketingKey = getBucketing(key);
106
115
  var treatment = evaluation.treatment, label = evaluation.label, changeNumber = evaluation.changeNumber, _a = evaluation.config, config = _a === void 0 ? null : _a, impressionsDisabled = evaluation.impressionsDisabled;
@@ -116,6 +125,7 @@ export function clientFactory(params) {
116
125
  bucketingKey: bucketingKey,
117
126
  label: label,
118
127
  changeNumber: changeNumber,
128
+ properties: properties
119
129
  },
120
130
  disabled: impressionsDisabled
121
131
  });
@@ -15,40 +15,35 @@ export function clientAttributesDecoration(log, client) {
15
15
  var clientGetTreatmentsWithConfigByFlagSets = client.getTreatmentsWithConfigByFlagSets;
16
16
  var clientGetTreatmentsByFlagSet = client.getTreatmentsByFlagSet;
17
17
  var clientGetTreatmentsWithConfigByFlagSet = client.getTreatmentsWithConfigByFlagSet;
18
- var clientTrack = client.track;
19
- function getTreatment(maybeKey, maybeFeatureFlagName, maybeAttributes) {
20
- return clientGetTreatment(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes));
18
+ function getTreatment(maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions) {
19
+ return clientGetTreatment(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes), maybeOptions);
21
20
  }
22
- function getTreatmentWithConfig(maybeKey, maybeFeatureFlagName, maybeAttributes) {
23
- return clientGetTreatmentWithConfig(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes));
21
+ function getTreatmentWithConfig(maybeKey, maybeFeatureFlagName, maybeAttributes, maybeOptions) {
22
+ return clientGetTreatmentWithConfig(maybeKey, maybeFeatureFlagName, combineAttributes(maybeAttributes), maybeOptions);
24
23
  }
25
- function getTreatments(maybeKey, maybeFeatureFlagNames, maybeAttributes) {
26
- return clientGetTreatments(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes));
24
+ function getTreatments(maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions) {
25
+ return clientGetTreatments(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes), maybeOptions);
27
26
  }
28
- function getTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, maybeAttributes) {
29
- return clientGetTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes));
27
+ function getTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, maybeAttributes, maybeOptions) {
28
+ return clientGetTreatmentsWithConfig(maybeKey, maybeFeatureFlagNames, combineAttributes(maybeAttributes), maybeOptions);
30
29
  }
31
- function getTreatmentsByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
32
- return clientGetTreatmentsByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes));
30
+ function getTreatmentsByFlagSets(maybeKey, maybeFlagSets, maybeAttributes, maybeOptions) {
31
+ return clientGetTreatmentsByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes), maybeOptions);
33
32
  }
34
- function getTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, maybeAttributes) {
35
- return clientGetTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes));
33
+ function getTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, maybeAttributes, maybeOptions) {
34
+ return clientGetTreatmentsWithConfigByFlagSets(maybeKey, maybeFlagSets, combineAttributes(maybeAttributes), maybeOptions);
36
35
  }
37
- function getTreatmentsByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
38
- return clientGetTreatmentsByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes));
36
+ function getTreatmentsByFlagSet(maybeKey, maybeFlagSet, maybeAttributes, maybeOptions) {
37
+ return clientGetTreatmentsByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes), maybeOptions);
39
38
  }
40
- function getTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, maybeAttributes) {
41
- return clientGetTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes));
42
- }
43
- function track(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties) {
44
- return clientTrack(maybeKey, maybeTT, maybeEvent, maybeEventValue, maybeProperties);
39
+ function getTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, maybeAttributes, maybeOptions) {
40
+ return clientGetTreatmentsWithConfigByFlagSet(maybeKey, maybeFlagSet, combineAttributes(maybeAttributes), maybeOptions);
45
41
  }
46
42
  function combineAttributes(maybeAttributes) {
47
43
  var storedAttributes = attributeStorage.getAll();
48
- if (Object.keys(storedAttributes).length > 0) {
49
- return objectAssign({}, storedAttributes, maybeAttributes);
50
- }
51
- return maybeAttributes;
44
+ return Object.keys(storedAttributes).length > 0 ?
45
+ objectAssign({}, storedAttributes, maybeAttributes) :
46
+ maybeAttributes;
52
47
  }
53
48
  return objectAssign(client, {
54
49
  getTreatment: getTreatment,
@@ -59,7 +54,6 @@ export function clientAttributesDecoration(log, client) {
59
54
  getTreatmentsWithConfigByFlagSets: getTreatmentsWithConfigByFlagSets,
60
55
  getTreatmentsByFlagSet: getTreatmentsByFlagSet,
61
56
  getTreatmentsWithConfigByFlagSet: getTreatmentsWithConfigByFlagSet,
62
- track: track,
63
57
  /**
64
58
  * Add an attribute to client's in memory attributes storage
65
59
  *