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

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 (237) hide show
  1. package/CHANGES.txt +3 -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/{sync/streaming/AuthClient/index.js → services/fetchAuth.js} +15 -16
  34. package/cjs/services/secureSplitHttpClient.js +36 -0
  35. package/cjs/services/serviceApi.js +147 -0
  36. package/cjs/services/splitApi.js +24 -10
  37. package/cjs/services/splitHttpClient.js +3 -5
  38. package/cjs/storages/AbstractDefinitionsCacheAsync.js +51 -0
  39. package/cjs/storages/AbstractDefinitionsCacheSync.js +76 -0
  40. package/cjs/storages/KeyBuilder.js +6 -6
  41. package/cjs/storages/KeyBuilderCS.js +5 -5
  42. package/cjs/storages/KeyBuilderSS.js +2 -2
  43. package/cjs/storages/getRolloutPlan.js +3 -3
  44. package/cjs/storages/inLocalStorage/DefinitionsCacheInLocal.js +195 -0
  45. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -2
  46. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +12 -11
  47. package/cjs/storages/inLocalStorage/index.js +6 -6
  48. package/cjs/storages/inLocalStorage/validateCache.js +3 -3
  49. package/cjs/storages/inMemory/DefinitionsCacheInMemory.js +122 -0
  50. package/cjs/storages/inMemory/InMemoryStorage.js +4 -4
  51. package/cjs/storages/inMemory/InMemoryStorageCS.js +5 -5
  52. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +7 -6
  53. package/cjs/storages/inMemory/SegmentsCacheInMemory.js +1 -1
  54. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +5 -5
  55. package/cjs/storages/inRedis/{SplitsCacheInRedis.js → DefinitionsCacheInRedis.js} +79 -77
  56. package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +4 -2
  57. package/cjs/storages/inRedis/index.js +2 -2
  58. package/cjs/storages/pluggable/DefinitionsCachePluggable.js +214 -0
  59. package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +4 -2
  60. package/cjs/storages/pluggable/index.js +2 -2
  61. package/cjs/storages/setRolloutPlan.js +4 -4
  62. package/cjs/storages/utils.js +1 -0
  63. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +5 -5
  64. package/cjs/sync/polling/fetchers/splitChangesFetcher.js +24 -15
  65. package/cjs/sync/polling/pollingManagerCS.js +86 -81
  66. package/cjs/sync/polling/pollingManagerSS.js +44 -36
  67. package/cjs/sync/polling/syncTasks/definitionsSyncTask.js +13 -0
  68. package/cjs/sync/polling/syncTasks/segmentsSyncTask.js +2 -3
  69. package/cjs/sync/polling/updaters/definitionChangesUpdater.js +207 -0
  70. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +3 -3
  71. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +6 -6
  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} +19 -20
  75. package/cjs/sync/streaming/constants.js +4 -3
  76. package/cjs/sync/streaming/parseUtils.js +14 -14
  77. package/cjs/sync/streaming/pushManager.js +22 -26
  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/{sync/streaming/AuthClient/index.js → services/fetchAuth.js} +13 -13
  129. package/esm/services/secureSplitHttpClient.js +32 -0
  130. package/esm/services/serviceApi.js +143 -0
  131. package/esm/services/splitApi.js +24 -10
  132. package/esm/services/splitHttpClient.js +3 -5
  133. package/esm/storages/AbstractDefinitionsCacheAsync.js +48 -0
  134. package/esm/storages/AbstractDefinitionsCacheSync.js +71 -0
  135. package/esm/storages/KeyBuilder.js +6 -6
  136. package/esm/storages/KeyBuilderCS.js +5 -5
  137. package/esm/storages/KeyBuilderSS.js +2 -2
  138. package/esm/storages/getRolloutPlan.js +3 -3
  139. package/esm/storages/inLocalStorage/DefinitionsCacheInLocal.js +192 -0
  140. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -2
  141. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +9 -8
  142. package/esm/storages/inLocalStorage/index.js +6 -6
  143. package/esm/storages/inLocalStorage/validateCache.js +3 -3
  144. package/esm/storages/inMemory/DefinitionsCacheInMemory.js +119 -0
  145. package/esm/storages/inMemory/InMemoryStorage.js +4 -4
  146. package/esm/storages/inMemory/InMemoryStorageCS.js +5 -5
  147. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +4 -3
  148. package/esm/storages/inMemory/SegmentsCacheInMemory.js +1 -1
  149. package/esm/storages/inMemory/TelemetryCacheInMemory.js +5 -5
  150. package/esm/storages/inRedis/{SplitsCacheInRedis.js → DefinitionsCacheInRedis.js} +78 -76
  151. package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +4 -2
  152. package/esm/storages/inRedis/index.js +2 -2
  153. package/esm/storages/pluggable/DefinitionsCachePluggable.js +211 -0
  154. package/esm/storages/pluggable/RBSegmentsCachePluggable.js +4 -2
  155. package/esm/storages/pluggable/index.js +2 -2
  156. package/esm/storages/setRolloutPlan.js +4 -4
  157. package/esm/storages/utils.js +1 -0
  158. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +6 -6
  159. package/esm/sync/polling/fetchers/splitChangesFetcher.js +25 -16
  160. package/esm/sync/polling/pollingManagerCS.js +87 -82
  161. package/esm/sync/polling/pollingManagerSS.js +44 -36
  162. package/esm/sync/polling/syncTasks/definitionsSyncTask.js +9 -0
  163. package/esm/sync/polling/syncTasks/segmentsSyncTask.js +2 -3
  164. package/esm/sync/polling/updaters/definitionChangesUpdater.js +201 -0
  165. package/esm/sync/polling/updaters/mySegmentsUpdater.js +3 -3
  166. package/esm/sync/polling/updaters/segmentChangesUpdater.js +7 -7
  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} +19 -20
  170. package/esm/sync/streaming/constants.js +3 -2
  171. package/esm/sync/streaming/parseUtils.js +11 -11
  172. package/esm/sync/streaming/pushManager.js +24 -28
  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/src/dtos/types.ts +4 -4
  194. package/src/services/authProvider.ts +2 -2
  195. package/src/{sync/streaming/AuthClient/index.ts → services/fetchAuth.ts} +3 -4
  196. package/src/services/splitApi.ts +1 -1
  197. package/src/services/types.ts +21 -4
  198. package/src/storages/AbstractDefinitionsCacheAsync.ts +3 -3
  199. package/src/storages/AbstractDefinitionsCacheSync.ts +2 -2
  200. package/src/storages/inLocalStorage/DefinitionsCacheInLocal.ts +2 -2
  201. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +3 -3
  202. package/src/storages/inMemory/DefinitionsCacheInMemory.ts +2 -2
  203. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +2 -2
  204. package/src/storages/inRedis/DefinitionsCacheInRedis.ts +6 -4
  205. package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +7 -5
  206. package/src/storages/pluggable/DefinitionsCachePluggable.ts +4 -2
  207. package/src/storages/pluggable/RBSegmentsCachePluggable.ts +5 -3
  208. package/src/storages/types.ts +6 -6
  209. package/src/sync/polling/fetchers/splitChangesFetcher.ts +5 -5
  210. package/src/sync/polling/types.ts +22 -1
  211. package/src/sync/polling/updaters/definitionChangesUpdater.ts +26 -20
  212. package/src/sync/streaming/SSEClient/index.ts +1 -1
  213. package/src/sync/streaming/SSEClient/types.ts +1 -1
  214. package/src/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.ts +15 -11
  215. package/src/sync/streaming/UpdateWorkers/types.ts +6 -0
  216. package/src/sync/streaming/parseUtils.ts +3 -4
  217. package/src/sync/streaming/pushManager.ts +4 -3
  218. package/cjs/storages/AbstractSplitsCacheAsync.js +0 -51
  219. package/cjs/storages/AbstractSplitsCacheSync.js +0 -76
  220. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +0 -194
  221. package/cjs/storages/inMemory/SplitsCacheInMemory.js +0 -121
  222. package/cjs/storages/pluggable/SplitsCachePluggable.js +0 -212
  223. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +0 -13
  224. package/cjs/sync/polling/updaters/splitChangesUpdater.js +0 -200
  225. package/cjs/sync/streaming/AuthClient/types.js +0 -2
  226. package/cjs/utils/inputValidation/splits.js +0 -25
  227. package/esm/storages/AbstractSplitsCacheAsync.js +0 -48
  228. package/esm/storages/AbstractSplitsCacheSync.js +0 -71
  229. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +0 -191
  230. package/esm/storages/inMemory/SplitsCacheInMemory.js +0 -118
  231. package/esm/storages/pluggable/SplitsCachePluggable.js +0 -209
  232. package/esm/sync/polling/syncTasks/splitsSyncTask.js +0 -9
  233. package/esm/sync/polling/updaters/splitChangesUpdater.js +0 -194
  234. package/esm/sync/streaming/AuthClient/types.js +0 -1
  235. package/esm/utils/inputValidation/splitExistence.js +0 -15
  236. package/esm/utils/inputValidation/splits.js +0 -21
  237. package/src/sync/streaming/AuthClient/types.ts +0 -19
@@ -4,7 +4,7 @@ import { eventTrackerFactory } from '../trackers/eventTracker';
4
4
  import { telemetryTrackerFactory } from '../trackers/telemetryTracker';
5
5
  import { createLoggerAPI } from '../logger/sdkLogger';
6
6
  import { NEW_FACTORY, RETRIEVE_MANAGER } from '../logger/constants';
7
- import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../readiness/constants';
7
+ import { SDK_DEFINITIONS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_DEFINITIONS_CACHE_LOADED } from '../readiness/constants';
8
8
  import { objectAssign } from '../utils/lang/objectAssign';
9
9
  import { setRolloutPlan } from '../storages/setRolloutPlan';
10
10
  import { getMatching } from '../utils/key';
@@ -13,7 +13,7 @@ import { FallbackTreatmentsCalculator } from '../evaluator/fallbackTreatmentsCal
13
13
  * Modular SDK factory
14
14
  */
15
15
  export function sdkFactory(params) {
16
- 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;
16
+ 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;
17
17
  var log = settings.log, initialRolloutPlan = settings.initialRolloutPlan, key = settings.core.key;
18
18
  // @TODO handle non-recoverable errors, such as, global `fetch` not available, invalid SDK Key, etc.
19
19
  // On non-recoverable errors, we should mark the SDK as destroyed and not start synchronization.
@@ -27,35 +27,31 @@ export function sdkFactory(params) {
27
27
  readiness.timeout();
28
28
  return;
29
29
  }
30
- readiness.splits.emit(SDK_SPLITS_ARRIVED);
30
+ readiness.definitions.emit(SDK_DEFINITIONS_ARRIVED);
31
31
  readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
32
32
  },
33
33
  onReadyFromCacheCb: function () {
34
- readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
34
+ readiness.definitions.emit(SDK_DEFINITIONS_CACHE_LOADED);
35
35
  }
36
36
  });
37
- var fallbackTreatmentsCalculator = FallbackTreatmentsCalculator(settings.fallbackTreatments);
37
+ var fallbackCalculator = FallbackTreatmentsCalculator(settings.fallbackTreatments);
38
38
  if (initialRolloutPlan) {
39
39
  setRolloutPlan(log, initialRolloutPlan, storage, key && getMatching(key));
40
- if (storage.splits.getChangeNumber() > -1)
41
- readiness.splits.emit(SDK_SPLITS_CACHE_LOADED, { initialCacheLoad: false /* Not an initial load, cache exists */ });
40
+ if (storage.definitions.getChangeNumber() > -1)
41
+ readiness.definitions.emit(SDK_DEFINITIONS_CACHE_LOADED, { initialCacheLoad: false /* Not an initial load, cache exists */ });
42
42
  }
43
43
  var clients = {};
44
44
  var telemetryTracker = telemetryTrackerFactory(storage.telemetry, platform.now);
45
45
  var integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings: settings, storage: storage, telemetryTracker: telemetryTracker });
46
46
  var impressionsTracker = impressionsTrackerFactory(params, storage, integrationsManager);
47
47
  var eventTracker = eventTrackerFactory(settings, storage.events, integrationsManager, storage.telemetry);
48
- // splitApi is used by SyncManager and Browser signal listener
49
- var splitApi = splitApiFactory && splitApiFactory(settings, platform, telemetryTracker);
50
- var ctx = { clients: clients, splitApi: splitApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform, fallbackTreatmentsCalculator: fallbackTreatmentsCalculator };
51
- var syncManager = syncManagerFactory && syncManagerFactory(ctx);
52
- ctx.syncManager = syncManager;
53
- // @TODO: move into platform, and call inside sdkClientFactory (if it's used only there)
54
- var signalListener = SignalListener && new SignalListener(syncManager, settings, storage, splitApi);
55
- ctx.signalListener = signalListener;
48
+ // serviceApi is used by SyncManager and Browser signal listener
49
+ var serviceApi = serviceApiFactory && serviceApiFactory(settings, platform, telemetryTracker);
50
+ var ctx = { clients: clients, serviceApi: serviceApi, eventTracker: eventTracker, impressionsTracker: impressionsTracker, telemetryTracker: telemetryTracker, sdkReadinessManager: sdkReadinessManager, readiness: readiness, settings: settings, storage: storage, platform: platform, fallbackCalculator: fallbackCalculator };
51
+ ctx.syncManager = syncManagerFactory && syncManagerFactory(ctx);
56
52
  // SDK client and manager
57
53
  var clientMethod = sdkClientMethodFactory(ctx);
58
- var managerInstance = sdkManagerFactory(settings, storage.splits, sdkReadinessManager);
54
+ var managerInstance = sdkManagerFactory(settings, storage.definitions, sdkReadinessManager);
59
55
  function init() {
60
56
  Object.keys(clients).map(function (key) { return clients[key].init(); });
61
57
  }
@@ -1,7 +1,7 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
2
  import { thenable } from '../utils/promise/thenable';
3
3
  import { find } from '../utils/lang';
4
- import { validateSplit, validateSplitExistence, validateIfOperational } from '../utils/inputValidation';
4
+ import { validateDefinition, validateDefinitionExistence, validateIfOperational } from '../utils/inputValidation';
5
5
  import { isConsumerMode } from '../utils/settingsValidation/mode';
6
6
  import { SPLIT_FN_LABEL, SPLITS_FN_LABEL, NAMES_FN_LABEL } from '../utils/constants';
7
7
  function collectTreatments(splitObject) {
@@ -50,18 +50,18 @@ export function sdkManagerFactory(settings, splits, _a) {
50
50
  * Get the feature flag object corresponding to the given feature flag name if valid
51
51
  */
52
52
  split: function (featureFlagName) {
53
- var splitName = validateSplit(log, featureFlagName, SPLIT_FN_LABEL);
53
+ var splitName = validateDefinition(log, featureFlagName, SPLIT_FN_LABEL);
54
54
  if (!validateIfOperational(log, readinessManager, SPLIT_FN_LABEL) || !splitName) {
55
55
  return isAsync ? Promise.resolve(null) : null;
56
56
  }
57
- var split = splits.getSplit(splitName);
57
+ var split = splits.get(splitName);
58
58
  if (thenable(split)) {
59
59
  return split.catch(function () { return null; }).then(function (result) {
60
- validateSplitExistence(log, readinessManager, splitName, result, SPLIT_FN_LABEL);
60
+ validateDefinitionExistence(log, readinessManager, splitName, result, SPLIT_FN_LABEL);
61
61
  return objectToView(result);
62
62
  });
63
63
  }
64
- validateSplitExistence(log, readinessManager, splitName, split, SPLIT_FN_LABEL);
64
+ validateDefinitionExistence(log, readinessManager, splitName, split, SPLIT_FN_LABEL);
65
65
  return objectToView(split);
66
66
  },
67
67
  /**
@@ -83,7 +83,7 @@ export function sdkManagerFactory(settings, splits, _a) {
83
83
  if (!validateIfOperational(log, readinessManager, NAMES_FN_LABEL)) {
84
84
  return isAsync ? Promise.resolve([]) : [];
85
85
  }
86
- var splitNames = splits.getSplitNames();
86
+ var splitNames = splits.getNames();
87
87
  return thenable(splitNames) ?
88
88
  splitNames.catch(function () { return []; }) : // handle possible rejections when using pluggable storage
89
89
  splitNames;
@@ -0,0 +1,76 @@
1
+ import { fetchAuthFactory } from './fetchAuth';
2
+ import { Backoff } from '../utils/Backoff';
3
+ import { LOG_PREFIX_SYNC_AUTH } from '../logger/constants';
4
+ import { TOKEN } from '../utils/constants';
5
+ var SKEW_SECONDS = 30;
6
+ function isExpired(credential) {
7
+ return Date.now() / 1000 + SKEW_SECONDS >= credential.decodedToken.exp;
8
+ }
9
+ function noCachedCredentialError() {
10
+ return new Error(LOG_PREFIX_SYNC_AUTH + 'stopped without a cached credential');
11
+ }
12
+ /**
13
+ * Factory of AuthProvider, which provides JWT credentials for authenticated HTTP requests.
14
+ * Credentials are fetched lazily on demand, cached in memory, and retried with backoff on failure.
15
+ */
16
+ export function authProviderFactory(settings, splitHttpClient, telemetryTracker) {
17
+ var urls = settings.urls, log = settings.log;
18
+ var fetchAuth = fetchAuthFactory(function () {
19
+ var url = "".concat(urls.auth, "/api/v3/auth?capabilities=config,aiconfig");
20
+ return splitHttpClient(url, undefined, telemetryTracker.trackHttp(TOKEN), false, true);
21
+ });
22
+ var backoff = new Backoff(fetchCredential);
23
+ var cachedCredential;
24
+ var inFlightPromise;
25
+ var stopped = false;
26
+ function fetchCredential() {
27
+ return fetchAuth().then(function (credential) {
28
+ log.info(LOG_PREFIX_SYNC_AUTH + 'credential fetched successfully');
29
+ cachedCredential = credential;
30
+ inFlightPromise = undefined;
31
+ backoff.reset();
32
+ return credential;
33
+ }).catch(function (error) {
34
+ // Avoid unnecessary retries after stop(): fall back to any cached credential, or reject
35
+ // (never resolve with `undefined`, which callers would otherwise send as an unauthenticated request).
36
+ if (stopped)
37
+ return cachedCredential || Promise.reject(noCachedCredentialError());
38
+ if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500) {
39
+ log.error(LOG_PREFIX_SYNC_AUTH + 'non-retryable error fetching credential (status ' + error.statusCode + '): ' + error.message);
40
+ inFlightPromise = undefined;
41
+ throw error;
42
+ }
43
+ log.warn(LOG_PREFIX_SYNC_AUTH + 'credential fetch failed (attempt ' + (backoff.attempts + 1) + '). Error: ' + error.message);
44
+ return backoff.scheduleCallAsync();
45
+ });
46
+ }
47
+ return {
48
+ credential: function () {
49
+ if (cachedCredential && !isExpired(cachedCredential)) {
50
+ return Promise.resolve(cachedCredential);
51
+ }
52
+ // Reuse any fetch already in flight (e.g. one started just before stop()), instead of firing a redundant one.
53
+ if (inFlightPromise)
54
+ return inFlightPromise;
55
+ // No cached credential to fall back to and stopped: reject so callers don't send an unauthenticated request.
56
+ if (stopped && !cachedCredential) {
57
+ return Promise.reject(noCachedCredentialError());
58
+ }
59
+ if (cachedCredential)
60
+ log.debug(LOG_PREFIX_SYNC_AUTH + 'cached credential expired');
61
+ // If stopped, this is a last, bounded refetch: fetchCredential()'s catch short-circuits (no backoff retry)
62
+ // once stopped, so it's a single attempt that falls back to the stale cached credential on failure.
63
+ return inFlightPromise = fetchCredential();
64
+ },
65
+ invalidate: function () {
66
+ cachedCredential = undefined;
67
+ },
68
+ stop: function () {
69
+ stopped = true;
70
+ // Keep any in-flight fetch and already-cached credential usable (e.g. by a final flush on destroy).
71
+ // If a retry is only pending (not actively in flight), settle it immediately instead of waiting out the
72
+ // backoff delay: with the cached credential if there is one, or rejected otherwise.
73
+ backoff.reset(cachedCredential ? { value: cachedCredential } : { error: noCachedCredentialError() });
74
+ }
75
+ };
76
+ }
@@ -12,7 +12,8 @@ var FORBIDDEN_HEADERS = new Set([
12
12
  'content-encoding',
13
13
  'accept',
14
14
  'keep-alive',
15
- 'x-fastly-debug'
15
+ 'x-fastly-debug',
16
+ 'x-harness-fme-sdk-version'
16
17
  ]);
17
18
  export function decorateHeaders(settings, headers) {
18
19
  var _a;
@@ -1,13 +1,11 @@
1
- import { objectAssign } from '../../../utils/lang/objectAssign';
2
- import { encodeToBase64 } from '../../../utils/base64';
3
- import { decodeJWTtoken } from '../../../utils/jwt';
4
- import { hash } from '../../../utils/murmur3/murmur3';
1
+ import { objectAssign } from '../utils/lang/objectAssign';
2
+ import { decodeJWTtoken } from '../utils/jwt';
5
3
  /**
6
4
  * Factory of authentication function.
7
5
  *
8
- * @param fetchAuth - `SplitAPI.fetchAuth` endpoint
6
+ * @param fetchAuth - /auth endpoint
9
7
  */
10
- export function authenticateFactory(fetchAuth) {
8
+ export function fetchAuthFactory(fetchAuth) {
11
9
  /**
12
10
  * Run authentication requests to Auth Server, and returns a promise that resolves with the decoded JTW token.
13
11
  * @param userKeys - set of user Keys to track membership updates. It is undefined for server-side API.
@@ -21,18 +19,20 @@ export function authenticateFactory(fetchAuth) {
21
19
  if (typeof decodedToken.iat !== 'number' || typeof decodedToken.exp !== 'number')
22
20
  throw new Error('token properties "issuedAt" (iat) or "expiration" (exp) are missing or invalid');
23
21
  var channels = JSON.parse(decodedToken['x-ably-capability']);
24
- return objectAssign({
22
+ var credential = objectAssign({
25
23
  decodedToken: decodedToken,
26
24
  channels: channels
27
25
  }, json);
26
+ // The `/api/v3/auth` endpoint nests the streaming settings under `config.streaming`. Normalize
27
+ // them into the flat `pushEnabled`/`connDelay` properties used by the PushManager.
28
+ var streaming = credential.config && credential.config.streaming;
29
+ if (streaming) {
30
+ credential.pushEnabled = streaming.enabled;
31
+ credential.connDelay = streaming.delay;
32
+ }
33
+ return credential;
28
34
  }
29
35
  return json;
30
36
  });
31
37
  };
32
38
  }
33
- /**
34
- * Returns the hash of a given user key
35
- */
36
- export function hashUserKey(userKey) {
37
- return encodeToBase64(hash(userKey, 0).toString());
38
- }
@@ -0,0 +1,32 @@
1
+ import { __assign } from "tslib";
2
+ /**
3
+ * Factory of Secure HTTP client, which authenticates requests using a JWT token.
4
+ * On 401 responses, invalidates the cached credential and retries once with a fresh token.
5
+ *
6
+ * @param splitHttpClient - `splitHttpClientFactory` to use for making requests
7
+ * @param authProvider - `authProviderFactory` to use for authentication
8
+ */
9
+ export function secureSplitHttpClientFactory(splitHttpClient, authProvider) {
10
+ function makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, token) {
11
+ return splitHttpClient(url, token ? __assign(__assign({}, options), { headers: __assign(__assign({}, options === null || options === void 0 ? void 0 : options.headers), { Authorization: "Bearer ".concat(token) }) }) : options, latencyTracker, logErrorsAsInfo, newVersionHeader);
12
+ }
13
+ var httpClient = function (url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt) {
14
+ if (newVersionHeader === void 0) { newVersionHeader = true; }
15
+ if (useJwt === void 0) { useJwt = true; }
16
+ return authProvider.credential().then(function (credential) {
17
+ return makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt ? credential.token : undefined)
18
+ .catch(function (error) {
19
+ if (error.statusCode === 401) {
20
+ // retry once for 401, in case the token has just expired
21
+ authProvider.invalidate();
22
+ return authProvider.credential().then(function (newCredential) {
23
+ return makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt ? newCredential.token : undefined);
24
+ });
25
+ }
26
+ throw error;
27
+ });
28
+ });
29
+ };
30
+ httpClient.stop = function () { return authProvider.stop(); };
31
+ return httpClient;
32
+ }
@@ -0,0 +1,143 @@
1
+ import { splitHttpClientFactory } from './splitHttpClient';
2
+ import { objectAssign } from '../utils/lang/objectAssign';
3
+ import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, SEGMENT, MEMBERSHIPS } from '../utils/constants';
4
+ import { ERROR_TOO_MANY_SETS } from '../logger/constants';
5
+ import { authProviderFactory } from './authProvider';
6
+ import { secureSplitHttpClientFactory } from './secureSplitHttpClient';
7
+ var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
8
+ /**
9
+ * Factory of ServiceApi objects, which group the collection of HTTP endpoints used by the SDKs
10
+ *
11
+ * @param settings - validated settings object
12
+ * @param platform - object containing environment-specific dependencies
13
+ * @param telemetryTracker - telemetry tracker
14
+ */
15
+ export function serviceApiFactory(settings, platform, telemetryTracker) {
16
+ var urls = settings.urls;
17
+ var filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
18
+ var SplitSDKImpressionsMode = settings.sync.impressionsMode;
19
+ var splitHttpClient = splitHttpClientFactory(settings, platform);
20
+ // Shared authProvider so that the SSE authentication (via `fetchAuth`,
21
+ // used by `pushManager`) and every authenticated HTTP request to the Configs
22
+ // API reuse the same cached credential instead of each fetching their own.
23
+ var authProvider = authProviderFactory(settings, splitHttpClient, telemetryTracker);
24
+ var secureSplitHttpClient = secureSplitHttpClientFactory(splitHttpClient, authProvider);
25
+ var initialAuth = true;
26
+ return {
27
+ fetchAuth: function () {
28
+ // Guard condition to avoid invalidating the cached credential on the first pushManager authentication
29
+ if (initialAuth)
30
+ initialAuth = false;
31
+ else
32
+ authProvider.invalidate();
33
+ return authProvider.credential();
34
+ },
35
+ // @TODO throw errors if health check requests fail, to log them in the Synchronizer
36
+ getSdkAPIHealthCheck: function () {
37
+ var url = "".concat(urls.sdk, "/api/version");
38
+ return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
39
+ },
40
+ getEventsAPIHealthCheck: function () {
41
+ var url = "".concat(urls.events, "/api/version");
42
+ return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
43
+ },
44
+ fetchSplitChanges: function (since, noCache, till, rbSince) {
45
+ 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 : '');
46
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SPLITS))
47
+ .catch(function (err) {
48
+ if (err.statusCode === 414)
49
+ settings.log.error(ERROR_TOO_MANY_SETS);
50
+ throw err;
51
+ });
52
+ },
53
+ fetchSegmentChanges: function (since, segmentName, noCache, till) {
54
+ var url = "".concat(urls.sdk, "/api/segmentChanges/").concat(segmentName, "?since=").concat(since).concat(till ? '&till=' + till : '');
55
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SEGMENT));
56
+ },
57
+ // @TODO support filterQueryString and handle ERROR_TOO_MANY_SETS error
58
+ fetchConfigs: function (since, noCache, till, rbSince) {
59
+ var url = "".concat(urls.configs, "/api/v1/configs?since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
60
+ return secureSplitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
61
+ },
62
+ fetchConfigsSegmentChanges: function (since, segmentName, noCache, till) {
63
+ var url = "".concat(urls.configs, "/api/v1/segmentChanges/").concat(segmentName, "?since=").concat(since).concat(till ? '&till=' + till : '');
64
+ return secureSplitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
65
+ },
66
+ fetchMemberships: function (userMatchingKey, noCache, till) {
67
+ /**
68
+ * URI encoding of user keys in order to:
69
+ * - avoid 400 responses (due to URI malformed). E.g.: '/api/memberships/%'
70
+ * - avoid 404 responses. E.g.: '/api/memberships/foo/bar'
71
+ * - match user keys with special characters. E.g.: 'foo%bar', 'foo/bar'
72
+ */
73
+ var url = "".concat(urls.sdk, "/api/memberships/").concat(encodeURIComponent(userMatchingKey)).concat(till ? '?till=' + till : '');
74
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(MEMBERSHIPS));
75
+ },
76
+ /**
77
+ * Post events.
78
+ *
79
+ * @param body - Events bulk payload
80
+ * @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
81
+ */
82
+ postEventsBulk: function (body, headers) {
83
+ var url = "".concat(urls.events, "/api/events/bulk");
84
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(EVENTS), false, false, false);
85
+ },
86
+ /**
87
+ * Post impressions.
88
+ *
89
+ * @param body - Impressions bulk payload
90
+ * @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
91
+ */
92
+ postTestImpressionsBulk: function (body, headers) {
93
+ var url = "".concat(urls.events, "/api/testImpressions/bulk");
94
+ return secureSplitHttpClient(url, {
95
+ // Adding extra headers to send impressions in OPTIMIZED or DEBUG modes.
96
+ method: 'POST',
97
+ body: body,
98
+ headers: objectAssign({ SplitSDKImpressionsMode: SplitSDKImpressionsMode }, headers)
99
+ }, telemetryTracker.trackHttp(IMPRESSIONS), false, false, false);
100
+ },
101
+ /**
102
+ * Post impressions counts.
103
+ *
104
+ * @param body - Impressions counts payload
105
+ * @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
106
+ */
107
+ postTestImpressionsCount: function (body, headers) {
108
+ var url = "".concat(urls.events, "/api/testImpressions/count");
109
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(IMPRESSIONS_COUNT), false, false, false);
110
+ },
111
+ /**
112
+ * Post unique keys for client side.
113
+ *
114
+ * @param body - unique keys payload
115
+ * @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
116
+ */
117
+ postUniqueKeysBulkCs: function (body, headers) {
118
+ var url = "".concat(urls.telemetry, "/api/v1/keys/cs");
119
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(TELEMETRY), false, false, false);
120
+ },
121
+ /**
122
+ * Post unique keys for server side.
123
+ *
124
+ * @param body - unique keys payload
125
+ * @param headers - Optionals headers to overwrite default ones. For example, it is used in producer mode to overwrite metadata headers.
126
+ */
127
+ postUniqueKeysBulkSs: function (body, headers) {
128
+ var url = "".concat(urls.telemetry, "/api/v1/keys/ss");
129
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(TELEMETRY), false, false, false);
130
+ },
131
+ postMetricsConfig: function (body, headers) {
132
+ var url = "".concat(urls.telemetry, "/api/v1/metrics/config");
133
+ return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(TELEMETRY), true);
134
+ },
135
+ postMetricsUsage: function (body, headers) {
136
+ var url = "".concat(urls.telemetry, "/api/v1/metrics/usage");
137
+ return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(TELEMETRY), true);
138
+ },
139
+ stop: function () {
140
+ secureSplitHttpClient.stop();
141
+ }
142
+ };
143
+ }
@@ -2,12 +2,14 @@ import { splitHttpClientFactory } from './splitHttpClient';
2
2
  import { objectAssign } from '../utils/lang/objectAssign';
3
3
  import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MEMBERSHIPS } from '../utils/constants';
4
4
  import { ERROR_TOO_MANY_SETS } from '../logger/constants';
5
+ import { fetchAuthFactory } from './fetchAuth';
5
6
  var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
6
7
  function userKeyToQueryParam(userKey) {
7
8
  return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
8
9
  }
10
+ // @TODO remove when migrating to the new `urls` defaults.
9
11
  /**
10
- * Factory of SplitApi objects, which group the collection of Split HTTP endpoints used by the SDK
12
+ * Factory of ServiceApi objects, which group the collection of Split HTTP endpoints used by the SDK
11
13
  *
12
14
  * @param settings - validated settings object
13
15
  * @param platform - object containing environment-specific dependencies
@@ -19,6 +21,15 @@ export function splitApiFactory(settings, platform, telemetryTracker) {
19
21
  var SplitSDKImpressionsMode = settings.sync.impressionsMode;
20
22
  var splitHttpClient = splitHttpClientFactory(settings, platform);
21
23
  return {
24
+ fetchAuth: fetchAuthFactory(function (userMatchingKeys) {
25
+ var url = "".concat(urls.auth, "/v2/auth?s=").concat(settings.sync.flagSpecVersion);
26
+ if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
27
+ var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
28
+ if (queryParams)
29
+ url += '&' + queryParams;
30
+ }
31
+ return splitHttpClient(url, undefined, telemetryTracker.trackHttp(TOKEN));
32
+ }),
22
33
  // @TODO throw errors if health check requests fail, to log them in the Synchronizer
23
34
  getSdkAPIHealthCheck: function () {
24
35
  var url = "".concat(urls.sdk, "/version");
@@ -28,15 +39,6 @@ export function splitApiFactory(settings, platform, telemetryTracker) {
28
39
  var url = "".concat(urls.events, "/version");
29
40
  return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
30
41
  },
31
- fetchAuth: function (userMatchingKeys) {
32
- var url = "".concat(urls.auth, "/v2/auth?s=").concat(settings.sync.flagSpecVersion);
33
- if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
34
- var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
35
- if (queryParams)
36
- url += '&' + queryParams;
37
- }
38
- return splitHttpClient(url, undefined, telemetryTracker.trackHttp(TOKEN));
39
- },
40
42
  fetchSplitChanges: function (since, noCache, till, rbSince) {
41
43
  var url = "".concat(urls.sdk, "/splitChanges?s=").concat(settings.sync.flagSpecVersion, "&since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
42
44
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SPLITS))
@@ -122,6 +124,18 @@ export function splitApiFactory(settings, platform, telemetryTracker) {
122
124
  postMetricsUsage: function (body, headers) {
123
125
  var url = "".concat(urls.telemetry, "/v1/metrics/usage");
124
126
  return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(TELEMETRY), true);
127
+ },
128
+ // Not used. Just here to satisfy the IServiceApi interface.
129
+ fetchConfigs: function (since, noCache, till, rbSince) {
130
+ var url = "".concat(urls.configs, "/v1/configs?since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
131
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
132
+ },
133
+ fetchConfigsSegmentChanges: function (since, segmentName, noCache, till) {
134
+ var url = "".concat(urls.configs, "/v1/segmentChanges/").concat(segmentName, "?since=").concat(since).concat(till ? '&till=' + till : '');
135
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
136
+ },
137
+ stop: function () {
138
+ // no-op
125
139
  }
126
140
  };
127
141
  }
@@ -21,19 +21,17 @@ export function splitHttpClientFactory(settings, _a) {
21
21
  var commonHeaders = {
22
22
  'Accept': 'application/json',
23
23
  'Content-Type': 'application/json',
24
- 'Authorization': "Bearer ".concat(authorizationKey),
25
- 'SplitSDKVersion': version
24
+ 'Authorization': "Bearer ".concat(authorizationKey)
26
25
  };
27
26
  if (ip)
28
27
  commonHeaders['SplitSDKMachineIP'] = ip;
29
28
  if (hostname)
30
29
  commonHeaders['SplitSDKMachineName'] = removeNonISO88591(hostname);
31
- return function httpClient(url, reqOpts, latencyTracker, logErrorsAsInfo) {
30
+ return function httpClient(url, reqOpts, latencyTracker, logErrorsAsInfo, newVersionHeader) {
32
31
  if (reqOpts === void 0) { reqOpts = {}; }
33
32
  if (latencyTracker === void 0) { latencyTracker = function () { }; }
34
- if (logErrorsAsInfo === void 0) { logErrorsAsInfo = false; }
35
33
  var request = objectAssign({
36
- headers: decorateHeaders(settings, objectAssign({}, commonHeaders, reqOpts.headers || {})),
34
+ headers: decorateHeaders(settings, objectAssign(newVersionHeader ? { 'X-Harness-FME-SDK-Version': version } : { 'SplitSDKVersion': version }, commonHeaders, reqOpts.headers || {})),
37
35
  method: reqOpts.method || 'GET',
38
36
  body: reqOpts.body
39
37
  }, options);
@@ -0,0 +1,48 @@
1
+ import { objectAssign } from '../utils/lang/objectAssign';
2
+ /**
3
+ * This class provides a skeletal implementation of the IDefinitionsCacheAsync interface
4
+ * to minimize the effort required to implement this interface.
5
+ */
6
+ var AbstractDefinitionsCacheAsync = /** @class */ (function () {
7
+ function AbstractDefinitionsCacheAsync() {
8
+ }
9
+ AbstractDefinitionsCacheAsync.prototype.update = function (toAdd, toRemove, changeNumber) {
10
+ var _this = this;
11
+ return Promise.all([
12
+ this.setChangeNumber(changeNumber),
13
+ Promise.all(toAdd.map(function (addedFF) { return _this.add(addedFF); })),
14
+ Promise.all(toRemove.map(function (removedFF) { return _this.remove(removedFF); }))
15
+ ]).then(function (_a) {
16
+ var added = _a[1], removed = _a[2];
17
+ return added.some(function (result) { return result; }) || removed.some(function (result) { return result; });
18
+ });
19
+ };
20
+ // @TODO revisit segment-related methods ('usesSegments', 'getRegisteredSegments', 'registerSegments')
21
+ // noop, just keeping the interface. This is used by standalone client-side API only, and so only implemented by InMemory and InLocalStorage.
22
+ AbstractDefinitionsCacheAsync.prototype.usesSegments = function () {
23
+ return Promise.resolve(true);
24
+ };
25
+ /**
26
+ * Kill `name` definition and set `defaultTreatment` and `changeNumber`.
27
+ * Used for SPLIT_KILL push notifications.
28
+ *
29
+ * @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,
30
+ * 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.
31
+ * The promise will never be rejected.
32
+ */
33
+ AbstractDefinitionsCacheAsync.prototype.killLocally = function (name, defaultTreatment, changeNumber) {
34
+ var _this = this;
35
+ return this.get(name).then(function (definition) {
36
+ if (definition && (!definition.changeNumber || definition.changeNumber < changeNumber)) {
37
+ var newDefinition = objectAssign({}, definition);
38
+ newDefinition.killed = true;
39
+ newDefinition.defaultTreatment = defaultTreatment;
40
+ newDefinition.changeNumber = changeNumber;
41
+ return _this.add(newDefinition);
42
+ }
43
+ return false;
44
+ }).catch(function () { return false; });
45
+ };
46
+ return AbstractDefinitionsCacheAsync;
47
+ }());
48
+ export { AbstractDefinitionsCacheAsync };
@@ -0,0 +1,71 @@
1
+ import { objectAssign } from '../utils/lang/objectAssign';
2
+ import { IN_SEGMENT, IN_LARGE_SEGMENT } from '../utils/constants';
3
+ /**
4
+ * This class provides a skeletal implementation of the IDefinitionsCacheSync interface
5
+ * to minimize the effort required to implement this interface.
6
+ */
7
+ var AbstractDefinitionsCacheSync = /** @class */ (function () {
8
+ function AbstractDefinitionsCacheSync() {
9
+ }
10
+ AbstractDefinitionsCacheSync.prototype.update = function (toAdd, toRemove, changeNumber) {
11
+ var _this = this;
12
+ var updated = toAdd.map(function (addedFF) { return _this.add(addedFF); }).some(function (result) { return result; });
13
+ updated = toRemove.map(function (removedFF) { return _this.remove(removedFF); }).some(function (result) { return result; }) || updated;
14
+ this.setChangeNumber(changeNumber);
15
+ return updated;
16
+ };
17
+ AbstractDefinitionsCacheSync.prototype.getMany = function (names) {
18
+ var _this = this;
19
+ var definitions = {};
20
+ names.forEach(function (name) {
21
+ definitions[name] = _this.get(name);
22
+ });
23
+ return definitions;
24
+ };
25
+ AbstractDefinitionsCacheSync.prototype.getAll = function () {
26
+ var _this = this;
27
+ return this.getNames().map(function (key) { return _this.get(key); });
28
+ };
29
+ /**
30
+ * Kill `name` definition and set `defaultTreatment` and `changeNumber`.
31
+ * Used for SPLIT_KILL push notifications.
32
+ *
33
+ * @returns `true` if the operation successed updating the definition, or `false` if no definition is updated,
34
+ * 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.
35
+ */
36
+ AbstractDefinitionsCacheSync.prototype.killLocally = function (name, defaultTreatment, changeNumber) {
37
+ var definition = this.get(name);
38
+ if (definition && (!definition.changeNumber || definition.changeNumber < changeNumber)) {
39
+ var newDefinition = objectAssign({}, definition);
40
+ newDefinition.killed = true;
41
+ newDefinition.defaultTreatment = defaultTreatment;
42
+ newDefinition.changeNumber = changeNumber;
43
+ return this.add(newDefinition);
44
+ }
45
+ return false;
46
+ };
47
+ return AbstractDefinitionsCacheSync;
48
+ }());
49
+ export { AbstractDefinitionsCacheSync };
50
+ /**
51
+ * Given a parsed definition, it returns a boolean flagging if its conditions use segments matchers (rules & whitelists).
52
+ * This util is intended to simplify the implementation of `definitionsCache::usesSegments` method
53
+ */
54
+ export function usesSegments(ruleEntity) {
55
+ var conditions = ruleEntity.conditions || [];
56
+ for (var i = 0; i < conditions.length; i++) {
57
+ var matchers = conditions[i].matcherGroup.matchers;
58
+ for (var j = 0; j < matchers.length; j++) {
59
+ var matcher = matchers[j].matcherType;
60
+ if (matcher === IN_SEGMENT || matcher === IN_LARGE_SEGMENT)
61
+ return true;
62
+ }
63
+ }
64
+ var excluded = ruleEntity.excluded;
65
+ if (excluded && excluded.segments && excluded.segments.length > 0)
66
+ return true;
67
+ return false;
68
+ }
69
+ export function usesSegmentsSync(storage) {
70
+ return storage.definitions.usesSegments() || storage.rbSegments.usesSegments();
71
+ }