@splitsoftware/splitio-commons 3.1.1-rc.10 → 3.1.1-rc.11

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 (208) hide show
  1. package/CHANGES.txt +2 -0
  2. package/cjs/evaluator/condition/index.js +2 -2
  3. package/cjs/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +5 -8
  4. package/cjs/evaluator/index.js +81 -71
  5. package/cjs/listeners/browser.js +2 -1
  6. package/cjs/listeners/node.js +4 -4
  7. package/cjs/logger/constants.js +15 -20
  8. package/cjs/logger/messages/debug.js +5 -6
  9. package/cjs/logger/messages/error.js +3 -3
  10. package/cjs/logger/messages/info.js +3 -4
  11. package/cjs/logger/messages/warn.js +6 -7
  12. package/cjs/platform/browser.js +15 -0
  13. package/cjs/platform/getEventSource/browser.js +8 -0
  14. package/cjs/platform/getEventSource/eventsource.js +480 -0
  15. package/cjs/platform/getEventSource/node.js +26 -0
  16. package/cjs/platform/getFetch/browser.js +9 -0
  17. package/cjs/platform/getFetch/node.js +27 -0
  18. package/cjs/platform/getOptions/node.js +25 -0
  19. package/cjs/platform/node.js +17 -0
  20. package/cjs/presets/serverSide.js +2 -2
  21. package/cjs/readiness/constants.js +5 -4
  22. package/cjs/readiness/readinessManager.js +23 -23
  23. package/cjs/readiness/sdkReadinessManager.js +1 -17
  24. package/cjs/sdkClient/client.js +24 -50
  25. package/cjs/sdkClient/clientInputValidation.js +6 -17
  26. package/cjs/sdkClient/sdkClient.js +3 -60
  27. package/cjs/sdkClient/sdkLifecycle.js +74 -0
  28. package/cjs/sdkClient/trackMethod.js +56 -0
  29. package/cjs/sdkFactory/index.js +11 -15
  30. package/cjs/sdkManager/index.js +5 -5
  31. package/cjs/services/authProvider.js +80 -0
  32. package/cjs/services/decorateHeaders.js +2 -1
  33. package/cjs/services/secureSplitHttpClient.js +36 -0
  34. package/cjs/services/serviceApi.js +147 -0
  35. package/cjs/services/splitApi.js +24 -10
  36. package/cjs/services/splitHttpClient.js +3 -5
  37. package/cjs/storages/AbstractDefinitionsCacheAsync.js +51 -0
  38. package/cjs/storages/AbstractDefinitionsCacheSync.js +76 -0
  39. package/cjs/storages/KeyBuilder.js +6 -6
  40. package/cjs/storages/KeyBuilderCS.js +5 -5
  41. package/cjs/storages/KeyBuilderSS.js +2 -2
  42. package/cjs/storages/getRolloutPlan.js +3 -3
  43. package/cjs/storages/inLocalStorage/DefinitionsCacheInLocal.js +194 -0
  44. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -2
  45. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +10 -10
  46. package/cjs/storages/inLocalStorage/index.js +6 -6
  47. package/cjs/storages/inLocalStorage/validateCache.js +3 -3
  48. package/cjs/storages/inMemory/DefinitionsCacheInMemory.js +121 -0
  49. package/cjs/storages/inMemory/InMemoryStorage.js +4 -4
  50. package/cjs/storages/inMemory/InMemoryStorageCS.js +5 -5
  51. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +5 -5
  52. package/cjs/storages/inMemory/SegmentsCacheInMemory.js +1 -1
  53. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +5 -5
  54. package/cjs/storages/inRedis/{SplitsCacheInRedis.js → DefinitionsCacheInRedis.js} +77 -77
  55. package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +1 -1
  56. package/cjs/storages/inRedis/index.js +2 -2
  57. package/cjs/storages/pluggable/DefinitionsCachePluggable.js +212 -0
  58. package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +1 -1
  59. package/cjs/storages/pluggable/index.js +2 -2
  60. package/cjs/storages/setRolloutPlan.js +4 -4
  61. package/cjs/storages/utils.js +1 -0
  62. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +5 -5
  63. package/cjs/sync/polling/fetchers/splitChangesFetcher.js +24 -15
  64. package/cjs/sync/polling/pollingManagerCS.js +86 -81
  65. package/cjs/sync/polling/pollingManagerSS.js +44 -36
  66. package/cjs/sync/polling/syncTasks/definitionsSyncTask.js +13 -0
  67. package/cjs/sync/polling/syncTasks/segmentsSyncTask.js +2 -3
  68. package/cjs/sync/polling/updaters/{splitChangesUpdater.js → definitionChangesUpdater.js} +66 -69
  69. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +3 -3
  70. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +6 -6
  71. package/cjs/sync/streaming/AuthClient/index.js +13 -14
  72. package/cjs/sync/streaming/SSEHandler/NotificationKeeper.js +1 -1
  73. package/cjs/sync/streaming/SSEHandler/index.js +2 -1
  74. package/cjs/sync/streaming/UpdateWorkers/{SplitsUpdateWorker.js → DefinitionsUpdateWorker.js} +16 -19
  75. package/cjs/sync/streaming/constants.js +4 -3
  76. package/cjs/sync/streaming/parseUtils.js +11 -11
  77. package/cjs/sync/streaming/pushManager.js +20 -25
  78. package/cjs/sync/submitters/eventsSubmitter.js +1 -1
  79. package/cjs/sync/submitters/impressionCountsSubmitter.js +1 -1
  80. package/cjs/sync/submitters/impressionsSubmitter.js +5 -4
  81. package/cjs/sync/submitters/telemetrySubmitter.js +3 -4
  82. package/cjs/sync/submitters/uniqueKeysSubmitter.js +1 -1
  83. package/cjs/sync/syncManagerOnline.js +5 -5
  84. package/cjs/utils/Backoff.js +35 -3
  85. package/cjs/utils/EventEmitter.js +391 -0
  86. package/cjs/utils/filter/bloomFilter.js +37 -0
  87. package/cjs/utils/inputValidation/{split.js → definition.js} +10 -10
  88. package/cjs/utils/inputValidation/{splitExistence.js → definitionExistence.js} +6 -6
  89. package/cjs/utils/inputValidation/definitions.js +25 -0
  90. package/cjs/utils/inputValidation/index.js +7 -7
  91. package/cjs/utils/inputValidation/isOperational.js +4 -4
  92. package/cjs/utils/inputValidation/target.js +22 -0
  93. package/cjs/utils/labels/index.js +3 -3
  94. package/cjs/utils/settingsValidation/index.js +2 -0
  95. package/cjs/utils/settingsValidation/splitFilters.js +3 -3
  96. package/cjs/utils/settingsValidation/url.js +6 -2
  97. package/esm/evaluator/condition/index.js +2 -2
  98. package/esm/evaluator/fallbackTreatmentsCalculator/fallbackSanitizer/index.js +5 -8
  99. package/esm/evaluator/index.js +80 -71
  100. package/esm/listeners/browser.js +2 -1
  101. package/esm/listeners/node.js +4 -4
  102. package/esm/logger/constants.js +12 -17
  103. package/esm/logger/messages/debug.js +5 -6
  104. package/esm/logger/messages/error.js +3 -3
  105. package/esm/logger/messages/info.js +3 -4
  106. package/esm/logger/messages/warn.js +6 -7
  107. package/esm/platform/browser.js +12 -0
  108. package/esm/platform/getEventSource/browser.js +4 -0
  109. package/esm/platform/getEventSource/eventsource.js +480 -0
  110. package/esm/platform/getEventSource/node.js +20 -0
  111. package/esm/platform/getFetch/browser.js +5 -0
  112. package/esm/platform/getFetch/node.js +22 -0
  113. package/esm/platform/getOptions/node.js +20 -0
  114. package/esm/platform/node.js +14 -0
  115. package/esm/presets/serverSide.js +2 -2
  116. package/esm/readiness/constants.js +4 -3
  117. package/esm/readiness/readinessManager.js +24 -24
  118. package/esm/readiness/sdkReadinessManager.js +2 -18
  119. package/esm/sdkClient/client.js +23 -50
  120. package/esm/sdkClient/clientInputValidation.js +8 -19
  121. package/esm/sdkClient/sdkClient.js +3 -60
  122. package/esm/sdkClient/sdkLifecycle.js +70 -0
  123. package/esm/sdkClient/trackMethod.js +52 -0
  124. package/esm/sdkFactory/index.js +12 -16
  125. package/esm/sdkManager/index.js +6 -6
  126. package/esm/services/authProvider.js +76 -0
  127. package/esm/services/decorateHeaders.js +2 -1
  128. package/esm/services/secureSplitHttpClient.js +32 -0
  129. package/esm/services/serviceApi.js +143 -0
  130. package/esm/services/splitApi.js +24 -10
  131. package/esm/services/splitHttpClient.js +3 -5
  132. package/esm/storages/AbstractDefinitionsCacheAsync.js +48 -0
  133. package/esm/storages/AbstractDefinitionsCacheSync.js +71 -0
  134. package/esm/storages/KeyBuilder.js +6 -6
  135. package/esm/storages/KeyBuilderCS.js +5 -5
  136. package/esm/storages/KeyBuilderSS.js +2 -2
  137. package/esm/storages/getRolloutPlan.js +3 -3
  138. package/esm/storages/inLocalStorage/DefinitionsCacheInLocal.js +191 -0
  139. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -2
  140. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +7 -7
  141. package/esm/storages/inLocalStorage/index.js +6 -6
  142. package/esm/storages/inLocalStorage/validateCache.js +3 -3
  143. package/esm/storages/inMemory/DefinitionsCacheInMemory.js +118 -0
  144. package/esm/storages/inMemory/InMemoryStorage.js +4 -4
  145. package/esm/storages/inMemory/InMemoryStorageCS.js +5 -5
  146. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +2 -2
  147. package/esm/storages/inMemory/SegmentsCacheInMemory.js +1 -1
  148. package/esm/storages/inMemory/TelemetryCacheInMemory.js +5 -5
  149. package/esm/storages/inRedis/{SplitsCacheInRedis.js → DefinitionsCacheInRedis.js} +76 -76
  150. package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +1 -1
  151. package/esm/storages/inRedis/index.js +2 -2
  152. package/esm/storages/pluggable/DefinitionsCachePluggable.js +209 -0
  153. package/esm/storages/pluggable/RBSegmentsCachePluggable.js +1 -1
  154. package/esm/storages/pluggable/index.js +2 -2
  155. package/esm/storages/setRolloutPlan.js +4 -4
  156. package/esm/storages/utils.js +1 -0
  157. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +6 -6
  158. package/esm/sync/polling/fetchers/splitChangesFetcher.js +25 -16
  159. package/esm/sync/polling/pollingManagerCS.js +87 -82
  160. package/esm/sync/polling/pollingManagerSS.js +44 -36
  161. package/esm/sync/polling/syncTasks/definitionsSyncTask.js +9 -0
  162. package/esm/sync/polling/syncTasks/segmentsSyncTask.js +2 -3
  163. package/esm/sync/polling/updaters/definitionChangesUpdater.js +191 -0
  164. package/esm/sync/polling/updaters/mySegmentsUpdater.js +3 -3
  165. package/esm/sync/polling/updaters/segmentChangesUpdater.js +7 -7
  166. package/esm/sync/streaming/AuthClient/index.js +11 -11
  167. package/esm/sync/streaming/SSEHandler/NotificationKeeper.js +2 -2
  168. package/esm/sync/streaming/SSEHandler/index.js +3 -2
  169. package/esm/sync/streaming/UpdateWorkers/{SplitsUpdateWorker.js → DefinitionsUpdateWorker.js} +15 -18
  170. package/esm/sync/streaming/constants.js +3 -2
  171. package/esm/sync/streaming/parseUtils.js +9 -9
  172. package/esm/sync/streaming/pushManager.js +22 -27
  173. package/esm/sync/submitters/eventsSubmitter.js +1 -1
  174. package/esm/sync/submitters/impressionCountsSubmitter.js +1 -1
  175. package/esm/sync/submitters/impressionsSubmitter.js +5 -4
  176. package/esm/sync/submitters/telemetrySubmitter.js +3 -4
  177. package/esm/sync/submitters/uniqueKeysSubmitter.js +1 -1
  178. package/esm/sync/syncManagerOnline.js +4 -4
  179. package/esm/utils/Backoff.js +35 -3
  180. package/esm/utils/EventEmitter.js +387 -0
  181. package/esm/utils/filter/bloomFilter.js +33 -0
  182. package/esm/utils/inputValidation/{split.js → definition.js} +8 -8
  183. package/esm/utils/inputValidation/definitionExistence.js +15 -0
  184. package/esm/utils/inputValidation/definitions.js +21 -0
  185. package/esm/utils/inputValidation/index.js +3 -3
  186. package/esm/utils/inputValidation/isOperational.js +4 -4
  187. package/esm/utils/inputValidation/target.js +18 -0
  188. package/esm/utils/labels/index.js +2 -2
  189. package/esm/utils/settingsValidation/index.js +2 -0
  190. package/esm/utils/settingsValidation/splitFilters.js +3 -3
  191. package/esm/utils/settingsValidation/url.js +6 -2
  192. package/package.json +1 -1
  193. package/cjs/storages/AbstractSplitsCacheAsync.js +0 -51
  194. package/cjs/storages/AbstractSplitsCacheSync.js +0 -76
  195. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +0 -194
  196. package/cjs/storages/inMemory/SplitsCacheInMemory.js +0 -121
  197. package/cjs/storages/pluggable/SplitsCachePluggable.js +0 -212
  198. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +0 -13
  199. package/cjs/utils/inputValidation/splits.js +0 -25
  200. package/esm/storages/AbstractSplitsCacheAsync.js +0 -48
  201. package/esm/storages/AbstractSplitsCacheSync.js +0 -71
  202. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +0 -191
  203. package/esm/storages/inMemory/SplitsCacheInMemory.js +0 -118
  204. package/esm/storages/pluggable/SplitsCachePluggable.js +0 -209
  205. package/esm/sync/polling/syncTasks/splitsSyncTask.js +0 -9
  206. package/esm/sync/polling/updaters/splitChangesUpdater.js +0 -194
  207. package/esm/utils/inputValidation/splitExistence.js +0 -15
  208. package/esm/utils/inputValidation/splits.js +0 -21
@@ -16,7 +16,7 @@ var fallbackTreatmentsCalculator_1 = require("../evaluator/fallbackTreatmentsCal
16
16
  * Modular SDK factory
17
17
  */
18
18
  function sdkFactory(params) {
19
- var settings = params.settings, platform = params.platform, storageFactory = params.storageFactory, splitApiFactory = params.splitApiFactory, extraProps = params.extraProps, syncManagerFactory = params.syncManagerFactory, SignalListener = params.SignalListener, integrationsManagerFactory = params.integrationsManagerFactory, sdkManagerFactory = params.sdkManagerFactory, sdkClientMethodFactory = params.sdkClientMethodFactory, lazyInit = params.lazyInit;
19
+ var settings = params.settings, platform = params.platform, storageFactory = params.storageFactory, serviceApiFactory = params.serviceApiFactory, extraProps = params.extraProps, syncManagerFactory = params.syncManagerFactory, integrationsManagerFactory = params.integrationsManagerFactory, sdkManagerFactory = params.sdkManagerFactory, sdkClientMethodFactory = params.sdkClientMethodFactory, lazyInit = params.lazyInit;
20
20
  var log = settings.log, initialRolloutPlan = settings.initialRolloutPlan, key = settings.core.key;
21
21
  // @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid SDK Key, etc.
22
22
  // On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
@@ -30,35 +30,31 @@ function sdkFactory(params) {
30
30
  readiness.timeout();
31
31
  return;
32
32
  }
33
- readiness.splits.emit(constants_2.SDK_SPLITS_ARRIVED);
33
+ readiness.definitions.emit(constants_2.SDK_DEFINITIONS_ARRIVED);
34
34
  readiness.segments.emit(constants_2.SDK_SEGMENTS_ARRIVED);
35
35
  },
36
36
  onReadyFromCacheCb: function () {
37
- readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED);
37
+ readiness.definitions.emit(constants_2.SDK_DEFINITIONS_CACHE_LOADED);
38
38
  }
39
39
  });
40
- var fallbackTreatmentsCalculator = (0, fallbackTreatmentsCalculator_1.FallbackTreatmentsCalculator)(settings.fallbackTreatments);
40
+ var fallbackCalculator = (0, fallbackTreatmentsCalculator_1.FallbackTreatmentsCalculator)(settings.fallbackTreatments);
41
41
  if (initialRolloutPlan) {
42
42
  (0, setRolloutPlan_1.setRolloutPlan)(log, initialRolloutPlan, storage, key && (0, key_1.getMatching)(key));
43
- if (storage.splits.getChangeNumber() > -1)
44
- readiness.splits.emit(constants_2.SDK_SPLITS_CACHE_LOADED, { initialCacheLoad: false /* Not an initial load, cache exists */ });
43
+ if (storage.definitions.getChangeNumber() > -1)
44
+ readiness.definitions.emit(constants_2.SDK_DEFINITIONS_CACHE_LOADED, { initialCacheLoad: false /* Not an initial load, cache exists */ });
45
45
  }
46
46
  var clients = {};
47
47
  var telemetryTracker = (0, telemetryTracker_1.telemetryTrackerFactory)(storage.telemetry, platform.now);
48
48
  var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage, telemetryTracker: telemetryTracker });
49
49
  var impressionsTracker = (0, impressionsTracker_1.impressionsTrackerFactory)(params, storage, integrationsManager);
50
50
  var eventTracker = (0, eventTracker_1.eventTrackerFactory)(settings, storage.events, integrationsManager, storage.telemetry);
51
- // splitApi is used by SyncManager and Browser signal listener
52
- var splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
53
- var ctx = { clients: clients, splitApi: splitApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform, fallbackTreatmentsCalculator: fallbackTreatmentsCalculator };
54
- var syncManager = syncManagerFactory && syncManagerFactory(ctx);
55
- ctx.syncManager = syncManager;
56
- // @TODO: move into platform, and call inside sdkClientFactory (if it's used only there)
57
- var signalListener = SignalListener && new SignalListener(syncManager, settings, storage, splitApi);
58
- ctx.signalListener = signalListener;
51
+ // serviceApi is used by SyncManager and Browser signal listener
52
+ var serviceApi = serviceApiFactory && serviceApiFactory(settings, platform, telemetryTracker);
53
+ var ctx = { clients: clients, serviceApi: serviceApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform, fallbackCalculator: fallbackCalculator };
54
+ ctx.syncManager = syncManagerFactory && syncManagerFactory(ctx);
59
55
  // SDK client and manager
60
56
  var clientMethod = sdkClientMethodFactory(ctx);
61
- var managerInstance = sdkManagerFactory(settings, storage.splits, sdkReadinessManager);
57
+ var managerInstance = sdkManagerFactory(settings, storage.definitions, sdkReadinessManager);
62
58
  function init() {
63
59
  Object.keys(clients).map(function (key) { return clients[key].init(); });
64
60
  }
@@ -53,18 +53,18 @@ function sdkManagerFactory(settings, splits, _a) {
53
53
  * Get the feature flag object corresponding to the given feature flag name if valid
54
54
  */
55
55
  split: function (featureFlagName) {
56
- var splitName = (0, inputValidation_1.validateSplit)(log, featureFlagName, constants_1.SPLIT_FN_LABEL);
56
+ var splitName = (0, inputValidation_1.validateDefinition)(log, featureFlagName, constants_1.SPLIT_FN_LABEL);
57
57
  if (!(0, inputValidation_1.validateIfOperational)(log, readinessManager, constants_1.SPLIT_FN_LABEL) || !splitName) {
58
58
  return isAsync ? Promise.resolve(null) : null;
59
59
  }
60
- var split = splits.getSplit(splitName);
60
+ var split = splits.get(splitName);
61
61
  if ((0, thenable_1.thenable)(split)) {
62
62
  return split.catch(function () { return null; }).then(function (result) {
63
- (0, inputValidation_1.validateSplitExistence)(log, readinessManager, splitName, result, constants_1.SPLIT_FN_LABEL);
63
+ (0, inputValidation_1.validateDefinitionExistence)(log, readinessManager, splitName, result, constants_1.SPLIT_FN_LABEL);
64
64
  return objectToView(result);
65
65
  });
66
66
  }
67
- (0, inputValidation_1.validateSplitExistence)(log, readinessManager, splitName, split, constants_1.SPLIT_FN_LABEL);
67
+ (0, inputValidation_1.validateDefinitionExistence)(log, readinessManager, splitName, split, constants_1.SPLIT_FN_LABEL);
68
68
  return objectToView(split);
69
69
  },
70
70
  /**
@@ -86,7 +86,7 @@ function sdkManagerFactory(settings, splits, _a) {
86
86
  if (!(0, inputValidation_1.validateIfOperational)(log, readinessManager, constants_1.NAMES_FN_LABEL)) {
87
87
  return isAsync ? Promise.resolve([]) : [];
88
88
  }
89
- var splitNames = splits.getSplitNames();
89
+ var splitNames = splits.getNames();
90
90
  return (0, thenable_1.thenable)(splitNames) ?
91
91
  splitNames.catch(function () { return []; }) : // handle possible rejections when using pluggable storage
92
92
  splitNames;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authProviderFactory = void 0;
4
+ var AuthClient_1 = require("../sync/streaming/AuthClient");
5
+ var Backoff_1 = require("../utils/Backoff");
6
+ var constants_1 = require("../logger/constants");
7
+ var constants_2 = require("../utils/constants");
8
+ var SKEW_SECONDS = 30;
9
+ function isExpired(credential) {
10
+ return Date.now() / 1000 + SKEW_SECONDS >= credential.decodedToken.exp;
11
+ }
12
+ function noCachedCredentialError() {
13
+ return new Error(constants_1.LOG_PREFIX_SYNC_AUTH + 'stopped without a cached credential');
14
+ }
15
+ /**
16
+ * Factory of AuthProvider, which provides JWT credentials for authenticated HTTP requests.
17
+ * Credentials are fetched lazily on demand, cached in memory, and retried with backoff on failure.
18
+ */
19
+ function authProviderFactory(settings, splitHttpClient, telemetryTracker) {
20
+ var urls = settings.urls, log = settings.log;
21
+ var fetchAuth = (0, AuthClient_1.fetchAuthFactory)(function () {
22
+ var url = "".concat(urls.auth, "/api/v3/auth?capabilities=config,aiconfig");
23
+ return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_2.TOKEN), false, true);
24
+ });
25
+ var backoff = new Backoff_1.Backoff(fetchCredential);
26
+ var cachedCredential;
27
+ var inFlightPromise;
28
+ var stopped = false;
29
+ function fetchCredential() {
30
+ return fetchAuth().then(function (credential) {
31
+ log.info(constants_1.LOG_PREFIX_SYNC_AUTH + 'credential fetched successfully');
32
+ cachedCredential = credential;
33
+ inFlightPromise = undefined;
34
+ backoff.reset();
35
+ return credential;
36
+ }).catch(function (error) {
37
+ // Avoid unnecessary retries after stop(): fall back to any cached credential, or reject
38
+ // (never resolve with `undefined`, which callers would otherwise send as an unauthenticated request).
39
+ if (stopped)
40
+ return cachedCredential || Promise.reject(noCachedCredentialError());
41
+ if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500) {
42
+ log.error(constants_1.LOG_PREFIX_SYNC_AUTH + 'non-retryable error fetching credential (status ' + error.statusCode + '): ' + error.message);
43
+ inFlightPromise = undefined;
44
+ throw error;
45
+ }
46
+ log.warn(constants_1.LOG_PREFIX_SYNC_AUTH + 'credential fetch failed (attempt ' + (backoff.attempts + 1) + '). Error: ' + error.message);
47
+ return backoff.scheduleCallAsync();
48
+ });
49
+ }
50
+ return {
51
+ credential: function () {
52
+ if (cachedCredential && !isExpired(cachedCredential)) {
53
+ return Promise.resolve(cachedCredential);
54
+ }
55
+ // Reuse any fetch already in flight (e.g. one started just before stop()), instead of firing a redundant one.
56
+ if (inFlightPromise)
57
+ return inFlightPromise;
58
+ // No cached credential to fall back to and stopped: reject so callers don't send an unauthenticated request.
59
+ if (stopped && !cachedCredential) {
60
+ return Promise.reject(noCachedCredentialError());
61
+ }
62
+ if (cachedCredential)
63
+ log.debug(constants_1.LOG_PREFIX_SYNC_AUTH + 'cached credential expired');
64
+ // If stopped, this is a last, bounded refetch: fetchCredential()'s catch short-circuits (no backoff retry)
65
+ // once stopped, so it's a single attempt that falls back to the stale cached credential on failure.
66
+ return inFlightPromise = fetchCredential();
67
+ },
68
+ invalidate: function () {
69
+ cachedCredential = undefined;
70
+ },
71
+ stop: function () {
72
+ stopped = true;
73
+ // Keep any in-flight fetch and already-cached credential usable (e.g. by a final flush on destroy).
74
+ // If a retry is only pending (not actively in flight), settle it immediately instead of waiting out the
75
+ // backoff delay: with the cached credential if there is one, or rejected otherwise.
76
+ backoff.reset(cachedCredential ? { value: cachedCredential } : { error: noCachedCredentialError() });
77
+ }
78
+ };
79
+ }
80
+ exports.authProviderFactory = authProviderFactory;
@@ -15,7 +15,8 @@ var FORBIDDEN_HEADERS = new Set([
15
15
  'content-encoding',
16
16
  'accept',
17
17
  'keep-alive',
18
- 'x-fastly-debug'
18
+ 'x-fastly-debug',
19
+ 'x-harness-fme-sdk-version'
19
20
  ]);
20
21
  function decorateHeaders(settings, headers) {
21
22
  var _a;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.secureSplitHttpClientFactory = void 0;
4
+ var tslib_1 = require("tslib");
5
+ /**
6
+ * Factory of Secure HTTP client, which authenticates requests using a JWT token.
7
+ * On 401 responses, invalidates the cached credential and retries once with a fresh token.
8
+ *
9
+ * @param splitHttpClient - `splitHttpClientFactory` to use for making requests
10
+ * @param authProvider - `authProviderFactory` to use for authentication
11
+ */
12
+ function secureSplitHttpClientFactory(splitHttpClient, authProvider) {
13
+ function makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, token) {
14
+ return splitHttpClient(url, token ? tslib_1.__assign(tslib_1.__assign({}, options), { headers: tslib_1.__assign(tslib_1.__assign({}, options === null || options === void 0 ? void 0 : options.headers), { Authorization: "Bearer ".concat(token) }) }) : options, latencyTracker, logErrorsAsInfo, newVersionHeader);
15
+ }
16
+ var httpClient = function (url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt) {
17
+ if (newVersionHeader === void 0) { newVersionHeader = true; }
18
+ if (useJwt === void 0) { useJwt = true; }
19
+ return authProvider.credential().then(function (credential) {
20
+ return makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt ? credential.token : undefined)
21
+ .catch(function (error) {
22
+ if (error.statusCode === 401) {
23
+ // retry once for 401, in case the token has just expired
24
+ authProvider.invalidate();
25
+ return authProvider.credential().then(function (newCredential) {
26
+ return makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt ? newCredential.token : undefined);
27
+ });
28
+ }
29
+ throw error;
30
+ });
31
+ });
32
+ };
33
+ httpClient.stop = function () { return authProvider.stop(); };
34
+ return httpClient;
35
+ }
36
+ exports.secureSplitHttpClientFactory = secureSplitHttpClientFactory;
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serviceApiFactory = void 0;
4
+ var splitHttpClient_1 = require("./splitHttpClient");
5
+ var objectAssign_1 = require("../utils/lang/objectAssign");
6
+ var constants_1 = require("../utils/constants");
7
+ var constants_2 = require("../logger/constants");
8
+ var authProvider_1 = require("./authProvider");
9
+ var secureSplitHttpClient_1 = require("./secureSplitHttpClient");
10
+ var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
11
+ /**
12
+ * Factory of ServiceApi objects, which group the collection of HTTP endpoints used by the SDKs
13
+ *
14
+ * @param settings - validated settings object
15
+ * @param platform - object containing environment-specific dependencies
16
+ * @param telemetryTracker - telemetry tracker
17
+ */
18
+ function serviceApiFactory(settings, platform, telemetryTracker) {
19
+ var urls = settings.urls;
20
+ var filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
21
+ var SplitSDKImpressionsMode = settings.sync.impressionsMode;
22
+ var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform);
23
+ // Shared authProvider so that the SSE authentication (via `fetchAuth`,
24
+ // used by `pushManager`) and every authenticated HTTP request to the Configs
25
+ // API reuse the same cached credential instead of each fetching their own.
26
+ var authProvider = (0, authProvider_1.authProviderFactory)(settings, splitHttpClient, telemetryTracker);
27
+ var secureSplitHttpClient = (0, secureSplitHttpClient_1.secureSplitHttpClientFactory)(splitHttpClient, authProvider);
28
+ var initialAuth = true;
29
+ return {
30
+ fetchAuth: function () {
31
+ // Guard condition to avoid invalidating the cached credential on the first pushManager authentication
32
+ if (initialAuth)
33
+ initialAuth = false;
34
+ else
35
+ authProvider.invalidate();
36
+ return authProvider.credential();
37
+ },
38
+ // @TODO throw errors if health check requests fail, to log them in the Synchronizer
39
+ getSdkAPIHealthCheck: function () {
40
+ var url = "".concat(urls.sdk, "/api/version");
41
+ return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
42
+ },
43
+ getEventsAPIHealthCheck: function () {
44
+ var url = "".concat(urls.events, "/api/version");
45
+ return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
46
+ },
47
+ fetchSplitChanges: function (since, noCache, till, rbSince) {
48
+ var url = "".concat(urls.sdk, "/api/splitChanges?s=").concat(settings.sync.flagSpecVersion, "&since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
49
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SPLITS))
50
+ .catch(function (err) {
51
+ if (err.statusCode === 414)
52
+ settings.log.error(constants_2.ERROR_TOO_MANY_SETS);
53
+ throw err;
54
+ });
55
+ },
56
+ fetchSegmentChanges: function (since, segmentName, noCache, till) {
57
+ var url = "".concat(urls.sdk, "/api/segmentChanges/").concat(segmentName, "?since=").concat(since).concat(till ? '&till=' + till : '');
58
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SEGMENT));
59
+ },
60
+ // @TODO support filterQueryString and handle ERROR_TOO_MANY_SETS error
61
+ fetchConfigs: function (since, noCache, till, rbSince) {
62
+ var url = "".concat(urls.configs, "/api/v1/configs?since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
63
+ return secureSplitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
64
+ },
65
+ fetchConfigsSegmentChanges: function (since, segmentName, noCache, till) {
66
+ var url = "".concat(urls.configs, "/api/v1/segmentChanges/").concat(segmentName, "?since=").concat(since).concat(till ? '&till=' + till : '');
67
+ return secureSplitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
68
+ },
69
+ fetchMemberships: function (userMatchingKey, noCache, till) {
70
+ /**
71
+ * URI encoding of user keys in order to:
72
+ * - avoid 400 responses (due to URI malformed). E.g.: '/api/memberships/%'
73
+ * - avoid 404 responses. E.g.: '/api/memberships/foo/bar'
74
+ * - match user keys with special characters. E.g.: 'foo%bar', 'foo/bar'
75
+ */
76
+ var url = "".concat(urls.sdk, "/api/memberships/").concat(encodeURIComponent(userMatchingKey)).concat(till ? '?till=' + till : '');
77
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.MEMBERSHIPS));
78
+ },
79
+ /**
80
+ * Post events.
81
+ *
82
+ * @param body - Events bulk payload
83
+ * @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
84
+ */
85
+ postEventsBulk: function (body, headers) {
86
+ var url = "".concat(urls.events, "/api/events/bulk");
87
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.EVENTS), false, false, false);
88
+ },
89
+ /**
90
+ * Post impressions.
91
+ *
92
+ * @param body - Impressions bulk payload
93
+ * @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
94
+ */
95
+ postTestImpressionsBulk: function (body, headers) {
96
+ var url = "".concat(urls.events, "/api/testImpressions/bulk");
97
+ return secureSplitHttpClient(url, {
98
+ // Adding extra headers to send impressions in OPTIMIZED or DEBUG modes.
99
+ method: 'POST',
100
+ body: body,
101
+ headers: (0, objectAssign_1.objectAssign)({ SplitSDKImpressionsMode: SplitSDKImpressionsMode }, headers)
102
+ }, telemetryTracker.trackHttp(constants_1.IMPRESSIONS), false, false, false);
103
+ },
104
+ /**
105
+ * Post impressions counts.
106
+ *
107
+ * @param body - Impressions counts payload
108
+ * @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
109
+ */
110
+ postTestImpressionsCount: function (body, headers) {
111
+ var url = "".concat(urls.events, "/api/testImpressions/count");
112
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.IMPRESSIONS_COUNT), false, false, false);
113
+ },
114
+ /**
115
+ * Post unique keys for client side.
116
+ *
117
+ * @param body - unique keys payload
118
+ * @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
119
+ */
120
+ postUniqueKeysBulkCs: function (body, headers) {
121
+ var url = "".concat(urls.telemetry, "/api/v1/keys/cs");
122
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), false, false, false);
123
+ },
124
+ /**
125
+ * Post unique keys for server side.
126
+ *
127
+ * @param body - unique keys payload
128
+ * @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
129
+ */
130
+ postUniqueKeysBulkSs: function (body, headers) {
131
+ var url = "".concat(urls.telemetry, "/api/v1/keys/ss");
132
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), false, false, false);
133
+ },
134
+ postMetricsConfig: function (body, headers) {
135
+ var url = "".concat(urls.telemetry, "/api/v1/metrics/config");
136
+ return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), true);
137
+ },
138
+ postMetricsUsage: function (body, headers) {
139
+ var url = "".concat(urls.telemetry, "/api/v1/metrics/usage");
140
+ return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), true);
141
+ },
142
+ stop: function () {
143
+ secureSplitHttpClient.stop();
144
+ }
145
+ };
146
+ }
147
+ exports.serviceApiFactory = serviceApiFactory;
@@ -5,12 +5,14 @@ var splitHttpClient_1 = require("./splitHttpClient");
5
5
  var objectAssign_1 = require("../utils/lang/objectAssign");
6
6
  var constants_1 = require("../utils/constants");
7
7
  var constants_2 = require("../logger/constants");
8
+ var AuthClient_1 = require("../sync/streaming/AuthClient");
8
9
  var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
9
10
  function userKeyToQueryParam(userKey) {
10
11
  return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
11
12
  }
13
+ // @TODO remove when migrating to the new `urls` defaults.
12
14
  /**
13
- * Factory of SplitApi objects, which group the collection of Split HTTP endpoints used by the SDK
15
+ * Factory of ServiceApi objects, which group the collection of Split HTTP endpoints used by the SDK
14
16
  *
15
17
  * @param settings - validated settings object
16
18
  * @param platform - object containing environment-specific dependencies
@@ -22,6 +24,15 @@ function splitApiFactory(settings, platform, telemetryTracker) {
22
24
  var SplitSDKImpressionsMode = settings.sync.impressionsMode;
23
25
  var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform);
24
26
  return {
27
+ fetchAuth: (0, AuthClient_1.fetchAuthFactory)(function (userMatchingKeys) {
28
+ var url = "".concat(urls.auth, "/v2/auth?s=").concat(settings.sync.flagSpecVersion);
29
+ if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
30
+ var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
31
+ if (queryParams)
32
+ url += '&' + queryParams;
33
+ }
34
+ return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_1.TOKEN));
35
+ }),
25
36
  // @TODO throw errors if health check requests fail, to log them in the Synchronizer
26
37
  getSdkAPIHealthCheck: function () {
27
38
  var url = "".concat(urls.sdk, "/version");
@@ -31,15 +42,6 @@ function splitApiFactory(settings, platform, telemetryTracker) {
31
42
  var url = "".concat(urls.events, "/version");
32
43
  return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
33
44
  },
34
- fetchAuth: function (userMatchingKeys) {
35
- var url = "".concat(urls.auth, "/v2/auth?s=").concat(settings.sync.flagSpecVersion);
36
- if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
37
- var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
38
- if (queryParams)
39
- url += '&' + queryParams;
40
- }
41
- return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_1.TOKEN));
42
- },
43
45
  fetchSplitChanges: function (since, noCache, till, rbSince) {
44
46
  var url = "".concat(urls.sdk, "/splitChanges?s=").concat(settings.sync.flagSpecVersion, "&since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
45
47
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SPLITS))
@@ -125,6 +127,18 @@ function splitApiFactory(settings, platform, telemetryTracker) {
125
127
  postMetricsUsage: function (body, headers) {
126
128
  var url = "".concat(urls.telemetry, "/v1/metrics/usage");
127
129
  return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), true);
130
+ },
131
+ // Not used. Just here to satisfy the IServiceApi interface.
132
+ fetchConfigs: function (since, noCache, till, rbSince) {
133
+ var url = "".concat(urls.configs, "/v1/configs?since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
134
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
135
+ },
136
+ fetchConfigsSegmentChanges: function (since, segmentName, noCache, till) {
137
+ var url = "".concat(urls.configs, "/v1/segmentChanges/").concat(segmentName, "?since=").concat(since).concat(till ? '&till=' + till : '');
138
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
139
+ },
140
+ stop: function () {
141
+ // no-op
128
142
  }
129
143
  };
130
144
  }
@@ -24,19 +24,17 @@ function splitHttpClientFactory(settings, _a) {
24
24
  var commonHeaders = {
25
25
  'Accept': 'application/json',
26
26
  'Content-Type': 'application/json',
27
- 'Authorization': "Bearer ".concat(authorizationKey),
28
- 'SplitSDKVersion': version
27
+ 'Authorization': "Bearer ".concat(authorizationKey)
29
28
  };
30
29
  if (ip)
31
30
  commonHeaders['SplitSDKMachineIP'] = ip;
32
31
  if (hostname)
33
32
  commonHeaders['SplitSDKMachineName'] = (0, decorateHeaders_1.removeNonISO88591)(hostname);
34
- return function httpClient(url, reqOpts, latencyTracker, logErrorsAsInfo) {
33
+ return function httpClient(url, reqOpts, latencyTracker, logErrorsAsInfo, newVersionHeader) {
35
34
  if (reqOpts === void 0) { reqOpts = {}; }
36
35
  if (latencyTracker === void 0) { latencyTracker = function () { }; }
37
- if (logErrorsAsInfo === void 0) { logErrorsAsInfo = false; }
38
36
  var request = (0, objectAssign_1.objectAssign)({
39
- headers: (0, decorateHeaders_1.decorateHeaders)(settings, (0, objectAssign_1.objectAssign)({}, commonHeaders, reqOpts.headers || {})),
37
+ headers: (0, decorateHeaders_1.decorateHeaders)(settings, (0, objectAssign_1.objectAssign)(newVersionHeader ? { 'X-Harness-FME-SDK-Version': version } : { 'SplitSDKVersion': version }, commonHeaders, reqOpts.headers || {})),
40
38
  method: reqOpts.method || 'GET',
41
39
  body: reqOpts.body
42
40
  }, options);
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AbstractDefinitionsCacheAsync = void 0;
4
+ var objectAssign_1 = require("../utils/lang/objectAssign");
5
+ /**
6
+ * This class provides a skeletal implementation of the IDefinitionsCacheAsync interface
7
+ * to minimize the effort required to implement this interface.
8
+ */
9
+ var AbstractDefinitionsCacheAsync = /** @class */ (function () {
10
+ function AbstractDefinitionsCacheAsync() {
11
+ }
12
+ AbstractDefinitionsCacheAsync.prototype.update = function (toAdd, toRemove, changeNumber) {
13
+ var _this = this;
14
+ return Promise.all([
15
+ this.setChangeNumber(changeNumber),
16
+ Promise.all(toAdd.map(function (addedFF) { return _this.add(addedFF); })),
17
+ Promise.all(toRemove.map(function (removedFF) { return _this.remove(removedFF); }))
18
+ ]).then(function (_a) {
19
+ var added = _a[1], removed = _a[2];
20
+ return added.some(function (result) { return result; }) || removed.some(function (result) { return result; });
21
+ });
22
+ };
23
+ // @TODO revisit segment-related methods ('usesSegments', 'getRegisteredSegments', 'registerSegments')
24
+ // noop, just keeping the interface. This is used by standalone client-side API only, and so only implemented by InMemory and InLocalStorage.
25
+ AbstractDefinitionsCacheAsync.prototype.usesSegments = function () {
26
+ return Promise.resolve(true);
27
+ };
28
+ /**
29
+ * Kill `name` definition and set `defaultTreatment` and `changeNumber`.
30
+ * Used for SPLIT_KILL push notifications.
31
+ *
32
+ * @returns a promise that is resolved once the definition kill operation is performed. The fulfillment value is a boolean: `true` if the operation succeeded updating the definition or `false` if no definition is updated,
33
+ * for instance, if the `changeNumber` is old, or if the definition is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
34
+ * The promise will never be rejected.
35
+ */
36
+ AbstractDefinitionsCacheAsync.prototype.killLocally = function (name, defaultTreatment, changeNumber) {
37
+ var _this = this;
38
+ return this.get(name).then(function (definition) {
39
+ if (definition && (!definition.changeNumber || definition.changeNumber < changeNumber)) {
40
+ var newDefinition = (0, objectAssign_1.objectAssign)({}, definition);
41
+ newDefinition.killed = true;
42
+ newDefinition.defaultTreatment = defaultTreatment;
43
+ newDefinition.changeNumber = changeNumber;
44
+ return _this.add(newDefinition);
45
+ }
46
+ return false;
47
+ }).catch(function () { return false; });
48
+ };
49
+ return AbstractDefinitionsCacheAsync;
50
+ }());
51
+ exports.AbstractDefinitionsCacheAsync = AbstractDefinitionsCacheAsync;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usesSegmentsSync = exports.usesSegments = exports.AbstractDefinitionsCacheSync = void 0;
4
+ var objectAssign_1 = require("../utils/lang/objectAssign");
5
+ var constants_1 = require("../utils/constants");
6
+ /**
7
+ * This class provides a skeletal implementation of the IDefinitionsCacheSync interface
8
+ * to minimize the effort required to implement this interface.
9
+ */
10
+ var AbstractDefinitionsCacheSync = /** @class */ (function () {
11
+ function AbstractDefinitionsCacheSync() {
12
+ }
13
+ AbstractDefinitionsCacheSync.prototype.update = function (toAdd, toRemove, changeNumber) {
14
+ var _this = this;
15
+ var updated = toAdd.map(function (addedFF) { return _this.add(addedFF); }).some(function (result) { return result; });
16
+ updated = toRemove.map(function (removedFF) { return _this.remove(removedFF); }).some(function (result) { return result; }) || updated;
17
+ this.setChangeNumber(changeNumber);
18
+ return updated;
19
+ };
20
+ AbstractDefinitionsCacheSync.prototype.getMany = function (names) {
21
+ var _this = this;
22
+ var definitions = {};
23
+ names.forEach(function (name) {
24
+ definitions[name] = _this.get(name);
25
+ });
26
+ return definitions;
27
+ };
28
+ AbstractDefinitionsCacheSync.prototype.getAll = function () {
29
+ var _this = this;
30
+ return this.getNames().map(function (key) { return _this.get(key); });
31
+ };
32
+ /**
33
+ * Kill `name` definition and set `defaultTreatment` and `changeNumber`.
34
+ * Used for SPLIT_KILL push notifications.
35
+ *
36
+ * @returns `true` if the operation successed updating the definition, or `false` if no definition is updated,
37
+ * for instance, if the `changeNumber` is old, or if the definition is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
38
+ */
39
+ AbstractDefinitionsCacheSync.prototype.killLocally = function (name, defaultTreatment, changeNumber) {
40
+ var definition = this.get(name);
41
+ if (definition && (!definition.changeNumber || definition.changeNumber < changeNumber)) {
42
+ var newDefinition = (0, objectAssign_1.objectAssign)({}, definition);
43
+ newDefinition.killed = true;
44
+ newDefinition.defaultTreatment = defaultTreatment;
45
+ newDefinition.changeNumber = changeNumber;
46
+ return this.add(newDefinition);
47
+ }
48
+ return false;
49
+ };
50
+ return AbstractDefinitionsCacheSync;
51
+ }());
52
+ exports.AbstractDefinitionsCacheSync = AbstractDefinitionsCacheSync;
53
+ /**
54
+ * Given a parsed definition, it returns a boolean flagging if its conditions use segments matchers (rules & whitelists).
55
+ * This util is intended to simplify the implementation of `definitionsCache::usesSegments` method
56
+ */
57
+ function usesSegments(ruleEntity) {
58
+ var conditions = ruleEntity.conditions || [];
59
+ for (var i = 0; i < conditions.length; i++) {
60
+ var matchers = conditions[i].matcherGroup.matchers;
61
+ for (var j = 0; j < matchers.length; j++) {
62
+ var matcher = matchers[j].matcherType;
63
+ if (matcher === constants_1.IN_SEGMENT || matcher === constants_1.IN_LARGE_SEGMENT)
64
+ return true;
65
+ }
66
+ }
67
+ var excluded = ruleEntity.excluded;
68
+ if (excluded && excluded.segments && excluded.segments.length > 0)
69
+ return true;
70
+ return false;
71
+ }
72
+ exports.usesSegments = usesSegments;
73
+ function usesSegmentsSync(storage) {
74
+ return storage.definitions.usesSegments() || storage.rbSegments.usesSegments();
75
+ }
76
+ exports.usesSegmentsSync = usesSegmentsSync;
@@ -16,16 +16,16 @@ var KeyBuilder = /** @class */ (function () {
16
16
  KeyBuilder.prototype.buildTrafficTypeKey = function (trafficType) {
17
17
  return "".concat(this.prefix, ".trafficType.").concat(trafficType);
18
18
  };
19
- KeyBuilder.prototype.buildFlagSetKey = function (flagSet) {
20
- return "".concat(this.prefix, ".flagSet.").concat(flagSet);
19
+ KeyBuilder.prototype.buildSetKey = function (set) {
20
+ return "".concat(this.prefix, ".flagSet.").concat(set);
21
21
  };
22
- KeyBuilder.prototype.buildSplitKey = function (splitName) {
23
- return "".concat(this.prefix, ".split.").concat(splitName);
22
+ KeyBuilder.prototype.buildDefinitionKey = function (definitionName) {
23
+ return "".concat(this.prefix, ".split.").concat(definitionName);
24
24
  };
25
- KeyBuilder.prototype.buildSplitsTillKey = function () {
25
+ KeyBuilder.prototype.buildDefinitionsTillKey = function () {
26
26
  return "".concat(this.prefix, ".splits.till");
27
27
  };
28
- KeyBuilder.prototype.buildSplitKeyPrefix = function () {
28
+ KeyBuilder.prototype.buildDefinitionKeyPrefix = function () {
29
29
  return "".concat(this.prefix, ".split.");
30
30
  };
31
31
  KeyBuilder.prototype.buildRBSegmentKey = function (rbsegmentName) {
@@ -9,7 +9,7 @@ var KeyBuilderCS = /** @class */ (function (_super) {
9
9
  function KeyBuilderCS(prefix, matchingKey) {
10
10
  var _this = _super.call(this, prefix) || this;
11
11
  _this.matchingKey = matchingKey;
12
- _this.regexSplitsCacheKey = new RegExp("^".concat(prefix, "\\.(splits?|trafficType|flagSet)\\."));
12
+ _this.regexDefinitionsCacheKey = new RegExp("^".concat(prefix, "\\.(splits?|trafficType|flagSet)\\."));
13
13
  return _this;
14
14
  }
15
15
  /**
@@ -26,19 +26,19 @@ var KeyBuilderCS = /** @class */ (function (_super) {
26
26
  KeyBuilderCS.prototype.buildLastUpdatedKey = function () {
27
27
  return "".concat(this.prefix, ".splits.lastUpdated");
28
28
  };
29
- KeyBuilderCS.prototype.isSplitsCacheKey = function (key) {
30
- return this.regexSplitsCacheKey.test(key);
29
+ KeyBuilderCS.prototype.isDefinitionsCacheKey = function (key) {
30
+ return this.regexDefinitionsCacheKey.test(key);
31
31
  };
32
32
  KeyBuilderCS.prototype.buildTillKey = function () {
33
33
  return "".concat(this.prefix, ".").concat(this.matchingKey, ".segments.till");
34
34
  };
35
- KeyBuilderCS.prototype.isSplitKey = function (key) {
35
+ KeyBuilderCS.prototype.isDefinitionKey = function (key) {
36
36
  return (0, lang_1.startsWith)(key, "".concat(this.prefix, ".split."));
37
37
  };
38
38
  KeyBuilderCS.prototype.isRBSegmentKey = function (key) {
39
39
  return (0, lang_1.startsWith)(key, "".concat(this.prefix, ".rbsegment."));
40
40
  };
41
- KeyBuilderCS.prototype.buildSplitsWithSegmentCountKey = function () {
41
+ KeyBuilderCS.prototype.buildDefinitionsWithSegmentCountKey = function () {
42
42
  return "".concat(this.prefix, ".splits.usingSegments");
43
43
  };
44
44
  KeyBuilderCS.prototype.buildLastClear = function () {