@rabbitio/ui-kit 1.0.0-beta.9 → 1.0.0-beta.91
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.
- package/.gitlab-ci.yml +29 -0
- package/.husky/commit-msg +19 -0
- package/.husky/pre-push +1 -0
- package/CHANGELOG.md +0 -0
- package/README.md +27 -18
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +16765 -0
- package/coverage/coverage-final.json +116 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +1001 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/rabbit-ui-kit/index.html +116 -0
- package/coverage/rabbit-ui-kit/index.js.html +88 -0
- package/coverage/rabbit-ui-kit/src/common-apis/adapters/analyticsAdapters/googleAnalyticsAdapter.js.html +148 -0
- package/coverage/rabbit-ui-kit/src/common-apis/adapters/analyticsAdapters/index.html +146 -0
- package/coverage/rabbit-ui-kit/src/common-apis/adapters/analyticsAdapters/metrikaAdapter.js.html +169 -0
- package/coverage/rabbit-ui-kit/src/common-apis/adapters/analyticsAdapters/mixpanelAdapter.js.html +199 -0
- package/coverage/rabbit-ui-kit/src/common-apis/adapters/axiosAdapter.js.html +190 -0
- package/coverage/rabbit-ui-kit/src/common-apis/adapters/index.html +131 -0
- package/coverage/rabbit-ui-kit/src/common-apis/adapters/qrUtils.js.html +139 -0
- package/coverage/rabbit-ui-kit/src/common-apis/external-apis/apiGroups.js.html +250 -0
- package/coverage/rabbit-ui-kit/src/common-apis/external-apis/emailAPI.js.html +133 -0
- package/coverage/rabbit-ui-kit/src/common-apis/external-apis/index.html +146 -0
- package/coverage/rabbit-ui-kit/src/common-apis/external-apis/ipAddressProviders.js.html +352 -0
- package/coverage/rabbit-ui-kit/src/common-apis/globalConstants.jsx.html +94 -0
- package/coverage/rabbit-ui-kit/src/common-apis/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/common-apis/models/blockchain.js.html +115 -0
- package/coverage/rabbit-ui-kit/src/common-apis/models/coin.js.html +829 -0
- package/coverage/rabbit-ui-kit/src/common-apis/models/index.html +146 -0
- package/coverage/rabbit-ui-kit/src/common-apis/models/protocol.js.html +100 -0
- package/coverage/rabbit-ui-kit/src/common-apis/services/fiatCurrenciesService.js.html +544 -0
- package/coverage/rabbit-ui-kit/src/common-apis/services/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/common-apis/utils/amountUtils.js.html +1162 -0
- package/coverage/rabbit-ui-kit/src/common-apis/utils/cache.js.html +811 -0
- package/coverage/rabbit-ui-kit/src/common-apis/utils/errorUtils.js.html +211 -0
- package/coverage/rabbit-ui-kit/src/common-apis/utils/index.html +191 -0
- package/coverage/rabbit-ui-kit/src/common-apis/utils/logging/index.html +131 -0
- package/coverage/rabbit-ui-kit/src/common-apis/utils/logging/logger.js.html +208 -0
- package/coverage/rabbit-ui-kit/src/common-apis/utils/logging/logsStorage.js.html +268 -0
- package/coverage/rabbit-ui-kit/src/common-apis/utils/postponeExecution.js.html +118 -0
- package/coverage/rabbit-ui-kit/src/common-apis/utils/rabbitTicker.js.html +157 -0
- package/coverage/rabbit-ui-kit/src/common-apis/utils/safeStringify.js.html +235 -0
- package/coverage/rabbit-ui-kit/src/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/index.js.html +376 -0
- package/coverage/rabbit-ui-kit/src/robust-api-caller/cacheAndConcurrentRequestsResolver.js.html +1570 -0
- package/coverage/rabbit-ui-kit/src/robust-api-caller/cachedRobustExternalApiCallerService.js.html +526 -0
- package/coverage/rabbit-ui-kit/src/robust-api-caller/cancelProcessing.js.html +172 -0
- package/coverage/rabbit-ui-kit/src/robust-api-caller/concurrentCalculationsMetadataHolder.js.html +310 -0
- package/coverage/rabbit-ui-kit/src/robust-api-caller/externalApiProvider.js.html +553 -0
- package/coverage/rabbit-ui-kit/src/robust-api-caller/externalServicesStatsCollector.js.html +319 -0
- package/coverage/rabbit-ui-kit/src/robust-api-caller/index.html +206 -0
- package/coverage/rabbit-ui-kit/src/robust-api-caller/robustExternalAPICallerService.js.html +997 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/exolixSwapProvider.js.html +1825 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/index.html +161 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/letsExchangeSwapProvider.js.html +1618 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/swapProvider.js.html +1819 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/swapspaceSwapProvider.js.html +1861 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/models/baseSwapCreationInfo.js.html +319 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/models/existingSwap.js.html +514 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/models/existingSwapWithFiatData.js.html +529 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/models/index.html +176 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/models/partner.js.html +166 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/models/swapProviderCoinInfo.js.html +331 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/services/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/services/publicSwapService.js.html +1555 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/utils/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/swaps-lib/utils/swapUtils.js.html +670 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/arrowIcon.jsx.html +124 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/arrowTosca.jsx.html +127 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/arrowWhite.jsx.html +127 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/darkRectangle.jsx.html +106 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/determinedError.jsx.html +439 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/failedValidationIcon.jsx.html +202 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/index.html +281 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/infoIcon.jsx.html +133 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/messageIcon.jsx.html +346 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/noticeQuestionIcon.jsx.html +247 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/successfulValidationIcon.jsx.html +163 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/supportDialogImage.jsx.html +268 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/assets/wrappedImages/walletIcon.jsx.html +151 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/AssetIcon/AssetIcon.jsx.html +256 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/AssetIcon/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/AssetSelection/AssetSelection.jsx.html +289 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/AssetSelection/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/BackgroundTitle/BackgroundTitle.jsx.html +187 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/BackgroundTitle/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/InformationMessage/InformationMessage.jsx.html +238 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/InformationMessage/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Input/Input.jsx.html +634 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Input/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/LoadingDots/LoadingDots.jsx.html +196 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/LoadingDots/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/NoticeIcon/NoticeIcon.jsx.html +277 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/NoticeIcon/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/QrCode/QrCode.jsx.html +217 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/QrCode/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/RateSelector/RateSelector.jsx.html +175 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/RateSelector/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/SupportChat/SupportChat.jsx.html +217 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/SupportChat/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Textarea/Textarea.jsx.html +529 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Textarea/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/TitleBox/TitleBox.jsx.html +508 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/TitleBox/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Tooltip/Tooltip.jsx.html +316 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Tooltip/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/TwoLinesOfText/LinesOfText.jsx.html +313 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/TwoLinesOfText/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Validation/Validation.jsx.html +202 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/Validation/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/Button/Button.jsx.html +712 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/Button/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/Close/Close.jsx.html +259 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/Close/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/LinkButton/LinkButton.jsx.html +421 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/LinkButton/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/RadioButtonWithText/RadioButtonWithText.jsx.html +415 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/atoms/buttons/RadioButtonWithText/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/AmountInput/AmountInput.jsx.html +1429 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/AmountInput/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/CoinPicker/CoinPicker.jsx.html +1474 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/CoinPicker/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/ColoredNotice/ColoredNotice.jsx.html +211 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/ColoredNotice/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/LineWithIconLink/LineWithIconLink.jsx.html +190 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/LineWithIconLink/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/LogoCarousel/LogoCarousel.jsx.html +307 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/LogoCarousel/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/SearchableCoinsList/SearchableCoinsList.jsx.html +496 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/SearchableCoinsList/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/TitledLineWithIconLink/TitledLineWithIconLink.jsx.html +181 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/molecules/TitledLineWithIconLink/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/CoinPickerDialogStep/CoinPickerDialogStep.jsx.html +283 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/CoinPickerDialogStep/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/Dialog.jsx.html +1567 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/DialogButtons/DialogButtons.jsx.html +481 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/DialogButtons/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/DialogStep/DialogStep.jsx.html +1747 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/DialogStep/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/Dialog/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/SwapForm/SwapForm.jsx.html +4207 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/SwapForm/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/WaitlistSubscription/WaitlistSubscription.jsx.html +559 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/organisms/WaitlistSubscription/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/templates/DeterminedErrorDialogStep/DeterminedErrorDialogStep.jsx.html +316 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/components/templates/DeterminedErrorDialogStep/index.html +116 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/hooks/index.html +146 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/hooks/useCallHandlingErrors.js.html +151 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/hooks/useIsHydrated.js.html +121 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/hooks/useReferredState.js.html +157 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/utils/index.html +161 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/utils/inputValueProviders.js.html +235 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/utils/textUtils.js.html +139 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/utils/uiUtils.js.html +121 -0
- package/coverage/rabbit-ui-kit/src/ui-kit/utils/urlQueryUtils.js.html +271 -0
- package/coverage/rabbit-ui-kit/stories/atoms/BackgroundTitle.stories.jsx.html +202 -0
- package/coverage/rabbit-ui-kit/stories/atoms/LinesOfText.stories.jsx.html +283 -0
- package/coverage/rabbit-ui-kit/stories/atoms/LoadingDots.stories.jsx.html +226 -0
- package/coverage/rabbit-ui-kit/stories/atoms/QrCode.stories.jsx.html +175 -0
- package/coverage/rabbit-ui-kit/stories/atoms/RateSelector.stories.jsx.html +136 -0
- package/coverage/rabbit-ui-kit/stories/atoms/Validation.stories.jsx.html +178 -0
- package/coverage/rabbit-ui-kit/stories/atoms/buttons/Button.stories.jsx.html +883 -0
- package/coverage/rabbit-ui-kit/stories/atoms/buttons/Close.stories.jsx.html +211 -0
- package/coverage/rabbit-ui-kit/stories/atoms/buttons/LinkButton.stories.jsx.html +301 -0
- package/coverage/rabbit-ui-kit/stories/atoms/buttons/index.html +146 -0
- package/coverage/rabbit-ui-kit/stories/atoms/index.html +191 -0
- package/coverage/rabbit-ui-kit/stories/molecules/AmountInput.stories.jsx.html +289 -0
- package/coverage/rabbit-ui-kit/stories/molecules/CoinPicker.stories.jsx.html +322 -0
- package/coverage/rabbit-ui-kit/stories/molecules/ColoredNotice.stories.jsx.html +178 -0
- package/coverage/rabbit-ui-kit/stories/molecules/LineWithIconLink.stories.jsx.html +154 -0
- package/coverage/rabbit-ui-kit/stories/molecules/LogoCarousel.stories.jsx.html +235 -0
- package/coverage/rabbit-ui-kit/stories/molecules/TitledLineWithIconLink.stories.jsx.html +160 -0
- package/coverage/rabbit-ui-kit/stories/molecules/index.html +191 -0
- package/coverage/rabbit-ui-kit/stories/organisms/Dialog/Dialog.stories.jsx.html +523 -0
- package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogButtons/DialogButtons.stories.jsx.html +328 -0
- package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogButtons/index.html +116 -0
- package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogStep/DialogStep.stories.jsx.html +337 -0
- package/coverage/rabbit-ui-kit/stories/organisms/Dialog/DialogStep/index.html +116 -0
- package/coverage/rabbit-ui-kit/stories/organisms/Dialog/index.html +116 -0
- package/coverage/rabbit-ui-kit/stories/organisms/WaitlistSubscription.stories.jsx.html +151 -0
- package/coverage/rabbit-ui-kit/stories/organisms/index.html +116 -0
- package/coverage/rabbit-ui-kit/stories/stubs/coins.jsx.html +6880 -0
- package/coverage/rabbit-ui-kit/stories/stubs/exampleContent.jsx.html +145 -0
- package/coverage/rabbit-ui-kit/stories/stubs/index.html +131 -0
- package/coverage/rabbit-ui-kit/stories/templates/DeterminedErrorDialogStep.stories.jsx.html +190 -0
- package/coverage/rabbit-ui-kit/stories/templates/index.html +116 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/dist/global.css +197 -0
- package/dist/global.css.map +1 -0
- package/dist/index.cjs +12451 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +2339 -8491
- package/dist/index.css.map +1 -1
- package/dist/index.modern.js +9597 -26
- package/dist/index.modern.js.map +1 -1
- package/dist/index.module.js +12357 -27
- package/dist/index.module.js.map +1 -1
- package/dist/index.umd.js +12442 -29
- package/dist/index.umd.js.map +1 -1
- package/package.json +35 -9
- package/raw +1000 -0
- package/src/common-apis/adapters/analyticsAdapters/googleAnalyticsAdapter.js +21 -0
- package/src/common-apis/adapters/analyticsAdapters/metrikaAdapter.js +28 -0
- package/src/common-apis/adapters/analyticsAdapters/mixpanelAdapter.js +38 -0
- package/src/common-apis/adapters/axiosAdapter.js +35 -0
- package/src/common-apis/adapters/qrUtils.js +18 -0
- package/src/common-apis/external-apis/apiGroups.js +55 -0
- package/src/common-apis/external-apis/emailAPI.js +16 -0
- package/src/common-apis/external-apis/ipAddressProviders.js +89 -0
- package/src/common-apis/globalConstants.jsx +3 -0
- package/src/common-apis/models/blockchain.js +10 -0
- package/src/common-apis/models/coin.js +248 -0
- package/src/common-apis/models/protocol.js +5 -0
- package/src/{common → common-apis/services}/fiatCurrenciesService.js +4 -12
- package/src/common-apis/tests/integration/external-apis/ipAddressProviders/getClientIpAddress.test.js +12 -0
- package/src/common-apis/tests/units/utils/amountUtils/composeRateText.test.js +152 -0
- package/src/{common → common-apis/utils}/amountUtils.js +72 -136
- package/src/common-apis/utils/cache.js +242 -0
- package/src/{common → common-apis/utils}/errorUtils.js +15 -0
- package/src/common-apis/utils/logging/logger.js +41 -0
- package/src/common-apis/utils/logging/logsStorage.js +61 -0
- package/src/common-apis/utils/postponeExecution.js +11 -0
- package/src/common-apis/utils/rabbitTicker.js +24 -0
- package/src/common-apis/utils/safeStringify.js +50 -0
- package/src/index.js +96 -9
- package/src/robust-api-caller/cacheAndConcurrentRequestsResolver.js +495 -0
- package/src/robust-api-caller/cachedRobustExternalApiCallerService.js +147 -0
- package/src/robust-api-caller/cancelProcessing.js +29 -0
- package/src/robust-api-caller/concurrentCalculationsMetadataHolder.js +75 -0
- package/src/robust-api-caller/externalApiProvider.js +156 -0
- package/src/robust-api-caller/externalServicesStatsCollector.js +78 -0
- package/src/robust-api-caller/robustExternalAPICallerService.js +304 -0
- package/src/robust-api-caller/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/_performCallAttempt.test.js +533 -0
- package/src/robust-api-caller/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/callExternalAPI.test.js +532 -0
- package/src/robust-api-caller/tests/robustExternalAPICallerService/robustExternalAPICallerService/constructor.test.js +19 -0
- package/src/swaps-lib/external-apis/exolixSwapProvider.js +580 -0
- package/src/swaps-lib/external-apis/letsExchangeSwapProvider.js +511 -0
- package/src/swaps-lib/external-apis/swapProvider.js +578 -0
- package/src/swaps-lib/external-apis/swapspaceSwapProvider.js +592 -0
- package/src/swaps-lib/models/baseSwapCreationInfo.js +78 -0
- package/src/swaps-lib/models/existingSwap.js +143 -0
- package/src/swaps-lib/models/existingSwapWithFiatData.js +148 -0
- package/src/swaps-lib/models/partner.js +27 -0
- package/src/swaps-lib/models/swapProviderCoinInfo.js +82 -0
- package/src/swaps-lib/services/publicSwapService.js +490 -0
- package/src/swaps-lib/test/external-apis/exolixSwapProvider/_fetchSupportedCurrenciesIfNeeded.test.js +34 -0
- package/src/swaps-lib/test/external-apis/exolixSwapProvider/createSwap.test.js +1043 -0
- package/src/swaps-lib/test/external-apis/exolixSwapProvider/getSwapInfo.test.js +611 -0
- package/src/swaps-lib/test/external-apis/swapProvider/getAllSupportedCurrencies.test.js +63 -0
- package/src/swaps-lib/test/external-apis/swapProvider/getDepositCurrencies.test.js +73 -0
- package/src/swaps-lib/test/external-apis/swapProvider/getWithdrawalCurrencies.test.js +102 -0
- package/src/swaps-lib/test/external-apis/swapProvider/removeProtocolNameFromCoinName.test.js +152 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/_fetchSupportedCurrenciesIfNeeded.test.js +536 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/createSwap.test.js +1214 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getSwapInfo.test.js +1707 -0
- package/src/swaps-lib/test/utils/swapUtils/safeHandleRequestsLimitExceeding.test.js +80 -0
- package/src/swaps-lib/utils/swapUtils.js +195 -0
- package/{styles → src/ui-kit/assets/styles}/_functions.scss +5 -0
- package/{styles → src/ui-kit/assets/styles}/_mixins.scss +2 -2
- package/{styles → src/ui-kit/assets/styles}/_placeholder.scss +3 -3
- package/{styles → src/ui-kit/assets/styles}/_variables.scss +17 -15
- package/src/ui-kit/assets/styles/fonts/NunitoSans-Bold.ttf +0 -0
- package/src/ui-kit/assets/styles/fonts/NunitoSans-ExtraBold.ttf +0 -0
- package/src/ui-kit/assets/styles/fonts/NunitoSans-Light.ttf +0 -0
- package/src/ui-kit/assets/styles/fonts/NunitoSans-Regular.ttf +0 -0
- package/src/ui-kit/assets/styles/fonts/NunitoSans-SemiBold.ttf +0 -0
- package/src/ui-kit/assets/styles/global.scss +171 -0
- package/src/ui-kit/assets/styles/index.scss +10 -0
- package/src/ui-kit/assets/wrappedImages/arrowIcon.jsx +13 -0
- package/src/ui-kit/assets/wrappedImages/arrowTosca.jsx +14 -0
- package/src/ui-kit/assets/wrappedImages/arrowWhite.jsx +14 -0
- package/src/ui-kit/assets/wrappedImages/darkRectangle.jsx +7 -0
- package/src/ui-kit/assets/wrappedImages/determinedError.jsx +118 -0
- package/src/ui-kit/assets/wrappedImages/failedValidationIcon.jsx +39 -0
- package/src/ui-kit/assets/wrappedImages/infoIcon.jsx +16 -0
- package/src/ui-kit/assets/wrappedImages/messageIcon.jsx +87 -0
- package/src/ui-kit/assets/wrappedImages/noticeQuestionIcon.jsx +54 -0
- package/src/ui-kit/assets/wrappedImages/successfulValidationIcon.jsx +26 -0
- package/src/ui-kit/assets/wrappedImages/supportDialogImage.jsx +61 -0
- package/src/ui-kit/assets/wrappedImages/walletIcon.jsx +22 -0
- package/src/ui-kit/components/atoms/AssetIcon/AssetIcon.jsx +57 -0
- package/src/{components → ui-kit/components}/atoms/AssetIcon/asset-icon.module.scss +1 -1
- package/src/ui-kit/components/atoms/AssetSelection/AssetSelection.jsx +68 -0
- package/src/ui-kit/components/atoms/AssetSelection/asset-selection.module.scss +56 -0
- package/src/ui-kit/components/atoms/BackgroundTitle/BackgroundTitle.jsx +34 -0
- package/src/ui-kit/components/atoms/BackgroundTitle/background-title.module.scss +52 -0
- package/src/ui-kit/components/atoms/InformationMessage/InformationMessage.jsx +51 -0
- package/src/ui-kit/components/atoms/InformationMessage/information-message.module.scss +38 -0
- package/src/ui-kit/components/atoms/Input/Input.jsx +183 -0
- package/src/ui-kit/components/atoms/Input/input.module.scss +107 -0
- package/src/{components → ui-kit/components}/atoms/LoadingDots/LoadingDots.jsx +8 -28
- package/src/{components → ui-kit/components}/atoms/LoadingDots/LoadingDots.module.scss +3 -2
- package/src/ui-kit/components/atoms/NoticeIcon/NoticeIcon.jsx +64 -0
- package/src/ui-kit/components/atoms/NoticeIcon/notice-icon.module.scss +14 -0
- package/src/ui-kit/components/atoms/QrCode/QrCode.jsx +44 -0
- package/src/ui-kit/components/atoms/QrCode/qr-code.module.scss +15 -0
- package/src/ui-kit/components/atoms/RateSelector/RateSelector.jsx +30 -0
- package/src/ui-kit/components/atoms/RateSelector/rate-selector.module.scss +47 -0
- package/src/{components → ui-kit/components}/atoms/SupportChat/SupportChat.jsx +5 -1
- package/src/ui-kit/components/atoms/Textarea/Textarea.jsx +148 -0
- package/src/ui-kit/components/atoms/Textarea/textarea.module.scss +71 -0
- package/src/ui-kit/components/atoms/TitleBox/TitleBox.jsx +141 -0
- package/src/ui-kit/components/atoms/TitleBox/title-box.module.scss +32 -0
- package/src/ui-kit/components/atoms/Tooltip/Tooltip.jsx +77 -0
- package/src/ui-kit/components/atoms/Tooltip/tooltip.module.scss +237 -0
- package/src/ui-kit/components/atoms/TwoLinesOfText/LinesOfText.jsx +76 -0
- package/src/ui-kit/components/atoms/TwoLinesOfText/lines-of-text.module.scss +65 -0
- package/src/ui-kit/components/atoms/Validation/Validation.jsx +39 -0
- package/src/ui-kit/components/atoms/Validation/validation.module.scss +19 -0
- package/src/{components → ui-kit/components}/atoms/buttons/Button/Button.jsx +24 -50
- package/src/{components → ui-kit/components}/atoms/buttons/Button/Button.module.scss +1 -1
- package/src/ui-kit/components/atoms/buttons/Close/Close.jsx +58 -0
- package/src/ui-kit/components/atoms/buttons/Close/close.module.scss +75 -0
- package/src/ui-kit/components/atoms/buttons/LinkButton/LinkButton.jsx +112 -0
- package/src/ui-kit/components/atoms/buttons/LinkButton/link-button.module.scss +49 -0
- package/src/ui-kit/components/atoms/buttons/RadioButtonWithText/RadioButtonWithText.jsx +110 -0
- package/src/ui-kit/components/atoms/buttons/RadioButtonWithText/radio-button-with-text.module.scss +86 -0
- package/src/ui-kit/components/molecules/AmountInput/AmountInput.jsx +448 -0
- package/src/ui-kit/components/molecules/AmountInput/amount-input.module.scss +233 -0
- package/src/ui-kit/components/molecules/CoinPicker/CoinPicker.jsx +463 -0
- package/src/ui-kit/components/molecules/CoinPicker/coin-picker.module.scss +207 -0
- package/src/ui-kit/components/molecules/ColoredNotice/ColoredNotice.jsx +42 -0
- package/src/ui-kit/components/molecules/ColoredNotice/colored-notice.module.scss +20 -0
- package/src/ui-kit/components/molecules/LineWithIconLink/LineWithIconLink.jsx +35 -0
- package/src/ui-kit/components/molecules/LineWithIconLink/line-with-icon-link.module.scss +25 -0
- package/src/ui-kit/components/molecules/LogoCarousel/LogoCarousel.jsx +74 -0
- package/src/ui-kit/components/molecules/LogoCarousel/logo-carousel.module.scss +106 -0
- package/src/ui-kit/components/molecules/SearchableCoinsList/SearchableCoinsList.jsx +137 -0
- package/src/ui-kit/components/molecules/TitledLineWithIconLink/TitledLineWithIconLink.jsx +32 -0
- package/src/ui-kit/components/organisms/CoinPickerDialogStep/CoinPickerDialogStep.jsx +66 -0
- package/src/ui-kit/components/organisms/Dialog/Dialog.jsx +494 -0
- package/src/ui-kit/components/organisms/Dialog/DialogButtons/DialogButtons.jsx +132 -0
- package/src/ui-kit/components/organisms/Dialog/DialogButtons/dialog-buttons.module.scss +25 -0
- package/src/ui-kit/components/organisms/Dialog/DialogStep/DialogStep.jsx +554 -0
- package/src/ui-kit/components/organisms/Dialog/DialogStep/dialog-step.module.scss +381 -0
- package/src/ui-kit/components/organisms/Dialog/dialog.module.scss +226 -0
- package/src/ui-kit/components/organisms/SwapForm/SwapForm.jsx +1374 -0
- package/src/ui-kit/components/organisms/SwapForm/swap-form.module.scss +134 -0
- package/src/ui-kit/components/organisms/WaitlistSubscription/WaitlistSubscription.jsx +158 -0
- package/src/ui-kit/components/templates/DeterminedErrorDialogStep/DeterminedErrorDialogStep.jsx +77 -0
- package/src/ui-kit/hooks/useCallHandlingErrors.js +22 -0
- package/src/ui-kit/hooks/useIsHydrated.js +12 -0
- package/src/ui-kit/hooks/useReferredState.js +24 -0
- package/src/ui-kit/tests/utils/inputValueProviders/provideFormatOfFloatValueByInputString.test.js +146 -0
- package/src/ui-kit/tests/utils/urlQueryUtils/getQueryParameterValues.test.js +65 -0
- package/src/ui-kit/tests/utils/urlQueryUtils/saveQueryParameterAndValues.test.js +104 -0
- package/src/ui-kit/utils/inputValueProviders.js +50 -0
- package/src/ui-kit/utils/textUtils.js +18 -0
- package/src/ui-kit/utils/uiUtils.js +12 -0
- package/src/ui-kit/utils/urlQueryUtils.js +62 -0
- package/stories/font.scss +40 -0
- package/stories/stubs/coins.jsx +2266 -0
- package/stories/stubs/exampleContent.jsx +20 -0
- package/src/components/atoms/AssetIcon/AssetIcon.jsx +0 -55
- package/styles/_global-classes.scss +0 -433
- package/styles/fonts/NunitoSans-Bold.ttf +0 -0
- package/styles/fonts/NunitoSans-ExtraBold.ttf +0 -0
- package/styles/fonts/NunitoSans-Light.ttf +0 -0
- package/styles/fonts/NunitoSans-Regular.ttf +0 -0
- package/styles/fonts/NunitoSans-SemiBold.ttf +0 -0
- package/styles/global-styles-index.scss +0 -74
- package/styles/index.scss +0 -33
- /package/{styles → src/ui-kit/assets/styles}/colors/_light-colors.scss +0 -0
- /package/{styles → src/ui-kit/assets/styles}/colors/_solid-colors.scss +0 -0
- /package/{styles → src/ui-kit/assets/styles}/size/_margin-size.scss +0 -0
- /package/{styles → src/ui-kit/assets/styles}/size/_padding-size.scss +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { v4 } from "uuid";
|
|
2
|
+
|
|
3
|
+
import { Logger } from "../common-apis/utils/logging/logger.js";
|
|
4
|
+
|
|
5
|
+
// TODO: [refactoring, low] Consider removing this logic task_id=c360f2af75764bde8badd9ff1cc00d48
|
|
6
|
+
export class ConcurrentCalculationsMetadataHolder {
|
|
7
|
+
constructor() {
|
|
8
|
+
this._calculations = {};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
startCalculation(domain, calculationsHistoryMaxLength = 100) {
|
|
12
|
+
if (!this._calculations[domain]) {
|
|
13
|
+
this._calculations[domain] = [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (this._calculations[domain].length > calculationsHistoryMaxLength) {
|
|
17
|
+
this._calculations[domain] = this._calculations[domain].slice(
|
|
18
|
+
Math.round(calculationsHistoryMaxLength * 0.2)
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const newCalculation = {
|
|
23
|
+
startTimestamp: Date.now(),
|
|
24
|
+
endTimestamp: null,
|
|
25
|
+
uuid: v4(),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
this._calculations[domain].push(newCalculation);
|
|
29
|
+
|
|
30
|
+
return newCalculation.uuid;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
endCalculation(domain, uuid, isFailed = false) {
|
|
34
|
+
try {
|
|
35
|
+
const calculation = this._calculations[domain].find(calculation => calculation?.uuid === uuid);
|
|
36
|
+
if (calculation) {
|
|
37
|
+
calculation.endTimestamp = Date.now();
|
|
38
|
+
calculation.isFiled = isFailed;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const elapsed = (((calculation?.endTimestamp ?? 0) - (calculation?.startTimestamp ?? 0)) / 1000).toFixed(1);
|
|
42
|
+
Logger.log("endCalculation", `${elapsed} ms: ${domain}.${(calculation?.uuid ?? "").slice(0, 7)}`);
|
|
43
|
+
|
|
44
|
+
return calculation;
|
|
45
|
+
} catch (e) {
|
|
46
|
+
Logger.logError(e, "endCalculation");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
isCalculationLate(domain, uuid) {
|
|
51
|
+
const queue = this._calculations[domain];
|
|
52
|
+
const analysingCalculation = queue.find(item => item.uuid === uuid);
|
|
53
|
+
return (
|
|
54
|
+
analysingCalculation &&
|
|
55
|
+
!!queue.find(
|
|
56
|
+
calculation =>
|
|
57
|
+
calculation.endTimestamp != null && calculation.startTimestamp > analysingCalculation.startTimestamp
|
|
58
|
+
)
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
printCalculationsWaitingMoreThanSpecifiedSeconds(waitingLastsMs = 2000) {
|
|
63
|
+
const calculations = Object.keys(this._calculations)
|
|
64
|
+
.map(domain => this._calculations[domain].map(c => ({ ...c, domain })))
|
|
65
|
+
.flat()
|
|
66
|
+
.filter(c => c.endTimestamp === null && Date.now() - c.startTimestamp > waitingLastsMs);
|
|
67
|
+
Logger.log(
|
|
68
|
+
"printCalculationsWaitingMoreThanSpecifiedSeconds",
|
|
69
|
+
`Calculations waiting more than ${(waitingLastsMs / 1000).toFixed(1)}s:\n` +
|
|
70
|
+
calculations.map(c => `${c.domain}.${c.uuid.slice(0, 8)}: ${Date.now() - c.startTimestamp}\n`)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const concurrentCalculationsMetadataHolder = new ConcurrentCalculationsMetadataHolder();
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
export class ExternalApiProvider {
|
|
2
|
+
/**
|
|
3
|
+
* Creates an instance of external api provider.
|
|
4
|
+
*
|
|
5
|
+
* If you need sub-request then use 'subRequestIndex' to check current request index in functions below.
|
|
6
|
+
* Also use array for 'httpMethod'.
|
|
7
|
+
*
|
|
8
|
+
* If the endpoint of dedicated provider has pagination then you should customize the behavior using
|
|
9
|
+
* "changeQueryParametersForPageNumber", "checkWhetherResponseIsForLastPage".
|
|
10
|
+
*
|
|
11
|
+
* We perform RPS counting all over the App to avoid blocking our clients due to abuses of the providers.
|
|
12
|
+
*
|
|
13
|
+
* @param endpoint {string} URL to the provider's endpoint. Note: you can customize it using composeQueryString
|
|
14
|
+
* @param [httpMethod] {string|string[]} one of "get", "post", "put", "patch", "delete" or an array of these values
|
|
15
|
+
* for request having sub-requests
|
|
16
|
+
* @param [timeout] {number} number of milliseconds to wait for the response
|
|
17
|
+
* @param [apiGroup] {ApiGroup} singleton object containing parameters of API group. Helpful when you use the same
|
|
18
|
+
* api for different providers to avoid hardcoding RPS inside each provider what can cause mistakes
|
|
19
|
+
* @param [specificHeaders] {Object} contains specific keys (headers) and values (their content) if needed for this provider
|
|
20
|
+
* @param [maxPageLength] {number} optional number of items per page if the request supports pagination
|
|
21
|
+
*/
|
|
22
|
+
constructor(
|
|
23
|
+
endpoint,
|
|
24
|
+
httpMethod,
|
|
25
|
+
timeout,
|
|
26
|
+
apiGroup,
|
|
27
|
+
specificHeaders = {},
|
|
28
|
+
maxPageLength = Number.MAX_SAFE_INTEGER
|
|
29
|
+
) {
|
|
30
|
+
this.endpoint = endpoint;
|
|
31
|
+
this.httpMethod = httpMethod ?? "get";
|
|
32
|
+
// TODO: [refactoring, critical] We have two timeouts for robust data retrieval - here and inside the service method call, need to remain the only
|
|
33
|
+
this.timeout = timeout ?? 10000;
|
|
34
|
+
// TODO: [refactoring, critical] We need single place for all RPSes as we use them as hardcoded constants now inside different services
|
|
35
|
+
this.apiGroup = apiGroup;
|
|
36
|
+
this.maxPageLength = maxPageLength ?? Number.MAX_SAFE_INTEGER;
|
|
37
|
+
this.niceFactor = 1;
|
|
38
|
+
this.specificHeaders = specificHeaders ?? {};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getRps() {
|
|
42
|
+
return this.apiGroup.rps ?? 2;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
isRpsExceeded() {
|
|
46
|
+
return this.apiGroup.isRpsExceeded();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
actualizeLastCalledTimestamp() {
|
|
50
|
+
this.apiGroup.actualizeLastCalledTimestamp();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getApiGroupId() {
|
|
54
|
+
return this.apiGroup.id;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Some endpoint can require several sub requests. Example is one request to get confirmed transactions
|
|
59
|
+
* and another request for unconfirmed transactions. You should override this method to return true for such requests.
|
|
60
|
+
*
|
|
61
|
+
* @return {boolean} true if this provider requires several requests to retrieve the data
|
|
62
|
+
*/
|
|
63
|
+
doesRequireSubRequests() {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Some endpoint support pagination. Override this method if so and implement corresponding methods.
|
|
69
|
+
*
|
|
70
|
+
* @return {boolean} true if this provider requires several requests to retrieve the data
|
|
71
|
+
*/
|
|
72
|
+
doesSupportPagination() {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Composes a query string to be added to the endpoint of this provider.
|
|
78
|
+
*
|
|
79
|
+
* @param params {any[]} params array passed to the RobustExternalAPICallerService
|
|
80
|
+
* @param [subRequestIndex] {number} optional number of the sub-request the call is performed for
|
|
81
|
+
* @returns {string} query string to be concatenated with endpoint
|
|
82
|
+
*/
|
|
83
|
+
composeQueryString(params, subRequestIndex = 0) {
|
|
84
|
+
return "";
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Composes a body to be added to the request
|
|
89
|
+
*
|
|
90
|
+
* @param params {any[]} params array passed to the RobustExternalAPICallerService
|
|
91
|
+
* @param [subRequestIndex] {number} optional number of the sub-request the call is performed for
|
|
92
|
+
* @returns {string}
|
|
93
|
+
*/
|
|
94
|
+
composeBody(params, subRequestIndex = 0) {
|
|
95
|
+
return "";
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Extracts data from the response and returns it
|
|
100
|
+
*
|
|
101
|
+
* @param response {Object} HTTP response returned by provider
|
|
102
|
+
* @param [params] {any[]} params array passed to the RobustExternalAPICallerService
|
|
103
|
+
* @param [subRequestIndex] {number} optional number of the sub-request the call is performed for
|
|
104
|
+
* @param iterationsData {any[]} array of data retrieved from previous sub-requests
|
|
105
|
+
* @returns {any}
|
|
106
|
+
*/
|
|
107
|
+
getDataByResponse(response, params = [], subRequestIndex = 0, iterationsData = []) {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Function changing the query string according to page number and previous response
|
|
113
|
+
* Only for endpoints supporting pagination
|
|
114
|
+
*
|
|
115
|
+
* @param params {any[]} params array passed to the RobustExternalAPICallerService
|
|
116
|
+
* @param previousResponse {Object} HTTP response returned by provider for previous call (previous page)
|
|
117
|
+
* @param pageNumber {number} new page number. We count from 0. You need to manually increment with 1 if your
|
|
118
|
+
* provider counts pages starting with 1
|
|
119
|
+
* @param [subRequestIndex] {number} optional number of the sub-request the call is performed for
|
|
120
|
+
* @returns {any[]}
|
|
121
|
+
*/
|
|
122
|
+
changeQueryParametersForPageNumber(params, previousResponse, pageNumber, subRequestIndex = 0) {
|
|
123
|
+
return params;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Function checking whether the response is for the last page to stop requesting for a next page.
|
|
128
|
+
* Only for endpoints supporting pagination.
|
|
129
|
+
*
|
|
130
|
+
* @param previousResponse {Object} HTTP response returned by provider for previous call (previous page)
|
|
131
|
+
* @param currentResponse {Object} HTTP response returned by provider for current call (current page, next after the previous)
|
|
132
|
+
* @param currentPageNumber {number} current page number (for current response)
|
|
133
|
+
* @param [subRequestIndex] {number} optional number of the sub-request the call is performed for
|
|
134
|
+
* @returns {boolean}
|
|
135
|
+
*/
|
|
136
|
+
checkWhetherResponseIsForLastPage(previousResponse, currentResponse, currentPageNumber, subRequestIndex = 0) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Resets the nice factor to default value
|
|
142
|
+
*/
|
|
143
|
+
resetNiceFactor() {
|
|
144
|
+
this.niceFactor = 1;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Internal method used for requests requiring sub-requests.
|
|
149
|
+
*
|
|
150
|
+
* @param iterationsData {any[]} iterations data retrieved from getDataByResponse called per sub-request.
|
|
151
|
+
* @return {any} by default flatten the passed iterations data array. Should be redefined if you need another logic.
|
|
152
|
+
*/
|
|
153
|
+
incorporateIterationsData(iterationsData) {
|
|
154
|
+
return iterationsData.flat();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { improveAndRethrow } from "../common-apis/utils/errorUtils.js";
|
|
2
|
+
import { Logger } from "../common-apis/utils/logging/logger.js";
|
|
3
|
+
|
|
4
|
+
export class ExternalServicesStatsCollector {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.stats = new Map();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
externalServiceFailed(serviceUrl, message) {
|
|
10
|
+
try {
|
|
11
|
+
const processMessage = (stat, errorMessage) => {
|
|
12
|
+
const errors = stat.errors ?? {};
|
|
13
|
+
errorMessage = errorMessage ?? "";
|
|
14
|
+
if (errorMessage.match(/.*network.+error.*/i)) {
|
|
15
|
+
errors["networkError"] = (errors["networkError"] || 0) + 1;
|
|
16
|
+
} else if (errorMessage.match(/.*timeout.+exceeded.*/i)) {
|
|
17
|
+
errors["timeoutExceeded"] = (errors["timeoutExceeded"] || 0) + 1;
|
|
18
|
+
} else if (errors["other"]) {
|
|
19
|
+
errors["other"].push(message);
|
|
20
|
+
} else {
|
|
21
|
+
errors["other"] = [message];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
stat.errors = errors;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (this.stats.has(serviceUrl)) {
|
|
28
|
+
const stat = this.stats.get(serviceUrl);
|
|
29
|
+
stat.callsCount += 1;
|
|
30
|
+
stat.failsCount += 1;
|
|
31
|
+
processMessage(stat, message);
|
|
32
|
+
} else {
|
|
33
|
+
this.stats.set(serviceUrl, { callsCount: 1, failsCount: 1 });
|
|
34
|
+
processMessage(this.stats.get(serviceUrl), message);
|
|
35
|
+
}
|
|
36
|
+
} catch (e) {
|
|
37
|
+
improveAndRethrow(e, "externalServiceFailed");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
externalServiceCalledWithoutError(serviceUrl) {
|
|
42
|
+
try {
|
|
43
|
+
if (this.stats.has(serviceUrl)) {
|
|
44
|
+
const stat = this.stats.get(serviceUrl);
|
|
45
|
+
stat.callsCount += 1;
|
|
46
|
+
} else {
|
|
47
|
+
this.stats.set(serviceUrl, { callsCount: 1, failsCount: 0 });
|
|
48
|
+
}
|
|
49
|
+
} catch (e) {
|
|
50
|
+
improveAndRethrow(e, "externalServiceCalledWithoutError");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns statistics about external services failures.
|
|
56
|
+
* Provides how many calls were performed and what the percent of failed calls. Also returns errors stat.
|
|
57
|
+
*
|
|
58
|
+
* @return {Array<object>} Array of objects of type { failsPerCent: number, calls: number }
|
|
59
|
+
* sorted by the highest fails percent desc
|
|
60
|
+
*/
|
|
61
|
+
getStats() {
|
|
62
|
+
try {
|
|
63
|
+
return Array.from(this.stats.keys())
|
|
64
|
+
.map(key => {
|
|
65
|
+
const stat = this.stats.get(key);
|
|
66
|
+
return {
|
|
67
|
+
url: key,
|
|
68
|
+
failsPerCent: ((stat.failsCount / stat.callsCount) * 100).toFixed(2),
|
|
69
|
+
calls: stat.callsCount,
|
|
70
|
+
errors: stat.errors ?? [],
|
|
71
|
+
};
|
|
72
|
+
})
|
|
73
|
+
.sort((s1, s2) => s1.failsPerCent - s2.failsPerCent);
|
|
74
|
+
} catch (e) {
|
|
75
|
+
Logger.logError(e, "getStats");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { improveAndRethrow } from "../common-apis/utils/errorUtils.js";
|
|
2
|
+
import { safeStringify } from "../common-apis/utils/safeStringify.js";
|
|
3
|
+
import { Logger } from "../common-apis/utils/logging/logger.js";
|
|
4
|
+
import { postponeExecution } from "../common-apis/utils/postponeExecution.js";
|
|
5
|
+
import { AxiosAdapter } from "../common-apis/adapters/axiosAdapter.js";
|
|
6
|
+
|
|
7
|
+
import { concurrentCalculationsMetadataHolder } from "./concurrentCalculationsMetadataHolder.js";
|
|
8
|
+
import { ExternalServicesStatsCollector } from "./externalServicesStatsCollector.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* TODO: [refactoring, critical] update backend copy of this service. Also there is a task to extract this
|
|
12
|
+
* service and other related to it stuff to dedicated npm package task_id=b008ee5e4a3f42c08c73831c4bb3db4e
|
|
13
|
+
*
|
|
14
|
+
* Template service needed to avoid duplication of the same logic when we need to call
|
|
15
|
+
* external APIs to retrieve some data. The idea is to use several API providers to retrieve the same data. It helps to
|
|
16
|
+
* improve the reliability of a data retrieval.
|
|
17
|
+
*/
|
|
18
|
+
export class RobustExternalAPICallerService {
|
|
19
|
+
static statsCollector = new ExternalServicesStatsCollector();
|
|
20
|
+
|
|
21
|
+
static getStats() {
|
|
22
|
+
return this.statsCollector.getStats();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param bio {string} service name for logging
|
|
27
|
+
* @param providersData {ExternalApiProvider[]} array of providers
|
|
28
|
+
* @param [logger] {function} function to be used for logging
|
|
29
|
+
*/
|
|
30
|
+
constructor(bio, providersData, logger = Logger.logError) {
|
|
31
|
+
providersData.forEach(provider => {
|
|
32
|
+
if ((!provider.endpoint && provider.endpoint !== "") || !provider.httpMethod) {
|
|
33
|
+
throw new Error(`Wrong format of providers data for: ${JSON.stringify(provider)}`);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// We add niceFactor - just number to order the providers array by. It is helpful to call
|
|
38
|
+
// less robust APIs only if more robust fails
|
|
39
|
+
this.providers = providersData;
|
|
40
|
+
providersData.forEach(provider => provider.resetNiceFactor());
|
|
41
|
+
this.bio = bio;
|
|
42
|
+
this._logger = (...args) => {
|
|
43
|
+
Logger.logError(...args);
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static defaultRPSFactor = 1;
|
|
48
|
+
static rpsMultiplier = 1.05;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Performs data retrieval from external APIs. Tries providers till the data is retrieved.
|
|
52
|
+
*
|
|
53
|
+
* @param parametersValues {array} array of values of the parameters for URL query string [and/or body]
|
|
54
|
+
* @param timeoutMS {number} http timeout to wait for response. If provider has its specific timeout value then it is used
|
|
55
|
+
* @param [cancelToken] {object|undefined} axios token to force-cancel requests from high-level code
|
|
56
|
+
* @param [attemptsCount] {number|undefined} number of attempts to be performed
|
|
57
|
+
* @param [doNotFailForNowData] {boolean|undefined} pass true if you do not want us to throw an error if we retrieved null data from all the providers
|
|
58
|
+
* @return {Promise<any>} resolving to retrieved data (or array of results if specific provider requires
|
|
59
|
+
* several requests. NOTE: we flatten nested arrays - results of each separate request done for the specific provider)
|
|
60
|
+
* @throws Error if requests to all providers are failed
|
|
61
|
+
*/
|
|
62
|
+
async callExternalAPI(
|
|
63
|
+
parametersValues = [],
|
|
64
|
+
timeoutMS = 3500,
|
|
65
|
+
cancelToken = null,
|
|
66
|
+
attemptsCount = 1,
|
|
67
|
+
doNotFailForNowData = false
|
|
68
|
+
) {
|
|
69
|
+
let result;
|
|
70
|
+
const calculationUuid = concurrentCalculationsMetadataHolder.startCalculation(this.bio);
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
for (let i = 0; (i < attemptsCount || result?.shouldBeForceRetried) && result?.data == null; ++i) {
|
|
74
|
+
/**
|
|
75
|
+
* We use rpsFactor to improve re-attempting to call the providers if the last attempt resulted with
|
|
76
|
+
* the fail due to abused RPSes of some (most part of) providers.
|
|
77
|
+
* The _performCallAttempt in such a case will return increased rpsFactor inside the result object.
|
|
78
|
+
*/
|
|
79
|
+
const rpsFactor = result ? result.rpsFactor : RobustExternalAPICallerService.defaultRPSFactor;
|
|
80
|
+
|
|
81
|
+
result = null;
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
if (i === 0 && !result?.shouldBeForceRetried) {
|
|
85
|
+
result = await this._performCallAttempt(
|
|
86
|
+
parametersValues,
|
|
87
|
+
timeoutMS,
|
|
88
|
+
cancelToken,
|
|
89
|
+
rpsFactor,
|
|
90
|
+
doNotFailForNowData
|
|
91
|
+
);
|
|
92
|
+
} else {
|
|
93
|
+
const maxRps = Math.max(...this.providers.map(provider => provider.getRps() ?? 0));
|
|
94
|
+
const waitingTimeMs = maxRps ? 1000 / (maxRps / rpsFactor) : 0;
|
|
95
|
+
|
|
96
|
+
result = await new Promise((resolve, reject) => {
|
|
97
|
+
setTimeout(async () => {
|
|
98
|
+
try {
|
|
99
|
+
resolve(
|
|
100
|
+
await this._performCallAttempt(
|
|
101
|
+
parametersValues,
|
|
102
|
+
timeoutMS,
|
|
103
|
+
cancelToken,
|
|
104
|
+
rpsFactor,
|
|
105
|
+
doNotFailForNowData
|
|
106
|
+
)
|
|
107
|
+
);
|
|
108
|
+
} catch (e) {
|
|
109
|
+
reject(e);
|
|
110
|
+
}
|
|
111
|
+
}, waitingTimeMs);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if (result.errors?.length) {
|
|
115
|
+
const errors = result.errors;
|
|
116
|
+
this._logger(
|
|
117
|
+
new Error(
|
|
118
|
+
`Failed at attempt ${i}. ${errors.length} errors. Messages: ${safeStringify(
|
|
119
|
+
errors.map(error => error.message)
|
|
120
|
+
)}: ${safeStringify(errors)}.`
|
|
121
|
+
),
|
|
122
|
+
`${this.bio}.callExternalAPI`,
|
|
123
|
+
"",
|
|
124
|
+
true
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
} catch (e) {
|
|
128
|
+
this._logger(e, `${this.bio}.callExternalAPI`, "Failed to perform external providers calling");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (result?.data == null) {
|
|
133
|
+
// TODO: [feature, moderate] looks like we should not fail for null data as it is strange - the provider will fail when processing data internally
|
|
134
|
+
const error = new Error(
|
|
135
|
+
`Failed to retrieve data. It means all attempts have been failed. DEV: add more attempts to this data retrieval`
|
|
136
|
+
);
|
|
137
|
+
if (!doNotFailForNowData) {
|
|
138
|
+
throw error;
|
|
139
|
+
} else {
|
|
140
|
+
this._logger(error, `${this.bio}.callExternalAPI`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return result?.data;
|
|
145
|
+
} catch (e) {
|
|
146
|
+
improveAndRethrow(e, `${this.bio}.callExternalAPI`);
|
|
147
|
+
} finally {
|
|
148
|
+
concurrentCalculationsMetadataHolder.endCalculation(this.bio, calculationUuid);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async _performCallAttempt(parametersValues, timeoutMS, cancelToken, rpsFactor, doNotFailForNowData) {
|
|
153
|
+
const providers = this._reorderProvidersByNiceFactor();
|
|
154
|
+
let data = undefined,
|
|
155
|
+
providerIndex = 0,
|
|
156
|
+
countOfRequestsDeclinedByRps = 0,
|
|
157
|
+
errors = [];
|
|
158
|
+
while (!data && providerIndex < providers.length) {
|
|
159
|
+
let provider = providers[providerIndex];
|
|
160
|
+
if (provider.isRpsExceeded()) {
|
|
161
|
+
/**
|
|
162
|
+
* Current provider's RPS is exceeded, so we try next provider. Also, we count such cases to make
|
|
163
|
+
* a decision about the force-retry need.
|
|
164
|
+
*/
|
|
165
|
+
++providerIndex;
|
|
166
|
+
++countOfRequestsDeclinedByRps;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const axiosConfig = {
|
|
172
|
+
...(cancelToken ? { cancelToken } : {}),
|
|
173
|
+
timeout: provider.timeout || timeoutMS,
|
|
174
|
+
headers: provider.specificHeaders ?? {},
|
|
175
|
+
};
|
|
176
|
+
const httpMethods = Array.isArray(provider.httpMethod) ? provider.httpMethod : [provider.httpMethod];
|
|
177
|
+
const iterationsData = [];
|
|
178
|
+
for (let subRequestIndex = 0; subRequestIndex < httpMethods.length; ++subRequestIndex) {
|
|
179
|
+
const query = provider.composeQueryString(parametersValues, subRequestIndex);
|
|
180
|
+
const endpoint = `${provider.endpoint}${query}`;
|
|
181
|
+
const axiosParams = [endpoint, axiosConfig];
|
|
182
|
+
if (["post", "put", "patch"].find(method => method === httpMethods[subRequestIndex])) {
|
|
183
|
+
const body = provider.composeBody(parametersValues, subRequestIndex) ?? null;
|
|
184
|
+
axiosParams.splice(1, 0, body);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let pageNumber = 0;
|
|
188
|
+
const responsesForPages = [];
|
|
189
|
+
let hasNextPage = provider.doesSupportPagination();
|
|
190
|
+
do {
|
|
191
|
+
if (subRequestIndex === 0 && pageNumber === 0) {
|
|
192
|
+
provider.actualizeLastCalledTimestamp();
|
|
193
|
+
responsesForPages[pageNumber] = await AxiosAdapter.call(
|
|
194
|
+
httpMethods[subRequestIndex],
|
|
195
|
+
...axiosParams
|
|
196
|
+
);
|
|
197
|
+
RobustExternalAPICallerService.statsCollector.externalServiceCalledWithoutError(
|
|
198
|
+
provider.getApiGroupId()
|
|
199
|
+
);
|
|
200
|
+
} else {
|
|
201
|
+
if (pageNumber > 0) {
|
|
202
|
+
const actualizedParams = provider.changeQueryParametersForPageNumber(
|
|
203
|
+
parametersValues,
|
|
204
|
+
responsesForPages[pageNumber - 1],
|
|
205
|
+
pageNumber,
|
|
206
|
+
subRequestIndex
|
|
207
|
+
);
|
|
208
|
+
const query = provider.composeQueryString(actualizedParams, subRequestIndex);
|
|
209
|
+
axiosParams[0] = `${provider.endpoint}${query}`;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* For second and more request we postpone each request to not exceed RPS
|
|
213
|
+
* of current provider. We use rpsFactor to dynamically increase the rps to avoid
|
|
214
|
+
* too frequent calls if we continue failing to retrieve the data due to RPS exceeding.
|
|
215
|
+
* TODO: [dev] test RPS factor logic (units or integration)
|
|
216
|
+
*/
|
|
217
|
+
|
|
218
|
+
const waitingTimeMS = provider.getRps() ? 1000 / (provider.getRps() / rpsFactor) : 0;
|
|
219
|
+
|
|
220
|
+
const postponeUntilRpsExceeded = async (recursionLevel = 0) => {
|
|
221
|
+
return await postponeExecution(async () => {
|
|
222
|
+
const maxCountOfPostponingAttempts = 2;
|
|
223
|
+
if (provider.isRpsExceeded() && recursionLevel < maxCountOfPostponingAttempts) {
|
|
224
|
+
return await postponeUntilRpsExceeded(recursionLevel + 1);
|
|
225
|
+
}
|
|
226
|
+
provider.actualizeLastCalledTimestamp();
|
|
227
|
+
return await AxiosAdapter.call(httpMethods[subRequestIndex], ...axiosParams);
|
|
228
|
+
}, waitingTimeMS);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
responsesForPages[pageNumber] = await postponeUntilRpsExceeded();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (hasNextPage) {
|
|
235
|
+
hasNextPage = !provider.checkWhetherResponseIsForLastPage(
|
|
236
|
+
responsesForPages[pageNumber - 1],
|
|
237
|
+
responsesForPages[pageNumber],
|
|
238
|
+
pageNumber,
|
|
239
|
+
subRequestIndex
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
pageNumber++;
|
|
243
|
+
} while (hasNextPage);
|
|
244
|
+
|
|
245
|
+
const responsesDataForPages = responsesForPages.map(response =>
|
|
246
|
+
provider.getDataByResponse(response, parametersValues, subRequestIndex, iterationsData)
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
let allData = responsesDataForPages;
|
|
250
|
+
if (Array.isArray(responsesDataForPages[0])) {
|
|
251
|
+
allData = responsesDataForPages.flat();
|
|
252
|
+
} else if (responsesDataForPages.length === 1) {
|
|
253
|
+
allData = responsesDataForPages[0];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
iterationsData.push(allData);
|
|
257
|
+
}
|
|
258
|
+
if (iterationsData.length) {
|
|
259
|
+
if (httpMethods.length > 1) {
|
|
260
|
+
data = provider.incorporateIterationsData(iterationsData);
|
|
261
|
+
} else {
|
|
262
|
+
data = iterationsData[0];
|
|
263
|
+
}
|
|
264
|
+
} else if (!doNotFailForNowData) {
|
|
265
|
+
RobustExternalAPICallerService.statsCollector.externalServiceFailed(
|
|
266
|
+
provider.getApiGroupId(),
|
|
267
|
+
"Response data was null for some reason"
|
|
268
|
+
);
|
|
269
|
+
punishProvider(provider);
|
|
270
|
+
}
|
|
271
|
+
} catch (e) {
|
|
272
|
+
punishProvider(provider);
|
|
273
|
+
RobustExternalAPICallerService.statsCollector.externalServiceFailed(
|
|
274
|
+
provider.getApiGroupId(),
|
|
275
|
+
e?.message
|
|
276
|
+
);
|
|
277
|
+
errors.push(e);
|
|
278
|
+
} finally {
|
|
279
|
+
providerIndex++;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// If we are declining more than 50% of providers (by exceeding RPS) then we note that it better to retry the whole process of providers requesting
|
|
284
|
+
const shouldBeForceRetried = data == null && countOfRequestsDeclinedByRps > Math.floor(providers.length * 0.5);
|
|
285
|
+
const rpsMultiplier = shouldBeForceRetried ? RobustExternalAPICallerService.rpsMultiplier : 1;
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
data: data ?? null,
|
|
289
|
+
shouldBeForceRetried,
|
|
290
|
+
rpsFactor: rpsFactor * rpsMultiplier,
|
|
291
|
+
errors,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
_reorderProvidersByNiceFactor() {
|
|
296
|
+
const providersCopy = [...this.providers];
|
|
297
|
+
|
|
298
|
+
return providersCopy.sort((p1, p2) => p2.niceFactor - p1.niceFactor);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function punishProvider(provider) {
|
|
303
|
+
provider.niceFactor = provider.niceFactor - 1;
|
|
304
|
+
}
|