@splitsoftware/splitio-commons 2.11.1-rc.2 → 2.12.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 (157) hide show
  1. package/CHANGES.txt +6 -2
  2. package/cjs/evaluator/condition/engineUtils.js +2 -2
  3. package/cjs/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +3 -3
  4. package/cjs/evaluator/fallbackTreatmentsCalculator/index.js +21 -32
  5. package/cjs/evaluator/matchers/whitelist.js +1 -1
  6. package/cjs/integrations/pluggable.js +1 -1
  7. package/cjs/listeners/node.js +2 -2
  8. package/cjs/logger/constants.js +3 -4
  9. package/cjs/logger/index.js +1 -1
  10. package/cjs/logger/messages/debug.js +1 -1
  11. package/cjs/logger/messages/error.js +1 -1
  12. package/cjs/logger/messages/info.js +2 -3
  13. package/cjs/logger/messages/warn.js +4 -4
  14. package/cjs/sdkClient/client.js +2 -3
  15. package/cjs/sdkClient/clientAttributesDecoration.js +3 -3
  16. package/cjs/sdkClient/clientInputValidation.js +36 -68
  17. package/cjs/sdkClient/identity.js +1 -1
  18. package/cjs/sdkClient/sdkClient.js +19 -7
  19. package/cjs/sdkFactory/index.js +8 -41
  20. package/cjs/services/splitApi.js +13 -13
  21. package/cjs/services/splitHttpClient.js +1 -1
  22. package/cjs/storages/KeyBuilder.js +12 -12
  23. package/cjs/storages/KeyBuilderCS.js +13 -13
  24. package/cjs/storages/KeyBuilderSS.js +15 -15
  25. package/cjs/storages/getRolloutPlan.js +1 -1
  26. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -1
  27. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +1 -1
  28. package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
  29. package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +1 -1
  30. package/cjs/storages/inMemory/SplitsCacheInMemory.js +1 -1
  31. package/cjs/storages/inRedis/EventsCacheInRedis.js +1 -1
  32. package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +5 -5
  33. package/cjs/storages/inRedis/ImpressionsCacheInRedis.js +1 -1
  34. package/cjs/storages/inRedis/RedisAdapter.js +8 -8
  35. package/cjs/storages/inRedis/SplitsCacheInRedis.js +6 -6
  36. package/cjs/storages/inRedis/TelemetryCacheInRedis.js +7 -7
  37. package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +3 -3
  38. package/cjs/storages/pluggable/EventsCachePluggable.js +1 -1
  39. package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +6 -6
  40. package/cjs/storages/pluggable/SplitsCachePluggable.js +4 -4
  41. package/cjs/storages/pluggable/TelemetryCachePluggable.js +7 -7
  42. package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +2 -2
  43. package/cjs/storages/pluggable/index.js +3 -3
  44. package/cjs/storages/pluggable/wrapperAdapter.js +1 -1
  45. package/cjs/storages/setRolloutPlan.js +3 -3
  46. package/cjs/storages/utils.js +6 -6
  47. package/cjs/sync/offline/splitsParser/parseCondition.js +1 -1
  48. package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
  49. package/cjs/sync/polling/pollingManagerSS.js +2 -2
  50. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +6 -6
  51. package/cjs/sync/polling/updaters/splitChangesUpdater.js +12 -10
  52. package/cjs/sync/streaming/SSEClient/index.js +2 -2
  53. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
  54. package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
  55. package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +2 -2
  56. package/cjs/sync/streaming/parseUtils.js +1 -1
  57. package/cjs/sync/submitters/submitter.js +1 -1
  58. package/cjs/trackers/eventTracker.js +10 -12
  59. package/cjs/trackers/impressionObserver/buildKey.js +1 -1
  60. package/cjs/trackers/impressionsTracker.js +37 -20
  61. package/cjs/trackers/uniqueKeysTracker.js +1 -1
  62. package/cjs/utils/inputValidation/apiKey.js +1 -1
  63. package/cjs/utils/inputValidation/attribute.js +2 -2
  64. package/cjs/utils/inputValidation/eventProperties.js +1 -1
  65. package/cjs/utils/inputValidation/isOperational.js +1 -1
  66. package/cjs/utils/lang/index.js +1 -1
  67. package/cjs/utils/lang/sets.js +4 -4
  68. package/cjs/utils/promise/timeout.js +1 -1
  69. package/cjs/utils/settingsValidation/splitFilters.js +2 -2
  70. package/cjs/utils/settingsValidation/url.js +5 -5
  71. package/esm/evaluator/condition/engineUtils.js +2 -2
  72. package/esm/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +3 -3
  73. package/esm/evaluator/fallbackTreatmentsCalculator/index.js +21 -33
  74. package/esm/evaluator/matchers/whitelist.js +1 -1
  75. package/esm/integrations/pluggable.js +1 -1
  76. package/esm/listeners/node.js +2 -2
  77. package/esm/logger/constants.js +0 -1
  78. package/esm/logger/index.js +1 -1
  79. package/esm/logger/messages/info.js +1 -2
  80. package/esm/logger/messages/warn.js +3 -3
  81. package/esm/sdkClient/client.js +3 -4
  82. package/esm/sdkClient/clientAttributesDecoration.js +3 -3
  83. package/esm/sdkClient/clientInputValidation.js +36 -68
  84. package/esm/sdkClient/identity.js +1 -1
  85. package/esm/sdkClient/sdkClient.js +20 -8
  86. package/esm/sdkFactory/index.js +8 -41
  87. package/esm/services/splitApi.js +13 -13
  88. package/esm/services/splitHttpClient.js +1 -1
  89. package/esm/storages/KeyBuilder.js +12 -12
  90. package/esm/storages/KeyBuilderCS.js +12 -12
  91. package/esm/storages/KeyBuilderSS.js +14 -14
  92. package/esm/storages/getRolloutPlan.js +1 -1
  93. package/esm/storages/inMemory/ImpressionCountsCacheInMemory.js +1 -1
  94. package/esm/storages/inRedis/EventsCacheInRedis.js +1 -1
  95. package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +4 -4
  96. package/esm/storages/inRedis/RedisAdapter.js +7 -7
  97. package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -4
  98. package/esm/storages/inRedis/TelemetryCacheInRedis.js +7 -7
  99. package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +1 -1
  100. package/esm/storages/pluggable/EventsCachePluggable.js +1 -1
  101. package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +5 -5
  102. package/esm/storages/pluggable/SplitsCachePluggable.js +2 -2
  103. package/esm/storages/pluggable/TelemetryCachePluggable.js +7 -7
  104. package/esm/storages/pluggable/UniqueKeysCachePluggable.js +1 -1
  105. package/esm/storages/pluggable/index.js +2 -2
  106. package/esm/storages/pluggable/wrapperAdapter.js +1 -1
  107. package/esm/storages/setRolloutPlan.js +3 -3
  108. package/esm/storages/utils.js +6 -6
  109. package/esm/sync/offline/splitsParser/parseCondition.js +1 -1
  110. package/esm/sync/polling/pollingManagerSS.js +2 -2
  111. package/esm/sync/polling/updaters/segmentChangesUpdater.js +6 -6
  112. package/esm/sync/polling/updaters/splitChangesUpdater.js +12 -10
  113. package/esm/sync/streaming/SSEClient/index.js +2 -2
  114. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +2 -2
  115. package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -2
  116. package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +2 -2
  117. package/esm/sync/streaming/parseUtils.js +1 -1
  118. package/esm/sync/submitters/submitter.js +1 -1
  119. package/esm/trackers/eventTracker.js +10 -12
  120. package/esm/trackers/impressionObserver/buildKey.js +1 -1
  121. package/esm/trackers/impressionsTracker.js +38 -21
  122. package/esm/trackers/uniqueKeysTracker.js +1 -1
  123. package/esm/utils/inputValidation/apiKey.js +1 -1
  124. package/esm/utils/inputValidation/attribute.js +2 -2
  125. package/esm/utils/inputValidation/isOperational.js +1 -1
  126. package/esm/utils/lang/sets.js +4 -4
  127. package/esm/utils/promise/timeout.js +1 -1
  128. package/esm/utils/settingsValidation/splitFilters.js +2 -2
  129. package/esm/utils/settingsValidation/url.js +5 -5
  130. package/package.json +5 -5
  131. package/src/dtos/types.ts +15 -15
  132. package/src/evaluator/condition/engineUtils.ts +2 -2
  133. package/src/evaluator/fallbackTreatmentsCalculator/index.ts +23 -41
  134. package/src/evaluator/matchers/whitelist.ts +2 -2
  135. package/src/evaluator/types.ts +2 -2
  136. package/src/evaluator/value/index.ts +1 -1
  137. package/src/integrations/pluggable.ts +1 -1
  138. package/src/logger/constants.ts +0 -1
  139. package/src/logger/messages/info.ts +1 -2
  140. package/src/logger/messages/warn.ts +3 -3
  141. package/src/sdkClient/client.ts +3 -5
  142. package/src/sdkClient/clientInputValidation.ts +38 -61
  143. package/src/sdkClient/sdkClient.ts +20 -5
  144. package/src/sdkFactory/index.ts +10 -47
  145. package/src/sdkFactory/types.ts +6 -3
  146. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +1 -1
  147. package/src/storages/inMemory/SplitsCacheInMemory.ts +1 -1
  148. package/src/storages/inRedis/SplitsCacheInRedis.ts +1 -1
  149. package/src/storages/pluggable/SplitsCachePluggable.ts +1 -1
  150. package/src/storages/setRolloutPlan.ts +2 -2
  151. package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
  152. package/src/sync/polling/updaters/splitChangesUpdater.ts +11 -9
  153. package/src/trackers/eventTracker.ts +7 -10
  154. package/src/trackers/impressionsTracker.ts +42 -26
  155. package/src/trackers/types.ts +3 -1
  156. package/src/utils/lang/sets.ts +4 -2
  157. package/types/splitio.d.ts +22 -18
@@ -37,7 +37,7 @@ export function SplitsUpdateWorker(log, storage, splitsSyncTask, splitsEventEmit
37
37
  segmentsSyncTask.execute(true);
38
38
  var attempts = backoff.attempts + 1;
39
39
  if (ff.isSync() && rbs.isSync()) {
40
- log.debug("Refresh completed" + (cdnBypass ? ' bypassing the CDN' : '') + " in " + attempts + " attempts.");
40
+ log.debug("Refresh completed".concat(cdnBypass ? ' bypassing the CDN' : '', " in ").concat(attempts, " attempts."));
41
41
  isHandlingEvent = false;
42
42
  return;
43
43
  }
@@ -46,7 +46,7 @@ export function SplitsUpdateWorker(log, storage, splitsSyncTask, splitsEventEmit
46
46
  return;
47
47
  }
48
48
  if (cdnBypass) {
49
- log.debug("No changes fetched after " + attempts + " attempts with CDN bypassed.");
49
+ log.debug("No changes fetched after ".concat(attempts, " attempts with CDN bypassed."));
50
50
  isHandlingEvent = false;
51
51
  }
52
52
  else {
@@ -27,7 +27,7 @@ function decompress(data, compression) {
27
27
  return algorithms.gunzipSync(binData);
28
28
  if (compression === ZLIB)
29
29
  return algorithms.unzlibSync(binData);
30
- throw new Error("Invalid compression algorithm #" + compression);
30
+ throw new Error("Invalid compression algorithm #".concat(compression));
31
31
  }
32
32
  /**
33
33
  * Decode, decompress and parse the provided 'data' into a KeyList object
@@ -13,7 +13,7 @@ export function submitterFactory(log, postClient, sourceCache, postRate, fromCac
13
13
  if (sourceCache.isEmpty() && !data)
14
14
  return Promise.resolve();
15
15
  data = sourceCache.pop(data);
16
- var dataCountMessage = typeof data.length === 'number' ? data.length + " " + dataName : dataName;
16
+ var dataCountMessage = typeof data.length === 'number' ? "".concat(data.length, " ").concat(dataName) : dataName;
17
17
  log[debugLogs ? 'debug' : 'info'](SUBMITTERS_PUSH, [dataCountMessage]);
18
18
  var jsonPayload = JSON.stringify(fromCacheToPayload ? fromCacheToPayload(data) : data);
19
19
  if (!maxRetries)
@@ -9,26 +9,24 @@ import { isConsumerMode } from '../utils/settingsValidation/mode';
9
9
  * @param eventsCache - cache to save events
10
10
  * @param integrationsManager - optional event handler used for integrations
11
11
  */
12
- export function eventTrackerFactory(settings, eventsCache, whenInit, integrationsManager, telemetryCache) {
12
+ export function eventTrackerFactory(settings, eventsCache, integrationsManager, telemetryCache) {
13
13
  var log = settings.log, mode = settings.mode;
14
14
  var isAsync = isConsumerMode(mode);
15
15
  function queueEventsCallback(eventData, tracked) {
16
16
  var eventTypeId = eventData.eventTypeId, trafficTypeName = eventData.trafficTypeName, key = eventData.key, value = eventData.value, timestamp = eventData.timestamp, properties = eventData.properties;
17
17
  // Logging every prop would be too much.
18
- var msg = "event of type \"" + eventTypeId + "\" for traffic type \"" + trafficTypeName + "\". Key: " + key + ". Value: " + value + ". Timestamp: " + timestamp + ". " + (properties ? 'With properties.' : 'With no properties.');
18
+ var msg = "event of type \"".concat(eventTypeId, "\" for traffic type \"").concat(trafficTypeName, "\". Key: ").concat(key, ". Value: ").concat(value, ". Timestamp: ").concat(timestamp, ". ").concat(properties ? 'With properties.' : 'With no properties.');
19
19
  if (tracked) {
20
20
  log.info(EVENTS_TRACKER_SUCCESS, [msg]);
21
21
  if (integrationsManager) {
22
- whenInit(function () {
23
- // Wrap in a timeout because we don't want it to be blocking.
24
- setTimeout(function () {
25
- // copy of event, to avoid unexpected behavior if modified by integrations
26
- var eventDataCopy = objectAssign({}, eventData);
27
- if (properties)
28
- eventDataCopy.properties = objectAssign({}, properties);
29
- // integrationsManager does not throw errors (they are internally handled by each integration module)
30
- integrationsManager.handleEvent(eventDataCopy);
31
- });
22
+ // Wrap in a timeout because we don't want it to be blocking.
23
+ setTimeout(function () {
24
+ // copy of event, to avoid unexpected behavior if modified by integrations
25
+ var eventDataCopy = objectAssign({}, eventData);
26
+ if (properties)
27
+ eventDataCopy.properties = objectAssign({}, properties);
28
+ // integrationsManager does not throw errors (they are internally handled by each integration module)
29
+ integrationsManager.handleEvent(eventDataCopy);
32
30
  });
33
31
  }
34
32
  }
@@ -1,3 +1,3 @@
1
1
  export function buildKey(impression) {
2
- return impression.keyName + ":" + impression.feature + ":" + impression.treatment + ":" + impression.label + ":" + impression.changeNumber;
2
+ return "".concat(impression.keyName, ":").concat(impression.feature, ":").concat(impression.treatment, ":").concat(impression.label, ":").concat(impression.changeNumber);
3
3
  }
@@ -1,13 +1,32 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
2
  import { thenable } from '../utils/promise/thenable';
3
3
  import { IMPRESSIONS_TRACKER_SUCCESS, ERROR_IMPRESSIONS_TRACKER, ERROR_IMPRESSIONS_LISTENER } from '../logger/constants';
4
- import { CONSENT_DECLINED, DEDUPED, QUEUED } from '../utils/constants';
4
+ import { CONSENT_DECLINED, DEBUG, DEDUPED, OPTIMIZED, QUEUED } from '../utils/constants';
5
+ import { strategyDebugFactory } from './strategy/strategyDebug';
6
+ import { strategyNoneFactory } from './strategy/strategyNone';
7
+ import { strategyOptimizedFactory } from './strategy/strategyOptimized';
8
+ import { uniqueKeysTrackerFactory } from './uniqueKeysTracker';
5
9
  /**
6
10
  * Impressions tracker stores impressions in cache and pass them to the listener and integrations manager if provided.
7
11
  */
8
- export function impressionsTrackerFactory(settings, impressionsCache, noneStrategy, strategy, whenInit, integrationsManager, telemetryCache) {
9
- var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version;
12
+ export function impressionsTrackerFactory(params, storage, integrationsManager) {
13
+ var settings = params.settings, impressionsObserverFactory = params.impressionsObserverFactory, filterAdapterFactory = params.filterAdapterFactory;
14
+ var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version, impressionsMode = settings.sync.impressionsMode;
15
+ var observer = impressionsObserverFactory();
16
+ var uniqueKeysTracker = uniqueKeysTrackerFactory(log, storage.uniqueKeys, filterAdapterFactory && filterAdapterFactory());
17
+ var noneStrategy = strategyNoneFactory(storage.impressionCounts, uniqueKeysTracker);
18
+ var strategy = impressionsMode === OPTIMIZED ?
19
+ strategyOptimizedFactory(observer, storage.impressionCounts) :
20
+ impressionsMode === DEBUG ?
21
+ strategyDebugFactory(observer) :
22
+ noneStrategy;
10
23
  return {
24
+ start: function () {
25
+ uniqueKeysTracker.start();
26
+ },
27
+ stop: function () {
28
+ uniqueKeysTracker.stop();
29
+ },
11
30
  track: function (impressions, attributes) {
12
31
  if (settings.userConsent === CONSENT_DECLINED)
13
32
  return;
@@ -20,7 +39,7 @@ export function impressionsTrackerFactory(settings, impressionsCache, noneStrate
20
39
  var impressionsLength = impressions.length;
21
40
  var impressionsToStoreLength = impressionsToStore.length;
22
41
  if (impressionsToStoreLength) {
23
- var res = impressionsCache.track(impressionsToStore.map(function (item) { return item.imp; }));
42
+ var res = storage.impressions.track(impressionsToStore.map(function (item) { return item.imp; }));
24
43
  // If we're on an async storage, handle error and log it.
25
44
  if (thenable(res)) {
26
45
  res.then(function () {
@@ -32,9 +51,9 @@ export function impressionsTrackerFactory(settings, impressionsCache, noneStrate
32
51
  else {
33
52
  // Record when impressionsCache is sync only (standalone mode)
34
53
  // @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded
35
- if (telemetryCache) {
36
- telemetryCache.recordImpressionStats(QUEUED, impressionsToStoreLength);
37
- telemetryCache.recordImpressionStats(DEDUPED, impressionsLength - impressionsToStoreLength);
54
+ if (storage.telemetry) {
55
+ storage.telemetry.recordImpressionStats(QUEUED, impressionsToStoreLength);
56
+ storage.telemetry.recordImpressionStats(DEDUPED, impressionsLength - impressionsToStoreLength);
38
57
  }
39
58
  }
40
59
  }
@@ -49,20 +68,18 @@ export function impressionsTrackerFactory(settings, impressionsCache, noneStrate
49
68
  hostname: hostname,
50
69
  sdkLanguageVersion: version
51
70
  };
52
- whenInit(function () {
53
- // Wrap in a timeout because we don't want it to be blocking.
54
- setTimeout(function () {
55
- // integrationsManager.handleImpression does not throw errors
56
- if (integrationsManager)
57
- integrationsManager.handleImpression(impressionData);
58
- try { // @ts-ignore. An exception on the listeners should not break the SDK.
59
- if (impressionListener)
60
- impressionListener.logImpression(impressionData);
61
- }
62
- catch (err) {
63
- log.error(ERROR_IMPRESSIONS_LISTENER, [err]);
64
- }
65
- });
71
+ // Wrap in a timeout because we don't want it to be blocking.
72
+ setTimeout(function () {
73
+ // integrationsManager.handleImpression does not throw errors
74
+ if (integrationsManager)
75
+ integrationsManager.handleImpression(impressionData);
76
+ try { // @ts-ignore. An exception on the listeners should not break the SDK.
77
+ if (impressionListener)
78
+ impressionListener.logImpression(impressionData);
79
+ }
80
+ catch (err) {
81
+ log.error(ERROR_IMPRESSIONS_LISTENER, [err]);
82
+ }
66
83
  });
67
84
  };
68
85
  for (var i = 0; i < impressionsLength; i++) {
@@ -19,7 +19,7 @@ export function uniqueKeysTrackerFactory(log, uniqueKeysCache, filterAdapter) {
19
19
  return {
20
20
  track: function (key, featureName) {
21
21
  if (!filterAdapter.add(key, featureName)) {
22
- log.debug(LOG_PREFIX_UNIQUE_KEYS_TRACKER + "The feature " + featureName + " and key " + key + " exist in the filter");
22
+ log.debug("".concat(LOG_PREFIX_UNIQUE_KEYS_TRACKER, "The feature ").concat(featureName, " and key ").concat(key, " exist in the filter"));
23
23
  return;
24
24
  }
25
25
  uniqueKeysCache.track(key, featureName);
@@ -34,7 +34,7 @@ export function validateAndTrackApiKey(log, maybeSdkKey) {
34
34
  }
35
35
  }
36
36
  else {
37
- log.warn(WARN_SDK_KEY, [usedKeysMap[sdkKey] + " factory/ies with this SDK Key"]);
37
+ log.warn(WARN_SDK_KEY, ["".concat(usedKeysMap[sdkKey], " factory/ies with this SDK Key")]);
38
38
  usedKeysMap[sdkKey]++;
39
39
  }
40
40
  }
@@ -1,7 +1,7 @@
1
1
  import { isString, isFiniteNumber, isBoolean } from '../../utils/lang';
2
2
  export function validateAttribute(log, attributeKey, attributeValue, method) {
3
3
  if (!isString(attributeKey) || attributeKey.length === 0) {
4
- log.warn(method + ": you passed an invalid attribute name, attribute name must be a non-empty string.");
4
+ log.warn("".concat(method, ": you passed an invalid attribute name, attribute name must be a non-empty string."));
5
5
  return false;
6
6
  }
7
7
  var isStringVal = isString(attributeValue);
@@ -9,7 +9,7 @@ export function validateAttribute(log, attributeKey, attributeValue, method) {
9
9
  var isBoolVal = isBoolean(attributeValue);
10
10
  var isArrayVal = Array.isArray(attributeValue);
11
11
  if (!(isStringVal || isFiniteVal || isBoolVal || isArrayVal)) { // If it's not of valid type.
12
- log.warn(method + ": you passed an invalid attribute value for " + attributeKey + ". Acceptable types are: string, number, boolean and array of strings.");
12
+ log.warn("".concat(method, ": you passed an invalid attribute value for ").concat(attributeKey, ". Acceptable types are: string, number, boolean and array of strings."));
13
13
  return false;
14
14
  }
15
15
  return true;
@@ -8,7 +8,7 @@ export function validateIfNotDestroyed(log, readinessManager, method) {
8
8
  export function validateIfReadyFromCache(log, readinessManager, method, featureFlagNameOrNames) {
9
9
  if (readinessManager.isReadyFromCache())
10
10
  return true;
11
- log.warn(CLIENT_NOT_READY_FROM_CACHE, [method, featureFlagNameOrNames ? " for feature flag " + featureFlagNameOrNames.toString() : '']);
11
+ log.warn(CLIENT_NOT_READY_FROM_CACHE, [method, featureFlagNameOrNames ? " for feature flag ".concat(featureFlagNameOrNames.toString()) : '']);
12
12
  return false;
13
13
  }
14
14
  // Operational means that the SDK is ready to evaluate (not destroyed and ready from cache)
@@ -10,8 +10,8 @@ export function setToArray(set) {
10
10
  export function returnSetsUnion(set, set2) {
11
11
  return new Set(setToArray(set).concat(setToArray(set2)));
12
12
  }
13
- export function returnDifference(list, list2) {
14
- if (list === void 0) { list = []; }
15
- if (list2 === void 0) { list2 = []; }
16
- return list.filter(function (item) { return list2.indexOf(item) === -1; });
13
+ export function returnDifference(list1, list2) {
14
+ list1 = list1 || [];
15
+ list2 = list2 || [];
16
+ return list1.filter(function (item) { return list2.indexOf(item) === -1; });
17
17
  }
@@ -3,7 +3,7 @@ export function timeout(ms, promise) {
3
3
  return promise;
4
4
  return new Promise(function (resolve, reject) {
5
5
  var tid = setTimeout(function () {
6
- reject(new Error("Operation timed out because it exceeded the configured time limit of " + ms + " ms."));
6
+ reject(new Error("Operation timed out because it exceeded the configured time limit of ".concat(ms, " ms.")));
7
7
  }, ms);
8
8
  promise.then(function (res) {
9
9
  clearTimeout(tid);
@@ -42,14 +42,14 @@ function validateFilterType(maybeFilterType) {
42
42
  */
43
43
  function validateSplitFilter(log, type, values, maxLength) {
44
44
  // validate and remove invalid and duplicated values
45
- var result = validateSplits(log, values, LOG_PREFIX_SETTINGS, type + " filter", type + " filter value");
45
+ var result = validateSplits(log, values, LOG_PREFIX_SETTINGS, "".concat(type, " filter"), "".concat(type, " filter value"));
46
46
  if (result) {
47
47
  if (type === 'bySet') {
48
48
  result = sanitizeFlagSets(log, result, LOG_PREFIX_SETTINGS);
49
49
  }
50
50
  // check max length
51
51
  if (result.length > maxLength)
52
- throw new Error(maxLength + " unique values can be specified at most for '" + type + "' filter. You passed " + result.length + ". Please consider reducing the amount or using other filter.");
52
+ throw new Error("".concat(maxLength, " unique values can be specified at most for '").concat(type, "' filter. You passed ").concat(result.length, ". Please consider reducing the amount or using other filter."));
53
53
  // sort values
54
54
  result.sort();
55
55
  }
@@ -12,16 +12,16 @@ var streamingEndpointMatcher = /^\/(sse|event-stream)/;
12
12
  */
13
13
  export function url(settings, target) {
14
14
  if (telemetryEndpointMatcher.test(target)) {
15
- return "" + settings.urls.telemetry + target;
15
+ return "".concat(settings.urls.telemetry).concat(target);
16
16
  }
17
17
  if (eventsEndpointMatcher.test(target)) {
18
- return "" + settings.urls.events + target;
18
+ return "".concat(settings.urls.events).concat(target);
19
19
  }
20
20
  if (authEndpointMatcher.test(target)) {
21
- return "" + settings.urls.auth + target;
21
+ return "".concat(settings.urls.auth).concat(target);
22
22
  }
23
23
  if (streamingEndpointMatcher.test(target)) {
24
- return "" + settings.urls.streaming + target;
24
+ return "".concat(settings.urls.streaming).concat(target);
25
25
  }
26
- return "" + settings.urls.sdk + target;
26
+ return "".concat(settings.urls.sdk).concat(target);
27
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "2.11.1-rc.2",
3
+ "version": "2.12.1",
4
4
  "description": "Split JavaScript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -60,10 +60,10 @@
60
60
  "@types/ioredis": "^4.28.0",
61
61
  "@types/jest": "^27.0.0",
62
62
  "@types/lodash": "^4.14.162",
63
- "@typescript-eslint/eslint-plugin": "^6.6.0",
64
- "@typescript-eslint/parser": "^6.6.0",
63
+ "@typescript-eslint/eslint-plugin": "^7.18.0",
64
+ "@typescript-eslint/parser": "^7.18.0",
65
65
  "cross-env": "^7.0.2",
66
- "eslint": "^8.48.0",
66
+ "eslint": "^8.56.0",
67
67
  "eslint-plugin-compat": "^6.0.1",
68
68
  "eslint-plugin-import": "^2.25.3",
69
69
  "eslint-plugin-tsdoc": "^0.3.0",
@@ -76,7 +76,7 @@
76
76
  "redis-server": "1.2.2",
77
77
  "rimraf": "^3.0.2",
78
78
  "ts-jest": "^27.0.5",
79
- "typescript": "4.4.4"
79
+ "typescript": "4.7.4"
80
80
  },
81
81
  "sideEffects": false
82
82
  }
package/src/dtos/types.ts CHANGED
@@ -23,7 +23,7 @@ export interface IBetweenStringMatcherData {
23
23
  }
24
24
 
25
25
  export interface IWhitelistMatcherData {
26
- whitelist: string[]
26
+ whitelist?: string[] | null
27
27
  }
28
28
 
29
29
  export interface IInSegmentMatcherData {
@@ -41,10 +41,10 @@ export interface IDependencyMatcherData {
41
41
 
42
42
  interface ISplitMatcherBase {
43
43
  matcherType: string
44
- negate: boolean
45
- keySelector: null | {
44
+ negate?: boolean
45
+ keySelector?: null | {
46
46
  trafficType: string,
47
- attribute: string | null
47
+ attribute?: string | null
48
48
  }
49
49
  userDefinedSegmentMatcherData?: null | IInSegmentMatcherData
50
50
  userDefinedLargeSegmentMatcherData?: null | IInLargeSegmentMatcherData
@@ -207,18 +207,18 @@ export interface IExcludedSegment {
207
207
  export interface IRBSegment {
208
208
  name: string,
209
209
  changeNumber: number,
210
- status: 'ACTIVE' | 'ARCHIVED',
211
- conditions?: ISplitCondition[],
210
+ status?: 'ACTIVE' | 'ARCHIVED',
211
+ conditions?: ISplitCondition[] | null,
212
212
  excluded?: {
213
213
  keys?: string[] | null,
214
214
  segments?: IExcludedSegment[] | null
215
- }
215
+ } | null
216
216
  }
217
217
 
218
218
  export interface ISplit {
219
219
  name: string,
220
220
  changeNumber: number,
221
- status: 'ACTIVE' | 'ARCHIVED',
221
+ status?: 'ACTIVE' | 'ARCHIVED',
222
222
  conditions: ISplitCondition[],
223
223
  prerequisites?: null | {
224
224
  n: string,
@@ -232,9 +232,9 @@ export interface ISplit {
232
232
  trafficAllocationSeed?: number
233
233
  configurations?: {
234
234
  [treatmentName: string]: string
235
- },
236
- sets?: string[],
237
- impressionsDisabled?: boolean
235
+ } | null,
236
+ sets?: string[] | null,
237
+ impressionsDisabled?: boolean | null
238
238
  }
239
239
 
240
240
  // Split definition used in offline mode
@@ -245,13 +245,13 @@ export interface ISplitChangesResponse {
245
245
  ff?: {
246
246
  t: number,
247
247
  s?: number,
248
- d: ISplit[]
249
- },
248
+ d?: ISplit[] | null,
249
+ } | null,
250
250
  rbs?: {
251
251
  t: number,
252
252
  s?: number,
253
- d: IRBSegment[]
254
- }
253
+ d?: IRBSegment[] | null,
254
+ } | null,
255
255
  }
256
256
 
257
257
  /** Interface of the parsed JSON response of `/segmentChanges/{segmentName}` */
@@ -18,10 +18,10 @@ export function getTreatment(log: ILogger, key: string, seed: number | undefined
18
18
  /**
19
19
  * Evaluates the traffic allocation to see if we should apply rollout conditions or not.
20
20
  */
21
- export function shouldApplyRollout(trafficAllocation: number, key: string, trafficAllocationSeed: number) {
21
+ export function shouldApplyRollout(trafficAllocation: number, bucketingKey: string, trafficAllocationSeed: number) {
22
22
  // For rollout, if traffic allocation for splits is 100%, we don't need to filter it because everything should evaluate the rollout.
23
23
  if (trafficAllocation < 100) {
24
- const _bucket = bucket(key, trafficAllocationSeed);
24
+ const _bucket = bucket(bucketingKey, trafficAllocationSeed);
25
25
 
26
26
  if (_bucket > trafficAllocation) {
27
27
  return false;
@@ -1,50 +1,32 @@
1
- import { FallbackTreatmentConfiguration, Treatment, TreatmentWithConfig } from '../../../types/splitio';
1
+ import { FallbackTreatmentConfiguration, TreatmentWithConfig } from '../../../types/splitio';
2
2
  import { CONTROL } from '../../utils/constants';
3
3
  import { isString } from '../../utils/lang';
4
4
 
5
- export type IFallbackTreatmentsCalculator = {
6
- resolve(flagName: string, label: string): TreatmentWithConfig & { label: string };
7
- }
5
+ export type IFallbackTreatmentsCalculator = (flagName: string, label?: string) => TreatmentWithConfig & { label: string };
8
6
 
9
7
  export const FALLBACK_PREFIX = 'fallback - ';
10
8
 
11
- export class FallbackTreatmentsCalculator implements IFallbackTreatmentsCalculator {
12
- private readonly fallbacks: FallbackTreatmentConfiguration;
13
-
14
- constructor(fallbacks: FallbackTreatmentConfiguration = {}) {
15
- this.fallbacks = fallbacks;
16
- }
17
-
18
- resolve(flagName: string, label: string): TreatmentWithConfig & { label: string } {
19
- const treatment = this.fallbacks.byFlag?.[flagName];
20
- if (treatment) {
21
- return this.copyWithLabel(treatment, label);
22
- }
23
-
24
- if (this.fallbacks.global) {
25
- return this.copyWithLabel(this.fallbacks.global, label);
26
- }
27
-
28
- return {
29
- treatment: CONTROL,
30
- config: null,
31
- label,
32
- };
33
- }
34
-
35
- private copyWithLabel(fallback: Treatment | TreatmentWithConfig, label: string): TreatmentWithConfig & { label: string } {
36
- if (isString(fallback)) {
37
- return {
38
- treatment: fallback,
9
+ export function FallbackTreatmentsCalculator(fallbacks: FallbackTreatmentConfiguration = {}): IFallbackTreatmentsCalculator {
10
+
11
+ return (flagName: string, label = '') => {
12
+ const fallback = fallbacks.byFlag?.[flagName] || fallbacks.global;
13
+
14
+ return fallback ?
15
+ isString(fallback) ?
16
+ {
17
+ treatment: fallback,
18
+ config: null,
19
+ label: `${FALLBACK_PREFIX}${label}`,
20
+ } :
21
+ {
22
+ treatment: fallback.treatment,
23
+ config: fallback.config,
24
+ label: `${FALLBACK_PREFIX}${label}`,
25
+ } :
26
+ {
27
+ treatment: CONTROL,
39
28
  config: null,
40
- label: `${FALLBACK_PREFIX}${label}`,
29
+ label,
41
30
  };
42
- }
43
-
44
- return {
45
- treatment: fallback.treatment,
46
- config: fallback.config,
47
- label: `${FALLBACK_PREFIX}${label}`,
48
- };
49
- }
31
+ };
50
32
  }
@@ -1,5 +1,5 @@
1
- export function whitelistMatcherContext(ruleAttr: string[]) {
2
- const whitelistSet = new Set(ruleAttr);
1
+ export function whitelistMatcherContext(ruleAttr?: string[] | null) {
2
+ const whitelistSet = new Set(ruleAttr || []);
3
3
 
4
4
  return function whitelistMatcher(runtimeAttr: string): boolean {
5
5
  const isInWhitelist = whitelistSet.has(runtimeAttr);
@@ -13,8 +13,8 @@ export interface IMatcherDto {
13
13
  name: string
14
14
  value?: string | number | boolean | string[] | IDependencyMatcherData | IBetweenMatcherData | IBetweenStringMatcherData | null
15
15
 
16
- attribute: string | null
17
- negate: boolean
16
+ attribute?: string | null
17
+ negate?: boolean
18
18
  dataType: string
19
19
  }
20
20
 
@@ -4,7 +4,7 @@ import { ILogger } from '../../logger/types';
4
4
  import { sanitize } from './sanitize';
5
5
  import { ENGINE_VALUE, ENGINE_VALUE_NO_ATTRIBUTES, ENGINE_VALUE_INVALID } from '../../logger/constants';
6
6
 
7
- function parseValue(log: ILogger, key: SplitIO.SplitKey, attributeName: string | null, attributes?: SplitIO.Attributes) {
7
+ function parseValue(log: ILogger, key: SplitIO.SplitKey, attributeName?: string | null, attributes?: SplitIO.Attributes) {
8
8
  let value = undefined;
9
9
  if (attributeName) {
10
10
  if (attributes) {
@@ -21,7 +21,7 @@ export function pluggableIntegrationsManagerFactory(
21
21
  // No need to check if `settings.integrations` is an array of functions. It was already validated
22
22
  integrations.forEach(integrationFactory => {
23
23
  let integration = integrationFactory(params);
24
- if (integration && integration.queue) listeners.push(integration);
24
+ if (integration) listeners.push(integration);
25
25
  });
26
26
 
27
27
  // If `listeners` is empty, not return a integration manager
@@ -32,7 +32,6 @@ export const ENGINE_DEFAULT = 41;
32
32
 
33
33
  export const CLIENT_READY_FROM_CACHE = 100;
34
34
  export const CLIENT_READY = 101;
35
- export const IMPRESSION = 102;
36
35
  export const IMPRESSION_QUEUEING = 103;
37
36
  export const NEW_SHARED_CLIENT = 104;
38
37
  export const NEW_FACTORY = 105;
@@ -8,8 +8,7 @@ export const codesInfo: [number, string][] = codesWarn.concat([
8
8
  [c.CLIENT_READY_FROM_CACHE, READY_MSG + ' from cache'],
9
9
  [c.CLIENT_READY, READY_MSG],
10
10
  // SDK
11
- [c.IMPRESSION, c.LOG_PREFIX_IMPRESSIONS_TRACKER +'Feature flag: %s. Key: %s. Evaluation: %s. Label: %s'],
12
- [c.IMPRESSION_QUEUEING, c.LOG_PREFIX_IMPRESSIONS_TRACKER +'Queueing corresponding impression.'],
11
+ [c.IMPRESSION_QUEUEING, c.LOG_PREFIX_IMPRESSIONS_TRACKER +'Queueing impression. Feature flag: %s. Key: %s. Evaluation: %s. Label: %s'],
13
12
  [c.NEW_SHARED_CLIENT, 'New shared client instance created.'],
14
13
  [c.NEW_FACTORY, 'New Split SDK instance created. %s'],
15
14
  [c.EVENTS_TRACKER_SUCCESS, c.LOG_PREFIX_EVENTS_TRACKER + 'Successfully queued %s'],
@@ -21,9 +21,9 @@ export const codesWarn: [number, string][] = codesError.concat([
21
21
  [c.WARN_TRIMMING_PROPERTIES, '%s: more than 300 properties were provided. Some of them will be trimmed when processed.'],
22
22
  [c.WARN_CONVERTING, '%s: %s "%s" is not of type string, converting.'],
23
23
  [c.WARN_TRIMMING, '%s: %s "%s" has extra whitespace, trimming.'],
24
- [c.WARN_NOT_EXISTENT_SPLIT, '%s: feature flag "%s" does not exist in this environment. Please double check what feature flags exist in the Split user interface.'],
24
+ [c.WARN_NOT_EXISTENT_SPLIT, '%s: feature flag "%s" does not exist in this environment. Please double check what feature flags exist in Harness FME UI.'],
25
25
  [c.WARN_LOWERCASE_TRAFFIC_TYPE, '%s: traffic_type_name should be all lowercase - converting string to lowercase.'],
26
- [c.WARN_NOT_EXISTENT_TT, '%s: traffic type "%s" does not have any corresponding feature flag in this environment, make sure you\'re tracking your events to a valid traffic type defined in the Split user interface.'],
26
+ [c.WARN_NOT_EXISTENT_TT, '%s: traffic type "%s" does not have any corresponding feature flag in this environment, make sure you\'re tracking your events to a valid traffic type defined in Harness FME UI.'],
27
27
  [c.WARN_FLAGSET_NOT_CONFIGURED, '%s: you passed %s which is not part of the configured FlagSetsFilter, ignoring Flag Set.'],
28
28
  // initialization / settings validation
29
29
  [c.WARN_INTEGRATION_INVALID, c.LOG_PREFIX_SETTINGS + ': %s integration item(s) at settings is invalid. %s'],
@@ -36,5 +36,5 @@ export const codesWarn: [number, string][] = codesError.concat([
36
36
  [c.STREAMING_PARSING_SPLIT_UPDATE, c.LOG_PREFIX_SYNC_STREAMING + 'Fetching SplitChanges due to an error processing %s notification: %s'],
37
37
  [c.WARN_INVALID_FLAGSET, '%s: you passed %s, flag set must adhere to the regular expressions %s. This means a flag set must start with a letter or number, be in lowercase, alphanumeric and have a max length of 50 characters. %s was discarded.'],
38
38
  [c.WARN_LOWERCASE_FLAGSET, '%s: flag set %s should be all lowercase - converting string to lowercase.'],
39
- [c.WARN_FLAGSET_WITHOUT_FLAGS, '%s: you passed %s flag set that does not contain cached feature flag names. Please double check what flag sets are in use in the Split user interface.'],
39
+ [c.WARN_FLAGSET_WITHOUT_FLAGS, '%s: you passed %s flag set that does not contain cached feature flag names. Please double check what flag sets are in use in Harness FME UI.'],
40
40
  ]);
@@ -7,7 +7,7 @@ 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, GET_TREATMENTS_WITH_CONFIG, GET_TREATMENTS_BY_FLAG_SETS, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS, GET_TREATMENTS_BY_FLAG_SET, GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET, GET_TREATMENT_WITH_CONFIG, GET_TREATMENT, GET_TREATMENTS, TRACK_FN_LABEL } from '../utils/constants';
8
8
  import { IEvaluationResult } from '../evaluator/types';
9
9
  import SplitIO from '../../types/splitio';
10
- import { IMPRESSION, IMPRESSION_QUEUEING } from '../logger/constants';
10
+ import { IMPRESSION_QUEUEING } from '../logger/constants';
11
11
  import { ISdkFactoryContext } from '../sdkFactory/types';
12
12
  import { isConsumerMode } from '../utils/settingsValidation/mode';
13
13
  import { Method } from '../sync/submitters/types';
@@ -147,16 +147,14 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
147
147
  let { treatment, label, config = null } = evaluation;
148
148
 
149
149
  if (treatment === CONTROL) {
150
- const fallbackTreatment = fallbackTreatmentsCalculator.resolve(featureFlagName, label);
150
+ const fallbackTreatment = fallbackTreatmentsCalculator(featureFlagName, label);
151
151
  treatment = fallbackTreatment.treatment;
152
152
  label = fallbackTreatment.label;
153
153
  config = fallbackTreatment.config;
154
154
  }
155
155
 
156
- log.info(IMPRESSION, [featureFlagName, matchingKey, treatment, label]);
157
-
158
156
  if (validateSplitExistence(log, readinessManager, featureFlagName, label, invokingMethodName)) {
159
- log.info(IMPRESSION_QUEUEING);
157
+ log.info(IMPRESSION_QUEUEING, [featureFlagName, matchingKey, treatment, label]);
160
158
  queue.push({
161
159
  imp: {
162
160
  feature: featureFlagName,